refactor WebRTCWrapper to allow for track adds

This commit is contained in:
Daniel Gultsch 2022-11-19 13:03:34 +01:00
parent 8fb2c11771
commit 27d8da2ab4
2 changed files with 80 additions and 34 deletions

View file

@ -3,7 +3,6 @@ package eu.siacs.conversations.xmpp.jingle;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -127,7 +126,7 @@ class VideoSourceWrapper {
this.context = context; this.context = context;
} }
public Optional<VideoSourceWrapper> create() { public VideoSourceWrapper create() {
final CameraEnumerator enumerator = new Camera2Enumerator(context); final CameraEnumerator enumerator = new Camera2Enumerator(context);
final Set<String> deviceNames = ImmutableSet.copyOf(enumerator.getDeviceNames()); final Set<String> deviceNames = ImmutableSet.copyOf(enumerator.getDeviceNames());
for (final String deviceName : deviceNames) { for (final String deviceName : deviceNames) {
@ -135,17 +134,16 @@ class VideoSourceWrapper {
final VideoSourceWrapper videoSourceWrapper = final VideoSourceWrapper videoSourceWrapper =
of(enumerator, deviceName, deviceNames); of(enumerator, deviceName, deviceNames);
if (videoSourceWrapper == null) { if (videoSourceWrapper == null) {
return Optional.absent(); return null;
} }
videoSourceWrapper.isFrontCamera = true; videoSourceWrapper.isFrontCamera = true;
return Optional.of(videoSourceWrapper); return videoSourceWrapper;
} }
} }
if (deviceNames.size() == 0) { if (deviceNames.size() == 0) {
return Optional.absent(); return null;
} else { } else {
return Optional.fromNullable( return of(enumerator, Iterables.get(deviceNames, 0), deviceNames);
of(enumerator, Iterables.get(deviceNames, 0), deviceNames));
} }
} }

View file

@ -196,6 +196,7 @@ public class WebRTCWrapper {
+ ")"); + ")");
} }
}; };
@Nullable private PeerConnectionFactory peerConnectionFactory = null;
@Nullable private PeerConnection peerConnection = null; @Nullable private PeerConnection peerConnection = null;
private AppRTCAudioManager appRTCAudioManager = null; private AppRTCAudioManager appRTCAudioManager = null;
private ToneManager toneManager = null; private ToneManager toneManager = null;
@ -260,7 +261,7 @@ public class WebRTCWrapper {
String.format( String.format(
"setUseHardwareAcousticEchoCanceler(%s) model=%s", "setUseHardwareAcousticEchoCanceler(%s) model=%s",
setUseHardwareAcousticEchoCanceler, Build.MODEL)); setUseHardwareAcousticEchoCanceler, Build.MODEL));
PeerConnectionFactory peerConnectionFactory = this.peerConnectionFactory =
PeerConnectionFactory.builder() PeerConnectionFactory.builder()
.setVideoDecoderFactory( .setVideoDecoderFactory(
new DefaultVideoDecoderFactory(eglBase.getEglBaseContext())) new DefaultVideoDecoderFactory(eglBase.getEglBaseContext()))
@ -268,7 +269,7 @@ public class WebRTCWrapper {
new DefaultVideoEncoderFactory( new DefaultVideoEncoderFactory(
eglBase.getEglBaseContext(), true, true)) eglBase.getEglBaseContext(), true, true))
.setAudioDeviceModule( .setAudioDeviceModule(
JavaAudioDeviceModule.builder(context) JavaAudioDeviceModule.builder(requireContext())
.setUseHardwareAcousticEchoCanceler( .setUseHardwareAcousticEchoCanceler(
setUseHardwareAcousticEchoCanceler) setUseHardwareAcousticEchoCanceler)
.createAudioDeviceModule()) .createAudioDeviceModule())
@ -276,36 +277,18 @@ public class WebRTCWrapper {
final PeerConnection.RTCConfiguration rtcConfig = buildConfiguration(iceServers); final PeerConnection.RTCConfiguration rtcConfig = buildConfiguration(iceServers);
final PeerConnection peerConnection = final PeerConnection peerConnection =
peerConnectionFactory.createPeerConnection(rtcConfig, peerConnectionObserver); requirePeerConnectionFactory()
.createPeerConnection(rtcConfig, peerConnectionObserver);
if (peerConnection == null) { if (peerConnection == null) {
throw new InitializationException("Unable to create PeerConnection"); throw new InitializationException("Unable to create PeerConnection");
} }
final Optional<VideoSourceWrapper> optionalVideoSourceWrapper = if (media.contains(Media.VIDEO)) {
media.contains(Media.VIDEO) addVideoTrack(peerConnection);
? 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.AUDIO)) { if (media.contains(Media.AUDIO)) {
// set up audio track addAudioTrack(peerConnection);
final AudioSource audioSource =
peerConnectionFactory.createAudioSource(new MediaConstraints());
final AudioTrack audioTrack =
peerConnectionFactory.createAudioTrack("my-audio-track", audioSource);
this.localAudioTrack = TrackWrapper.addTrack(peerConnection, audioTrack);
} }
peerConnection.setAudioPlayout(true); peerConnection.setAudioPlayout(true);
peerConnection.setAudioRecording(true); peerConnection.setAudioRecording(true);
@ -313,6 +296,58 @@ public class WebRTCWrapper {
this.peerConnection = peerConnection; 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( private static PeerConnection.RTCConfiguration buildConfiguration(
final List<PeerConnection.IceServer> iceServers) { final List<PeerConnection.IceServer> iceServers) {
final PeerConnection.RTCConfiguration rtcConfig = final PeerConnection.RTCConfiguration rtcConfig =
@ -344,6 +379,7 @@ public class WebRTCWrapper {
synchronized void close() { synchronized void close() {
final PeerConnection peerConnection = this.peerConnection; final PeerConnection peerConnection = this.peerConnection;
final PeerConnectionFactory peerConnectionFactory = this.peerConnectionFactory;
final VideoSourceWrapper videoSourceWrapper = this.videoSourceWrapper; final VideoSourceWrapper videoSourceWrapper = this.videoSourceWrapper;
final AppRTCAudioManager audioManager = this.appRTCAudioManager; final AppRTCAudioManager audioManager = this.appRTCAudioManager;
final EglBase eglBase = this.eglBase; final EglBase eglBase = this.eglBase;
@ -363,12 +399,15 @@ public class WebRTCWrapper {
} catch (final InterruptedException e) { } catch (final InterruptedException e) {
Log.e(Config.LOGTAG, "unable to stop capturing"); Log.e(Config.LOGTAG, "unable to stop capturing");
} }
// TODO call dispose videoSourceWrapper.dispose();
} }
if (eglBase != null) { if (eglBase != null) {
eglBase.release(); eglBase.release();
this.eglBase = null; this.eglBase = null;
} }
if (peerConnectionFactory != null) {
peerConnectionFactory.dispose();
}
} }
synchronized void verifyClosed() { synchronized void verifyClosed() {
@ -530,6 +569,7 @@ public class WebRTCWrapper {
} }
} }
@Nonnull
private PeerConnection requirePeerConnection() { private PeerConnection requirePeerConnection() {
final PeerConnection peerConnection = this.peerConnection; final PeerConnection peerConnection = this.peerConnection;
if (peerConnection == null) { if (peerConnection == null) {
@ -538,6 +578,15 @@ public class WebRTCWrapper {
return peerConnection; 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) { void addIceCandidate(IceCandidate iceCandidate) {
requirePeerConnection().addIceCandidate(iceCandidate); requirePeerConnection().addIceCandidate(iceCandidate);
} }
@ -626,5 +675,4 @@ public class WebRTCWrapper {
super(message); super(message);
} }
} }
} }