summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/webrtc/modules/utility
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/webrtc/modules/utility')
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/BUILD.gn72
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/DEPS8
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/OWNERS6
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/include/audio_frame_operations.h20
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/include/helpers_android.h87
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/include/jvm_android.h188
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/include/mock/mock_process_thread.h44
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/include/process_thread.h77
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/source/helpers_android.cc123
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/source/jvm_android.cc289
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.cc224
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.h88
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl_unittest.cc321
-rw-r--r--third_party/libwebrtc/webrtc/modules/utility/utility_gn/moz.build233
14 files changed, 1780 insertions, 0 deletions
diff --git a/third_party/libwebrtc/webrtc/modules/utility/BUILD.gn b/third_party/libwebrtc/webrtc/modules/utility/BUILD.gn
new file mode 100644
index 0000000000..cba8b17b09
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/BUILD.gn
@@ -0,0 +1,72 @@
+# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../webrtc.gni")
+
+rtc_static_library("utility") {
+ sources = [
+ "include/audio_frame_operations.h",
+ "include/helpers_android.h",
+ "include/jvm_android.h",
+ "include/process_thread.h",
+ "source/helpers_android.cc",
+ "source/jvm_android.cc",
+ "source/process_thread_impl.cc",
+ "source/process_thread_impl.h",
+ ]
+
+ if (!build_with_chromium && is_clang) {
+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+ }
+
+ if (is_ios) {
+ libs = [ "AVFoundation.framework" ]
+ }
+
+ deps = [
+ "..:module_api",
+ "../..:webrtc_common",
+ "../../audio/utility:audio_frame_operations",
+ "../../common_audio",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:rtc_task_queue",
+ "../../system_wrappers",
+ "../media_file",
+ ]
+}
+
+rtc_source_set("mock_process_thread") {
+ testonly = true
+ sources = [
+ "include/mock/mock_process_thread.h",
+ ]
+ deps = [
+ ":utility",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:test_support",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_source_set("utility_unittests") {
+ testonly = true
+
+ sources = [
+ "source/process_thread_impl_unittest.cc",
+ ]
+ deps = [
+ ":utility",
+ "..:module_api",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:rtc_task_queue",
+ "../../test:test_support",
+ "//testing/gmock",
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/webrtc/modules/utility/DEPS b/third_party/libwebrtc/webrtc/modules/utility/DEPS
new file mode 100644
index 0000000000..d693ea6221
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+ # TODO(aleloi): remove when clients update. See
+ # bugs.webrtc.org/6548.
+ "+audio/utility/audio_frame_operations.h",
+ "+common_audio",
+ "+common_video",
+ "+system_wrappers",
+]
diff --git a/third_party/libwebrtc/webrtc/modules/utility/OWNERS b/third_party/libwebrtc/webrtc/modules/utility/OWNERS
new file mode 100644
index 0000000000..debeaab6d4
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/OWNERS
@@ -0,0 +1,6 @@
+perkj@webrtc.org
+
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from a reviewer in this file.
+per-file *.gn=*
+per-file *.gni=*
diff --git a/third_party/libwebrtc/webrtc/modules/utility/include/audio_frame_operations.h b/third_party/libwebrtc/webrtc/modules/utility/include/audio_frame_operations.h
new file mode 100644
index 0000000000..adaadfeca7
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/include/audio_frame_operations.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_UTILITY_INCLUDE_AUDIO_FRAME_OPERATIONS_H_
+#define MODULES_UTILITY_INCLUDE_AUDIO_FRAME_OPERATIONS_H_
+// The contents of this file have moved to
+// //audio/utility. This file is deprecated.
+
+// TODO(aleloi): Remove this file when clients have updated their
+// includes. See bugs.webrtc.org/6548.
+#include "audio/utility/audio_frame_operations.h"
+
+#endif // #ifndef MODULES_UTILITY_INCLUDE_AUDIO_FRAME_OPERATIONS_H_
diff --git a/third_party/libwebrtc/webrtc/modules/utility/include/helpers_android.h b/third_party/libwebrtc/webrtc/modules/utility/include/helpers_android.h
new file mode 100644
index 0000000000..c1d9ad87ec
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/include/helpers_android.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_UTILITY_INCLUDE_HELPERS_ANDROID_H_
+#define MODULES_UTILITY_INCLUDE_HELPERS_ANDROID_H_
+
+#include <jni.h>
+#include <string>
+
+// Abort the process if |jni| has a Java exception pending.
+// TODO(henrika): merge with CHECK_JNI_EXCEPTION() in jni_helpers.h.
+#define CHECK_EXCEPTION(jni) \
+ RTC_CHECK(!jni->ExceptionCheck()) \
+ << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
+
+namespace webrtc {
+
+// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
+JNIEnv* GetEnv(JavaVM* jvm);
+
+// Return a |jlong| that will correctly convert back to |ptr|. This is needed
+// because the alternative (of silently passing a 32-bit pointer to a vararg
+// function expecting a 64-bit param) picks up garbage in the high 32 bits.
+jlong PointerTojlong(void* ptr);
+
+// JNIEnv-helper methods that wraps the API which uses the JNI interface
+// pointer (JNIEnv*). It allows us to RTC_CHECK success and that no Java
+// exception is thrown while calling the method.
+jmethodID GetMethodID(
+ JNIEnv* jni, jclass c, const char* name, const char* signature);
+
+jmethodID GetStaticMethodID(
+ JNIEnv* jni, jclass c, const char* name, const char* signature);
+
+jclass FindClass(JNIEnv* jni, const char* name);
+
+jobject NewGlobalRef(JNIEnv* jni, jobject o);
+
+void DeleteGlobalRef(JNIEnv* jni, jobject o);
+
+// Return thread ID as a string.
+std::string GetThreadId();
+
+// Return thread ID as string suitable for debug logging.
+std::string GetThreadInfo();
+
+// Attach thread to JVM if necessary and detach at scope end if originally
+// attached.
+class AttachThreadScoped {
+ public:
+ explicit AttachThreadScoped(JavaVM* jvm);
+ ~AttachThreadScoped();
+ JNIEnv* env();
+
+ private:
+ bool attached_;
+ JavaVM* jvm_;
+ JNIEnv* env_;
+};
+
+// Scoped holder for global Java refs.
+template<class T> // T is jclass, jobject, jintArray, etc.
+class ScopedGlobalRef {
+ public:
+ ScopedGlobalRef(JNIEnv* jni, T obj)
+ : jni_(jni), obj_(static_cast<T>(NewGlobalRef(jni, obj))) {}
+ ~ScopedGlobalRef() {
+ DeleteGlobalRef(jni_, obj_);
+ }
+ T operator*() const {
+ return obj_;
+ }
+ private:
+ JNIEnv* jni_;
+ T obj_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_UTILITY_INCLUDE_HELPERS_ANDROID_H_
diff --git a/third_party/libwebrtc/webrtc/modules/utility/include/jvm_android.h b/third_party/libwebrtc/webrtc/modules/utility/include/jvm_android.h
new file mode 100644
index 0000000000..f899263f76
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/include/jvm_android.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_UTILITY_INCLUDE_JVM_ANDROID_H_
+#define MODULES_UTILITY_INCLUDE_JVM_ANDROID_H_
+
+#include <jni.h>
+
+#include <memory>
+#include <string>
+
+#include "modules/utility/include/helpers_android.h"
+#include "rtc_base/thread_checker.h"
+
+namespace webrtc {
+
+// The JNI interface pointer (JNIEnv) is valid only in the current thread.
+// Should another thread need to access the Java VM, it must first call
+// AttachCurrentThread() to attach itself to the VM and obtain a JNI interface
+// pointer. The native thread remains attached to the VM until it calls
+// DetachCurrentThread() to detach.
+class AttachCurrentThreadIfNeeded {
+ public:
+ AttachCurrentThreadIfNeeded();
+ ~AttachCurrentThreadIfNeeded();
+
+ private:
+ rtc::ThreadChecker thread_checker_;
+ bool attached_;
+};
+
+// This class is created by the NativeRegistration class and is used to wrap
+// the actual Java object handle (jobject) on which we can call methods from
+// C++ in to Java. See example in JVM for more details.
+// TODO(henrika): extend support for type of function calls.
+class GlobalRef {
+ public:
+ GlobalRef(JNIEnv* jni, jobject object);
+ ~GlobalRef();
+
+ jboolean CallBooleanMethod(jmethodID methodID, ...);
+ jint CallIntMethod(jmethodID methodID, ...);
+ void CallVoidMethod(jmethodID methodID, ...);
+
+ private:
+ JNIEnv* const jni_;
+ const jobject j_object_;
+};
+
+// Wraps the jclass object on which we can call GetMethodId() functions to
+// query method IDs.
+class JavaClass {
+ public:
+ JavaClass(JNIEnv* jni, jclass clazz) : jni_(jni), j_class_(clazz) {}
+ ~JavaClass() {}
+
+ jmethodID GetMethodId(const char* name, const char* signature);
+ jmethodID GetStaticMethodId(const char* name, const char* signature);
+ jobject CallStaticObjectMethod(jmethodID methodID, ...);
+ jint CallStaticIntMethod(jmethodID methodID, ...);
+
+ protected:
+ JNIEnv* const jni_;
+ jclass const j_class_;
+};
+
+// Adds support of the NewObject factory method to the JavaClass class.
+// See example in JVM for more details on how to use it.
+class NativeRegistration : public JavaClass {
+ public:
+ NativeRegistration(JNIEnv* jni, jclass clazz);
+ ~NativeRegistration();
+
+ std::unique_ptr<GlobalRef> NewObject(
+ const char* name, const char* signature, ...);
+
+ private:
+ JNIEnv* const jni_;
+};
+
+// This class is created by the JVM class and is used to expose methods that
+// needs the JNI interface pointer but its main purpose is to create a
+// NativeRegistration object given name of a Java class and a list of native
+// methods. See example in JVM for more details.
+class JNIEnvironment {
+ public:
+ explicit JNIEnvironment(JNIEnv* jni);
+ ~JNIEnvironment();
+
+ // Registers native methods with the Java class specified by |name|.
+ // Note that the class name must be one of the names in the static
+ // |loaded_classes| array defined in jvm_android.cc.
+ // This method must be called on the construction thread.
+ std::unique_ptr<NativeRegistration> RegisterNatives(
+ const char* name, const JNINativeMethod *methods, int num_methods);
+
+ // Converts from Java string to std::string.
+ // This method must be called on the construction thread.
+ std::string JavaToStdString(const jstring& j_string);
+
+ private:
+ rtc::ThreadChecker thread_checker_;
+ JNIEnv* const jni_;
+};
+
+// Main class for working with Java from C++ using JNI in WebRTC.
+//
+// Example usage:
+//
+// // At initialization (e.g. in JNI_OnLoad), call JVM::Initialize.
+// JNIEnv* jni = ::base::android::AttachCurrentThread();
+// JavaVM* jvm = NULL;
+// jni->GetJavaVM(&jvm);
+// webrtc::JVM::Initialize(jvm);
+//
+// // Header (.h) file of example class called User.
+// std::unique_ptr<JNIEnvironment> env;
+// std::unique_ptr<NativeRegistration> reg;
+// std::unique_ptr<GlobalRef> obj;
+//
+// // Construction (in .cc file) of User class.
+// User::User() {
+// // Calling thread must be attached to the JVM.
+// env = JVM::GetInstance()->environment();
+// reg = env->RegisterNatives("org/webrtc/WebRtcTest", ,);
+// obj = reg->NewObject("<init>", ,);
+// }
+//
+// // Each User method can now use |reg| and |obj| and call Java functions
+// // in WebRtcTest.java, e.g. boolean init() {}.
+// bool User::Foo() {
+// jmethodID id = reg->GetMethodId("init", "()Z");
+// return obj->CallBooleanMethod(id);
+// }
+//
+// // And finally, e.g. in JNI_OnUnLoad, call JVM::Uninitialize.
+// JVM::Uninitialize();
+class JVM {
+ public:
+ // Stores global handles to the Java VM interface.
+ // Should be called once on a thread that is attached to the JVM.
+ static void Initialize(JavaVM* jvm);
+ // Like the method above but also passes the context to the ContextUtils
+ // class. This method should be used by pure-C++ Android users that can't call
+ // ContextUtils.initialize directly.
+ static void Initialize(JavaVM* jvm, jobject context);
+ // Clears handles stored in Initialize(). Must be called on same thread as
+ // Initialize().
+ static void Uninitialize();
+ // Gives access to the global Java VM interface pointer, which then can be
+ // used to create a valid JNIEnvironment object or to get a JavaClass object.
+ static JVM* GetInstance();
+
+ // Creates a JNIEnvironment object.
+ // This method returns a NULL pointer if AttachCurrentThread() has not been
+ // called successfully. Use the AttachCurrentThreadIfNeeded class if needed.
+ std::unique_ptr<JNIEnvironment> environment();
+
+ // Returns a JavaClass object given class |name|.
+ // Note that the class name must be one of the names in the static
+ // |loaded_classes| array defined in jvm_android.cc.
+ // This method must be called on the construction thread.
+ JavaClass GetClass(const char* name);
+
+ // TODO(henrika): can we make these private?
+ JavaVM* jvm() const { return jvm_; }
+
+ protected:
+ JVM(JavaVM* jvm);
+ ~JVM();
+
+ private:
+ JNIEnv* jni() const { return GetEnv(jvm_); }
+
+ rtc::ThreadChecker thread_checker_;
+ JavaVM* const jvm_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_UTILITY_INCLUDE_JVM_ANDROID_H_
diff --git a/third_party/libwebrtc/webrtc/modules/utility/include/mock/mock_process_thread.h b/third_party/libwebrtc/webrtc/modules/utility/include/mock/mock_process_thread.h
new file mode 100644
index 0000000000..fb88e40074
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/include/mock/mock_process_thread.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_UTILITY_INCLUDE_MOCK_MOCK_PROCESS_THREAD_H_
+#define MODULES_UTILITY_INCLUDE_MOCK_MOCK_PROCESS_THREAD_H_
+
+#include <memory>
+
+#include "modules/utility/include/process_thread.h"
+#include "rtc_base/location.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockProcessThread : public ProcessThread {
+ public:
+ // TODO(nisse): Valid overrides commented out, because the gmock
+ // methods don't use any override declarations, and we want to avoid
+ // warnings from -Winconsistent-missing-override. See
+ // http://crbug.com/428099.
+ MOCK_METHOD0(Start, void());
+ MOCK_METHOD0(Stop, void());
+ MOCK_METHOD1(WakeUp, void(Module* module));
+ MOCK_METHOD1(PostTask, void(rtc::QueuedTask* task));
+ MOCK_METHOD2(RegisterModule, void(Module* module, const rtc::Location&));
+ MOCK_METHOD1(DeRegisterModule, void(Module* module));
+
+ // MOCK_METHOD1 gets confused with mocking this method, so we work around it
+ // by overriding the method from the interface and forwarding the call to a
+ // mocked, simpler method.
+ void PostTask(std::unique_ptr<rtc::QueuedTask> task) /*override*/ {
+ PostTask(task.get());
+ }
+};
+
+} // namespace webrtc
+#endif // MODULES_UTILITY_INCLUDE_MOCK_MOCK_PROCESS_THREAD_H_
diff --git a/third_party/libwebrtc/webrtc/modules/utility/include/process_thread.h b/third_party/libwebrtc/webrtc/modules/utility/include/process_thread.h
new file mode 100644
index 0000000000..28e1191085
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/include/process_thread.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_UTILITY_INCLUDE_PROCESS_THREAD_H_
+#define MODULES_UTILITY_INCLUDE_PROCESS_THREAD_H_
+
+#include <memory>
+
+#include "typedefs.h" // NOLINT(build/include)
+
+#if defined(WEBRTC_WIN)
+// Due to a bug in the std::unique_ptr implementation that ships with MSVS,
+// we need the full definition of QueuedTask, on Windows.
+#include "rtc_base/task_queue.h"
+#else
+namespace rtc {
+class QueuedTask;
+}
+#endif
+
+namespace rtc {
+class Location;
+}
+
+namespace webrtc {
+class Module;
+
+// TODO(tommi): ProcessThread probably doesn't need to be a virtual
+// interface. There exists one override besides ProcessThreadImpl,
+// MockProcessThread, but when looking at how it is used, it seems
+// a nullptr might suffice (or simply an actual ProcessThread instance).
+class ProcessThread {
+ public:
+ virtual ~ProcessThread();
+
+ static std::unique_ptr<ProcessThread> Create(const char* thread_name);
+
+ // Starts the worker thread. Must be called from the construction thread.
+ virtual void Start() = 0;
+
+ // Stops the worker thread. Must be called from the construction thread.
+ virtual void Stop() = 0;
+
+ // Wakes the thread up to give a module a chance to do processing right
+ // away. This causes the worker thread to wake up and requery the specified
+ // module for when it should be called back. (Typically the module should
+ // return 0 from TimeUntilNextProcess on the worker thread at that point).
+ // Can be called on any thread.
+ virtual void WakeUp(Module* module) = 0;
+
+ // Queues a task object to run on the worker thread. Ownership of the
+ // task object is transferred to the ProcessThread and the object will
+ // either be deleted after running on the worker thread, or on the
+ // construction thread of the ProcessThread instance, if the task did not
+ // get a chance to run (e.g. posting the task while shutting down or when
+ // the thread never runs).
+ virtual void PostTask(std::unique_ptr<rtc::QueuedTask> task) = 0;
+
+ // Adds a module that will start to receive callbacks on the worker thread.
+ // Can be called from any thread.
+ virtual void RegisterModule(Module* module, const rtc::Location& from) = 0;
+
+ // Removes a previously registered module.
+ // Can be called from any thread.
+ virtual void DeRegisterModule(Module* module) = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_UTILITY_INCLUDE_PROCESS_THREAD_H_
diff --git a/third_party/libwebrtc/webrtc/modules/utility/source/helpers_android.cc b/third_party/libwebrtc/webrtc/modules/utility/source/helpers_android.cc
new file mode 100644
index 0000000000..c5a91235e3
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/source/helpers_android.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/utility/include/helpers_android.h"
+#include "rtc_base/checks.h"
+
+#include <android/log.h>
+#include <assert.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#define TAG "HelpersAndroid"
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
+
+namespace webrtc {
+
+JNIEnv* GetEnv(JavaVM* jvm) {
+ void* env = NULL;
+ jint status = jvm->GetEnv(&env, JNI_VERSION_1_6);
+ RTC_CHECK(((env != NULL) && (status == JNI_OK)) ||
+ ((env == NULL) && (status == JNI_EDETACHED)))
+ << "Unexpected GetEnv return: " << status << ":" << env;
+ return reinterpret_cast<JNIEnv*>(env);
+}
+
+// Return a |jlong| that will correctly convert back to |ptr|. This is needed
+// because the alternative (of silently passing a 32-bit pointer to a vararg
+// function expecting a 64-bit param) picks up garbage in the high 32 bits.
+jlong PointerTojlong(void* ptr) {
+ static_assert(sizeof(intptr_t) <= sizeof(jlong),
+ "Time to rethink the use of jlongs");
+ // Going through intptr_t to be obvious about the definedness of the
+ // conversion from pointer to integral type. intptr_t to jlong is a standard
+ // widening by the static_assert above.
+ jlong ret = reinterpret_cast<intptr_t>(ptr);
+ RTC_DCHECK(reinterpret_cast<void*>(ret) == ptr);
+ return ret;
+}
+
+jmethodID GetMethodID (
+ JNIEnv* jni, jclass c, const char* name, const char* signature) {
+ jmethodID m = jni->GetMethodID(c, name, signature);
+ CHECK_EXCEPTION(jni) << "Error during GetMethodID: " << name << ", "
+ << signature;
+ RTC_CHECK(m) << name << ", " << signature;
+ return m;
+}
+
+jmethodID GetStaticMethodID (
+ JNIEnv* jni, jclass c, const char* name, const char* signature) {
+ jmethodID m = jni->GetStaticMethodID(c, name, signature);
+ CHECK_EXCEPTION(jni) << "Error during GetStaticMethodID: " << name << ", "
+ << signature;
+ RTC_CHECK(m) << name << ", " << signature;
+ return m;
+}
+
+jclass FindClass(JNIEnv* jni, const char* name) {
+ jclass c = jni->FindClass(name);
+ CHECK_EXCEPTION(jni) << "Error during FindClass: " << name;
+ RTC_CHECK(c) << name;
+ return c;
+}
+
+jobject NewGlobalRef(JNIEnv* jni, jobject o) {
+ jobject ret = jni->NewGlobalRef(o);
+ CHECK_EXCEPTION(jni) << "Error during NewGlobalRef";
+ RTC_CHECK(ret);
+ return ret;
+}
+
+void DeleteGlobalRef(JNIEnv* jni, jobject o) {
+ jni->DeleteGlobalRef(o);
+ CHECK_EXCEPTION(jni) << "Error during DeleteGlobalRef";
+}
+
+std::string GetThreadId() {
+ char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
+ int thread_id = gettid();
+ RTC_CHECK_LT(snprintf(buf, sizeof(buf), "%i", thread_id),
+ static_cast<int>(sizeof(buf)))
+ << "Thread id is bigger than uint64??";
+ return std::string(buf);
+}
+
+std::string GetThreadInfo() {
+ return "@[tid=" + GetThreadId() + "]";
+}
+
+AttachThreadScoped::AttachThreadScoped(JavaVM* jvm)
+ : attached_(false), jvm_(jvm), env_(NULL) {
+ env_ = GetEnv(jvm);
+ if (!env_) {
+ // Adding debug log here so we can track down potential leaks and figure
+ // out why we sometimes see "Native thread exiting without having called
+ // DetachCurrentThread" in logcat outputs.
+ ALOGD("Attaching thread to JVM%s", GetThreadInfo().c_str());
+ jint res = jvm->AttachCurrentThread(&env_, NULL);
+ attached_ = (res == JNI_OK);
+ RTC_CHECK(attached_) << "AttachCurrentThread failed: " << res;
+ }
+}
+
+AttachThreadScoped::~AttachThreadScoped() {
+ if (attached_) {
+ ALOGD("Detaching thread from JVM%s", GetThreadInfo().c_str());
+ jint res = jvm_->DetachCurrentThread();
+ RTC_CHECK(res == JNI_OK) << "DetachCurrentThread failed: " << res;
+ RTC_CHECK(!GetEnv(jvm_));
+ }
+}
+
+JNIEnv* AttachThreadScoped::env() { return env_; }
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/modules/utility/source/jvm_android.cc b/third_party/libwebrtc/webrtc/modules/utility/source/jvm_android.cc
new file mode 100644
index 0000000000..f828d218ae
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/source/jvm_android.cc
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <android/log.h>
+
+#include <memory>
+
+#include "modules/utility/include/jvm_android.h"
+
+#include "rtc_base/checks.h"
+
+namespace mozilla {
+namespace jni {
+jclass GetClassRef(JNIEnv* aEnv, const char* aClassName);
+}
+}
+
+#define TAG "JVM"
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
+
+namespace webrtc {
+
+JVM* g_jvm;
+
+// TODO(henrika): add more clases here if needed.
+struct {
+ const char* name;
+ jclass clazz;
+} loaded_classes[] = {
+ {"org/webrtc/voiceengine/BuildInfo", nullptr},
+ {"org/webrtc/voiceengine/WebRtcAudioManager", nullptr},
+ {"org/webrtc/voiceengine/WebRtcAudioRecord", nullptr},
+ {"org/webrtc/voiceengine/WebRtcAudioTrack", nullptr},
+};
+
+// Android's FindClass() is trickier than usual because the app-specific
+// ClassLoader is not consulted when there is no app-specific frame on the
+// stack. Consequently, we only look up all classes once in native WebRTC.
+// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
+void LoadClasses(JNIEnv* jni) {
+ ALOGD("LoadClasses");
+ for (auto& c : loaded_classes) {
+ ALOGD("name: %s", c.name);
+ jclass clsRef = mozilla::jni::GetClassRef(jni, c.name);
+ RTC_CHECK(clsRef) << c.name;
+ c.clazz = static_cast<jclass>(jni->NewGlobalRef(clsRef));
+ jni->DeleteLocalRef(clsRef);
+ }
+}
+
+void FreeClassReferences(JNIEnv* jni) {
+ for (auto& c : loaded_classes) {
+ jni->DeleteGlobalRef(c.clazz);
+ c.clazz = nullptr;
+ }
+}
+
+jclass LookUpClass(const char* name) {
+ for (auto& c : loaded_classes) {
+ if (strcmp(c.name, name) == 0)
+ return c.clazz;
+ }
+ RTC_CHECK(false) << "Unable to find class in lookup table";
+ return 0;
+}
+
+// AttachCurrentThreadIfNeeded implementation.
+AttachCurrentThreadIfNeeded::AttachCurrentThreadIfNeeded()
+ : attached_(false) {
+ ALOGD("AttachCurrentThreadIfNeeded::ctor%s", GetThreadInfo().c_str());
+ JavaVM* jvm = JVM::GetInstance()->jvm();
+ RTC_CHECK(jvm);
+ JNIEnv* jni = GetEnv(jvm);
+ if (!jni) {
+ ALOGD("Attaching thread to JVM");
+ JNIEnv* env = nullptr;
+ jint ret = jvm->AttachCurrentThread(&env, nullptr);
+ attached_ = (ret == JNI_OK);
+ }
+}
+
+AttachCurrentThreadIfNeeded::~AttachCurrentThreadIfNeeded() {
+ ALOGD("AttachCurrentThreadIfNeeded::dtor%s", GetThreadInfo().c_str());
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ if (attached_) {
+ ALOGD("Detaching thread from JVM");
+ jint res = JVM::GetInstance()->jvm()->DetachCurrentThread();
+ RTC_CHECK(res == JNI_OK) << "DetachCurrentThread failed: " << res;
+ }
+}
+
+// GlobalRef implementation.
+GlobalRef::GlobalRef(JNIEnv* jni, jobject object)
+ : jni_(jni), j_object_(NewGlobalRef(jni, object)) {
+ ALOGD("GlobalRef::ctor%s", GetThreadInfo().c_str());
+}
+
+GlobalRef::~GlobalRef() {
+ ALOGD("GlobalRef::dtor%s", GetThreadInfo().c_str());
+ DeleteGlobalRef(jni_, j_object_);
+}
+
+jboolean GlobalRef::CallBooleanMethod(jmethodID methodID, ...) {
+ va_list args;
+ va_start(args, methodID);
+ jboolean res = jni_->CallBooleanMethodV(j_object_, methodID, args);
+ CHECK_EXCEPTION(jni_) << "Error during CallBooleanMethod";
+ va_end(args);
+ return res;
+}
+
+jint GlobalRef::CallIntMethod(jmethodID methodID, ...) {
+ va_list args;
+ va_start(args, methodID);
+ jint res = jni_->CallIntMethodV(j_object_, methodID, args);
+ CHECK_EXCEPTION(jni_) << "Error during CallIntMethod";
+ va_end(args);
+ return res;
+}
+
+void GlobalRef::CallVoidMethod(jmethodID methodID, ...) {
+ va_list args;
+ va_start(args, methodID);
+ jni_->CallVoidMethodV(j_object_, methodID, args);
+ CHECK_EXCEPTION(jni_) << "Error during CallVoidMethod";
+ va_end(args);
+}
+
+// NativeRegistration implementation.
+NativeRegistration::NativeRegistration(JNIEnv* jni, jclass clazz)
+ : JavaClass(jni, clazz), jni_(jni) {
+ ALOGD("NativeRegistration::ctor%s", GetThreadInfo().c_str());
+}
+
+NativeRegistration::~NativeRegistration() {
+ ALOGD("NativeRegistration::dtor%s", GetThreadInfo().c_str());
+ jni_->UnregisterNatives(j_class_);
+ CHECK_EXCEPTION(jni_) << "Error during UnregisterNatives";
+}
+
+std::unique_ptr<GlobalRef> NativeRegistration::NewObject(
+ const char* name, const char* signature, ...) {
+ ALOGD("NativeRegistration::NewObject%s", GetThreadInfo().c_str());
+ va_list args;
+ va_start(args, signature);
+ jobject obj = jni_->NewObjectV(j_class_,
+ GetMethodID(jni_, j_class_, name, signature),
+ args);
+ CHECK_EXCEPTION(jni_) << "Error during NewObjectV";
+ va_end(args);
+ return std::unique_ptr<GlobalRef>(new GlobalRef(jni_, obj));
+}
+
+// JavaClass implementation.
+jmethodID JavaClass::GetMethodId(
+ const char* name, const char* signature) {
+ return GetMethodID(jni_, j_class_, name, signature);
+}
+
+jmethodID JavaClass::GetStaticMethodId(
+ const char* name, const char* signature) {
+ return GetStaticMethodID(jni_, j_class_, name, signature);
+}
+
+jobject JavaClass::CallStaticObjectMethod(jmethodID methodID, ...) {
+ va_list args;
+ va_start(args, methodID);
+ jobject res = jni_->CallStaticObjectMethodV(j_class_, methodID, args);
+ CHECK_EXCEPTION(jni_) << "Error during CallStaticObjectMethod";
+ return res;
+}
+
+jint JavaClass::CallStaticIntMethod(jmethodID methodID, ...) {
+ va_list args;
+ va_start(args, methodID);
+ jint res = jni_->CallStaticIntMethodV(j_class_, methodID, args);
+ CHECK_EXCEPTION(jni_) << "Error during CallStaticIntMethod";
+ return res;
+}
+
+// JNIEnvironment implementation.
+JNIEnvironment::JNIEnvironment(JNIEnv* jni) : jni_(jni) {
+ ALOGD("JNIEnvironment::ctor%s", GetThreadInfo().c_str());
+}
+
+JNIEnvironment::~JNIEnvironment() {
+ ALOGD("JNIEnvironment::dtor%s", GetThreadInfo().c_str());
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+std::unique_ptr<NativeRegistration> JNIEnvironment::RegisterNatives(
+ const char* name, const JNINativeMethod *methods, int num_methods) {
+ ALOGD("JNIEnvironment::RegisterNatives(%s)", name);
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ jclass clazz = LookUpClass(name);
+ jni_->RegisterNatives(clazz, methods, num_methods);
+ CHECK_EXCEPTION(jni_) << "Error during RegisterNatives";
+ return std::unique_ptr<NativeRegistration>(
+ new NativeRegistration(jni_, clazz));
+}
+
+std::string JNIEnvironment::JavaToStdString(const jstring& j_string) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ const char* jchars = jni_->GetStringUTFChars(j_string, nullptr);
+ CHECK_EXCEPTION(jni_);
+ const int size = jni_->GetStringUTFLength(j_string);
+ CHECK_EXCEPTION(jni_);
+ std::string ret(jchars, size);
+ jni_->ReleaseStringUTFChars(j_string, jchars);
+ CHECK_EXCEPTION(jni_);
+ return ret;
+}
+
+// static
+void JVM::Initialize(JavaVM* jvm) {
+ ALOGD("JVM::Initialize%s", GetThreadInfo().c_str());
+ if (g_jvm) {
+ return;
+ }
+ g_jvm = new JVM(jvm);
+}
+
+void JVM::Initialize(JavaVM* jvm, jobject context) {
+ Initialize(jvm);
+
+ // Pass in the context to the new ContextUtils class.
+ JNIEnv* jni = g_jvm->jni();
+ jclass context_utils = FindClass(jni, "org/webrtc/ContextUtils");
+ jmethodID initialize_method = jni->GetStaticMethodID(
+ context_utils, "initialize", "(Landroid/content/Context;)V");
+ jni->CallStaticVoidMethod(context_utils, initialize_method, context);
+}
+
+// static
+void JVM::Uninitialize() {
+ ALOGD("JVM::Uninitialize%s", GetThreadInfo().c_str());
+ RTC_DCHECK(g_jvm);
+ delete g_jvm;
+ g_jvm = nullptr;
+}
+
+// static
+JVM* JVM::GetInstance() {
+ RTC_DCHECK(g_jvm);
+ return g_jvm;
+}
+
+JVM::JVM(JavaVM* jvm) : jvm_(jvm) {
+ ALOGD("JVM::JVM%s", GetThreadInfo().c_str());
+ RTC_CHECK(jni()) << "AttachCurrentThread() must be called on this thread.";
+ LoadClasses(jni());
+}
+
+JVM::~JVM() {
+ ALOGD("JVM::~JVM%s", GetThreadInfo().c_str());
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ FreeClassReferences(jni());
+}
+
+std::unique_ptr<JNIEnvironment> JVM::environment() {
+ ALOGD("JVM::environment%s", GetThreadInfo().c_str());
+ // The JNIEnv is used for thread-local storage. For this reason, we cannot
+ // share a JNIEnv between threads. If a piece of code has no other way to get
+ // its JNIEnv, we should share the JavaVM, and use GetEnv to discover the
+ // thread's JNIEnv. (Assuming it has one, if not, use AttachCurrentThread).
+ // See // http://developer.android.com/training/articles/perf-jni.html.
+ JNIEnv* jni = GetEnv(jvm_);
+ if (!jni) {
+ ALOGE("AttachCurrentThread() has not been called on this thread.");
+ return std::unique_ptr<JNIEnvironment>();
+ }
+ return std::unique_ptr<JNIEnvironment>(new JNIEnvironment(jni));
+}
+
+JavaClass JVM::GetClass(const char* name) {
+ ALOGD("JVM::GetClass(%s)%s", name, GetThreadInfo().c_str());
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ return JavaClass(jni(), LookUpClass(name));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.cc b/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.cc
new file mode 100644
index 0000000000..014624e48c
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.cc
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/utility/source/process_thread_impl.h"
+
+#include "modules/include/module.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/timeutils.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+namespace {
+
+// We use this constant internally to signal that a module has requested
+// a callback right away. When this is set, no call to TimeUntilNextProcess
+// should be made, but Process() should be called directly.
+const int64_t kCallProcessImmediately = -1;
+
+int64_t GetNextCallbackTime(Module* module, int64_t time_now) {
+ int64_t interval = module->TimeUntilNextProcess();
+ if (interval < 0) {
+ // Falling behind, we should call the callback now.
+ return time_now;
+ }
+ return time_now + interval;
+}
+}
+
+ProcessThread::~ProcessThread() {}
+
+// static
+std::unique_ptr<ProcessThread> ProcessThread::Create(
+ const char* thread_name) {
+ return std::unique_ptr<ProcessThread>(new ProcessThreadImpl(thread_name));
+}
+
+ProcessThreadImpl::ProcessThreadImpl(const char* thread_name)
+ : wake_up_(EventWrapper::Create()),
+ stop_(false),
+ thread_name_(thread_name) {}
+
+ProcessThreadImpl::~ProcessThreadImpl() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(!thread_.get());
+ RTC_DCHECK(!stop_);
+
+ while (!queue_.empty()) {
+ delete queue_.front();
+ queue_.pop();
+ }
+}
+
+void ProcessThreadImpl::Start() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(!thread_.get());
+ if (thread_.get())
+ return;
+
+ RTC_DCHECK(!stop_);
+
+ for (ModuleCallback& m : modules_)
+ m.module->ProcessThreadAttached(this);
+
+ thread_.reset(
+ new rtc::PlatformThread(&ProcessThreadImpl::Run, this, thread_name_));
+ thread_->Start();
+}
+
+void ProcessThreadImpl::Stop() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ if(!thread_.get())
+ return;
+
+ {
+ rtc::CritScope lock(&lock_);
+ stop_ = true;
+ }
+
+ wake_up_->Set();
+
+ thread_->Stop();
+ stop_ = false;
+
+ thread_.reset();
+ for (ModuleCallback& m : modules_)
+ m.module->ProcessThreadAttached(nullptr);
+}
+
+void ProcessThreadImpl::WakeUp(Module* module) {
+ // Allowed to be called on any thread.
+ {
+ rtc::CritScope lock(&lock_);
+ for (ModuleCallback& m : modules_) {
+ if (m.module == module)
+ m.next_callback = kCallProcessImmediately;
+ }
+ }
+ wake_up_->Set();
+}
+
+void ProcessThreadImpl::PostTask(std::unique_ptr<rtc::QueuedTask> task) {
+ // Allowed to be called on any thread.
+ {
+ rtc::CritScope lock(&lock_);
+ queue_.push(task.release());
+ }
+ wake_up_->Set();
+}
+
+void ProcessThreadImpl::RegisterModule(Module* module,
+ const rtc::Location& from) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(module) << from.ToString();
+
+#if RTC_DCHECK_IS_ON
+ {
+ // Catch programmer error.
+ rtc::CritScope lock(&lock_);
+ for (const ModuleCallback& mc : modules_) {
+ RTC_DCHECK(mc.module != module)
+ << "Already registered here: " << mc.location.ToString() << "\n"
+ << "Now attempting from here: " << from.ToString();
+ }
+ }
+#endif
+
+ // Now that we know the module isn't in the list, we'll call out to notify
+ // the module that it's attached to the worker thread. We don't hold
+ // the lock while we make this call.
+ if (thread_.get())
+ module->ProcessThreadAttached(this);
+
+ {
+ rtc::CritScope lock(&lock_);
+ modules_.push_back(ModuleCallback(module, from));
+ }
+
+ // Wake the thread calling ProcessThreadImpl::Process() to update the
+ // waiting time. The waiting time for the just registered module may be
+ // shorter than all other registered modules.
+ wake_up_->Set();
+}
+
+void ProcessThreadImpl::DeRegisterModule(Module* module) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(module);
+
+ {
+ rtc::CritScope lock(&lock_);
+ modules_.remove_if([&module](const ModuleCallback& m) {
+ return m.module == module;
+ });
+ }
+
+ // Notify the module that it's been detached.
+ module->ProcessThreadAttached(nullptr);
+}
+
+// static
+bool ProcessThreadImpl::Run(void* obj) {
+ return static_cast<ProcessThreadImpl*>(obj)->Process();
+}
+
+bool ProcessThreadImpl::Process() {
+ TRACE_EVENT1("webrtc", "ProcessThreadImpl", "name", thread_name_);
+ int64_t now = rtc::TimeMillis();
+ int64_t next_checkpoint = now + (1000 * 60);
+
+ {
+ rtc::CritScope lock(&lock_);
+ if (stop_)
+ return false;
+ for (ModuleCallback& m : modules_) {
+ // TODO(tommi): Would be good to measure the time TimeUntilNextProcess
+ // takes and dcheck if it takes too long (e.g. >=10ms). Ideally this
+ // operation should not require taking a lock, so querying all modules
+ // should run in a matter of nanoseconds.
+ if (m.next_callback == 0)
+ m.next_callback = GetNextCallbackTime(m.module, now);
+
+ if (m.next_callback <= now ||
+ m.next_callback == kCallProcessImmediately) {
+ {
+ TRACE_EVENT2("webrtc", "ModuleProcess", "function",
+ m.location.function_name(), "file",
+ m.location.file_and_line());
+ m.module->Process();
+ }
+ // Use a new 'now' reference to calculate when the next callback
+ // should occur. We'll continue to use 'now' above for the baseline
+ // of calculating how long we should wait, to reduce variance.
+ int64_t new_now = rtc::TimeMillis();
+ m.next_callback = GetNextCallbackTime(m.module, new_now);
+ }
+
+ if (m.next_callback < next_checkpoint)
+ next_checkpoint = m.next_callback;
+ }
+
+ while (!queue_.empty()) {
+ rtc::QueuedTask* task = queue_.front();
+ queue_.pop();
+ lock_.Leave();
+ task->Run();
+ delete task;
+ lock_.Enter();
+ }
+ }
+
+ int64_t time_to_wait = next_checkpoint - rtc::TimeMillis();
+ if (time_to_wait > 0)
+ wake_up_->Wait(static_cast<unsigned long>(time_to_wait));
+
+ return true;
+}
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.h b/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.h
new file mode 100644
index 0000000000..9856fba576
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_UTILITY_SOURCE_PROCESS_THREAD_IMPL_H_
+#define MODULES_UTILITY_SOURCE_PROCESS_THREAD_IMPL_H_
+
+#include <list>
+#include <memory>
+#include <queue>
+
+#include "modules/utility/include/process_thread.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/location.h"
+#include "rtc_base/platform_thread.h"
+#include "rtc_base/thread_checker.h"
+#include "system_wrappers/include/event_wrapper.h"
+#include "typedefs.h" // NOLINT(build/include)
+
+namespace webrtc {
+
+class ProcessThreadImpl : public ProcessThread {
+ public:
+ explicit ProcessThreadImpl(const char* thread_name);
+ ~ProcessThreadImpl() override;
+
+ void Start() override;
+ void Stop() override;
+
+ void WakeUp(Module* module) override;
+ void PostTask(std::unique_ptr<rtc::QueuedTask> task) override;
+
+ void RegisterModule(Module* module, const rtc::Location& from) override;
+ void DeRegisterModule(Module* module) override;
+
+ protected:
+ static bool Run(void* obj);
+ bool Process();
+
+ private:
+ struct ModuleCallback {
+ ModuleCallback() = delete;
+ ModuleCallback(ModuleCallback&& cb) = default;
+ ModuleCallback(const ModuleCallback& cb) = default;
+ ModuleCallback(Module* module, const rtc::Location& location)
+ : module(module), location(location) {}
+ bool operator==(const ModuleCallback& cb) const {
+ return cb.module == module;
+ }
+
+ Module* const module;
+ int64_t next_callback = 0; // Absolute timestamp.
+ const rtc::Location location;
+
+ private:
+ ModuleCallback& operator=(ModuleCallback&);
+ };
+
+ typedef std::list<ModuleCallback> ModuleList;
+
+ // Warning: For some reason, if |lock_| comes immediately before |modules_|
+ // with the current class layout, we will start to have mysterious crashes
+ // on Mac 10.9 debug. I (Tommi) suspect we're hitting some obscure alignemnt
+ // issues, but I haven't figured out what they are, if there are alignment
+ // requirements for mutexes on Mac or if there's something else to it.
+ // So be careful with changing the layout.
+ rtc::CriticalSection lock_; // Used to guard modules_, tasks_ and stop_.
+
+ rtc::ThreadChecker thread_checker_;
+ const std::unique_ptr<EventWrapper> wake_up_;
+ // TODO(pbos): Remove unique_ptr and stop recreating the thread.
+ std::unique_ptr<rtc::PlatformThread> thread_;
+
+ ModuleList modules_;
+ std::queue<rtc::QueuedTask*> queue_;
+ bool stop_;
+ const char* thread_name_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_UTILITY_SOURCE_PROCESS_THREAD_IMPL_H_
diff --git a/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl_unittest.cc b/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl_unittest.cc
new file mode 100644
index 0000000000..d27896410e
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl_unittest.cc
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <memory>
+#include <utility>
+
+#include "modules/include/module.h"
+#include "modules/utility/source/process_thread_impl.h"
+#include "rtc_base/location.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/timeutils.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+// The length of time, in milliseconds, to wait for an event to become signaled.
+// Set to a fairly large value as there is quite a bit of variation on some
+// Windows bots.
+static const int kEventWaitTimeout = 500;
+
+class MockModule : public Module {
+ public:
+ MOCK_METHOD0(TimeUntilNextProcess, int64_t());
+ MOCK_METHOD0(Process, void());
+ MOCK_METHOD1(ProcessThreadAttached, void(ProcessThread*));
+};
+
+class RaiseEventTask : public rtc::QueuedTask {
+ public:
+ RaiseEventTask(EventWrapper* event) : event_(event) {}
+ bool Run() override {
+ event_->Set();
+ return true;
+ }
+
+ private:
+ EventWrapper* event_;
+};
+
+ACTION_P(SetEvent, event) {
+ event->Set();
+}
+
+ACTION_P(Increment, counter) {
+ ++(*counter);
+}
+
+ACTION_P(SetTimestamp, ptr) {
+ *ptr = rtc::TimeMillis();
+}
+
+TEST(ProcessThreadImpl, StartStop) {
+ ProcessThreadImpl thread("ProcessThread");
+ thread.Start();
+ thread.Stop();
+}
+
+TEST(ProcessThreadImpl, MultipleStartStop) {
+ ProcessThreadImpl thread("ProcessThread");
+ for (int i = 0; i < 5; ++i) {
+ thread.Start();
+ thread.Stop();
+ }
+}
+
+// Verifies that we get at least call back to Process() on the worker thread.
+TEST(ProcessThreadImpl, ProcessCall) {
+ ProcessThreadImpl thread("ProcessThread");
+ thread.Start();
+
+ std::unique_ptr<EventWrapper> event(EventWrapper::Create());
+
+ MockModule module;
+ EXPECT_CALL(module, TimeUntilNextProcess())
+ .WillOnce(Return(0))
+ .WillRepeatedly(Return(1));
+ EXPECT_CALL(module, Process())
+ .WillOnce(DoAll(SetEvent(event.get()), Return()))
+ .WillRepeatedly(Return());
+ EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
+
+ thread.RegisterModule(&module, RTC_FROM_HERE);
+ EXPECT_EQ(kEventSignaled, event->Wait(kEventWaitTimeout));
+
+ EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
+ thread.Stop();
+}
+
+// Same as ProcessCall except the module is registered before the
+// call to Start().
+TEST(ProcessThreadImpl, ProcessCall2) {
+ ProcessThreadImpl thread("ProcessThread");
+ std::unique_ptr<EventWrapper> event(EventWrapper::Create());
+
+ MockModule module;
+ EXPECT_CALL(module, TimeUntilNextProcess())
+ .WillOnce(Return(0))
+ .WillRepeatedly(Return(1));
+ EXPECT_CALL(module, Process())
+ .WillOnce(DoAll(SetEvent(event.get()), Return()))
+ .WillRepeatedly(Return());
+
+ thread.RegisterModule(&module, RTC_FROM_HERE);
+
+ EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
+ thread.Start();
+ EXPECT_EQ(kEventSignaled, event->Wait(kEventWaitTimeout));
+
+ EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
+ thread.Stop();
+}
+
+// Tests setting up a module for callbacks and then unregister that module.
+// After unregistration, we should not receive any further callbacks.
+TEST(ProcessThreadImpl, Deregister) {
+ ProcessThreadImpl thread("ProcessThread");
+ std::unique_ptr<EventWrapper> event(EventWrapper::Create());
+
+ int process_count = 0;
+ MockModule module;
+ EXPECT_CALL(module, TimeUntilNextProcess())
+ .WillOnce(Return(0))
+ .WillRepeatedly(Return(1));
+ EXPECT_CALL(module, Process())
+ .WillOnce(DoAll(SetEvent(event.get()),
+ Increment(&process_count),
+ Return()))
+ .WillRepeatedly(DoAll(Increment(&process_count), Return()));
+
+ thread.RegisterModule(&module, RTC_FROM_HERE);
+
+ EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
+ thread.Start();
+
+ EXPECT_EQ(kEventSignaled, event->Wait(kEventWaitTimeout));
+
+ EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
+ thread.DeRegisterModule(&module);
+
+ EXPECT_GE(process_count, 1);
+ int count_after_deregister = process_count;
+
+ // We shouldn't get any more callbacks.
+ EXPECT_EQ(kEventTimeout, event->Wait(20));
+ EXPECT_EQ(count_after_deregister, process_count);
+ thread.Stop();
+}
+
+// Helper function for testing receiving a callback after a certain amount of
+// time. There's some variance of timing built into it to reduce chance of
+// flakiness on bots.
+void ProcessCallAfterAFewMs(int64_t milliseconds) {
+ ProcessThreadImpl thread("ProcessThread");
+ thread.Start();
+
+ std::unique_ptr<EventWrapper> event(EventWrapper::Create());
+
+ MockModule module;
+ int64_t start_time = 0;
+ int64_t called_time = 0;
+ EXPECT_CALL(module, TimeUntilNextProcess())
+ .WillOnce(DoAll(SetTimestamp(&start_time),
+ Return(milliseconds)))
+ .WillRepeatedly(Return(milliseconds));
+ EXPECT_CALL(module, Process())
+ .WillOnce(DoAll(SetTimestamp(&called_time),
+ SetEvent(event.get()),
+ Return()))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
+ thread.RegisterModule(&module, RTC_FROM_HERE);
+
+ // Add a buffer of 50ms due to slowness of some trybots
+ // (e.g. win_drmemory_light)
+ EXPECT_EQ(kEventSignaled, event->Wait(milliseconds + 50));
+
+ EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
+ thread.Stop();
+
+ ASSERT_GT(start_time, 0);
+ ASSERT_GT(called_time, 0);
+ // Use >= instead of > since due to rounding and timer accuracy (or lack
+ // thereof), can make the test run in "0"ms time.
+ EXPECT_GE(called_time, start_time);
+ // Check for an acceptable range.
+ uint32_t diff = called_time - start_time;
+ EXPECT_GE(diff, milliseconds - 15);
+ EXPECT_LT(diff, milliseconds + 15);
+}
+
+// DISABLED for now since the virtual build bots are too slow :(
+// TODO(tommi): Fix.
+TEST(ProcessThreadImpl, DISABLED_ProcessCallAfter5ms) {
+ ProcessCallAfterAFewMs(5);
+}
+
+// DISABLED for now since the virtual build bots are too slow :(
+// TODO(tommi): Fix.
+TEST(ProcessThreadImpl, DISABLED_ProcessCallAfter50ms) {
+ ProcessCallAfterAFewMs(50);
+}
+
+// DISABLED for now since the virtual build bots are too slow :(
+// TODO(tommi): Fix.
+TEST(ProcessThreadImpl, DISABLED_ProcessCallAfter200ms) {
+ ProcessCallAfterAFewMs(200);
+}
+
+// Runs callbacks with the goal of getting up to 50 callbacks within a second
+// (on average 1 callback every 20ms). On real hardware, we're usually pretty
+// close to that, but the test bots that run on virtual machines, will
+// typically be in the range 30-40 callbacks.
+// DISABLED for now since this can take up to 2 seconds to run on the slowest
+// build bots.
+// TODO(tommi): Fix.
+TEST(ProcessThreadImpl, DISABLED_Process50Times) {
+ ProcessThreadImpl thread("ProcessThread");
+ thread.Start();
+
+ std::unique_ptr<EventWrapper> event(EventWrapper::Create());
+
+ MockModule module;
+ int callback_count = 0;
+ // Ask for a callback after 20ms.
+ EXPECT_CALL(module, TimeUntilNextProcess())
+ .WillRepeatedly(Return(20));
+ EXPECT_CALL(module, Process())
+ .WillRepeatedly(DoAll(Increment(&callback_count),
+ Return()));
+
+ EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
+ thread.RegisterModule(&module, RTC_FROM_HERE);
+
+ EXPECT_EQ(kEventTimeout, event->Wait(1000));
+
+ EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
+ thread.Stop();
+
+ printf("Callback count: %i\n", callback_count);
+ // Check that we got called back up to 50 times.
+ // Some of the try bots run on slow virtual machines, so the lower bound
+ // is much more relaxed to avoid flakiness.
+ EXPECT_GE(callback_count, 25);
+ EXPECT_LE(callback_count, 50);
+}
+
+// Tests that we can wake up the worker thread to give us a callback right
+// away when we know the thread is sleeping.
+TEST(ProcessThreadImpl, WakeUp) {
+ ProcessThreadImpl thread("ProcessThread");
+ thread.Start();
+
+ std::unique_ptr<EventWrapper> started(EventWrapper::Create());
+ std::unique_ptr<EventWrapper> called(EventWrapper::Create());
+
+ MockModule module;
+ int64_t start_time;
+ int64_t called_time;
+
+ // Ask for a callback after 1000ms.
+ // TimeUntilNextProcess will be called twice.
+ // The first time we use it to get the thread into a waiting state.
+ // Then we wake the thread and there should not be another call made to
+ // TimeUntilNextProcess before Process() is called.
+ // The second time TimeUntilNextProcess is then called, is after Process
+ // has been called and we don't expect any more calls.
+ EXPECT_CALL(module, TimeUntilNextProcess())
+ .WillOnce(DoAll(SetTimestamp(&start_time),
+ SetEvent(started.get()),
+ Return(1000)))
+ .WillOnce(Return(1000));
+ EXPECT_CALL(module, Process())
+ .WillOnce(
+ DoAll(SetTimestamp(&called_time), SetEvent(called.get()), Return()))
+ .WillRepeatedly(Return());
+
+ EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
+ thread.RegisterModule(&module, RTC_FROM_HERE);
+
+ EXPECT_EQ(kEventSignaled, started->Wait(kEventWaitTimeout));
+ thread.WakeUp(&module);
+ EXPECT_EQ(kEventSignaled, called->Wait(kEventWaitTimeout));
+
+ EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
+ thread.Stop();
+
+ EXPECT_GE(called_time, start_time);
+ uint32_t diff = called_time - start_time;
+ // We should have been called back much quicker than 1sec.
+ EXPECT_LE(diff, 100u);
+}
+
+// Tests that we can post a task that gets run straight away on the worker
+// thread.
+TEST(ProcessThreadImpl, PostTask) {
+ ProcessThreadImpl thread("ProcessThread");
+ std::unique_ptr<EventWrapper> task_ran(EventWrapper::Create());
+ std::unique_ptr<RaiseEventTask> task(new RaiseEventTask(task_ran.get()));
+ thread.Start();
+ thread.PostTask(std::move(task));
+ EXPECT_EQ(kEventSignaled, task_ran->Wait(kEventWaitTimeout));
+ thread.Stop();
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/webrtc/modules/utility/utility_gn/moz.build b/third_party/libwebrtc/webrtc/modules/utility/utility_gn/moz.build
new file mode 100644
index 0000000000..781f096e41
--- /dev/null
+++ b/third_party/libwebrtc/webrtc/modules/utility/utility_gn/moz.build
@@ -0,0 +1,233 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["CHROMIUM_BUILD"] = True
+DEFINES["V8_DEPRECATION_WARNINGS"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_RESTRICT_LOGGING"] = True
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "/ipc/chromium/src",
+ "/ipc/glue",
+ "/third_party/libwebrtc/webrtc/",
+ "/third_party/libwebrtc/webrtc/common_audio/resampler/include/",
+ "/third_party/libwebrtc/webrtc/common_audio/signal_processing/include/",
+ "/third_party/libwebrtc/webrtc/common_audio/vad/include/"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/webrtc/modules/utility/source/process_thread_impl.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+ DEFINES["WTF_USE_DYNAMIC_ANNOTATIONS"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION"] = "r12b"
+ DEFINES["DISABLE_NACL"] = True
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["NO_TCMALLOC"] = True
+ DEFINES["USE_OPENSSL_CERTS"] = "1"
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["__GNU_SOURCE"] = "1"
+
+ OS_LIBS += [
+ "log"
+ ]
+
+ UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/webrtc/modules/utility/source/helpers_android.cc",
+ "/third_party/libwebrtc/webrtc/modules/utility/source/jvm_android.cc"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["NO_TCMALLOC"] = True
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORE"] = "0"
+
+ OS_LIBS += [
+ "-framework Foundation"
+ ]
+
+if CONFIG["OS_TARGET"] == "DragonFly":
+
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+if CONFIG["OS_TARGET"] == "FreeBSD":
+
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+ OS_LIBS += [
+ "rt"
+ ]
+
+if CONFIG["OS_TARGET"] == "NetBSD":
+
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NO_TCMALLOC"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "1"
+ DEFINES["UNICODE"] = True
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_CRT_SECURE_NO_WARNINGS"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_USING_V110_SDK71_"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "DragonFly":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "FreeBSD":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "NetBSD":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_FORTIFY_SOURCE"] = "2"
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["CR_XCODE_VERSION"] = "0120"
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["CR_XCODE_VERSION"] = "0920"
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "FreeBSD":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["DISABLE_NACL"] = True
+ DEFINES["NO_TCMALLOC"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "NetBSD":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+Library("utility_gn")