@@ 3,7 3,6 @@ package eu.siacs.conversations.xmpp.jingle;
import android.content.Context;
import android.util.Log;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.ListenableFuture;
@@ 127,7 126,7 @@ class VideoSourceWrapper {
this.context = context;
}
- public Optional<VideoSourceWrapper> create() {
+ public VideoSourceWrapper create() {
final CameraEnumerator enumerator = new Camera2Enumerator(context);
final Set<String> deviceNames = ImmutableSet.copyOf(enumerator.getDeviceNames());
for (final String deviceName : deviceNames) {
@@ 135,17 134,16 @@ class VideoSourceWrapper {
final VideoSourceWrapper videoSourceWrapper =
of(enumerator, deviceName, deviceNames);
if (videoSourceWrapper == null) {
- return Optional.absent();
+ return null;
}
videoSourceWrapper.isFrontCamera = true;
- return Optional.of(videoSourceWrapper);
+ return videoSourceWrapper;
}
}
if (deviceNames.size() == 0) {
- return Optional.absent();
+ return null;
} else {
- return Optional.fromNullable(
- of(enumerator, Iterables.get(deviceNames, 0), deviceNames));
+ return of(enumerator, Iterables.get(deviceNames, 0), deviceNames);
}
}
@@ 196,6 196,7 @@ public class WebRTCWrapper {
+ ")");
}
};
+ @Nullable private PeerConnectionFactory peerConnectionFactory = null;
@Nullable private PeerConnection peerConnection = null;
private AppRTCAudioManager appRTCAudioManager = null;
private ToneManager toneManager = null;
@@ 260,7 261,7 @@ public class WebRTCWrapper {
String.format(
"setUseHardwareAcousticEchoCanceler(%s) model=%s",
setUseHardwareAcousticEchoCanceler, Build.MODEL));
- PeerConnectionFactory peerConnectionFactory =
+ this.peerConnectionFactory =
PeerConnectionFactory.builder()
.setVideoDecoderFactory(
new DefaultVideoDecoderFactory(eglBase.getEglBaseContext()))
@@ 268,7 269,7 @@ public class WebRTCWrapper {
new DefaultVideoEncoderFactory(
eglBase.getEglBaseContext(), true, true))
.setAudioDeviceModule(
- JavaAudioDeviceModule.builder(context)
+ JavaAudioDeviceModule.builder(requireContext())
.setUseHardwareAcousticEchoCanceler(
setUseHardwareAcousticEchoCanceler)
.createAudioDeviceModule())
@@ 276,36 277,18 @@ public class WebRTCWrapper {
final PeerConnection.RTCConfiguration rtcConfig = buildConfiguration(iceServers);
final PeerConnection peerConnection =
- peerConnectionFactory.createPeerConnection(rtcConfig, peerConnectionObserver);
+ requirePeerConnectionFactory()
+ .createPeerConnection(rtcConfig, peerConnectionObserver);
if (peerConnection == null) {
throw new InitializationException("Unable to create PeerConnection");
}
- final Optional<VideoSourceWrapper> optionalVideoSourceWrapper =
- media.contains(Media.VIDEO)
- ? new VideoSourceWrapper.Factory(requireContext()).create()
- : Optional.absent();
-
- if (optionalVideoSourceWrapper.isPresent()) {
- this.videoSourceWrapper = optionalVideoSourceWrapper.get();
- this.videoSourceWrapper.initialize(
- peerConnectionFactory, context, eglBase.getEglBaseContext());
- this.videoSourceWrapper.startCapture();
-
- final VideoTrack videoTrack =
- peerConnectionFactory.createVideoTrack(
- "my-video-track", this.videoSourceWrapper.getVideoSource());
-
- this.localVideoTrack = TrackWrapper.addTrack(peerConnection, videoTrack);
+ if (media.contains(Media.VIDEO)) {
+ addVideoTrack(peerConnection);
}
if (media.contains(Media.AUDIO)) {
- // set up audio track
- final AudioSource audioSource =
- peerConnectionFactory.createAudioSource(new MediaConstraints());
- final AudioTrack audioTrack =
- peerConnectionFactory.createAudioTrack("my-audio-track", audioSource);
- this.localAudioTrack = TrackWrapper.addTrack(peerConnection, audioTrack);
+ addAudioTrack(peerConnection);
}
peerConnection.setAudioPlayout(true);
peerConnection.setAudioRecording(true);
@@ 313,6 296,58 @@ public class WebRTCWrapper {
this.peerConnection = peerConnection;
}
+ private VideoSourceWrapper initializeVideoSourceWrapper() {
+ final VideoSourceWrapper existingVideoSourceWrapper = this.videoSourceWrapper;
+ if (existingVideoSourceWrapper != null) {
+ existingVideoSourceWrapper.startCapture();
+ return existingVideoSourceWrapper;
+ }
+ final VideoSourceWrapper videoSourceWrapper =
+ new VideoSourceWrapper.Factory(requireContext()).create();
+ if (videoSourceWrapper == null) {
+ throw new IllegalStateException("Could not instantiate VideoSourceWrapper");
+ }
+ videoSourceWrapper.initialize(
+ requirePeerConnectionFactory(), requireContext(), eglBase.getEglBaseContext());
+ videoSourceWrapper.startCapture();
+ return videoSourceWrapper;
+ }
+
+ public synchronized boolean addTrack(final Media media) {
+ if (media == Media.VIDEO) {
+ return addVideoTrack(requirePeerConnection());
+ } else if (media == Media.AUDIO) {
+ return addAudioTrack(requirePeerConnection());
+ }
+ throw new IllegalStateException(String.format("Could not add track for %s", media));
+ }
+
+ private boolean addAudioTrack(final PeerConnection peerConnection) {
+ final AudioSource audioSource =
+ requirePeerConnectionFactory().createAudioSource(new MediaConstraints());
+ final AudioTrack audioTrack =
+ requirePeerConnectionFactory().createAudioTrack("my-audio-track", audioSource);
+ this.localAudioTrack = TrackWrapper.addTrack(peerConnection, audioTrack);
+ return true;
+ }
+
+ private boolean addVideoTrack(final PeerConnection peerConnection) {
+ Preconditions.checkState(
+ this.localVideoTrack == null, "A local video track already exists");
+ final VideoSourceWrapper videoSourceWrapper;
+ try {
+ videoSourceWrapper = initializeVideoSourceWrapper();
+ } catch (final IllegalStateException e) {
+ Log.d(Config.LOGTAG, "could not add video track", e);
+ return false;
+ }
+ final VideoTrack videoTrack =
+ requirePeerConnectionFactory()
+ .createVideoTrack("my-video-track", videoSourceWrapper.getVideoSource());
+ this.localVideoTrack = TrackWrapper.addTrack(peerConnection, videoTrack);
+ return true;
+ }
+
private static PeerConnection.RTCConfiguration buildConfiguration(
final List<PeerConnection.IceServer> iceServers) {
final PeerConnection.RTCConfiguration rtcConfig =
@@ 344,6 379,7 @@ public class WebRTCWrapper {
synchronized void close() {
final PeerConnection peerConnection = this.peerConnection;
+ final PeerConnectionFactory peerConnectionFactory = this.peerConnectionFactory;
final VideoSourceWrapper videoSourceWrapper = this.videoSourceWrapper;
final AppRTCAudioManager audioManager = this.appRTCAudioManager;
final EglBase eglBase = this.eglBase;
@@ 363,12 399,15 @@ public class WebRTCWrapper {
} catch (final InterruptedException e) {
Log.e(Config.LOGTAG, "unable to stop capturing");
}
- // TODO call dispose
+ videoSourceWrapper.dispose();
}
if (eglBase != null) {
eglBase.release();
this.eglBase = null;
}
+ if (peerConnectionFactory != null) {
+ peerConnectionFactory.dispose();
+ }
}
synchronized void verifyClosed() {
@@ 530,6 569,7 @@ public class WebRTCWrapper {
}
}
+ @Nonnull
private PeerConnection requirePeerConnection() {
final PeerConnection peerConnection = this.peerConnection;
if (peerConnection == null) {
@@ 538,6 578,15 @@ public class WebRTCWrapper {
return peerConnection;
}
+ @Nonnull
+ private PeerConnectionFactory requirePeerConnectionFactory() {
+ final PeerConnectionFactory peerConnectionFactory = this.peerConnectionFactory;
+ if (peerConnectionFactory == null) {
+ throw new IllegalStateException("Make sure PeerConnectionFactory is initialized");
+ }
+ return peerConnectionFactory;
+ }
+
void addIceCandidate(IceCandidate iceCandidate) {
requirePeerConnection().addIceCandidate(iceCandidate);
}
@@ 626,5 675,4 @@ public class WebRTCWrapper {
super(message);
}
}
-
}