package org.webrtc; import android.content.Context; import android.os.Process; import androidx.annotation.Nullable; import java.util.List; import java.util.Objects; import org.webrtc.Logging; import org.webrtc.NativeLibrary; import org.webrtc.PeerConnection; import org.webrtc.audio.AudioDeviceModule; import org.webrtc.audio.JavaAudioDeviceModule; public class PeerConnectionFactory { private static final String TAG = "PeerConnectionFactory"; public static final String TRIAL_ENABLED = "Enabled"; private static final String VIDEO_CAPTURER_THREAD_NAME = "VideoCapturerThread"; @Deprecated public static final String VIDEO_FRAME_EMIT_TRIAL = "VideoFrameEmit"; private static volatile boolean internalTracerInitialized; @Nullable private static ThreadInfo staticNetworkThread; @Nullable private static ThreadInfo staticSignalingThread; @Nullable private static ThreadInfo staticWorkerThread; private long nativeFactory; @Nullable private volatile ThreadInfo networkThread; @Nullable private volatile ThreadInfo signalingThread; @Nullable private volatile ThreadInfo workerThread; public static class Builder { private AudioDecoderFactoryFactory audioDecoderFactoryFactory; @Nullable private AudioDeviceModule audioDeviceModule; private AudioEncoderFactoryFactory audioEncoderFactoryFactory; @Nullable private AudioProcessingFactory audioProcessingFactory; @Nullable private FecControllerFactoryFactoryInterface fecControllerFactoryFactory; @Nullable private NetEqFactoryFactory neteqFactoryFactory; @Nullable private NetworkControllerFactoryFactory networkControllerFactoryFactory; @Nullable private NetworkStatePredictorFactoryFactory networkStatePredictorFactoryFactory; @Nullable private Options options; @Nullable private VideoDecoderFactory videoDecoderFactory; @Nullable private VideoEncoderFactory videoEncoderFactory; private Builder() { this.audioEncoderFactoryFactory = new BuiltinAudioEncoderFactoryFactory(); this.audioDecoderFactoryFactory = new BuiltinAudioDecoderFactoryFactory(); } public PeerConnectionFactory createPeerConnectionFactory() { PeerConnectionFactory.access$100(); if (this.audioDeviceModule == null) { this.audioDeviceModule = JavaAudioDeviceModule.builder(ContextUtils.getApplicationContext()).createAudioDeviceModule(); } Context applicationContext = ContextUtils.getApplicationContext(); Options options = this.options; long nativeAudioDeviceModulePointer = this.audioDeviceModule.getNativeAudioDeviceModulePointer(); long createNativeAudioEncoderFactory = this.audioEncoderFactoryFactory.createNativeAudioEncoderFactory(); long createNativeAudioDecoderFactory = this.audioDecoderFactoryFactory.createNativeAudioDecoderFactory(); VideoEncoderFactory videoEncoderFactory = this.videoEncoderFactory; VideoDecoderFactory videoDecoderFactory = this.videoDecoderFactory; AudioProcessingFactory audioProcessingFactory = this.audioProcessingFactory; long j = 0; long createNative = audioProcessingFactory == null ? 0 : audioProcessingFactory.createNative(); FecControllerFactoryFactoryInterface fecControllerFactoryFactoryInterface = this.fecControllerFactoryFactory; long createNative2 = fecControllerFactoryFactoryInterface == null ? 0 : fecControllerFactoryFactoryInterface.createNative(); NetworkControllerFactoryFactory networkControllerFactoryFactory = this.networkControllerFactoryFactory; long createNativeNetworkControllerFactory = networkControllerFactoryFactory == null ? 0 : networkControllerFactoryFactory.createNativeNetworkControllerFactory(); NetworkStatePredictorFactoryFactory networkStatePredictorFactoryFactory = this.networkStatePredictorFactoryFactory; long createNativeNetworkStatePredictorFactory = networkStatePredictorFactoryFactory == null ? 0 : networkStatePredictorFactoryFactory.createNativeNetworkStatePredictorFactory(); NetEqFactoryFactory netEqFactoryFactory = this.neteqFactoryFactory; if (netEqFactoryFactory != null) { j = netEqFactoryFactory.createNativeNetEqFactory(); } return PeerConnectionFactory.access$200(applicationContext, options, nativeAudioDeviceModulePointer, createNativeAudioEncoderFactory, createNativeAudioDecoderFactory, videoEncoderFactory, videoDecoderFactory, createNative, createNative2, createNativeNetworkControllerFactory, createNativeNetworkStatePredictorFactory, j); } public Builder setAudioDecoderFactoryFactory(AudioDecoderFactoryFactory audioDecoderFactoryFactory) { if (audioDecoderFactoryFactory != null) { this.audioDecoderFactoryFactory = audioDecoderFactoryFactory; return this; } throw new IllegalArgumentException("PeerConnectionFactory.Builder does not accept a null AudioDecoderFactoryFactory."); } public Builder setAudioDeviceModule(AudioDeviceModule audioDeviceModule) { this.audioDeviceModule = audioDeviceModule; return this; } public Builder setAudioEncoderFactoryFactory(AudioEncoderFactoryFactory audioEncoderFactoryFactory) { if (audioEncoderFactoryFactory != null) { this.audioEncoderFactoryFactory = audioEncoderFactoryFactory; return this; } throw new IllegalArgumentException("PeerConnectionFactory.Builder does not accept a null AudioEncoderFactoryFactory."); } public Builder setAudioProcessingFactory(AudioProcessingFactory audioProcessingFactory) { Objects.requireNonNull(audioProcessingFactory, "PeerConnectionFactory builder does not accept a null AudioProcessingFactory."); this.audioProcessingFactory = audioProcessingFactory; return this; } public Builder setFecControllerFactoryFactoryInterface(FecControllerFactoryFactoryInterface fecControllerFactoryFactoryInterface) { this.fecControllerFactoryFactory = fecControllerFactoryFactoryInterface; return this; } public Builder setNetEqFactoryFactory(NetEqFactoryFactory netEqFactoryFactory) { this.neteqFactoryFactory = netEqFactoryFactory; return this; } public Builder setNetworkControllerFactoryFactory(NetworkControllerFactoryFactory networkControllerFactoryFactory) { this.networkControllerFactoryFactory = networkControllerFactoryFactory; return this; } public Builder setNetworkStatePredictorFactoryFactory(NetworkStatePredictorFactoryFactory networkStatePredictorFactoryFactory) { this.networkStatePredictorFactoryFactory = networkStatePredictorFactoryFactory; return this; } public Builder setOptions(Options options) { this.options = options; return this; } public Builder setVideoDecoderFactory(VideoDecoderFactory videoDecoderFactory) { this.videoDecoderFactory = videoDecoderFactory; return this; } public Builder setVideoEncoderFactory(VideoEncoderFactory videoEncoderFactory) { this.videoEncoderFactory = videoEncoderFactory; return this; } } public static class InitializationOptions { public final Context applicationContext; public final boolean enableInternalTracer; public final String fieldTrials; @Nullable public Loggable loggable; @Nullable public Logging.Severity loggableSeverity; public final NativeLibraryLoader nativeLibraryLoader; public final String nativeLibraryName; public static class Builder { private final Context applicationContext; private boolean enableInternalTracer; private String fieldTrials = ""; @Nullable private Loggable loggable; @Nullable private Logging.Severity loggableSeverity; private NativeLibraryLoader nativeLibraryLoader = new NativeLibrary.DefaultLoader(); private String nativeLibraryName = "jingle_peerconnection_so"; public Builder(Context context) { this.applicationContext = context; } public InitializationOptions createInitializationOptions() { return new InitializationOptions(this.applicationContext, this.fieldTrials, this.enableInternalTracer, this.nativeLibraryLoader, this.nativeLibraryName, this.loggable, this.loggableSeverity); } public Builder setEnableInternalTracer(boolean z2) { this.enableInternalTracer = z2; return this; } public Builder setFieldTrials(String str) { this.fieldTrials = str; return this; } public Builder setInjectableLogger(Loggable loggable, Logging.Severity severity) { this.loggable = loggable; this.loggableSeverity = severity; return this; } public Builder setNativeLibraryLoader(NativeLibraryLoader nativeLibraryLoader) { this.nativeLibraryLoader = nativeLibraryLoader; return this; } public Builder setNativeLibraryName(String str) { this.nativeLibraryName = str; return this; } } private InitializationOptions(Context context, String str, boolean z2, NativeLibraryLoader nativeLibraryLoader, String str2, @Nullable Loggable loggable, @Nullable Logging.Severity severity) { this.applicationContext = context; this.fieldTrials = str; this.enableInternalTracer = z2; this.nativeLibraryLoader = nativeLibraryLoader; this.nativeLibraryName = str2; this.loggable = loggable; this.loggableSeverity = severity; } public static Builder builder(Context context) { return new Builder(context); } } public static class Options { public static final int ADAPTER_TYPE_ANY = 32; public static final int ADAPTER_TYPE_CELLULAR = 4; public static final int ADAPTER_TYPE_ETHERNET = 1; public static final int ADAPTER_TYPE_LOOPBACK = 16; public static final int ADAPTER_TYPE_UNKNOWN = 0; public static final int ADAPTER_TYPE_VPN = 8; public static final int ADAPTER_TYPE_WIFI = 2; public boolean disableEncryption; public boolean disableNetworkMonitor; public int networkIgnoreMask; @CalledByNative("Options") public boolean getDisableEncryption() { return this.disableEncryption; } @CalledByNative("Options") public boolean getDisableNetworkMonitor() { return this.disableNetworkMonitor; } @CalledByNative("Options") public int getNetworkIgnoreMask() { return this.networkIgnoreMask; } } public static class ThreadInfo { public final Thread thread; public final int tid; private ThreadInfo(Thread thread, int i) { this.thread = thread; this.tid = i; } public static ThreadInfo getCurrent() { return new ThreadInfo(Thread.currentThread(), Process.myTid()); } } @CalledByNative public PeerConnectionFactory(long j) { checkInitializeHasBeenCalled(); if (j != 0) { this.nativeFactory = j; return; } throw new RuntimeException("Failed to initialize PeerConnectionFactory!"); } public static /* synthetic */ void access$100() { checkInitializeHasBeenCalled(); } public static /* synthetic */ PeerConnectionFactory access$200(Context context, Options options, long j, long j2, long j3, VideoEncoderFactory videoEncoderFactory, VideoDecoderFactory videoDecoderFactory, long j4, long j5, long j6, long j7, long j8) { return nativeCreatePeerConnectionFactory(context, options, j, j2, j3, videoEncoderFactory, videoDecoderFactory, j4, j5, j6, j7, j8); } public static Builder builder() { return new Builder(); } private static void checkInitializeHasBeenCalled() { if (!NativeLibrary.isLoaded() || ContextUtils.getApplicationContext() == null) { throw new IllegalStateException("PeerConnectionFactory.initialize was not called before creating a PeerConnectionFactory."); } } private void checkPeerConnectionFactoryExists() { if (this.nativeFactory == 0) { throw new IllegalStateException("PeerConnectionFactory has been disposed."); } } public static String fieldTrialsFindFullName(String str) { return NativeLibrary.isLoaded() ? nativeFindFieldTrialsFullName(str) : ""; } public static void initialize(InitializationOptions initializationOptions) { ContextUtils.initialize(initializationOptions.applicationContext); NativeLibrary.initialize(initializationOptions.nativeLibraryLoader, initializationOptions.nativeLibraryName); nativeInitializeAndroidGlobals(); nativeInitializeFieldTrials(initializationOptions.fieldTrials); if (initializationOptions.enableInternalTracer && !internalTracerInitialized) { initializeInternalTracer(); } Loggable loggable = initializationOptions.loggable; if (loggable != null) { Logging.injectLoggable(loggable, initializationOptions.loggableSeverity); nativeInjectLoggable(new JNILogging(initializationOptions.loggable), initializationOptions.loggableSeverity.ordinal()); return; } Logging.d("PeerConnectionFactory", "PeerConnectionFactory was initialized without an injected Loggable. Any existing Loggable will be deleted."); Logging.deleteInjectedLoggable(); nativeDeleteLoggable(); } @Deprecated public static void initializeFieldTrials(String str) { nativeInitializeFieldTrials(str); } private static void initializeInternalTracer() { internalTracerInitialized = true; nativeInitializeInternalTracer(); } private static native long nativeCreateAudioSource(long j, MediaConstraints mediaConstraints); private static native long nativeCreateAudioTrack(long j, String str, long j2); private static native long nativeCreateLocalMediaStream(long j, String str); private static native long nativeCreatePeerConnection(long j, PeerConnection.RTCConfiguration rTCConfiguration, MediaConstraints mediaConstraints, long j2, SSLCertificateVerifier sSLCertificateVerifier); private static native PeerConnectionFactory nativeCreatePeerConnectionFactory(Context context, Options options, long j, long j2, long j3, VideoEncoderFactory videoEncoderFactory, VideoDecoderFactory videoDecoderFactory, long j4, long j5, long j6, long j7, long j8); private static native long nativeCreateVideoSource(long j, boolean z2, boolean z3); private static native long nativeCreateVideoTrack(long j, String str, long j2); private static native void nativeDeleteLoggable(); private static native String nativeFindFieldTrialsFullName(String str); private static native void nativeFreeFactory(long j); private static native long nativeGetNativePeerConnectionFactory(long j); private static native void nativeInitializeAndroidGlobals(); private static native void nativeInitializeFieldTrials(String str); private static native void nativeInitializeInternalTracer(); private static native void nativeInjectLoggable(JNILogging jNILogging, int i); private static native void nativePrintStackTrace(int i); private static native void nativePrintStackTracesOfRegisteredThreads(); private static native void nativeShutdownInternalTracer(); private static native boolean nativeStartAecDump(long j, int i, int i2); private static native boolean nativeStartInternalTracingCapture(String str); private static native void nativeStopAecDump(long j); private static native void nativeStopInternalTracingCapture(); @CalledByNative private void onNetworkThreadReady() { this.networkThread = ThreadInfo.getCurrent(); staticNetworkThread = this.networkThread; Logging.d("PeerConnectionFactory", "onNetworkThreadReady"); } @CalledByNative private void onSignalingThreadReady() { this.signalingThread = ThreadInfo.getCurrent(); staticSignalingThread = this.signalingThread; Logging.d("PeerConnectionFactory", "onSignalingThreadReady"); } @CalledByNative private void onWorkerThreadReady() { this.workerThread = ThreadInfo.getCurrent(); staticWorkerThread = this.workerThread; Logging.d("PeerConnectionFactory", "onWorkerThreadReady"); } private static void printStackTrace(@Nullable ThreadInfo threadInfo, boolean z2) { if (threadInfo != null) { String name = threadInfo.thread.getName(); StackTraceElement[] stackTrace = threadInfo.thread.getStackTrace(); if (stackTrace.length > 0) { Logging.w("PeerConnectionFactory", name + " stacktrace:"); for (StackTraceElement stackTraceElement : stackTrace) { Logging.w("PeerConnectionFactory", stackTraceElement.toString()); } } if (z2) { Logging.w("PeerConnectionFactory", "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***"); Logging.w("PeerConnectionFactory", "pid: " + Process.myPid() + ", tid: " + threadInfo.tid + ", name: " + name + " >>> WebRTC <<<"); nativePrintStackTrace(threadInfo.tid); } } } @Deprecated public static void printStackTraces() { printStackTrace(staticNetworkThread, false); printStackTrace(staticWorkerThread, false); printStackTrace(staticSignalingThread, false); } public static void shutdownInternalTracer() { internalTracerInitialized = false; nativeShutdownInternalTracer(); } public static boolean startInternalTracingCapture(String str) { return nativeStartInternalTracingCapture(str); } public static void stopInternalTracingCapture() { nativeStopInternalTracingCapture(); } public AudioSource createAudioSource(MediaConstraints mediaConstraints) { checkPeerConnectionFactoryExists(); return new AudioSource(nativeCreateAudioSource(this.nativeFactory, mediaConstraints)); } public AudioTrack createAudioTrack(String str, AudioSource audioSource) { checkPeerConnectionFactoryExists(); return new AudioTrack(nativeCreateAudioTrack(this.nativeFactory, str, audioSource.getNativeAudioSource())); } public MediaStream createLocalMediaStream(String str) { checkPeerConnectionFactoryExists(); return new MediaStream(nativeCreateLocalMediaStream(this.nativeFactory, str)); } @Nullable @Deprecated public PeerConnection createPeerConnection(List list, MediaConstraints mediaConstraints, PeerConnection.Observer observer) { return createPeerConnection(new PeerConnection.RTCConfiguration(list), mediaConstraints, observer); } @Nullable public PeerConnection createPeerConnection(List list, PeerConnection.Observer observer) { return createPeerConnection(new PeerConnection.RTCConfiguration(list), observer); } @Nullable @Deprecated public PeerConnection createPeerConnection(PeerConnection.RTCConfiguration rTCConfiguration, MediaConstraints mediaConstraints, PeerConnection.Observer observer) { return createPeerConnectionInternal(rTCConfiguration, mediaConstraints, observer, null); } @Nullable public PeerConnection createPeerConnection(PeerConnection.RTCConfiguration rTCConfiguration, PeerConnection.Observer observer) { return createPeerConnection(rTCConfiguration, (MediaConstraints) null, observer); } @Nullable public PeerConnection createPeerConnection(PeerConnection.RTCConfiguration rTCConfiguration, PeerConnectionDependencies peerConnectionDependencies) { return createPeerConnectionInternal(rTCConfiguration, null, peerConnectionDependencies.getObserver(), peerConnectionDependencies.getSSLCertificateVerifier()); } @Nullable public PeerConnection createPeerConnectionInternal(PeerConnection.RTCConfiguration rTCConfiguration, MediaConstraints mediaConstraints, PeerConnection.Observer observer, SSLCertificateVerifier sSLCertificateVerifier) { checkPeerConnectionFactoryExists(); long createNativePeerConnectionObserver = PeerConnection.createNativePeerConnectionObserver(observer); if (createNativePeerConnectionObserver == 0) { return null; } long nativeCreatePeerConnection = nativeCreatePeerConnection(this.nativeFactory, rTCConfiguration, mediaConstraints, createNativePeerConnectionObserver, sSLCertificateVerifier); if (nativeCreatePeerConnection == 0) { return null; } return new PeerConnection(nativeCreatePeerConnection); } public VideoSource createVideoSource(boolean z2) { return createVideoSource(z2, true); } public VideoSource createVideoSource(boolean z2, boolean z3) { checkPeerConnectionFactoryExists(); return new VideoSource(nativeCreateVideoSource(this.nativeFactory, z2, z3)); } public VideoTrack createVideoTrack(String str, VideoSource videoSource) { checkPeerConnectionFactoryExists(); return new VideoTrack(nativeCreateVideoTrack(this.nativeFactory, str, videoSource.getNativeVideoTrackSource())); } public void dispose() { checkPeerConnectionFactoryExists(); nativeFreeFactory(this.nativeFactory); this.networkThread = null; this.workerThread = null; this.signalingThread = null; this.nativeFactory = 0; } public long getNativeOwnedFactoryAndThreads() { checkPeerConnectionFactoryExists(); return this.nativeFactory; } public long getNativePeerConnectionFactory() { checkPeerConnectionFactoryExists(); return nativeGetNativePeerConnectionFactory(this.nativeFactory); } public void printInternalStackTraces(boolean z2) { printStackTrace(this.signalingThread, z2); printStackTrace(this.workerThread, z2); printStackTrace(this.networkThread, z2); if (z2) { nativePrintStackTracesOfRegisteredThreads(); } } public boolean startAecDump(int i, int i2) { checkPeerConnectionFactoryExists(); return nativeStartAecDump(this.nativeFactory, i, i2); } public void stopAecDump() { checkPeerConnectionFactoryExists(); nativeStopAecDump(this.nativeFactory); } }