~singpolyma/cheogram-android

27d8da2ab4e927a4b81c266a2501ed666eaedd4b — Daniel Gultsch 1 year, 5 months ago 8fb2c11
refactor WebRTCWrapper to allow for track adds
M src/main/java/eu/siacs/conversations/xmpp/jingle/VideoSourceWrapper.java => src/main/java/eu/siacs/conversations/xmpp/jingle/VideoSourceWrapper.java +5 -7
@@ 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);
            }
        }


M src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java => src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java +75 -27
@@ 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);
        }
    }

}