1 /*
2  *  Copyright 2013 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.webrtc;
12 
13 import android.content.Context;
14 import android.os.Process;
15 import android.support.annotation.Nullable;
16 import java.util.List;
17 import org.webrtc.Logging.Severity;
18 import org.webrtc.PeerConnection;
19 import org.webrtc.audio.AudioDeviceModule;
20 import org.webrtc.audio.JavaAudioDeviceModule;
21 
22 /**
23  * Java wrapper for a C++ PeerConnectionFactoryInterface.  Main entry point to
24  * the PeerConnection API for clients.
25  */
26 public class PeerConnectionFactory {
27   public static final String TRIAL_ENABLED = "Enabled";
28   @Deprecated public static final String VIDEO_FRAME_EMIT_TRIAL = "VideoFrameEmit";
29 
30   private static final String TAG = "PeerConnectionFactory";
31   private static final String VIDEO_CAPTURER_THREAD_NAME = "VideoCapturerThread";
32 
33   /** Helper class holding both Java and C++ thread info. */
34   private static class ThreadInfo {
35     final Thread thread;
36     final int tid;
37 
getCurrent()38     public static ThreadInfo getCurrent() {
39       return new ThreadInfo(Thread.currentThread(), Process.myTid());
40     }
41 
ThreadInfo(Thread thread, int tid)42     private ThreadInfo(Thread thread, int tid) {
43       this.thread = thread;
44       this.tid = tid;
45     }
46   }
47 
48   private static volatile boolean internalTracerInitialized;
49 
50   // Remove these once deprecated static printStackTrace() is gone.
51   @Nullable private static ThreadInfo staticNetworkThread;
52   @Nullable private static ThreadInfo staticWorkerThread;
53   @Nullable private static ThreadInfo staticSignalingThread;
54 
55   private long nativeFactory;
56   @Nullable private volatile ThreadInfo networkThread;
57   @Nullable private volatile ThreadInfo workerThread;
58   @Nullable private volatile ThreadInfo signalingThread;
59 
60   public static class InitializationOptions {
61     final Context applicationContext;
62     final String fieldTrials;
63     final boolean enableInternalTracer;
64     final NativeLibraryLoader nativeLibraryLoader;
65     final String nativeLibraryName;
66     @Nullable Loggable loggable;
67     @Nullable Severity loggableSeverity;
68 
InitializationOptions(Context applicationContext, String fieldTrials, boolean enableInternalTracer, NativeLibraryLoader nativeLibraryLoader, String nativeLibraryName, @Nullable Loggable loggable, @Nullable Severity loggableSeverity)69     private InitializationOptions(Context applicationContext, String fieldTrials,
70         boolean enableInternalTracer, NativeLibraryLoader nativeLibraryLoader,
71         String nativeLibraryName, @Nullable Loggable loggable,
72         @Nullable Severity loggableSeverity) {
73       this.applicationContext = applicationContext;
74       this.fieldTrials = fieldTrials;
75       this.enableInternalTracer = enableInternalTracer;
76       this.nativeLibraryLoader = nativeLibraryLoader;
77       this.nativeLibraryName = nativeLibraryName;
78       this.loggable = loggable;
79       this.loggableSeverity = loggableSeverity;
80     }
81 
builder(Context applicationContext)82     public static Builder builder(Context applicationContext) {
83       return new Builder(applicationContext);
84     }
85 
86     public static class Builder {
87       private final Context applicationContext;
88       private String fieldTrials = "";
89       private boolean enableInternalTracer;
90       private NativeLibraryLoader nativeLibraryLoader = new NativeLibrary.DefaultLoader();
91       private String nativeLibraryName = "jingle_peerconnection_so";
92       @Nullable private Loggable loggable;
93       @Nullable private Severity loggableSeverity;
94 
Builder(Context applicationContext)95       Builder(Context applicationContext) {
96         this.applicationContext = applicationContext;
97       }
98 
setFieldTrials(String fieldTrials)99       public Builder setFieldTrials(String fieldTrials) {
100         this.fieldTrials = fieldTrials;
101         return this;
102       }
103 
setEnableInternalTracer(boolean enableInternalTracer)104       public Builder setEnableInternalTracer(boolean enableInternalTracer) {
105         this.enableInternalTracer = enableInternalTracer;
106         return this;
107       }
108 
setNativeLibraryLoader(NativeLibraryLoader nativeLibraryLoader)109       public Builder setNativeLibraryLoader(NativeLibraryLoader nativeLibraryLoader) {
110         this.nativeLibraryLoader = nativeLibraryLoader;
111         return this;
112       }
113 
setNativeLibraryName(String nativeLibraryName)114       public Builder setNativeLibraryName(String nativeLibraryName) {
115         this.nativeLibraryName = nativeLibraryName;
116         return this;
117       }
118 
setInjectableLogger(Loggable loggable, Severity severity)119       public Builder setInjectableLogger(Loggable loggable, Severity severity) {
120         this.loggable = loggable;
121         this.loggableSeverity = severity;
122         return this;
123       }
124 
createInitializationOptions()125       public PeerConnectionFactory.InitializationOptions createInitializationOptions() {
126         return new PeerConnectionFactory.InitializationOptions(applicationContext, fieldTrials,
127             enableInternalTracer, nativeLibraryLoader, nativeLibraryName, loggable,
128             loggableSeverity);
129       }
130     }
131   }
132 
133   public static class Options {
134     // Keep in sync with webrtc/rtc_base/network.h!
135     //
136     // These bit fields are defined for |networkIgnoreMask| below.
137     static final int ADAPTER_TYPE_UNKNOWN = 0;
138     static final int ADAPTER_TYPE_ETHERNET = 1 << 0;
139     static final int ADAPTER_TYPE_WIFI = 1 << 1;
140     static final int ADAPTER_TYPE_CELLULAR = 1 << 2;
141     static final int ADAPTER_TYPE_VPN = 1 << 3;
142     static final int ADAPTER_TYPE_LOOPBACK = 1 << 4;
143     static final int ADAPTER_TYPE_ANY = 1 << 5;
144 
145     public int networkIgnoreMask;
146     public boolean disableEncryption;
147     public boolean disableNetworkMonitor;
148 
149     @CalledByNative("Options")
getNetworkIgnoreMask()150     int getNetworkIgnoreMask() {
151       return networkIgnoreMask;
152     }
153 
154     @CalledByNative("Options")
getDisableEncryption()155     boolean getDisableEncryption() {
156       return disableEncryption;
157     }
158 
159     @CalledByNative("Options")
getDisableNetworkMonitor()160     boolean getDisableNetworkMonitor() {
161       return disableNetworkMonitor;
162     }
163   }
164 
165   public static class Builder {
166     @Nullable private Options options;
167     @Nullable private AudioDeviceModule audioDeviceModule;
168     private AudioEncoderFactoryFactory audioEncoderFactoryFactory =
169         new BuiltinAudioEncoderFactoryFactory();
170     private AudioDecoderFactoryFactory audioDecoderFactoryFactory =
171         new BuiltinAudioDecoderFactoryFactory();
172     @Nullable private VideoEncoderFactory videoEncoderFactory;
173     @Nullable private VideoDecoderFactory videoDecoderFactory;
174     @Nullable private AudioProcessingFactory audioProcessingFactory;
175     @Nullable private FecControllerFactoryFactoryInterface fecControllerFactoryFactory;
176     @Nullable private NetworkControllerFactoryFactory networkControllerFactoryFactory;
177     @Nullable private NetworkStatePredictorFactoryFactory networkStatePredictorFactoryFactory;
178     @Nullable private NetEqFactoryFactory neteqFactoryFactory;
179 
Builder()180     private Builder() {}
181 
setOptions(Options options)182     public Builder setOptions(Options options) {
183       this.options = options;
184       return this;
185     }
186 
setAudioDeviceModule(AudioDeviceModule audioDeviceModule)187     public Builder setAudioDeviceModule(AudioDeviceModule audioDeviceModule) {
188       this.audioDeviceModule = audioDeviceModule;
189       return this;
190     }
191 
setAudioEncoderFactoryFactory( AudioEncoderFactoryFactory audioEncoderFactoryFactory)192     public Builder setAudioEncoderFactoryFactory(
193         AudioEncoderFactoryFactory audioEncoderFactoryFactory) {
194       if (audioEncoderFactoryFactory == null) {
195         throw new IllegalArgumentException(
196             "PeerConnectionFactory.Builder does not accept a null AudioEncoderFactoryFactory.");
197       }
198       this.audioEncoderFactoryFactory = audioEncoderFactoryFactory;
199       return this;
200     }
201 
setAudioDecoderFactoryFactory( AudioDecoderFactoryFactory audioDecoderFactoryFactory)202     public Builder setAudioDecoderFactoryFactory(
203         AudioDecoderFactoryFactory audioDecoderFactoryFactory) {
204       if (audioDecoderFactoryFactory == null) {
205         throw new IllegalArgumentException(
206             "PeerConnectionFactory.Builder does not accept a null AudioDecoderFactoryFactory.");
207       }
208       this.audioDecoderFactoryFactory = audioDecoderFactoryFactory;
209       return this;
210     }
211 
setVideoEncoderFactory(VideoEncoderFactory videoEncoderFactory)212     public Builder setVideoEncoderFactory(VideoEncoderFactory videoEncoderFactory) {
213       this.videoEncoderFactory = videoEncoderFactory;
214       return this;
215     }
216 
setVideoDecoderFactory(VideoDecoderFactory videoDecoderFactory)217     public Builder setVideoDecoderFactory(VideoDecoderFactory videoDecoderFactory) {
218       this.videoDecoderFactory = videoDecoderFactory;
219       return this;
220     }
221 
setAudioProcessingFactory(AudioProcessingFactory audioProcessingFactory)222     public Builder setAudioProcessingFactory(AudioProcessingFactory audioProcessingFactory) {
223       if (audioProcessingFactory == null) {
224         throw new NullPointerException(
225             "PeerConnectionFactory builder does not accept a null AudioProcessingFactory.");
226       }
227       this.audioProcessingFactory = audioProcessingFactory;
228       return this;
229     }
230 
setFecControllerFactoryFactoryInterface( FecControllerFactoryFactoryInterface fecControllerFactoryFactory)231     public Builder setFecControllerFactoryFactoryInterface(
232         FecControllerFactoryFactoryInterface fecControllerFactoryFactory) {
233       this.fecControllerFactoryFactory = fecControllerFactoryFactory;
234       return this;
235     }
236 
setNetworkControllerFactoryFactory( NetworkControllerFactoryFactory networkControllerFactoryFactory)237     public Builder setNetworkControllerFactoryFactory(
238         NetworkControllerFactoryFactory networkControllerFactoryFactory) {
239       this.networkControllerFactoryFactory = networkControllerFactoryFactory;
240       return this;
241     }
242 
setNetworkStatePredictorFactoryFactory( NetworkStatePredictorFactoryFactory networkStatePredictorFactoryFactory)243     public Builder setNetworkStatePredictorFactoryFactory(
244         NetworkStatePredictorFactoryFactory networkStatePredictorFactoryFactory) {
245       this.networkStatePredictorFactoryFactory = networkStatePredictorFactoryFactory;
246       return this;
247     }
248 
249     /**
250      * Sets a NetEqFactoryFactory for the PeerConnectionFactory. When using a
251      * custom NetEqFactoryFactory, the AudioDecoderFactoryFactory will be set
252      * to null. The AudioDecoderFactoryFactory should be wrapped in the
253      * NetEqFactoryFactory.
254      */
setNetEqFactoryFactory(NetEqFactoryFactory neteqFactoryFactory)255     public Builder setNetEqFactoryFactory(NetEqFactoryFactory neteqFactoryFactory) {
256       this.neteqFactoryFactory = neteqFactoryFactory;
257       return this;
258     }
259 
createPeerConnectionFactory()260     public PeerConnectionFactory createPeerConnectionFactory() {
261       checkInitializeHasBeenCalled();
262       if (audioDeviceModule == null) {
263         audioDeviceModule = JavaAudioDeviceModule.builder(ContextUtils.getApplicationContext())
264                                 .createAudioDeviceModule();
265       }
266       return nativeCreatePeerConnectionFactory(ContextUtils.getApplicationContext(), options,
267           audioDeviceModule.getNativeAudioDeviceModulePointer(),
268           audioEncoderFactoryFactory.createNativeAudioEncoderFactory(),
269           audioDecoderFactoryFactory.createNativeAudioDecoderFactory(), videoEncoderFactory,
270           videoDecoderFactory,
271           audioProcessingFactory == null ? 0 : audioProcessingFactory.createNative(),
272           fecControllerFactoryFactory == null ? 0 : fecControllerFactoryFactory.createNative(),
273           networkControllerFactoryFactory == null
274               ? 0
275               : networkControllerFactoryFactory.createNativeNetworkControllerFactory(),
276           networkStatePredictorFactoryFactory == null
277               ? 0
278               : networkStatePredictorFactoryFactory.createNativeNetworkStatePredictorFactory(),
279           neteqFactoryFactory == null ? 0 : neteqFactoryFactory.createNativeNetEqFactory());
280     }
281   }
282 
builder()283   public static Builder builder() {
284     return new Builder();
285   }
286 
287   /**
288    * Loads and initializes WebRTC. This must be called at least once before creating a
289    * PeerConnectionFactory. Replaces all the old initialization methods. Must not be called while
290    * a PeerConnectionFactory is alive.
291    */
initialize(InitializationOptions options)292   public static void initialize(InitializationOptions options) {
293     ContextUtils.initialize(options.applicationContext);
294     NativeLibrary.initialize(options.nativeLibraryLoader, options.nativeLibraryName);
295     nativeInitializeAndroidGlobals();
296     nativeInitializeFieldTrials(options.fieldTrials);
297     if (options.enableInternalTracer && !internalTracerInitialized) {
298       initializeInternalTracer();
299     }
300     if (options.loggable != null) {
301       Logging.injectLoggable(options.loggable, options.loggableSeverity);
302       nativeInjectLoggable(new JNILogging(options.loggable), options.loggableSeverity.ordinal());
303     } else {
304       Logging.d(TAG,
305           "PeerConnectionFactory was initialized without an injected Loggable. "
306               + "Any existing Loggable will be deleted.");
307       Logging.deleteInjectedLoggable();
308       nativeDeleteLoggable();
309     }
310   }
311 
checkInitializeHasBeenCalled()312   private static void checkInitializeHasBeenCalled() {
313     if (!NativeLibrary.isLoaded() || ContextUtils.getApplicationContext() == null) {
314       throw new IllegalStateException(
315           "PeerConnectionFactory.initialize was not called before creating a "
316           + "PeerConnectionFactory.");
317     }
318   }
319 
initializeInternalTracer()320   private static void initializeInternalTracer() {
321     internalTracerInitialized = true;
322     nativeInitializeInternalTracer();
323   }
324 
shutdownInternalTracer()325   public static void shutdownInternalTracer() {
326     internalTracerInitialized = false;
327     nativeShutdownInternalTracer();
328   }
329 
330   // Field trial initialization. Must be called before PeerConnectionFactory
331   // is created.
332   // Deprecated, use PeerConnectionFactory.initialize instead.
333   @Deprecated
initializeFieldTrials(String fieldTrialsInitString)334   public static void initializeFieldTrials(String fieldTrialsInitString) {
335     nativeInitializeFieldTrials(fieldTrialsInitString);
336   }
337 
338   // Wrapper of webrtc::field_trial::FindFullName. Develop the feature with default behaviour off.
339   // Example usage:
340   // if (PeerConnectionFactory.fieldTrialsFindFullName("WebRTCExperiment").equals("Enabled")) {
341   //   method1();
342   // } else {
343   //   method2();
344   // }
fieldTrialsFindFullName(String name)345   public static String fieldTrialsFindFullName(String name) {
346     return NativeLibrary.isLoaded() ? nativeFindFieldTrialsFullName(name) : "";
347   }
348   // Start/stop internal capturing of internal tracing.
startInternalTracingCapture(String tracingFilename)349   public static boolean startInternalTracingCapture(String tracingFilename) {
350     return nativeStartInternalTracingCapture(tracingFilename);
351   }
352 
stopInternalTracingCapture()353   public static void stopInternalTracingCapture() {
354     nativeStopInternalTracingCapture();
355   }
356 
357   @CalledByNative
PeerConnectionFactory(long nativeFactory)358   PeerConnectionFactory(long nativeFactory) {
359     checkInitializeHasBeenCalled();
360     if (nativeFactory == 0) {
361       throw new RuntimeException("Failed to initialize PeerConnectionFactory!");
362     }
363     this.nativeFactory = nativeFactory;
364   }
365 
366   /**
367    * Internal helper function to pass the parameters down into the native JNI bridge.
368    */
369   @Nullable
createPeerConnectionInternal(PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, PeerConnection.Observer observer, SSLCertificateVerifier sslCertificateVerifier)370   PeerConnection createPeerConnectionInternal(PeerConnection.RTCConfiguration rtcConfig,
371       MediaConstraints constraints, PeerConnection.Observer observer,
372       SSLCertificateVerifier sslCertificateVerifier) {
373     checkPeerConnectionFactoryExists();
374     long nativeObserver = PeerConnection.createNativePeerConnectionObserver(observer);
375     if (nativeObserver == 0) {
376       return null;
377     }
378     long nativePeerConnection = nativeCreatePeerConnection(
379         nativeFactory, rtcConfig, constraints, nativeObserver, sslCertificateVerifier);
380     if (nativePeerConnection == 0) {
381       return null;
382     }
383     return new PeerConnection(nativePeerConnection);
384   }
385 
386   /**
387    * Deprecated. PeerConnection constraints are deprecated. Supply values in rtcConfig struct
388    * instead and use the method without constraints in the signature.
389    */
390   @Nullable
391   @Deprecated
createPeerConnection(PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, PeerConnection.Observer observer)392   public PeerConnection createPeerConnection(PeerConnection.RTCConfiguration rtcConfig,
393       MediaConstraints constraints, PeerConnection.Observer observer) {
394     return createPeerConnectionInternal(
395         rtcConfig, constraints, observer, /* sslCertificateVerifier= */ null);
396   }
397 
398   /**
399    * Deprecated. PeerConnection constraints are deprecated. Supply values in rtcConfig struct
400    * instead and use the method without constraints in the signature.
401    */
402   @Nullable
403   @Deprecated
createPeerConnection(List<PeerConnection.IceServer> iceServers, MediaConstraints constraints, PeerConnection.Observer observer)404   public PeerConnection createPeerConnection(List<PeerConnection.IceServer> iceServers,
405       MediaConstraints constraints, PeerConnection.Observer observer) {
406     PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
407     return createPeerConnection(rtcConfig, constraints, observer);
408   }
409 
410   @Nullable
createPeerConnection( List<PeerConnection.IceServer> iceServers, PeerConnection.Observer observer)411   public PeerConnection createPeerConnection(
412       List<PeerConnection.IceServer> iceServers, PeerConnection.Observer observer) {
413     PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
414     return createPeerConnection(rtcConfig, observer);
415   }
416 
417   @Nullable
createPeerConnection( PeerConnection.RTCConfiguration rtcConfig, PeerConnection.Observer observer)418   public PeerConnection createPeerConnection(
419       PeerConnection.RTCConfiguration rtcConfig, PeerConnection.Observer observer) {
420     return createPeerConnection(rtcConfig, null /* constraints */, observer);
421   }
422 
423   @Nullable
createPeerConnection( PeerConnection.RTCConfiguration rtcConfig, PeerConnectionDependencies dependencies)424   public PeerConnection createPeerConnection(
425       PeerConnection.RTCConfiguration rtcConfig, PeerConnectionDependencies dependencies) {
426     return createPeerConnectionInternal(rtcConfig, null /* constraints */,
427         dependencies.getObserver(), dependencies.getSSLCertificateVerifier());
428   }
429 
createLocalMediaStream(String label)430   public MediaStream createLocalMediaStream(String label) {
431     checkPeerConnectionFactoryExists();
432     return new MediaStream(nativeCreateLocalMediaStream(nativeFactory, label));
433   }
434 
435   /**
436    * Create video source with given parameters. If alignTimestamps is false, the caller is
437    * responsible for aligning the frame timestamps to rtc::TimeNanos(). This can be used to achieve
438    * higher accuracy if there is a big delay between frame creation and frames being delivered to
439    * the returned video source. If alignTimestamps is true, timestamps will be aligned to
440    * rtc::TimeNanos() when they arrive to the returned video source.
441    */
createVideoSource(boolean isScreencast, boolean alignTimestamps)442   public VideoSource createVideoSource(boolean isScreencast, boolean alignTimestamps) {
443     checkPeerConnectionFactoryExists();
444     return new VideoSource(nativeCreateVideoSource(nativeFactory, isScreencast, alignTimestamps));
445   }
446 
447   /**
448    * Same as above with alignTimestamps set to true.
449    *
450    * @see #createVideoSource(boolean, boolean)
451    */
createVideoSource(boolean isScreencast)452   public VideoSource createVideoSource(boolean isScreencast) {
453     return createVideoSource(isScreencast, /* alignTimestamps= */ true);
454   }
455 
createVideoTrack(String id, VideoSource source)456   public VideoTrack createVideoTrack(String id, VideoSource source) {
457     checkPeerConnectionFactoryExists();
458     return new VideoTrack(
459         nativeCreateVideoTrack(nativeFactory, id, source.getNativeVideoTrackSource()));
460   }
461 
createAudioSource(MediaConstraints constraints)462   public AudioSource createAudioSource(MediaConstraints constraints) {
463     checkPeerConnectionFactoryExists();
464     return new AudioSource(nativeCreateAudioSource(nativeFactory, constraints));
465   }
466 
createAudioTrack(String id, AudioSource source)467   public AudioTrack createAudioTrack(String id, AudioSource source) {
468     checkPeerConnectionFactoryExists();
469     return new AudioTrack(nativeCreateAudioTrack(nativeFactory, id, source.getNativeAudioSource()));
470   }
471 
472   // Starts recording an AEC dump. Ownership of the file is transfered to the
473   // native code. If an AEC dump is already in progress, it will be stopped and
474   // a new one will start using the provided file.
startAecDump(int file_descriptor, int filesize_limit_bytes)475   public boolean startAecDump(int file_descriptor, int filesize_limit_bytes) {
476     checkPeerConnectionFactoryExists();
477     return nativeStartAecDump(nativeFactory, file_descriptor, filesize_limit_bytes);
478   }
479 
480   // Stops recording an AEC dump. If no AEC dump is currently being recorded,
481   // this call will have no effect.
stopAecDump()482   public void stopAecDump() {
483     checkPeerConnectionFactoryExists();
484     nativeStopAecDump(nativeFactory);
485   }
486 
dispose()487   public void dispose() {
488     checkPeerConnectionFactoryExists();
489     nativeFreeFactory(nativeFactory);
490     networkThread = null;
491     workerThread = null;
492     signalingThread = null;
493     nativeFactory = 0;
494   }
495 
496   /** Returns a pointer to the native webrtc::PeerConnectionFactoryInterface. */
getNativePeerConnectionFactory()497   public long getNativePeerConnectionFactory() {
498     checkPeerConnectionFactoryExists();
499     return nativeGetNativePeerConnectionFactory(nativeFactory);
500   }
501 
502   /** Returns a pointer to the native OwnedFactoryAndThreads object */
getNativeOwnedFactoryAndThreads()503   public long getNativeOwnedFactoryAndThreads() {
504     checkPeerConnectionFactoryExists();
505     return nativeFactory;
506   }
507 
checkPeerConnectionFactoryExists()508   private void checkPeerConnectionFactoryExists() {
509     if (nativeFactory == 0) {
510       throw new IllegalStateException("PeerConnectionFactory has been disposed.");
511     }
512   }
513 
printStackTrace( @ullable ThreadInfo threadInfo, boolean printNativeStackTrace)514   private static void printStackTrace(
515       @Nullable ThreadInfo threadInfo, boolean printNativeStackTrace) {
516     if (threadInfo == null) {
517       // Thread callbacks have not been completed yet, ignore call.
518       return;
519     }
520     final String threadName = threadInfo.thread.getName();
521     StackTraceElement[] stackTraces = threadInfo.thread.getStackTrace();
522     if (stackTraces.length > 0) {
523       Logging.w(TAG, threadName + " stacktrace:");
524       for (StackTraceElement stackTrace : stackTraces) {
525         Logging.w(TAG, stackTrace.toString());
526       }
527     }
528     if (printNativeStackTrace) {
529       // Imitate output from debuggerd/tombstone so that stack trace can easily be symbolized with
530       // ndk-stack.
531       Logging.w(TAG, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***");
532       Logging.w(TAG,
533           "pid: " + Process.myPid() + ", tid: " + threadInfo.tid + ", name: " + threadName
534               + "  >>> WebRTC <<<");
535       nativePrintStackTrace(threadInfo.tid);
536     }
537   }
538 
539   /** Deprecated, use non-static version instead. */
540   @Deprecated
printStackTraces()541   public static void printStackTraces() {
542     printStackTrace(staticNetworkThread, /* printNativeStackTrace= */ false);
543     printStackTrace(staticWorkerThread, /* printNativeStackTrace= */ false);
544     printStackTrace(staticSignalingThread, /* printNativeStackTrace= */ false);
545   }
546 
547   /**
548    * Print the Java stack traces for the critical threads used by PeerConnectionFactory, namely;
549    * signaling thread, worker thread, and network thread. If printNativeStackTraces is true, also
550    * attempt to print the C++ stack traces for these (and some other) threads.
551    */
printInternalStackTraces(boolean printNativeStackTraces)552   public void printInternalStackTraces(boolean printNativeStackTraces) {
553     printStackTrace(signalingThread, printNativeStackTraces);
554     printStackTrace(workerThread, printNativeStackTraces);
555     printStackTrace(networkThread, printNativeStackTraces);
556     if (printNativeStackTraces) {
557       nativePrintStackTracesOfRegisteredThreads();
558     }
559   }
560 
561   @CalledByNative
onNetworkThreadReady()562   private void onNetworkThreadReady() {
563     networkThread = ThreadInfo.getCurrent();
564     staticNetworkThread = networkThread;
565     Logging.d(TAG, "onNetworkThreadReady");
566   }
567 
568   @CalledByNative
onWorkerThreadReady()569   private void onWorkerThreadReady() {
570     workerThread = ThreadInfo.getCurrent();
571     staticWorkerThread = workerThread;
572     Logging.d(TAG, "onWorkerThreadReady");
573   }
574 
575   @CalledByNative
onSignalingThreadReady()576   private void onSignalingThreadReady() {
577     signalingThread = ThreadInfo.getCurrent();
578     staticSignalingThread = signalingThread;
579     Logging.d(TAG, "onSignalingThreadReady");
580   }
581 
582   // Must be called at least once before creating a PeerConnectionFactory
583   // (for example, at application startup time).
nativeInitializeAndroidGlobals()584   private static native void nativeInitializeAndroidGlobals();
nativeInitializeFieldTrials(String fieldTrialsInitString)585   private static native void nativeInitializeFieldTrials(String fieldTrialsInitString);
nativeFindFieldTrialsFullName(String name)586   private static native String nativeFindFieldTrialsFullName(String name);
nativeInitializeInternalTracer()587   private static native void nativeInitializeInternalTracer();
588   // Internal tracing shutdown, called to prevent resource leaks. Must be called after
589   // PeerConnectionFactory is gone to prevent races with code performing tracing.
nativeShutdownInternalTracer()590   private static native void nativeShutdownInternalTracer();
nativeStartInternalTracingCapture(String tracingFilename)591   private static native boolean nativeStartInternalTracingCapture(String tracingFilename);
nativeStopInternalTracingCapture()592   private static native void nativeStopInternalTracingCapture();
593 
nativeCreatePeerConnectionFactory(Context context, Options options, long nativeAudioDeviceModule, long audioEncoderFactory, long audioDecoderFactory, VideoEncoderFactory encoderFactory, VideoDecoderFactory decoderFactory, long nativeAudioProcessor, long nativeFecControllerFactory, long nativeNetworkControllerFactory, long nativeNetworkStatePredictorFactory, long neteqFactory)594   private static native PeerConnectionFactory nativeCreatePeerConnectionFactory(Context context,
595       Options options, long nativeAudioDeviceModule, long audioEncoderFactory,
596       long audioDecoderFactory, VideoEncoderFactory encoderFactory,
597       VideoDecoderFactory decoderFactory, long nativeAudioProcessor,
598       long nativeFecControllerFactory, long nativeNetworkControllerFactory,
599       long nativeNetworkStatePredictorFactory, long neteqFactory);
600 
nativeCreatePeerConnection(long factory, PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, long nativeObserver, SSLCertificateVerifier sslCertificateVerifier)601   private static native long nativeCreatePeerConnection(long factory,
602       PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, long nativeObserver,
603       SSLCertificateVerifier sslCertificateVerifier);
nativeCreateLocalMediaStream(long factory, String label)604   private static native long nativeCreateLocalMediaStream(long factory, String label);
nativeCreateVideoSource( long factory, boolean is_screencast, boolean alignTimestamps)605   private static native long nativeCreateVideoSource(
606       long factory, boolean is_screencast, boolean alignTimestamps);
nativeCreateVideoTrack( long factory, String id, long nativeVideoSource)607   private static native long nativeCreateVideoTrack(
608       long factory, String id, long nativeVideoSource);
nativeCreateAudioSource(long factory, MediaConstraints constraints)609   private static native long nativeCreateAudioSource(long factory, MediaConstraints constraints);
nativeCreateAudioTrack(long factory, String id, long nativeSource)610   private static native long nativeCreateAudioTrack(long factory, String id, long nativeSource);
nativeStartAecDump( long factory, int file_descriptor, int filesize_limit_bytes)611   private static native boolean nativeStartAecDump(
612       long factory, int file_descriptor, int filesize_limit_bytes);
nativeStopAecDump(long factory)613   private static native void nativeStopAecDump(long factory);
nativeFreeFactory(long factory)614   private static native void nativeFreeFactory(long factory);
nativeGetNativePeerConnectionFactory(long factory)615   private static native long nativeGetNativePeerConnectionFactory(long factory);
nativeInjectLoggable(JNILogging jniLogging, int severity)616   private static native void nativeInjectLoggable(JNILogging jniLogging, int severity);
nativeDeleteLoggable()617   private static native void nativeDeleteLoggable();
nativePrintStackTrace(int tid)618   private static native void nativePrintStackTrace(int tid);
nativePrintStackTracesOfRegisteredThreads()619   private static native void nativePrintStackTracesOfRegisteredThreads();
620 }
621