public void createPeerConnectionFactory(
      final Context context,
      final EGLContext renderEGLContext,
      final PeerConnectionParameters peerConnectionParameters,
      final PeerConnectionEvents events) {
    this.peerConnectionParameters = peerConnectionParameters;
    this.events = events;
    videoCallEnabled = peerConnectionParameters.videoCallEnabled;
    // Reset variables to initial states.
    factory = null;
    peerConnection = null;
    preferIsac = false;
    preferH264 = false;
    videoSourceStopped = false;
    isError = false;
    queuedRemoteCandidates = null;
    localSdp = null; // either offer or answer SDP
    mediaStream = null;
    videoCapturer = null;
    renderVideo = true;
    localVideoTrack = null;
    remoteVideoTrack = null;
    statsTimer = new Timer();

    executor.execute(
        new Runnable() {
          @Override
          public void run() {
            createPeerConnectionFactoryInternal(context, renderEGLContext);
          }
        });
  }
 private PeerConnectionClient() {
   executor = new LooperExecutor();
   // Looper thread is started once in private ctor and is used for all
   // peer connection API calls to ensure new peer connection factory is
   // created on the same thread as previously destroyed factory.
   executor.requestStart();
 }
 public void switchCamera() {
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           switchCameraInternal();
         }
       });
 }
 public void close() {
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           closeInternal();
         }
       });
 }
 private void reportError(final String errorMessage) {
   Log.e(TAG, "Peerconnection error: " + errorMessage);
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           if (!isError) {
             events.onPeerConnectionError(errorMessage);
             isError = true;
           }
         }
       });
 }
 public void startVideoSource() {
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           if (videoSource != null && videoSourceStopped) {
             Log.d(TAG, "Restart video source.");
             videoSource.restart();
             videoSourceStopped = false;
           }
         }
       });
 }
 public void stopVideoSource() {
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           if (videoSource != null && !videoSourceStopped) {
             Log.d(TAG, "Stop video source.");
             videoSource.stop();
             videoSourceStopped = true;
           }
         }
       });
 }
 public void createAnswer() {
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           if (peerConnection != null && !isError) {
             Log.d(TAG, "PC create ANSWER");
             isInitiator = false;
             peerConnection.createAnswer(sdpObserver, sdpMediaConstraints);
           }
         }
       });
 }
 public void setRemoteDescription(final SessionDescription sdp) {
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           if (peerConnection == null || isError) {
             return;
           }
           String sdpDescription = sdp.description;
           if (preferIsac) {
             sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true);
           }
           if (videoCallEnabled && preferH264) {
             sdpDescription = preferCodec(sdpDescription, VIDEO_CODEC_H264, false);
           }
           if (videoCallEnabled && peerConnectionParameters.videoStartBitrate > 0) {
             sdpDescription =
                 setStartBitrate(
                     VIDEO_CODEC_VP8,
                     true,
                     sdpDescription,
                     peerConnectionParameters.videoStartBitrate);
             sdpDescription =
                 setStartBitrate(
                     VIDEO_CODEC_VP9,
                     true,
                     sdpDescription,
                     peerConnectionParameters.videoStartBitrate);
             sdpDescription =
                 setStartBitrate(
                     VIDEO_CODEC_H264,
                     true,
                     sdpDescription,
                     peerConnectionParameters.videoStartBitrate);
           }
           if (peerConnectionParameters.audioStartBitrate > 0) {
             sdpDescription =
                 setStartBitrate(
                     AUDIO_CODEC_OPUS,
                     false,
                     sdpDescription,
                     peerConnectionParameters.audioStartBitrate);
           }
           Log.d(TAG, "Set remote SDP.");
           SessionDescription sdpRemote = new SessionDescription(sdp.type, sdpDescription);
           peerConnection.setRemoteDescription(sdpObserver, sdpRemote);
         }
       });
 }
 public void addRemoteIceCandidate(final IceCandidate candidate) {
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           if (peerConnection != null && !isError) {
             if (queuedRemoteCandidates != null) {
               queuedRemoteCandidates.add(candidate);
             } else {
               peerConnection.addIceCandidate(candidate);
             }
           }
         }
       });
 }
 public void setVideoEnabled(final boolean enable) {
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           renderVideo = enable;
           if (localVideoTrack != null) {
             localVideoTrack.setEnabled(renderVideo);
           }
           if (remoteVideoTrack != null) {
             remoteVideoTrack.setEnabled(renderVideo);
           }
         }
       });
 }
 public void createPeerConnection(
     final VideoRenderer.Callbacks localRender,
     final VideoRenderer.Callbacks remoteRender,
     final SignalingParameters signalingParameters) {
   if (peerConnectionParameters == null) {
     Log.e(TAG, "Creating peer connection without initializing factory.");
     return;
   }
   this.localRender = localRender;
   this.remoteRender = remoteRender;
   this.signalingParameters = signalingParameters;
   executor.execute(
       new Runnable() {
         @Override
         public void run() {
           createMediaConstraintsInternal();
           createPeerConnectionInternal();
         }
       });
 }