diff --git a/.gitignore b/.gitignore
index fe29bb6..4be594a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -399,7 +399,6 @@
 /third_party/omaha/src/omaha
 /third_party/openmax_dl/
 /third_party/openh264/src
-/third_party/opus/src
 /third_party/ow2_asm/lib/*.jar
 /third_party/pdfsqueeze
 /third_party/pdfium
diff --git a/DEPS b/DEPS
index 693a8341..2431f726 100644
--- a/DEPS
+++ b/DEPS
@@ -36,11 +36,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'a2b9fdfe0b2dd3408064b7cfd1bf8677eaf06491',
+  'skia_revision': '2825bad08cc2ad63f0f11f50039c944914d07e0a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'be9e04df4e08e7f555454cdf6921291a0f598d4a',
+  'v8_revision': '17edea67a345a36f19a6ef15dd34edb2c88b2cc1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -56,7 +56,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'ea3ff9eaaa508b9cbc7f52bc92d189eacbc7a935',
+  'pdfium_revision': 'a72ab5e0908ca29cfda91b3037da9b74cb06b93f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -88,7 +88,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'c1a1d1b3ed6c100bc0ae7ff7812be4d9a193de9d',
+  'catapult_revision': 'd7bc1bf8cb0bcbf2dd998828cc65486b901db11d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -214,7 +214,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'c2fc3d0525b5dbfe8ee83e178fd2c847535c45ce', # commit position 13611
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '518d267d7cf4c1076882c1a463f4ee6acb488e6b', # commit position 13633
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -240,9 +240,6 @@
   'src/third_party/pywebsocket/src':
     Var('chromium_git') + '/external/github.com/google/pywebsocket.git' + '@' + '2d7b73c3acbd0f41dcab487ae5c97c6feae06ce2',
 
-  'src/third_party/opus/src':
-   Var('chromium_git') + '/chromium/deps/opus.git' + '@' + 'aa32042a50f2cbe0ff9d339948cb4712f5cc3d6e',
-
   'src/media/cdm/api':
    Var('chromium_git') + '/chromium/cdm.git' + '@' + '245af7782c9f54d776722a2c7b53372ee040e5fc',
 
@@ -383,7 +380,7 @@
 
     # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
     'src/third_party/chromite':
-     Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ef7e4378c78f032e6746cf65c725f0a1c69d5824',
+     Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '762cbcd93409c51d08af25b7be0c1f7f5a8a2eec',
 
     # Dependency of chromite.git and skia.
     'src/third_party/pyelftools':
diff --git a/android_webview/browser/surfaces_instance.h b/android_webview/browser/surfaces_instance.h
index 5dec3d8b..eb01f71 100644
--- a/android_webview/browser/surfaces_instance.h
+++ b/android_webview/browser/surfaces_instance.h
@@ -61,10 +61,6 @@
   // cc::DisplayClient overrides.
   void DisplayOutputSurfaceLost() override {}
   void DisplaySetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override {}
-  void DisplayWillDrawAndSwap(
-      bool will_draw_and_swap,
-      const cc::RenderPassList& render_passes) override {}
-  void DisplayDidDrawAndSwap() override {}
 
   // cc::SurfaceFactoryClient implementation.
   void ReturnResources(const cc::ReturnedResourceArray& resources) override;
diff --git a/android_webview/native/android_protocol_handler.cc b/android_webview/native/android_protocol_handler.cc
index e7edb5d..51c64f79 100644
--- a/android_webview/native/android_protocol_handler.cc
+++ b/android_webview/native/android_protocol_handler.cc
@@ -32,6 +32,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ClearException;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 
diff --git a/android_webview/native/aw_autofill_client.cc b/android_webview/native/aw_autofill_client.cc
index 5c34dc4..f149041 100644
--- a/android_webview/native/aw_autofill_client.cc
+++ b/android_webview/native/aw_autofill_client.cc
@@ -28,6 +28,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::WebContents;
 
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 9d01a230..75cb684 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -90,6 +90,7 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::JavaRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
diff --git a/android_webview/native/aw_contents_statics.cc b/android_webview/native/aw_contents_statics.cc
index f34d2755..c827903 100644
--- a/android_webview/native/aw_contents_statics.cc
+++ b/android_webview/native/aw_contents_statics.cc
@@ -19,7 +19,9 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
 using content::BrowserThread;
 
 namespace android_webview {
diff --git a/android_webview/native/aw_debug.cc b/android_webview/native/aw_debug.cc
index fcfb50b1..37a43cc 100644
--- a/android_webview/native/aw_debug.cc
+++ b/android_webview/native/aw_debug.cc
@@ -15,6 +15,7 @@
 
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace android_webview {
diff --git a/android_webview/native/aw_dev_tools_server.cc b/android_webview/native/aw_dev_tools_server.cc
index 87a1e68..6180d0c 100644
--- a/android_webview/native/aw_dev_tools_server.cc
+++ b/android_webview/native/aw_dev_tools_server.cc
@@ -24,6 +24,7 @@
 #include "net/base/net_errors.h"
 #include "net/socket/unix_domain_server_socket_posix.h"
 
+using base::android::JavaParamRef;
 using content::DevToolsAgentHost;
 using content::RenderViewHost;
 using content::WebContents;
diff --git a/android_webview/native/aw_form_database.cc b/android_webview/native/aw_form_database.cc
index 8e31e886..3e3ebb9 100644
--- a/android_webview/native/aw_form_database.cc
+++ b/android_webview/native/aw_form_database.cc
@@ -12,6 +12,8 @@
 #include "base/time/time.h"
 #include "jni/AwFormDatabase_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace android_webview {
 
 namespace {
diff --git a/android_webview/native/aw_gl_functor.cc b/android_webview/native/aw_gl_functor.cc
index 55a7f64..2a92546e 100644
--- a/android_webview/native/aw_gl_functor.cc
+++ b/android_webview/native/aw_gl_functor.cc
@@ -9,6 +9,8 @@
 #include "jni/AwGLFunctor_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 using content::BrowserThread;
 
 extern "C" {
diff --git a/android_webview/native/aw_http_auth_handler.cc b/android_webview/native/aw_http_auth_handler.cc
index 8f4293b..a310863 100644
--- a/android_webview/native/aw_http_auth_handler.cc
+++ b/android_webview/native/aw_http_auth_handler.cc
@@ -14,6 +14,7 @@
 #include "content/public/browser/web_contents.h"
 
 using base::android::ConvertJavaStringToUTF16;
+using base::android::JavaParamRef;
 using content::BrowserThread;
 
 namespace android_webview {
diff --git a/android_webview/native/aw_message_port_service_impl.cc b/android_webview/native/aw_message_port_service_impl.cc
index 65f7bb0..3aaa580 100644
--- a/android_webview/native/aw_message_port_service_impl.cc
+++ b/android_webview/native/aw_message_port_service_impl.cc
@@ -19,6 +19,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaIntArray;
diff --git a/android_webview/native/aw_pdf_exporter.cc b/android_webview/native/aw_pdf_exporter.cc
index af08f1ff..05aef83 100644
--- a/android_webview/native/aw_pdf_exporter.cc
+++ b/android_webview/native/aw_pdf_exporter.cc
@@ -11,6 +11,9 @@
 #include "printing/print_settings.h"
 #include "printing/units.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace android_webview {
 
 AwPdfExporter::AwPdfExporter(JNIEnv* env,
diff --git a/android_webview/native/aw_picture.cc b/android_webview/native/aw_picture.cc
index cbce8daa..edc2003e 100644
--- a/android_webview/native/aw_picture.cc
+++ b/android_webview/native/aw_picture.cc
@@ -9,6 +9,8 @@
 #include "jni/AwPicture_jni.h"
 #include "third_party/skia/include/core/SkPicture.h"
 
+using base::android::JavaParamRef;
+
 namespace android_webview {
 
 AwPicture::AwPicture(sk_sp<SkPicture> picture)
diff --git a/android_webview/native/aw_quota_manager_bridge_impl.cc b/android_webview/native/aw_quota_manager_bridge_impl.cc
index 7c44772..b53b032 100644
--- a/android_webview/native/aw_quota_manager_bridge_impl.cc
+++ b/android_webview/native/aw_quota_manager_bridge_impl.cc
@@ -20,6 +20,8 @@
 #include "url/gurl.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 using content::BrowserThread;
 using content::StoragePartition;
 using storage::QuotaClient;
diff --git a/android_webview/native/aw_resource.cc b/android_webview/native/aw_resource.cc
index 270c0c6a9..6400a1a 100644
--- a/android_webview/native/aw_resource.cc
+++ b/android_webview/native/aw_resource.cc
@@ -9,6 +9,8 @@
 #include "base/android/scoped_java_ref.h"
 #include "jni/AwResource_jni.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace android_webview {
 namespace AwResource {
 
diff --git a/android_webview/native/aw_settings.cc b/android_webview/native/aw_settings.cc
index 85b61aa..77892fd 100644
--- a/android_webview/native/aw_settings.cc
+++ b/android_webview/native/aw_settings.cc
@@ -23,6 +23,7 @@
 
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::RendererPreferences;
 using content::WebPreferences;
diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc
index c825f63..a586e44c 100644
--- a/android_webview/native/aw_web_contents_delegate.cc
+++ b/android_webview/native/aw_web_contents_delegate.cc
@@ -34,6 +34,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::FileChooserParams;
 using content::WebContents;
diff --git a/android_webview/native/cookie_manager.cc b/android_webview/native/cookie_manager.cc
index ab43638f..05bb0ce 100644
--- a/android_webview/native/cookie_manager.cc
+++ b/android_webview/native/cookie_manager.cc
@@ -45,7 +45,9 @@
 using base::WaitableEvent;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertJavaStringToUTF16;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
 using content::BrowserThread;
 using net::CookieList;
 
diff --git a/android_webview/native/permission/aw_permission_request.cc b/android_webview/native/permission/aw_permission_request.cc
index 84b311e..1c1e34b 100644
--- a/android_webview/native/permission/aw_permission_request.cc
+++ b/android_webview/native/permission/aw_permission_request.cc
@@ -12,6 +12,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace android_webview {
diff --git a/android_webview/native/token_binding_manager_bridge.cc b/android_webview/native/token_binding_manager_bridge.cc
index 6744173..7f4d4aa 100644
--- a/android_webview/native/token_binding_manager_bridge.cc
+++ b/android_webview/native/token_binding_manager_bridge.cc
@@ -15,7 +15,9 @@
 #include "net/base/net_errors.h"
 
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
 using content::BrowserThread;
 
 namespace android_webview {
diff --git a/base/android/animation_frame_time_histogram.cc b/base/android/animation_frame_time_histogram.cc
index 2cf7516f..c2b48d32 100644
--- a/base/android/animation_frame_time_histogram.cc
+++ b/base/android/animation_frame_time_histogram.cc
@@ -8,6 +8,8 @@
 #include "base/metrics/histogram_macros.h"
 #include "jni/AnimationFrameTimeHistogram_jni.h"
 
+using base::android::JavaParamRef;
+
 // static
 void SaveHistogram(JNIEnv* env,
                    const JavaParamRef<jobject>& jcaller,
diff --git a/base/android/command_line_android.cc b/base/android/command_line_android.cc
index e196aedd..21ae182 100644
--- a/base/android/command_line_android.cc
+++ b/base/android/command_line_android.cc
@@ -12,6 +12,8 @@
 
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 using base::CommandLine;
 
 namespace {
diff --git a/base/android/content_uri_utils.cc b/base/android/content_uri_utils.cc
index fec01576..e35505fe 100644
--- a/base/android/content_uri_utils.cc
+++ b/base/android/content_uri_utils.cc
@@ -10,6 +10,7 @@
 #include "jni/ContentUriUtils_jni.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
 
 namespace base {
 
diff --git a/base/android/field_trial_list.cc b/base/android/field_trial_list.cc
index 9731a48..5150b812 100644
--- a/base/android/field_trial_list.cc
+++ b/base/android/field_trial_list.cc
@@ -12,6 +12,8 @@
 
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 static ScopedJavaLocalRef<jstring> FindFullName(
     JNIEnv* env,
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h
index 31e51b7..8c63c25c 100644
--- a/base/android/jni_generator/golden_sample_for_tests_jni.h
+++ b/base/android/jni_generator/golden_sample_for_tests_jni.h
@@ -46,15 +46,16 @@
 
 // Step 2: method stubs.
 
-static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
-    const JavaParamRef<jstring>& param);
+static jlong Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller,
+    const base::android::JavaParamRef<jstring>& param);
 
 extern "C" __attribute__((visibility("default")))
 jlong Java_org_chromium_example_jni_1generator_SampleForTests_nativeInit(JNIEnv*
     env, jobject jcaller,
     jstring param) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller),
-      JavaParamRef<jstring>(env, param));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller),
+      base::android::JavaParamRef<jstring>(env, param));
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -65,49 +66,54 @@
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
-  return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
+  return native->Destroy(env, base::android::JavaParamRef<jobject>(env,
+      jcaller));
 }
 
-static jdouble GetDoubleFunction(JNIEnv* env, const JavaParamRef<jobject>&
-    jcaller);
+static jdouble GetDoubleFunction(JNIEnv* env, const
+    base::android::JavaParamRef<jobject>& jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jdouble
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetDoubleFunction(JNIEnv*
     env, jobject jcaller) {
-  return GetDoubleFunction(env, JavaParamRef<jobject>(env, jcaller));
+  return GetDoubleFunction(env, base::android::JavaParamRef<jobject>(env,
+      jcaller));
 }
 
-static jfloat GetFloatFunction(JNIEnv* env, const JavaParamRef<jclass>&
-    jcaller);
+static jfloat GetFloatFunction(JNIEnv* env, const
+    base::android::JavaParamRef<jclass>& jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jfloat
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetFloatFunction(JNIEnv*
     env, jclass jcaller) {
-  return GetFloatFunction(env, JavaParamRef<jclass>(env, jcaller));
+  return GetFloatFunction(env, base::android::JavaParamRef<jclass>(env,
+      jcaller));
 }
 
-static void SetNonPODDatatype(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
-    const JavaParamRef<jobject>& rect);
+static void SetNonPODDatatype(JNIEnv* env, const
+    base::android::JavaParamRef<jobject>& jcaller,
+    const base::android::JavaParamRef<jobject>& rect);
 
 extern "C" __attribute__((visibility("default")))
 void
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeSetNonPODDatatype(JNIEnv*
     env, jobject jcaller,
     jobject rect) {
-  return SetNonPODDatatype(env, JavaParamRef<jobject>(env, jcaller),
-      JavaParamRef<jobject>(env, rect));
+  return SetNonPODDatatype(env, base::android::JavaParamRef<jobject>(env,
+      jcaller), base::android::JavaParamRef<jobject>(env, rect));
 }
 
-static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, const
-    JavaParamRef<jobject>& jcaller);
+static base::android::ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jobject
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetNonPODDatatype(JNIEnv*
     env, jobject jcaller) {
-  return GetNonPODDatatype(env, JavaParamRef<jobject>(env, jcaller)).Release();
+  return GetNonPODDatatype(env, base::android::JavaParamRef<jobject>(env,
+      jcaller)).Release();
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -118,7 +124,8 @@
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
-  return native->Method(env, JavaParamRef<jobject>(env, jcaller));
+  return native->Method(env, base::android::JavaParamRef<jobject>(env,
+      jcaller));
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -130,7 +137,8 @@
   CPPClass::InnerClass* native =
       reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
   CHECK_NATIVE_PTR(env, jcaller, native, "MethodOtherP0", 0);
-  return native->MethodOtherP0(env, JavaParamRef<jobject>(env, jcaller));
+  return native->MethodOtherP0(env, base::android::JavaParamRef<jobject>(env,
+      jcaller));
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -142,8 +150,8 @@
     jobject b) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "AddStructB");
-  return native->AddStructB(env, JavaParamRef<jobject>(env, jcaller),
-      JavaParamRef<jobject>(env, b));
+  return native->AddStructB(env, base::android::JavaParamRef<jobject>(env,
+      jcaller), base::android::JavaParamRef<jobject>(env, b));
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -155,7 +163,7 @@
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "IterateAndDoSomethingWithStructB");
   return native->IterateAndDoSomethingWithStructB(env,
-      JavaParamRef<jobject>(env, jcaller));
+      base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -166,18 +174,19 @@
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "ReturnAString", NULL);
-  return native->ReturnAString(env, JavaParamRef<jobject>(env,
+  return native->ReturnAString(env, base::android::JavaParamRef<jobject>(env,
       jcaller)).Release();
 }
 
-static jint GetInnerIntFunction(JNIEnv* env, const JavaParamRef<jclass>&
-    jcaller);
+static jint GetInnerIntFunction(JNIEnv* env, const
+    base::android::JavaParamRef<jclass>& jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024InnerClass_nativeGetInnerIntFunction(JNIEnv*
     env, jclass jcaller) {
-  return GetInnerIntFunction(env, JavaParamRef<jclass>(env, jcaller));
+  return GetInnerIntFunction(env, base::android::JavaParamRef<jclass>(env,
+      jcaller));
 }
 
 static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0;
@@ -272,8 +281,8 @@
 }
 
 static base::subtle::AtomicWord g_InnerStructA_create = 0;
-static ScopedJavaLocalRef<jobject> Java_InnerStructA_create(JNIEnv* env, jlong
-    l,
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InnerStructA_create(JNIEnv* env, jlong l,
     JniIntWrapper i,
     jstring s) {
   CHECK_CLAZZ(env, InnerStructA_clazz(env),
@@ -296,7 +305,7 @@
       env->CallStaticObjectMethod(InnerStructA_clazz(env),
           method_id, l, as_jint(i), s);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_SampleForTests_addStructA = 0;
@@ -367,8 +376,8 @@
 }
 
 static base::subtle::AtomicWord g_InnerStructB_getValue = 0;
-static ScopedJavaLocalRef<jstring> Java_InnerStructB_getValue(JNIEnv* env,
-    jobject obj) {
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_InnerStructB_getValue(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       InnerStructB_clazz(env), NULL);
   jmethodID method_id =
@@ -386,7 +395,7 @@
       static_cast<jstring>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jstring>(env, ret);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index f4c6f28..1946d48d 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -138,7 +138,7 @@
 def WrapCTypeForDeclaration(c_type):
   """Wrap the C datatype in a JavaRef if required."""
   if re.match(RE_SCOPED_JNI_TYPES, c_type):
-    return 'const JavaParamRef<' + c_type + '>&'
+    return 'const base::android::JavaParamRef<' + c_type + '>&'
   else:
     return c_type
 
@@ -958,7 +958,8 @@
     return template.substitute(values)
 
   def GetJavaParamRefForCall(self, c_type, name):
-    return Template('JavaParamRef<${TYPE}>(env, ${NAME})').substitute({
+    return Template(
+        'base::android::JavaParamRef<${TYPE}>(env, ${NAME})').substitute({
         'TYPE': c_type,
         'NAME': name,
     })
@@ -987,7 +988,8 @@
     post_call = ''
     if re.match(RE_SCOPED_JNI_TYPES, return_type):
       post_call = '.Release()'
-      return_declaration = 'ScopedJavaLocalRef<' + return_type + '>'
+      return_declaration = ('base::android::ScopedJavaLocalRef<' + return_type +
+                            '>')
     values = {
         'RETURN': return_type,
         'RETURN_DECLARATION': return_declaration,
@@ -1071,7 +1073,7 @@
       pre_call = ' ' + pre_call
       return_declaration = return_type + ' ret ='
       if re.match(RE_SCOPED_JNI_TYPES, return_type):
-        return_type = 'ScopedJavaLocalRef<' + return_type + '>'
+        return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>'
         return_clause = 'return ' + return_type + '(env, ret);'
       else:
         return_clause = 'return ret;'
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
index dd2d454..cc319845 100644
--- a/base/android/jni_generator/testCalledByNatives.golden
+++ b/base/android/jni_generator/testCalledByNatives.golden
@@ -32,8 +32,9 @@
 // Step 2: method stubs.
 
 static base::subtle::AtomicWord g_TestJni_showConfirmInfoBar = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_showConfirmInfoBar(JNIEnv* env,
-    jobject obj, JniIntWrapper nativeInfoBar,
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_showConfirmInfoBar(JNIEnv* env, jobject obj, JniIntWrapper
+    nativeInfoBar,
     jstring buttonOk,
     jstring buttonCancel,
     jstring title,
@@ -61,12 +62,13 @@
           method_id, as_jint(nativeInfoBar), buttonOk, buttonCancel, title,
               icon);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_showAutoLoginInfoBar = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_showAutoLoginInfoBar(JNIEnv*
-    env, jobject obj, JniIntWrapper nativeInfoBar,
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_showAutoLoginInfoBar(JNIEnv* env, jobject obj, JniIntWrapper
+    nativeInfoBar,
     jstring realm,
     jstring account,
     jstring args) {
@@ -91,7 +93,7 @@
       env->CallObjectMethod(obj,
           method_id, as_jint(nativeInfoBar), realm, account, args);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
@@ -145,8 +147,8 @@
 }
 
 static base::subtle::AtomicWord g_TestJni_openUrl = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv* env, jstring
-    url) {
+static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv*
+    env, jstring url) {
   CHECK_CLAZZ(env, TestJni_clazz(env),
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -165,7 +167,7 @@
       env->CallStaticObjectMethod(TestJni_clazz(env),
           method_id, url);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0;
@@ -223,8 +225,8 @@
 }
 
 static base::subtle::AtomicWord g_TestJni_returnByteArray = 0;
-static ScopedJavaLocalRef<jbyteArray> Java_TestJni_returnByteArray(JNIEnv* env,
-    jobject obj) {
+static base::android::ScopedJavaLocalRef<jbyteArray>
+    Java_TestJni_returnByteArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -242,12 +244,12 @@
       static_cast<jbyteArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jbyteArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jbyteArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnBooleanArray = 0;
-static ScopedJavaLocalRef<jbooleanArray> Java_TestJni_returnBooleanArray(JNIEnv*
-    env, jobject obj) {
+static base::android::ScopedJavaLocalRef<jbooleanArray>
+    Java_TestJni_returnBooleanArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -265,12 +267,12 @@
       static_cast<jbooleanArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jbooleanArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jbooleanArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnCharArray = 0;
-static ScopedJavaLocalRef<jcharArray> Java_TestJni_returnCharArray(JNIEnv* env,
-    jobject obj) {
+static base::android::ScopedJavaLocalRef<jcharArray>
+    Java_TestJni_returnCharArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -288,12 +290,12 @@
       static_cast<jcharArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jcharArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jcharArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnShortArray = 0;
-static ScopedJavaLocalRef<jshortArray> Java_TestJni_returnShortArray(JNIEnv*
-    env, jobject obj) {
+static base::android::ScopedJavaLocalRef<jshortArray>
+    Java_TestJni_returnShortArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -311,12 +313,12 @@
       static_cast<jshortArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jshortArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jshortArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnIntArray = 0;
-static ScopedJavaLocalRef<jintArray> Java_TestJni_returnIntArray(JNIEnv* env,
-    jobject obj) {
+static base::android::ScopedJavaLocalRef<jintArray>
+    Java_TestJni_returnIntArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -334,12 +336,12 @@
       static_cast<jintArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jintArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jintArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnLongArray = 0;
-static ScopedJavaLocalRef<jlongArray> Java_TestJni_returnLongArray(JNIEnv* env,
-    jobject obj) {
+static base::android::ScopedJavaLocalRef<jlongArray>
+    Java_TestJni_returnLongArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -357,12 +359,12 @@
       static_cast<jlongArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jlongArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jlongArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnDoubleArray = 0;
-static ScopedJavaLocalRef<jdoubleArray> Java_TestJni_returnDoubleArray(JNIEnv*
-    env, jobject obj) {
+static base::android::ScopedJavaLocalRef<jdoubleArray>
+    Java_TestJni_returnDoubleArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -380,12 +382,12 @@
       static_cast<jdoubleArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jdoubleArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jdoubleArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnObjectArray = 0;
-static ScopedJavaLocalRef<jobjectArray> Java_TestJni_returnObjectArray(JNIEnv*
-    env, jobject obj) {
+static base::android::ScopedJavaLocalRef<jobjectArray>
+    Java_TestJni_returnObjectArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -403,11 +405,11 @@
       static_cast<jobjectArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobjectArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_returnArrayOfByteArray = 0;
-static ScopedJavaLocalRef<jobjectArray>
+static base::android::ScopedJavaLocalRef<jobjectArray>
     Java_TestJni_returnArrayOfByteArray(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
@@ -426,12 +428,12 @@
       static_cast<jobjectArray>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobjectArray>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_getCompressFormat = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_getCompressFormat(JNIEnv* env,
-    jobject obj) {
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_getCompressFormat(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -449,12 +451,12 @@
       env->CallObjectMethod(obj,
           method_id);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_TestJni_getCompressFormatList = 0;
-static ScopedJavaLocalRef<jobject> Java_TestJni_getCompressFormatList(JNIEnv*
-    env, jobject obj) {
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_getCompressFormatList(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       TestJni_clazz(env), NULL);
   jmethodID method_id =
@@ -472,7 +474,7 @@
       env->CallObjectMethod(obj,
           method_id);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
index 2ef3e93..11554b2b 100644
--- a/base/android/jni_generator/testConstantsFromJavaP.golden
+++ b/base/android/jni_generator/testConstantsFromJavaP.golden
@@ -134,7 +134,7 @@
 
 static base::subtle::AtomicWord
     g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
     env, jlong p0,
     jlong p1,
@@ -150,7 +150,7 @@
     JniIntWrapper p11,
     JniIntWrapper p12,
     JniIntWrapper p13) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
     env, jlong p0,
     jlong p1,
@@ -182,12 +182,12 @@
               as_jint(p7), p8, p9, as_jint(p10), as_jint(p11), as_jint(p12),
               as_jint(p13));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord
     g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
     jlong p0,
     jlong p1,
@@ -202,7 +202,7 @@
     JniIntWrapper p10,
     JniIntWrapper p11,
     JniIntWrapper p12) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
     jlong p0,
     jlong p1,
@@ -232,12 +232,12 @@
           method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6), p7,
               p8, as_jint(p9), as_jint(p10), as_jint(p11), as_jint(p12));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I
     = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
     jlong p1,
     JniIntWrapper p2,
@@ -250,7 +250,7 @@
     jfloat p9,
     JniIntWrapper p10,
     JniIntWrapper p11) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
     jlong p1,
     JniIntWrapper p2,
@@ -278,12 +278,12 @@
           method_id, p0, p1, as_jint(p2), p3, p4, p5, p6, as_jint(p7), p8, p9,
               as_jint(p10), as_jint(p11));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord
     g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
     jlong p1,
     JniIntWrapper p2,
@@ -297,7 +297,7 @@
     jfloat p10,
     JniIntWrapper p11,
     JniIntWrapper p12) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
     jlong p1,
     JniIntWrapper p2,
@@ -326,18 +326,18 @@
           method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, p6, p7,
               as_jint(p8), p9, p10, as_jint(p11), as_jint(p12));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_I = 0;
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
     jlong p1,
     JniIntWrapper p2,
     jfloat p3,
     jfloat p4,
     JniIntWrapper p5) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject>
+static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
     jlong p1,
     JniIntWrapper p2,
@@ -358,14 +358,15 @@
       env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0, p1, as_jint(p2), p3, p4, as_jint(p5));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_obtainAVME_AVME = 0;
-static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainAVME_AVME(JNIEnv* env,
-    jobject p0) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainAVME_AVME(JNIEnv* env,
-    jobject p0) {
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) {
   CHECK_CLAZZ(env, MotionEvent_clazz(env),
       MotionEvent_clazz(env), NULL);
   jmethodID method_id =
@@ -380,14 +381,15 @@
       env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_obtainNoHistory = 0;
-static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainNoHistory(JNIEnv* env,
-    jobject p0) __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainNoHistory(JNIEnv* env,
-    jobject p0) {
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) {
   CHECK_CLAZZ(env, MotionEvent_clazz(env),
       MotionEvent_clazz(env), NULL);
   jmethodID method_id =
@@ -402,7 +404,7 @@
       env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_recycle = 0;
@@ -2020,10 +2022,11 @@
 }
 
 static base::subtle::AtomicWord g_MotionEvent_toString = 0;
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_toString(JNIEnv* env,
-    jobject obj) __attribute__ ((unused));
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_toString(JNIEnv* env,
-    jobject obj) {
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_toString(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_toString(JNIEnv* env, jobject obj) {
   CHECK_CLAZZ(env, obj,
       MotionEvent_clazz(env), NULL);
   jmethodID method_id =
@@ -2038,14 +2041,15 @@
       static_cast<jstring>(env->CallObjectMethod(obj,
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jstring>(env, ret);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_actionToString = 0;
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_actionToString(JNIEnv* env,
-    JniIntWrapper p0) __attribute__ ((unused));
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_actionToString(JNIEnv* env,
-    JniIntWrapper p0) {
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) {
   CHECK_CLAZZ(env, MotionEvent_clazz(env),
       MotionEvent_clazz(env), NULL);
   jmethodID method_id =
@@ -2060,14 +2064,15 @@
       static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, as_jint(p0)));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jstring>(env, ret);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_axisToString = 0;
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_axisToString(JNIEnv* env,
-    JniIntWrapper p0) __attribute__ ((unused));
-static ScopedJavaLocalRef<jstring> Java_MotionEvent_axisToString(JNIEnv* env,
-    JniIntWrapper p0) {
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) {
   CHECK_CLAZZ(env, MotionEvent_clazz(env),
       MotionEvent_clazz(env), NULL);
   jmethodID method_id =
@@ -2082,7 +2087,7 @@
       static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, as_jint(p0)));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jstring>(env, ret);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 static base::subtle::AtomicWord g_MotionEvent_axisFromString = 0;
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
index 18e10820..9b7ba65 100644
--- a/base/android/jni_generator/testFromJavaP.golden
+++ b/base/android/jni_generator/testFromJavaP.golden
@@ -221,9 +221,10 @@
 }
 
 static base::subtle::AtomicWord g_InputStream_Constructor = 0;
-static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env)
-    __attribute__ ((unused));
-static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env) {
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InputStream_Constructor(JNIEnv* env) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InputStream_Constructor(JNIEnv* env) {
   CHECK_CLAZZ(env, InputStream_clazz(env),
       InputStream_clazz(env), NULL);
   jmethodID method_id =
@@ -238,7 +239,7 @@
       env->NewObject(InputStream_clazz(env),
           method_id);
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
index 8ee609e4..fc68bc8 100644
--- a/base/android/jni_generator/testInnerClassNatives.golden
+++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -31,12 +31,13 @@
 
 // Step 2: method stubs.
 
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env, jobject
     jcaller) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
index 25f2ffe..554b37a 100644
--- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -32,19 +32,21 @@
 
 // Step 2: method stubs.
 
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env, jobject jcaller) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv* env,
     jobject jcaller) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
index 978432d00..9ad94db8 100644
--- a/base/android/jni_generator/testInnerClassNativesMultiple.golden
+++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -36,20 +36,22 @@
 
 // Step 2: method stubs.
 
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env, jobject
     jcaller) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv* env,
     jobject jcaller) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
index 616af717..48c1616 100644
--- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -27,17 +27,18 @@
 
 // Step 2: method stubs.
 
-static void DoSomething(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
-    const JavaParamRef<jobject>& callback1,
-    const JavaParamRef<jobject>& callback2);
+static void DoSomething(JNIEnv* env, const base::android::JavaParamRef<jclass>&
+    jcaller,
+    const base::android::JavaParamRef<jobject>& callback1,
+    const base::android::JavaParamRef<jobject>& callback2);
 
 extern "C" __attribute__((visibility("default")))
 void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv* env, jclass jcaller,
     jobject callback1,
     jobject callback2) {
-  return DoSomething(env, JavaParamRef<jclass>(env, jcaller),
-      JavaParamRef<jobject>(env, callback1), JavaParamRef<jobject>(env,
-      callback2));
+  return DoSomething(env, base::android::JavaParamRef<jclass>(env, jcaller),
+      base::android::JavaParamRef<jobject>(env, callback1),
+      base::android::JavaParamRef<jobject>(env, callback2));
 }
 
 static base::subtle::AtomicWord g_Foo_calledByNative = 0;
diff --git a/base/android/jni_generator/testNativeExportsOnlyOption.golden b/base/android/jni_generator/testNativeExportsOnlyOption.golden
index 97ef057..a024f87 100644
--- a/base/android/jni_generator/testNativeExportsOnlyOption.golden
+++ b/base/android/jni_generator/testNativeExportsOnlyOption.golden
@@ -36,7 +36,8 @@
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
   CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
-  return native->StaticMethod(env, JavaParamRef<jobject>(env, jcaller), arg1);
+  return native->StaticMethod(env, base::android::JavaParamRef<jobject>(env,
+      jcaller), arg1);
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -48,25 +49,28 @@
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
   CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
-  return native->Method(env, JavaParamRef<jobject>(env, jcaller), arg1);
+  return native->Method(env, base::android::JavaParamRef<jobject>(env, jcaller),
+      arg1);
 }
 
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
     env, jobject jcaller) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
     env, jobject jcaller) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
 static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
@@ -94,7 +98,7 @@
 
 static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
     0;
-static ScopedJavaLocalRef<jstring>
+static base::android::ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
     JniIntWrapper iParam) {
   CHECK_CLAZZ(env, obj,
@@ -115,7 +119,7 @@
       static_cast<jstring>(env->CallObjectMethod(obj,
           method_id, as_jint(iParam)));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jstring>(env, ret);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
@@ -166,7 +170,7 @@
 
 static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
     0;
-static ScopedJavaLocalRef<jstring>
+static base::android::ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
   CHECK_CLAZZ(env, SampleForTests_clazz(env),
       SampleForTests_clazz(env), NULL);
@@ -185,7 +189,7 @@
 static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
           method_id));
   jni_generator::CheckException(env);
-  return ScopedJavaLocalRef<jstring>(env, ret);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
index ca2f61a..e2f64cd 100644
--- a/base/android/jni_generator/testNatives.golden
+++ b/base/android/jni_generator/testNatives.golden
@@ -27,11 +27,12 @@
 
 // Step 2: method stubs.
 
-static jint Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller);
+static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env, jobject jcaller) {
-  return Init(env, JavaParamRef<jobject>(env, jcaller));
+  return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -41,7 +42,8 @@
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
-  return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
+  return native->Destroy(env, base::android::JavaParamRef<jobject>(env,
+      jcaller));
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -55,26 +57,26 @@
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmark", 0);
-  return native->AddBookmark(env, JavaParamRef<jobject>(env, jcaller),
-      JavaParamRef<jstring>(env, url), JavaParamRef<jstring>(env, title),
-      isFolder, parentId);
+  return native->AddBookmark(env, base::android::JavaParamRef<jobject>(env,
+      jcaller), base::android::JavaParamRef<jstring>(env, url),
+      base::android::JavaParamRef<jstring>(env, title), isFolder, parentId);
 }
 
-static ScopedJavaLocalRef<jstring> GetDomainAndRegistry(JNIEnv* env, const
-    JavaParamRef<jclass>& jcaller,
-    const JavaParamRef<jstring>& url);
+static base::android::ScopedJavaLocalRef<jstring> GetDomainAndRegistry(JNIEnv*
+    env, const base::android::JavaParamRef<jclass>& jcaller,
+    const base::android::JavaParamRef<jstring>& url);
 
 extern "C" __attribute__((visibility("default")))
 jstring Java_org_chromium_TestJni_nativeGetDomainAndRegistry(JNIEnv* env, jclass
     jcaller,
     jstring url) {
-  return GetDomainAndRegistry(env, JavaParamRef<jclass>(env, jcaller),
-      JavaParamRef<jstring>(env, url)).Release();
+  return GetDomainAndRegistry(env, base::android::JavaParamRef<jclass>(env,
+      jcaller), base::android::JavaParamRef<jstring>(env, url)).Release();
 }
 
 static void CreateHistoricalTabFromState(JNIEnv* env, const
-    JavaParamRef<jclass>& jcaller,
-    const JavaParamRef<jbyteArray>& state,
+    base::android::JavaParamRef<jclass>& jcaller,
+    const base::android::JavaParamRef<jbyteArray>& state,
     jint tab_index);
 
 extern "C" __attribute__((visibility("default")))
@@ -82,44 +84,47 @@
     jclass jcaller,
     jbyteArray state,
     jint tab_index) {
-  return CreateHistoricalTabFromState(env, JavaParamRef<jclass>(env, jcaller),
-      JavaParamRef<jbyteArray>(env, state), tab_index);
+  return CreateHistoricalTabFromState(env,
+      base::android::JavaParamRef<jclass>(env, jcaller),
+      base::android::JavaParamRef<jbyteArray>(env, state), tab_index);
 }
 
-static ScopedJavaLocalRef<jbyteArray> GetStateAsByteArray(JNIEnv* env, const
-    JavaParamRef<jobject>& jcaller,
-    const JavaParamRef<jobject>& view);
+static base::android::ScopedJavaLocalRef<jbyteArray> GetStateAsByteArray(JNIEnv*
+    env, const base::android::JavaParamRef<jobject>& jcaller,
+    const base::android::JavaParamRef<jobject>& view);
 
 extern "C" __attribute__((visibility("default")))
 jbyteArray Java_org_chromium_TestJni_nativeGetStateAsByteArray(JNIEnv* env,
     jobject jcaller,
     jobject view) {
-  return GetStateAsByteArray(env, JavaParamRef<jobject>(env, jcaller),
-      JavaParamRef<jobject>(env, view)).Release();
+  return GetStateAsByteArray(env, base::android::JavaParamRef<jobject>(env,
+      jcaller), base::android::JavaParamRef<jobject>(env, view)).Release();
 }
 
-static ScopedJavaLocalRef<jobjectArray> GetAutofillProfileGUIDs(JNIEnv* env,
-    const JavaParamRef<jclass>& jcaller);
+static base::android::ScopedJavaLocalRef<jobjectArray>
+    GetAutofillProfileGUIDs(JNIEnv* env, const
+    base::android::JavaParamRef<jclass>& jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jobjectArray Java_org_chromium_TestJni_nativeGetAutofillProfileGUIDs(JNIEnv*
     env, jclass jcaller) {
-  return GetAutofillProfileGUIDs(env, JavaParamRef<jclass>(env,
+  return GetAutofillProfileGUIDs(env, base::android::JavaParamRef<jclass>(env,
       jcaller)).Release();
 }
 
-static void SetRecognitionResults(JNIEnv* env, const JavaParamRef<jobject>&
-    jcaller,
+static void SetRecognitionResults(JNIEnv* env, const
+    base::android::JavaParamRef<jobject>& jcaller,
     jint sessionId,
-    const JavaParamRef<jobjectArray>& results);
+    const base::android::JavaParamRef<jobjectArray>& results);
 
 extern "C" __attribute__((visibility("default")))
 void Java_org_chromium_TestJni_nativeSetRecognitionResults(JNIEnv* env, jobject
     jcaller,
     jint sessionId,
     jobjectArray results) {
-  return SetRecognitionResults(env, JavaParamRef<jobject>(env, jcaller),
-      sessionId, JavaParamRef<jobjectArray>(env, results));
+  return SetRecognitionResults(env, base::android::JavaParamRef<jobject>(env,
+      jcaller), sessionId, base::android::JavaParamRef<jobjectArray>(env,
+      results));
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -136,30 +141,36 @@
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmarkFromAPI", 0);
-  return native->AddBookmarkFromAPI(env, JavaParamRef<jobject>(env, jcaller),
-      JavaParamRef<jstring>(env, url), JavaParamRef<jobject>(env, created),
-      JavaParamRef<jobject>(env, isBookmark), JavaParamRef<jobject>(env, date),
-      JavaParamRef<jbyteArray>(env, favicon), JavaParamRef<jstring>(env, title),
-      JavaParamRef<jobject>(env, visits));
+  return native->AddBookmarkFromAPI(env,
+      base::android::JavaParamRef<jobject>(env, jcaller),
+      base::android::JavaParamRef<jstring>(env, url),
+      base::android::JavaParamRef<jobject>(env, created),
+      base::android::JavaParamRef<jobject>(env, isBookmark),
+      base::android::JavaParamRef<jobject>(env, date),
+      base::android::JavaParamRef<jbyteArray>(env, favicon),
+      base::android::JavaParamRef<jstring>(env, title),
+      base::android::JavaParamRef<jobject>(env, visits));
 }
 
-static jint FindAll(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
-    const JavaParamRef<jstring>& find);
+static jint FindAll(JNIEnv* env, const base::android::JavaParamRef<jobject>&
+    jcaller,
+    const base::android::JavaParamRef<jstring>& find);
 
 extern "C" __attribute__((visibility("default")))
 jint Java_org_chromium_TestJni_nativeFindAll(JNIEnv* env, jobject jcaller,
     jstring find) {
-  return FindAll(env, JavaParamRef<jobject>(env, jcaller),
-      JavaParamRef<jstring>(env, find));
+  return FindAll(env, base::android::JavaParamRef<jobject>(env, jcaller),
+      base::android::JavaParamRef<jstring>(env, find));
 }
 
-static ScopedJavaLocalRef<jobject> GetInnerClass(JNIEnv* env, const
-    JavaParamRef<jclass>& jcaller);
+static base::android::ScopedJavaLocalRef<jobject> GetInnerClass(JNIEnv* env,
+    const base::android::JavaParamRef<jclass>& jcaller);
 
 extern "C" __attribute__((visibility("default")))
 jobject Java_org_chromium_TestJni_nativeGetInnerClass(JNIEnv* env, jclass
     jcaller) {
-  return GetInnerClass(env, JavaParamRef<jclass>(env, jcaller)).Release();
+  return GetInnerClass(env, base::android::JavaParamRef<jclass>(env,
+      jcaller)).Release();
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -173,10 +184,11 @@
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "QueryBitmap", NULL);
-  return native->QueryBitmap(env, JavaParamRef<jobject>(env, jcaller),
-      JavaParamRef<jobjectArray>(env, projection), JavaParamRef<jstring>(env,
-      selection), JavaParamRef<jobjectArray>(env, selectionArgs),
-      JavaParamRef<jstring>(env, sortOrder)).Release();
+  return native->QueryBitmap(env, base::android::JavaParamRef<jobject>(env,
+      jcaller), base::android::JavaParamRef<jobjectArray>(env, projection),
+      base::android::JavaParamRef<jstring>(env, selection),
+      base::android::JavaParamRef<jobjectArray>(env, selectionArgs),
+      base::android::JavaParamRef<jstring>(env, sortOrder)).Release();
 }
 
 extern "C" __attribute__((visibility("default")))
@@ -189,20 +201,21 @@
   DataFetcherImplAndroid* native =
       reinterpret_cast<DataFetcherImplAndroid*>(nativeDataFetcherImplAndroid);
   CHECK_NATIVE_PTR(env, jcaller, native, "GotOrientation");
-  return native->GotOrientation(env, JavaParamRef<jobject>(env, jcaller), alpha,
-      beta, gamma);
+  return native->GotOrientation(env, base::android::JavaParamRef<jobject>(env,
+      jcaller), alpha, beta, gamma);
 }
 
-static ScopedJavaLocalRef<jthrowable> MessWithJavaException(JNIEnv* env, const
-    JavaParamRef<jclass>& jcaller,
-    const JavaParamRef<jthrowable>& e);
+static base::android::ScopedJavaLocalRef<jthrowable>
+    MessWithJavaException(JNIEnv* env, const
+    base::android::JavaParamRef<jclass>& jcaller,
+    const base::android::JavaParamRef<jthrowable>& e);
 
 extern "C" __attribute__((visibility("default")))
 jthrowable Java_org_chromium_TestJni_nativeMessWithJavaException(JNIEnv* env,
     jclass jcaller,
     jthrowable e) {
-  return MessWithJavaException(env, JavaParamRef<jclass>(env, jcaller),
-      JavaParamRef<jthrowable>(env, e)).Release();
+  return MessWithJavaException(env, base::android::JavaParamRef<jclass>(env,
+      jcaller), base::android::JavaParamRef<jthrowable>(env, e)).Release();
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
index 61711c3..9dddf2fe4 100644
--- a/base/android/jni_generator/testNativesLong.golden
+++ b/base/android/jni_generator/testNativesLong.golden
@@ -33,7 +33,8 @@
   ChromeBrowserProvider* native =
       reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
   CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
-  return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
+  return native->Destroy(env, base::android::JavaParamRef<jobject>(env,
+      jcaller));
 }
 
 // Step 3: RegisterNatives.
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
index 75c8f6b..db61dec5 100644
--- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -27,14 +27,15 @@
 
 // Step 2: method stubs.
 
-static void DoSomething(JNIEnv* env, const JavaParamRef<jclass>& jcaller,
-    const JavaParamRef<jobject>& callback);
+static void DoSomething(JNIEnv* env, const base::android::JavaParamRef<jclass>&
+    jcaller,
+    const base::android::JavaParamRef<jobject>& callback);
 
 extern "C" __attribute__((visibility("default")))
 void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv* env, jclass jcaller,
     jobject callback) {
-  return DoSomething(env, JavaParamRef<jclass>(env, jcaller),
-      JavaParamRef<jobject>(env, callback));
+  return DoSomething(env, base::android::JavaParamRef<jclass>(env, jcaller),
+      base::android::JavaParamRef<jobject>(env, callback));
 }
 
 static base::subtle::AtomicWord g_Foo_calledByNative = 0;
diff --git a/base/android/memory_pressure_listener_android.cc b/base/android/memory_pressure_listener_android.cc
index 5975b94..32e0871 100644
--- a/base/android/memory_pressure_listener_android.cc
+++ b/base/android/memory_pressure_listener_android.cc
@@ -8,6 +8,8 @@
 #include "base/memory/memory_pressure_listener.h"
 #include "jni/MemoryPressureListener_jni.h"
 
+using base::android::JavaParamRef;
+
 // Defined and called by JNI.
 static void OnMemoryPressure(JNIEnv* env,
                              const JavaParamRef<jclass>& clazz,
diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc
index a0eee12..ab56949a 100644
--- a/base/message_loop/message_pump_android.cc
+++ b/base/message_loop/message_pump_android.cc
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "jni/SystemMessageHandler_jni.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 // ----------------------------------------------------------------------------
diff --git a/base/test/test_file_util_android.cc b/base/test/test_file_util_android.cc
index 7f442a80..71f5dc5 100644
--- a/base/test/test_file_util_android.cc
+++ b/base/test/test_file_util_android.cc
@@ -10,6 +10,8 @@
 #include "base/files/file_path.h"
 #include "jni/ContentUriTestUtils_jni.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace base {
 
 FilePath InsertImageIntoMediaStore(const FilePath& path) {
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
index 6c64a17d..fa1a344 100644
--- a/base/threading/simple_thread.cc
+++ b/base/threading/simple_thread.cc
@@ -12,39 +12,29 @@
 namespace base {
 
 SimpleThread::SimpleThread(const std::string& name_prefix)
-    : name_prefix_(name_prefix),
-      name_(name_prefix),
-      thread_(),
-      event_(WaitableEvent::ResetPolicy::MANUAL,
-             WaitableEvent::InitialState::NOT_SIGNALED),
-      tid_(0),
-      joined_(false) {}
+    : SimpleThread(name_prefix, Options()) {}
 
 SimpleThread::SimpleThread(const std::string& name_prefix,
                            const Options& options)
     : name_prefix_(name_prefix),
       name_(name_prefix),
       options_(options),
-      thread_(),
       event_(WaitableEvent::ResetPolicy::MANUAL,
-             WaitableEvent::InitialState::NOT_SIGNALED),
-      tid_(0),
-      joined_(false) {}
+             WaitableEvent::InitialState::NOT_SIGNALED) {}
 
 SimpleThread::~SimpleThread() {
   DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
-  DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
+  DCHECK(thread_.is_null()) << "Joinable SimpleThread destroyed without being "
+                            << "Join()ed.";
 }
 
 void SimpleThread::Start() {
   DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
-  bool success;
-  if (options_.priority() == ThreadPriority::NORMAL) {
-    success = PlatformThread::Create(options_.stack_size(), this, &thread_);
-  } else {
-    success = PlatformThread::CreateWithPriority(options_.stack_size(), this,
-                                                 &thread_, options_.priority());
-  }
+  bool success = options_.joinable
+      ? PlatformThread::CreateWithPriority(options_.stack_size, this,
+                                           &thread_, options_.priority)
+      : PlatformThread::CreateNonJoinableWithPriority(
+            options_.stack_size, this, options_.priority);
   DCHECK(success);
   base::ThreadRestrictions::ScopedAllowWait allow_wait;
   event_.Wait();  // Wait for the thread to complete initialization.
@@ -53,7 +43,9 @@
 void SimpleThread::Join() {
   DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread.";
   DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times.";
+  DCHECK(!thread_.is_null()) << "A non-joinable thread can't be joined.";
   PlatformThread::Join(thread_);
+  thread_ = PlatformThreadHandle();
   joined_ = true;
 }
 
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
index 3deeb10..dd1fc6c 100644
--- a/base/threading/simple_thread.h
+++ b/base/threading/simple_thread.h
@@ -48,6 +48,7 @@
 
 #include "base/base_export.h"
 #include "base/compiler_specific.h"
+#include "base/macros.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
@@ -58,25 +59,25 @@
 // virtual Run method, or you can use the DelegateSimpleThread interface.
 class BASE_EXPORT SimpleThread : public PlatformThread::Delegate {
  public:
-  class BASE_EXPORT Options {
+  struct BASE_EXPORT Options {
    public:
-    Options() : stack_size_(0), priority_(ThreadPriority::NORMAL) {}
-    explicit Options(ThreadPriority priority)
-        : stack_size_(0), priority_(priority) {}
-    ~Options() {}
+    Options() = default;
+    explicit Options(ThreadPriority priority_in) : priority(priority_in) {}
+    ~Options() = default;
 
-    // We use the standard compiler-supplied copy constructor.
+    // Allow copies.
+    Options(const Options& other) = default;
+    Options& operator=(const Options& other) = default;
 
     // A custom stack size, or 0 for the system default.
-    void set_stack_size(size_t size) { stack_size_ = size; }
-    size_t stack_size() const { return stack_size_; }
+    size_t stack_size = 0;
 
-    // A custom thread priority.
-    void set_priority(ThreadPriority priority) { priority_ = priority; }
-    ThreadPriority priority() const { return priority_; }
-   private:
-    size_t stack_size_;
-    ThreadPriority priority_;
+    ThreadPriority priority = ThreadPriority::NORMAL;
+
+    // If false, the thread's PlatformThreadHandle will not be kept around and
+    // the SimpleThread instance will not be required to be Join()'ed before
+    // being destroyed
+    bool joinable = true;
   };
 
   // Create a SimpleThread.  |options| should be used to manage any specific
@@ -106,7 +107,7 @@
   // Return True if Start() has ever been called.
   bool HasBeenStarted();
 
-  // Return True if Join() has evern been called.
+  // Return True if Join() has ever been called.
   bool HasBeenJoined() { return joined_; }
 
   // Overridden from PlatformThread::Delegate:
@@ -116,10 +117,12 @@
   const std::string name_prefix_;
   std::string name_;
   const Options options_;
-  PlatformThreadHandle thread_;  // PlatformThread handle, invalid after Join!
+  PlatformThreadHandle thread_;  // PlatformThread handle, reset after Join.
   WaitableEvent event_;          // Signaled if Start() was ever called.
-  PlatformThreadId tid_;         // The backing thread's id.
-  bool joined_;                  // True if Join has been called.
+  PlatformThreadId tid_ = kInvalidThreadId;  // The backing thread's id.
+  bool joined_ = false;          // True if Join has been called.
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleThread);
 };
 
 class BASE_EXPORT DelegateSimpleThread : public SimpleThread {
@@ -142,6 +145,8 @@
 
  private:
   Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(DelegateSimpleThread);
 };
 
 // DelegateSimpleThreadPool allows you to start up a fixed number of threads,
@@ -186,6 +191,8 @@
   std::queue<Delegate*> delegates_;
   base::Lock lock_;            // Locks delegates_
   WaitableEvent dry_;    // Not signaled when there is no work to do.
+
+  DISALLOW_COPY_AND_ASSIGN(DelegateSimpleThreadPool);
 };
 
 }  // namespace base
diff --git a/base/threading/simple_thread_unittest.cc b/base/threading/simple_thread_unittest.cc
index 14dd459..6c64a04 100644
--- a/base/threading/simple_thread_unittest.cc
+++ b/base/threading/simple_thread_unittest.cc
@@ -2,16 +2,29 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+
 #include "base/atomic_sequence_num.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/gtest_util.h"
+#include "base/threading/platform_thread.h"
 #include "base/threading/simple_thread.h"
+#include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
 
 namespace {
 
+// Sleeps a tiny amount to augment chances of tests using it running in races
+// should there be any while the tested thread is alive.
+class SleepRunner : public DelegateSimpleThread::Delegate {
+  void Run() override {
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(20));
+  }
+};
+
 class SetIntRunner : public DelegateSimpleThread::Delegate {
  public:
   SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
@@ -133,6 +146,25 @@
             std::string("event_waiter/") + IntToString(thread.tid()));
 }
 
+TEST(SimpleThreadTest, JoinNonJoinableThreadDeath) {
+  SleepRunner runner;
+  SimpleThread::Options options;
+  options.joinable = false;
+  DelegateSimpleThread thread(&runner, "noop_runner", options);
+
+  thread.Start();
+  EXPECT_DCHECK_DEATH(thread.Join(), "");
+}
+
+TEST(SimpleThreadTest, DeleteNonJoinableWithoutJoinIsSafe) {
+  SleepRunner runner;
+  SimpleThread::Options options;
+  options.joinable = false;
+  DelegateSimpleThread thread(&runner, "noop_runner", options);
+  thread.Start();
+  // Nothing blows up when |thread| goes out of scope.
+}
+
 TEST(SimpleThreadTest, ThreadPool) {
   AtomicSequenceNumber seq;
   SeqRunner runner(&seq);
diff --git a/blimp/client/app/android/blimp_client_session_android.cc b/blimp/client/app/android/blimp_client_session_android.cc
index c0f220c..4f9e410 100644
--- a/blimp/client/app/android/blimp_client_session_android.cc
+++ b/blimp/client/app/android/blimp_client_session_android.cc
@@ -17,6 +17,8 @@
 #include "jni/BlimpClientSession_jni.h"
 #include "net/base/net_errors.h"
 
+using base::android::JavaParamRef;
+
 namespace blimp {
 namespace client {
 namespace {
diff --git a/blimp/client/app/android/blimp_library_loader.cc b/blimp/client/app/android/blimp_library_loader.cc
index c9dd93c..f07ca629 100644
--- a/blimp/client/app/android/blimp_library_loader.cc
+++ b/blimp/client/app/android/blimp_library_loader.cc
@@ -19,6 +19,8 @@
 #include "net/android/net_jni_registrar.h"
 #include "ui/gl/gl_surface.h"
 
+using base::android::JavaParamRef;
+
 namespace {
 
 bool OnLibrariesLoaded(JNIEnv* env, jclass clazz) {
diff --git a/blimp/client/app/android/blimp_view.cc b/blimp/client/app/android/blimp_view.cc
index 50bde2b..013c791 100644
--- a/blimp/client/app/android/blimp_view.cc
+++ b/blimp/client/app/android/blimp_view.cc
@@ -11,6 +11,8 @@
 #include "ui/events/android/motion_event_android.h"
 #include "ui/gfx/geometry/size.h"
 
+using base::android::JavaParamRef;
+
 namespace blimp {
 namespace client {
 
diff --git a/blimp/client/app/android/tab_control_feature_android.cc b/blimp/client/app/android/tab_control_feature_android.cc
index 7994ed9..c19c25f 100644
--- a/blimp/client/app/android/tab_control_feature_android.cc
+++ b/blimp/client/app/android/tab_control_feature_android.cc
@@ -9,6 +9,8 @@
 #include "jni/TabControlFeature_jni.h"
 #include "ui/gfx/geometry/size.h"
 
+using base::android::JavaParamRef;
+
 namespace blimp {
 namespace client {
 
diff --git a/blimp/client/app/android/toolbar.cc b/blimp/client/app/android/toolbar.cc
index 72f6f96..f9f8f05 100644
--- a/blimp/client/app/android/toolbar.cc
+++ b/blimp/client/app/android/toolbar.cc
@@ -12,6 +12,9 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace blimp {
 namespace client {
 
diff --git a/blimp/client/app/android/web_input_box.cc b/blimp/client/app/android/web_input_box.cc
index c20841c9..c84ee73 100644
--- a/blimp/client/app/android/web_input_box.cc
+++ b/blimp/client/app/android/web_input_box.cc
@@ -9,6 +9,8 @@
 #include "jni/WebInputBox_jni.h"
 #include "ui/base/ime/text_input_type.h"
 
+using base::android::JavaParamRef;
+
 namespace blimp {
 namespace client {
 
diff --git a/blimp/client/core/contents/android/blimp_contents_factory.cc b/blimp/client/core/contents/android/blimp_contents_factory.cc
index ca64ff6..92a2ec9 100644
--- a/blimp/client/core/contents/android/blimp_contents_factory.cc
+++ b/blimp/client/core/contents/android/blimp_contents_factory.cc
@@ -10,6 +10,8 @@
 #include "blimp/client/core/contents/blimp_contents_impl.h"
 #include "jni/BlimpContentsFactory_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace blimp {
 namespace client {
 
diff --git a/blimp/client/core/contents/android/blimp_navigation_controller_impl_android.cc b/blimp/client/core/contents/android/blimp_navigation_controller_impl_android.cc
index a2e375e..f8abded0 100644
--- a/blimp/client/core/contents/android/blimp_navigation_controller_impl_android.cc
+++ b/blimp/client/core/contents/android/blimp_navigation_controller_impl_android.cc
@@ -12,6 +12,8 @@
 #include "base/memory/ptr_util.h"
 #include "jni/BlimpNavigationControllerImpl_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace blimp {
 namespace client {
 
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py
index 36f87f0..be411bb 100755
--- a/build/android/gyp/dex.py
+++ b/build/android/gyp/dex.py
@@ -168,11 +168,10 @@
           dex_cmd.append('--incremental')
           for path in changed_paths:
             changed_subpaths = set(changes.IterChangedSubpaths(path))
-            # Not a fundamental restriction, but it's the case right now and it
-            # simplifies the logic to assume so.
-            assert changed_subpaths, 'All inputs should be zip files.'
-            build_utils.ExtractAll(path, path=classes_temp_dir,
-                                   predicate=lambda p: p in changed_subpaths)
+            # Note: |changed_subpaths| may be empty if nothing changed.
+            if changed_subpaths:
+              build_utils.ExtractAll(path, path=classes_temp_dir,
+                                     predicate=lambda p: p in changed_subpaths)
           paths = [classes_temp_dir]
 
     dex_cmd += paths
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index 689d85f7..aa78715 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -170,18 +170,9 @@
     _generate_entitlements_target_with_toolchain_suffix =
         "$_generate_entitlements_target$_toolchain_suffix"
 
-    # TODO: the correct way to generate _generate_entitlements_output would
-    # be the following, but get_label_info() ignores the toolchain specifier
-    # so use a workaround.
-    #
-    # _generate_entitlements_output =
-    #     get_label_info(
-    #         _generate_entitlements_target_with_toolchain_suffix,
-    #         "target_gen_dir") +
-    #     "/$_output_name.xcent"
-    _generate_entitlements_output = "$root_build_dir/gen" + get_label_info(
-                                        _generate_entitlements_target,
-                                        "dir") + "/" + "$_output_name.xcent"
+    _generate_entitlements_output =
+        get_label_info(_generate_entitlements_target_with_toolchain_suffix,
+                       "target_gen_dir") + "/$_output_name.xcent"
 
     _executable_extra_inputs += [ _generate_entitlements_output ]
     _executable_extra_deps +=
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 600920a7..4137362 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -604,6 +604,8 @@
     "test/begin_frame_args_test.h",
     "test/begin_frame_source_test.cc",
     "test/begin_frame_source_test.h",
+    "test/failure_output_surface.cc",
+    "test/failure_output_surface.h",
     "test/fake_channel_impl.cc",
     "test/fake_channel_impl.h",
     "test/fake_client_picture_cache.cc",
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index a171014..d8250ea 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -176,6 +176,8 @@
       'test/begin_frame_args_test.h',
       'test/begin_frame_source_test.cc',
       'test/begin_frame_source_test.h',
+      'test/failure_output_surface.cc',
+      'test/failure_output_surface.h',
       'test/fake_channel_impl.cc',
       'test/fake_channel_impl.h',
       'test/fake_client_picture_cache.cc',
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 0597cd76..5f40deb 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -174,6 +174,14 @@
 // Check that SurfaceSequence is sent through swap promise.
 class SurfaceLayerSwapPromiseWithDraw : public SurfaceLayerSwapPromise {
  public:
+  SurfaceLayerSwapPromiseWithDraw() : SurfaceLayerSwapPromise() {}
+
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    auto ret = FakeOutputSurface::CreateDelegating3d();
+    output_surface_ = ret.get();
+    return std::move(ret);
+  }
+
   void ChangeTree() override {
     ++commit_count_;
     switch (commit_count_) {
@@ -189,9 +197,9 @@
     }
   }
 
-  void DisplayReceivedCompositorFrameOnThread(
-      const CompositorFrame& frame) override {
-    const std::vector<uint32_t>& satisfied = frame.metadata.satisfies_sequences;
+  void SwapBuffersCompleteOnThread() override {
+    std::vector<uint32_t>& satisfied =
+        output_surface_->last_sent_frame()->metadata.satisfies_sequences;
     EXPECT_LE(satisfied.size(), 1u);
     if (satisfied.size() == 1) {
       // Eventually the one SurfaceSequence should be satisfied, but only
@@ -211,6 +219,8 @@
     // callback.
     EXPECT_TRUE(satisfied_sequence_.is_null());
   }
+
+  FakeOutputSurface* output_surface_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithDraw);
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 39cad04..15d2131 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -34,7 +34,6 @@
 #include "cc/test/layer_test_common.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/stub_layer_tree_host_single_thread_client.h"
-#include "cc/test/test_delegating_output_surface.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/blocking_task_runner.h"
@@ -632,29 +631,12 @@
 
 class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
  public:
-  TextureLayerImplWithMailboxThreadedCallback() = default;
-
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override {
-    bool synchronous_composite =
-        !HasImplThread() &&
-        !layer_tree_host()->settings().single_thread_proxy_scheduler;
-    // Allow relaim resources for this test so that mailboxes in the display
-    // will be returned inside the commit that replaces them.
-    bool force_disable_reclaim_resources = false;
-    return base::MakeUnique<TestDelegatingOutputSurface>(
-        compositor_context_provider, std::move(worker_context_provider),
-        CreateDisplayOutputSurface(compositor_context_provider),
-        shared_bitmap_manager(), gpu_memory_buffer_manager(),
-        layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
-        synchronous_composite, force_disable_reclaim_resources);
-  }
+  TextureLayerImplWithMailboxThreadedCallback()
+      : callback_count_(0),
+        commit_count_(0) {}
 
   // Make sure callback is received on main and doesn't block the impl thread.
-  void ReleaseCallback(char mailbox_char,
-                       const gpu::SyncToken& sync_token,
-                       bool lost_resource) {
+  void ReleaseCallback(const gpu::SyncToken& sync_token, bool lost_resource) {
     EXPECT_EQ(true, main_thread_.CalledOnValidThread());
     EXPECT_FALSE(lost_resource);
     ++callback_count_;
@@ -665,15 +647,12 @@
     std::unique_ptr<SingleReleaseCallback> callback =
         SingleReleaseCallback::Create(base::Bind(
             &TextureLayerImplWithMailboxThreadedCallback::ReleaseCallback,
-            base::Unretained(this), mailbox_char));
+            base::Unretained(this)));
     layer_->SetTextureMailbox(
         TextureMailbox(MailboxFromChar(mailbox_char),
                        SyncTokenFromUInt(static_cast<uint32_t>(mailbox_char)),
                        GL_TEXTURE_2D),
         std::move(callback));
-    // Damage the layer so we send a new frame with the new mailbox to the
-    // Display compositor.
-    layer_->SetNeedsDisplay();
   }
 
   void BeginTest() override {
@@ -724,17 +703,32 @@
         layer_->SetTextureMailbox(TextureMailbox(), nullptr);
         break;
       case 4:
+        // With impl painting, the texture mailbox will still be on the impl
+        // thread when the commit finishes, because the layer is not drawble
+        // when it has no texture mailbox, and thus does not block the commit
+        // on activation. So, we wait for activation.
+        // TODO(danakj): fix this. crbug.com/277953
+        layer_tree_host()->SetNeedsCommit();
+        break;
+      case 5:
         EXPECT_EQ(4, callback_count_);
         // Restore a mailbox for the next step.
         SetMailbox('5');
         break;
-      case 5:
+      case 6:
         // Case #5: remove layer from tree. Callback should *not* be called, the
         // mailbox is returned to the main thread.
         EXPECT_EQ(4, callback_count_);
         layer_->RemoveFromParent();
         break;
-      case 6:
+      case 7:
+        // With impl painting, the texture mailbox will still be on the impl
+        // thread when the commit finishes, because the layer is not around to
+        // block the commit on activation anymore. So, we wait for activation.
+        // TODO(danakj): fix this. crbug.com/277953
+        layer_tree_host()->SetNeedsCommit();
+        break;
+      case 8:
         EXPECT_EQ(4, callback_count_);
         // Resetting the mailbox will call the callback now.
         layer_->SetTextureMailbox(TextureMailbox(), nullptr);
@@ -751,8 +745,8 @@
 
  private:
   base::ThreadChecker main_thread_;
-  int callback_count_ = 0;
-  int commit_count_ = 0;
+  int callback_count_;
+  int commit_count_;
   scoped_refptr<Layer> root_;
   scoped_refptr<TextureLayer> layer_;
 };
diff --git a/cc/output/delegating_renderer_unittest.cc b/cc/output/delegating_renderer_unittest.cc
index 0394d12..2af413d4 100644
--- a/cc/output/delegating_renderer_unittest.cc
+++ b/cc/output/delegating_renderer_unittest.cc
@@ -13,7 +13,22 @@
 
 namespace cc {
 
-class DelegatingRendererTest : public LayerTreeTest {};
+class DelegatingRendererTest : public LayerTreeTest {
+ public:
+  DelegatingRendererTest() : LayerTreeTest(), output_surface_(NULL) {}
+  ~DelegatingRendererTest() override {}
+
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    std::unique_ptr<FakeOutputSurface> output_surface =
+        FakeOutputSurface::CreateDelegating3d();
+    output_surface_ = output_surface.get();
+    return std::move(output_surface);
+  }
+
+ protected:
+  TestWebGraphicsContext3D* context3d_;
+  FakeOutputSurface* output_surface_;
+};
 
 class DelegatingRendererTestDraw : public DelegatingRendererTest {
  public:
@@ -24,30 +39,40 @@
 
   void AfterTest() override {}
 
+  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                   LayerTreeHostImpl::FrameData* frame,
+                                   DrawResult draw_result) override {
+    EXPECT_EQ(0u, output_surface_->num_sent_frames());
+
+    const CompositorFrame* last_frame = output_surface_->last_sent_frame();
+    EXPECT_EQ(nullptr, last_frame);
+    return DRAW_SUCCESS;
+  }
+
   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
-    EXPECT_EQ(0, num_swaps_);
+    EXPECT_EQ(0u, output_surface_->num_sent_frames());
     drawn_viewport_ = host_impl->DeviceViewport();
   }
 
-  void DisplayReceivedCompositorFrameOnThread(
-      const CompositorFrame& frame) override {
-    EXPECT_EQ(1, ++num_swaps_);
+  void SwapBuffersCompleteOnThread() override {
+    EXPECT_EQ(1u, output_surface_->num_sent_frames());
 
-    DelegatedFrameData* last_frame_data = frame.delegated_frame_data.get();
-    ASSERT_TRUE(frame.delegated_frame_data);
-    EXPECT_FALSE(frame.gl_frame_data);
+    const CompositorFrame* last_frame = output_surface_->last_sent_frame();
+    DelegatedFrameData* last_frame_data =
+        last_frame->delegated_frame_data.get();
+    ASSERT_TRUE(last_frame->delegated_frame_data);
+    EXPECT_FALSE(last_frame->gl_frame_data);
     EXPECT_EQ(drawn_viewport_,
               last_frame_data->render_pass_list.back()->output_rect);
-    EXPECT_EQ(0.5f, frame.metadata.min_page_scale_factor);
-    EXPECT_EQ(4.f, frame.metadata.max_page_scale_factor);
+    EXPECT_EQ(0.5f, last_frame->metadata.min_page_scale_factor);
+    EXPECT_EQ(4.f, last_frame->metadata.max_page_scale_factor);
 
-    EXPECT_EQ(0u, frame.delegated_frame_data->resource_list.size());
-    EXPECT_EQ(1u, frame.delegated_frame_data->render_pass_list.size());
+    EXPECT_EQ(0u, last_frame->delegated_frame_data->resource_list.size());
+    EXPECT_EQ(1u, last_frame->delegated_frame_data->render_pass_list.size());
 
     EndTest();
   }
 
-  int num_swaps_ = 0;
   gfx::Rect drawn_viewport_;
 };
 
@@ -78,17 +103,23 @@
     return draw_result;
   }
 
-  void DisplayReceivedCompositorFrameOnThread(
-      const CompositorFrame& frame) override {
-    ASSERT_TRUE(frame.delegated_frame_data);
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+    EXPECT_EQ(0u, output_surface_->num_sent_frames());
+  }
 
-    EXPECT_EQ(2u, frame.delegated_frame_data->render_pass_list.size());
+  void SwapBuffersCompleteOnThread() override {
+    EXPECT_EQ(1u, output_surface_->num_sent_frames());
+
+    const CompositorFrame* last_frame = output_surface_->last_sent_frame();
+    ASSERT_TRUE(last_frame->delegated_frame_data);
+
+    EXPECT_EQ(2u, last_frame->delegated_frame_data->render_pass_list.size());
     // Each render pass has 10 resources in it. And the root render pass has a
     // mask resource used when drawing the child render pass, as well as its
     // replica (it's added twice). The number 10 may change if
     // AppendOneOfEveryQuadType() is updated, and the value here should be
     // updated accordingly.
-    EXPECT_EQ(22u, frame.delegated_frame_data->resource_list.size());
+    EXPECT_EQ(22u, last_frame->delegated_frame_data->resource_list.size());
 
     EndTest();
   }
diff --git a/cc/output/renderer_unittest.cc b/cc/output/renderer_unittest.cc
index e02110d..9fe079a 100644
--- a/cc/output/renderer_unittest.cc
+++ b/cc/output/renderer_unittest.cc
@@ -42,8 +42,7 @@
  public:
   explicit MockContextProvider(
       std::unique_ptr<TestWebGraphicsContext3D> context)
-      : TestContextProvider(base::MakeUnique<TestContextSupport>(),
-                            base::MakeUnique<TestGLES2Interface>(),
+      : TestContextProvider(base::MakeUnique<TestGLES2Interface>(),
                             std::move(context)) {}
   MOCK_METHOD0(DeleteCachedResources, void());
 
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index 9ded1a21..fe35c7b 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -288,8 +288,6 @@
     should_draw = false;
   }
 
-  client_->DisplayWillDrawAndSwap(should_draw, frame_data->render_pass_list);
-
   if (should_draw) {
     gfx::Rect device_viewport_rect = external_viewport_.IsEmpty()
                                          ? gfx::Rect(current_surface_size_)
@@ -341,7 +339,6 @@
     DidSwapBuffersComplete();
   }
 
-  client_->DisplayDidDrawAndSwap();
   return true;
 }
 
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 0fc2fb0..24942a9 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -115,7 +115,6 @@
   }
 
   bool has_scheduler() const { return !!scheduler_; }
-  DirectRenderer* renderer_for_testing() const { return renderer_.get(); }
 
  private:
   void InitializeRenderer();
@@ -125,8 +124,8 @@
   gpu::GpuMemoryBufferManager* const gpu_memory_buffer_manager_;
   const RendererSettings settings_;
 
-  DisplayClient* client_ = nullptr;
-  SurfaceManager* surface_manager_ = nullptr;
+  DisplayClient* client_;
+  SurfaceManager* surface_manager_;
   uint32_t compositor_surface_namespace_;
   SurfaceId current_surface_id_;
   gfx::Size current_surface_size_;
diff --git a/cc/surfaces/display_client.h b/cc/surfaces/display_client.h
index 432b44ac..8f7be8b9 100644
--- a/cc/surfaces/display_client.h
+++ b/cc/surfaces/display_client.h
@@ -5,8 +5,6 @@
 #ifndef CC_SURFACES_DISPLAY_CLIENT_H_
 #define CC_SURFACES_DISPLAY_CLIENT_H_
 
-#include "cc/quads/render_pass.h"
-
 namespace cc {
 struct ManagedMemoryPolicy;
 
@@ -15,9 +13,6 @@
   virtual ~DisplayClient() {}
   virtual void DisplayOutputSurfaceLost() = 0;
   virtual void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) = 0;
-  virtual void DisplayWillDrawAndSwap(bool will_draw_and_swap,
-                                      const RenderPassList& render_passes) = 0;
-  virtual void DisplayDidDrawAndSwap() = 0;
 };
 
 }  // namespace cc
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
index 51e7fd6..74c6508 100644
--- a/cc/surfaces/display_unittest.cc
+++ b/cc/surfaces/display_unittest.cc
@@ -164,9 +164,6 @@
  public:
   void DisplayOutputSurfaceLost() override {}
   void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) override {}
-  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
-                              const RenderPassList& render_passes) override {}
-  void DisplayDidDrawAndSwap() override {}
 };
 
 void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index 294840b..3b1d59d 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -75,7 +75,7 @@
 
   factory_.SubmitCompositorFrame(
       delegated_surface_id_, std::move(frame),
-      base::Bind(&SurfaceDisplayOutputSurface::DidDrawCallback,
+      base::Bind(&SurfaceDisplayOutputSurface::SwapBuffersComplete,
                  base::Unretained(this)));
 }
 
@@ -153,19 +153,7 @@
   SetMemoryPolicy(policy);
 }
 
-void SurfaceDisplayOutputSurface::DisplayWillDrawAndSwap(
-    bool will_draw_and_swap,
-    const RenderPassList& render_passes) {
-  // This notification is not relevant to our client outside of tests.
-}
-
-void SurfaceDisplayOutputSurface::DisplayDidDrawAndSwap() {
-  // This notification is not relevant to our client outside of tests. We
-  // unblock the client from DidDrawCallback() when the surface is going to
-  // be drawn.
-}
-
-void SurfaceDisplayOutputSurface::DidDrawCallback() {
+void SurfaceDisplayOutputSurface::SwapBuffersComplete() {
   // TODO(danakj): Why the lost check?
   if (!output_surface_lost_)
     client_->DidSwapBuffersComplete();
diff --git a/cc/surfaces/surface_display_output_surface.h b/cc/surfaces/surface_display_output_surface.h
index d5f2d9f..f1bd5ea 100644
--- a/cc/surfaces/surface_display_output_surface.h
+++ b/cc/surfaces/surface_display_output_surface.h
@@ -55,12 +55,9 @@
   // DisplayClient implementation.
   void DisplayOutputSurfaceLost() override;
   void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
-  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
-                              const RenderPassList& render_passes) override;
-  void DisplayDidDrawAndSwap() override;
 
  private:
-  void DidDrawCallback();
+  void SwapBuffersComplete();
 
   // This class is only meant to be used on a single thread.
   base::ThreadChecker thread_checker_;
diff --git a/cc/test/failure_output_surface.cc b/cc/test/failure_output_surface.cc
new file mode 100644
index 0000000..64c9b8a
--- /dev/null
+++ b/cc/test/failure_output_surface.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/test/failure_output_surface.h"
+
+namespace cc {
+
+FailureOutputSurface::FailureOutputSurface(bool is_delegating)
+    : FakeOutputSurface(nullptr, nullptr, is_delegating) {}
+
+bool FailureOutputSurface::BindToClient(OutputSurfaceClient* client) {
+  // This will force this output surface to not initialize in LTHI
+  // and eventually get back to LTH::DidFailToInitializeOutputSurface;
+  return false;
+}
+
+}  // namespace cc
diff --git a/cc/test/failure_output_surface.h b/cc/test/failure_output_surface.h
new file mode 100644
index 0000000..a7aca5b
--- /dev/null
+++ b/cc/test/failure_output_surface.h
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TEST_FAILURE_OUTPUT_SURFACE_H_
+#define CC_TEST_FAILURE_OUTPUT_SURFACE_H_
+
+#include "base/macros.h"
+#include "cc/test/fake_output_surface.h"
+
+namespace cc {
+
+class FailureOutputSurface : public FakeOutputSurface {
+ public:
+  explicit FailureOutputSurface(bool is_delegating);
+
+  bool BindToClient(OutputSurfaceClient* client) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FailureOutputSurface);
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_FAILURE_OUTPUT_SURFACE_H_
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index f3748ca..e985bcf5 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -46,8 +46,9 @@
 
   static std::unique_ptr<FakeOutputSurface> Create3d(
       std::unique_ptr<TestGLES2Interface> gl) {
-    return base::WrapUnique(new FakeOutputSurface(
-        TestContextProvider::Create(std::move(gl)), nullptr, false));
+    return base::WrapUnique(
+        new FakeOutputSurface(TestContextProvider::Create(std::move(gl)),
+                              TestContextProvider::CreateWorker(), false));
   }
 
   static std::unique_ptr<FakeOutputSurface> Create3d(
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index ae31dba..901bff9 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -37,49 +37,27 @@
 
 LayerTreePixelTest::~LayerTreePixelTest() {}
 
-std::unique_ptr<TestDelegatingOutputSurface>
-    LayerTreePixelTest::CreateDelegatingOutputSurface(
-        scoped_refptr<ContextProvider>,
-        scoped_refptr<ContextProvider>) {
+void LayerTreePixelTest::InitializeSettings(LayerTreeSettings* settings) {
+  // The PixelTestDelegatingOutputSurface will provide a BeginFrameSource.
+  settings->use_output_surface_begin_frame_source = true;
+}
+
+std::unique_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface() {
+  // Always test Webview shenanigans.
+  gfx::Size surface_expansion_size(40, 60);
+
   scoped_refptr<TestInProcessContextProvider> compositor_context_provider;
   scoped_refptr<TestInProcessContextProvider> worker_context_provider;
+  scoped_refptr<TestInProcessContextProvider> display_context_provider;
+  std::unique_ptr<PixelTestOutputSurface> display_output_surface;
   if (test_type_ == PIXEL_TEST_GL) {
     compositor_context_provider = new TestInProcessContextProvider(nullptr);
     worker_context_provider =
         new TestInProcessContextProvider(compositor_context_provider.get());
-  }
-  bool synchronous_composite =
-      !HasImplThread() &&
-      !layer_tree_host()->settings().single_thread_proxy_scheduler;
-  // Allow resource reclaiming for partial raster tests to get back
-  // resources from the Display.
-  bool force_disable_reclaim_resources = false;
-  auto delegating_output_surface =
-      base::MakeUnique<TestDelegatingOutputSurface>(
-          compositor_context_provider, std::move(worker_context_provider),
-          CreateDisplayOutputSurface(compositor_context_provider),
-          shared_bitmap_manager(), gpu_memory_buffer_manager(),
-          RendererSettings(), ImplThreadTaskRunner(), synchronous_composite,
-          force_disable_reclaim_resources);
-  delegating_output_surface->display()->SetEnlargePassTextureAmountForTesting(
-      enlarge_texture_amount_);
-  return delegating_output_surface;
-}
-
-std::unique_ptr<OutputSurface> LayerTreePixelTest::CreateDisplayOutputSurface(
-    scoped_refptr<ContextProvider> compositor_context_provider) {
-  // Always test Webview shenanigans.
-  gfx::Size surface_expansion_size(40, 60);
-
-  std::unique_ptr<PixelTestOutputSurface> display_output_surface;
-  if (test_type_ == PIXEL_TEST_GL) {
+    display_context_provider = new TestInProcessContextProvider(nullptr);
     bool flipped_output_surface = false;
     display_output_surface = base::MakeUnique<PixelTestOutputSurface>(
-        // Pixel tests use a separate context for the Display to more closely
-        // mimic texture transport from the renderer process to the Display
-        // compositor.
-        make_scoped_refptr(new TestInProcessContextProvider(nullptr)), nullptr,
-        flipped_output_surface);
+        std::move(display_context_provider), nullptr, flipped_output_surface);
   } else {
     std::unique_ptr<PixelTestSoftwareOutputDevice> software_output_device(
         new PixelTestSoftwareOutputDevice);
@@ -88,7 +66,20 @@
         std::move(software_output_device));
   }
   display_output_surface->set_surface_expansion_size(surface_expansion_size);
-  return std::move(display_output_surface);
+
+  auto* task_runner = ImplThreadTaskRunner();
+  bool synchronous_composite =
+      !HasImplThread() &&
+      !layer_tree_host()->settings().single_thread_proxy_scheduler;
+  auto delegating_output_surface =
+      base::MakeUnique<TestDelegatingOutputSurface>(
+          std::move(compositor_context_provider),
+          std::move(worker_context_provider), std::move(display_output_surface),
+          shared_bitmap_manager(), gpu_memory_buffer_manager(),
+          RendererSettings(), task_runner, synchronous_composite);
+  delegating_output_surface->display()->SetEnlargePassTextureAmountForTesting(
+      enlarge_texture_amount_);
+  return std::move(delegating_output_surface);
 }
 
 std::unique_ptr<CopyOutputRequest>
diff --git a/cc/test/layer_tree_pixel_test.h b/cc/test/layer_tree_pixel_test.h
index 3e266cb2..3ab75b4 100644
--- a/cc/test/layer_tree_pixel_test.h
+++ b/cc/test/layer_tree_pixel_test.h
@@ -41,11 +41,8 @@
   ~LayerTreePixelTest() override;
 
   // LayerTreeTest overrides.
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override;
-  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider) override;
+  void InitializeSettings(LayerTreeSettings* settings) override;
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override;
 
   virtual std::unique_ptr<CopyOutputRequest> CreateCopyOutputRequest();
 
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 5f64fc2c..49d4a70 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -28,8 +28,9 @@
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/test_context_provider.h"
-#include "cc/test/test_delegating_output_surface.h"
+#include "cc/test/test_gpu_memory_buffer_manager.h"
 #include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
@@ -182,6 +183,15 @@
     test_hooks_->DrawLayersOnThread(this);
   }
 
+  void DidSwapBuffersComplete() override {
+    LayerTreeHostImpl::DidSwapBuffersComplete();
+    test_hooks_->SwapBuffersCompleteOnThread();
+  }
+
+  void ReclaimResources(const ReturnedResourceArray& resources) override {
+    LayerTreeHostImpl::ReclaimResources(resources);
+  }
+
   void NotifyReadyToActivate() override {
     if (block_notify_ready_to_activate_for_testing_) {
       notify_ready_to_activate_was_blocked_ = true;
@@ -431,34 +441,19 @@
   bool test_started_;
 };
 
-class LayerTreeTestDelegatingOutputSurfaceClient
-    : public TestDelegatingOutputSurfaceClient {
- public:
-  explicit LayerTreeTestDelegatingOutputSurfaceClient(TestHooks* hooks)
-      : hooks_(hooks) {}
-
-  // TestDelegatingOutputSurfaceClient implementation.
-  void DisplayReceivedCompositorFrame(const CompositorFrame& frame) override {
-    hooks_->DisplayReceivedCompositorFrameOnThread(frame);
-  }
-  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
-                              const RenderPassList& render_passes) override {
-    hooks_->DisplayWillDrawAndSwapOnThread(will_draw_and_swap, render_passes);
-  }
-  void DisplayDidDrawAndSwap() override {
-    hooks_->DisplayDidDrawAndSwapOnThread();
-  }
-
- private:
-  TestHooks* hooks_;
-};
-
 LayerTreeTest::LayerTreeTest()
-    : remote_proto_channel_bridge_(this),
+    : external_begin_frame_source_(nullptr),
+      remote_proto_channel_bridge_(this),
       image_serialization_processor_(
           base::WrapUnique(new FakeImageSerializationProcessor)),
-      delegating_output_surface_client_(
-          new LayerTreeTestDelegatingOutputSurfaceClient(this)),
+      beginning_(false),
+      end_when_begin_returns_(false),
+      timed_out_(false),
+      scheduled_(false),
+      started_(false),
+      ended_(false),
+      delegating_renderer_(false),
+      timeout_seconds_(0),
       weak_factory_(this) {
   main_thread_weak_ptr_ = weak_factory_.GetWeakPtr();
 
@@ -605,6 +600,16 @@
                  main_thread_weak_ptr_));
 }
 
+void LayerTreeTest::SetOutputSurfaceOnLayerTreeHost(
+    std::unique_ptr<OutputSurface> output_surface) {
+  if (IsRemoteTest()) {
+    DCHECK(remote_client_layer_tree_host_);
+    remote_client_layer_tree_host_->SetOutputSurface(std::move(output_surface));
+  } else {
+    layer_tree_host_->SetOutputSurface(std::move(output_surface));
+  }
+}
+
 std::unique_ptr<OutputSurface>
 LayerTreeTest::ReleaseOutputSurfaceOnLayerTreeHost() {
   if (IsRemoteTest()) {
@@ -630,6 +635,14 @@
 void LayerTreeTest::DoBeginTest() {
   client_ = LayerTreeHostClientForTesting::Create(this);
 
+  std::unique_ptr<FakeExternalBeginFrameSource> external_begin_frame_source;
+  if (settings_.use_external_begin_frame_source) {
+    DCHECK(!IsRemoteTest());
+    external_begin_frame_source.reset(new FakeExternalBeginFrameSource(
+        settings_.renderer_settings.refresh_rate, true));
+    external_begin_frame_source_ = external_begin_frame_source.get();
+  }
+
   DCHECK(!impl_thread_ || impl_thread_->task_runner().get());
 
   if (IsRemoteTest()) {
@@ -637,7 +650,8 @@
     layer_tree_host_ = LayerTreeHostForTesting::Create(
         this, mode_, client_.get(), &remote_proto_channel_bridge_.channel_main,
         nullptr, nullptr, task_graph_runner_.get(), settings_,
-        base::ThreadTaskRunnerHandle::Get(), nullptr, nullptr,
+        base::ThreadTaskRunnerHandle::Get(), nullptr,
+        std::move(external_begin_frame_source),
         image_serialization_processor_.get());
     DCHECK(remote_proto_channel_bridge_.channel_main.HasReceiver());
   } else {
@@ -645,7 +659,8 @@
         this, mode_, client_.get(), nullptr, shared_bitmap_manager_.get(),
         gpu_memory_buffer_manager_.get(), task_graph_runner_.get(), settings_,
         base::ThreadTaskRunnerHandle::Get(),
-        impl_thread_ ? impl_thread_->task_runner() : nullptr, nullptr,
+        impl_thread_ ? impl_thread_->task_runner() : NULL,
+        std::move(external_begin_frame_source),
         image_serialization_processor_.get());
   }
 
@@ -813,11 +828,7 @@
   settings_.verify_transform_tree_calculations = true;
   settings_.renderer_settings.buffer_to_texture_target_map =
       DefaultBufferToTextureTargetMapForTesting();
-  // The TestDelegatingOutputSurface will provide a BeginFrameSource.
-  settings_.use_output_surface_begin_frame_source = true;
   InitializeSettings(&settings_);
-  DCHECK(settings_.use_output_surface_begin_frame_source);
-  DCHECK(!settings_.use_external_begin_frame_source);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
@@ -838,46 +849,22 @@
 }
 
 void LayerTreeTest::RequestNewOutputSurface() {
-  scoped_refptr<TestContextProvider> shared_context_provider =
-      TestContextProvider::Create();
-  scoped_refptr<TestContextProvider> worker_context_provider =
-      TestContextProvider::CreateWorker();
-
-  auto delegating_output_surface = CreateDelegatingOutputSurface(
-      std::move(shared_context_provider), std::move(worker_context_provider));
-  delegating_output_surface->SetClient(delegating_output_surface_client_.get());
-
-  if (IsRemoteTest()) {
-    DCHECK(remote_client_layer_tree_host_);
-    remote_client_layer_tree_host_->SetOutputSurface(
-        std::move(delegating_output_surface));
-  } else {
-    layer_tree_host_->SetOutputSurface(std::move(delegating_output_surface));
+  if (settings_.use_external_begin_frame_source &&
+      settings_.wait_for_beginframe_interval) {
+    DCHECK(external_begin_frame_source_);
   }
+  SetOutputSurfaceOnLayerTreeHost(CreateOutputSurface());
 }
 
-std::unique_ptr<TestDelegatingOutputSurface>
-LayerTreeTest::CreateDelegatingOutputSurface(
-    scoped_refptr<ContextProvider> compositor_context_provider,
-    scoped_refptr<ContextProvider> worker_context_provider) {
-  bool synchronous_composite =
-      !HasImplThread() &&
-      !layer_tree_host()->settings().single_thread_proxy_scheduler;
-  // Disable reclaim resources by default to act like the Display lives
-  // out-of-process.
-  bool force_disable_reclaim_resources = true;
-  return base::MakeUnique<TestDelegatingOutputSurface>(
-      compositor_context_provider, std::move(worker_context_provider),
-      CreateDisplayOutputSurface(compositor_context_provider),
-      shared_bitmap_manager(), gpu_memory_buffer_manager(),
-      layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
-      synchronous_composite, force_disable_reclaim_resources);
-}
+std::unique_ptr<OutputSurface> LayerTreeTest::CreateOutputSurface() {
+  if (delegating_renderer_)
+    return FakeOutputSurface::CreateDelegating3d();
 
-std::unique_ptr<OutputSurface> LayerTreeTest::CreateDisplayOutputSurface(
-    scoped_refptr<ContextProvider> compositor_context_provider) {
-  // By default the Display shares a context with the LayerTreeHostImpl.
-  return FakeOutputSurface::Create3d(std::move(compositor_context_provider));
+  // Make a worker context in a non-delegating OutputSurface. This is an
+  // exceptional situation for these tests as they put a non-delegating
+  // OutputSurface into the LayerTreeHost.
+  return FakeOutputSurface::Create3d(TestContextProvider::Create(),
+                                     TestContextProvider::CreateWorker());
 }
 
 void LayerTreeTest::DestroyLayerTreeHost() {
@@ -922,6 +909,10 @@
   DCHECK(task_runner_provider()->HasImplThread());
 }
 
+TaskGraphRunner* LayerTreeTest::task_graph_runner() const {
+  return task_graph_runner_.get();
+}
+
 TaskRunnerProvider* LayerTreeTest::task_runner_provider() const {
   // All LayerTreeTests can use the task runner provider to access the impl
   // thread. In the remote mode, the impl thread of the compositor lives on
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index d682495..678b5d7 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -9,15 +9,14 @@
 #include "base/threading/thread.h"
 #include "cc/animation/animation_delegate.h"
 #include "cc/test/remote_proto_channel_bridge.h"
-#include "cc/test/test_gpu_memory_buffer_manager.h"
 #include "cc/test/test_hooks.h"
-#include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
 class AnimationPlayer;
+class FakeExternalBeginFrameSource;
 class FakeLayerTreeHostClient;
 class FakeOutputSurface;
 class LayerImpl;
@@ -25,12 +24,10 @@
 class LayerTreeHostForTesting;
 class LayerTreeHostClient;
 class LayerTreeHostImpl;
-class LayerTreeTestDelegatingOutputSurfaceClient;
 class ProxyImpl;
 class ProxyMain;
 class RemoteChannelImplForTest;
 class TestContextProvider;
-class TestDelegatingOutputSurface;
 class TestGpuMemoryBufferManager;
 class TestTaskGraphRunner;
 class TestWebGraphicsContext3D;
@@ -116,6 +113,8 @@
   void DispatchCompositeImmediately();
   void DispatchNextCommitWaitsForActivation();
 
+  void SetOutputSurfaceOnLayerTreeHost(
+      std::unique_ptr<OutputSurface> output_surface);
   std::unique_ptr<OutputSurface> ReleaseOutputSurfaceOnLayerTreeHost();
   void SetVisibleOnLayerTreeHost(bool visible);
 
@@ -138,9 +137,7 @@
   }
   Proxy* remote_client_proxy() const;
   TaskRunnerProvider* task_runner_provider() const;
-  TaskGraphRunner* task_graph_runner() const {
-    return task_graph_runner_.get();
-  }
+  TaskGraphRunner* task_graph_runner() const;
   bool TestEnded() const { return ended_; }
 
   LayerTreeHost* layer_tree_host();
@@ -149,7 +146,7 @@
   SharedBitmapManager* shared_bitmap_manager() const {
     return shared_bitmap_manager_.get();
   }
-  gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() {
+  TestGpuMemoryBufferManager* gpu_memory_buffer_manager() {
     return gpu_memory_buffer_manager_.get();
   }
 
@@ -161,20 +158,9 @@
 
   // By default, output surface recreation is synchronous.
   void RequestNewOutputSurface() override;
-  // Override this and call the base class to change what ContextProviders will
-  // be used (such as for pixel tests). Or override it and create your own
-  // TestDelegatingOutputSurface to control how it is created.
-  virtual std::unique_ptr<TestDelegatingOutputSurface>
-  CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider);
-  // Override this and call the base class to change what ContextProvider will
-  // be used, such as to prevent sharing the context with the delegating
-  // OutputSurface. Or override it and create your own OutputSurface to change
-  // what type of OutputSurface is used, such as a real OutputSurface for pixel
-  // tests or a software-compositing OutputSurface.
-  virtual std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider);
+  // Override this for pixel tests, where you need a real output surface, or
+  // if you want to control the output surface used for drawing.
+  virtual std::unique_ptr<OutputSurface> CreateOutputSurface();
 
   bool IsRemoteTest() const;
 
@@ -191,22 +177,21 @@
   // The LayerTreeHost created by the cc embedder on the client in remote mode.
   std::unique_ptr<LayerTreeHostForTesting> remote_client_layer_tree_host_;
 
+  FakeExternalBeginFrameSource* external_begin_frame_source_;
   RemoteProtoChannelBridge remote_proto_channel_bridge_;
 
   std::unique_ptr<ImageSerializationProcessor> image_serialization_processor_;
 
-  bool beginning_ = false;
-  bool end_when_begin_returns_ = false;
-  bool timed_out_ = false;
-  bool scheduled_ = false;
-  bool started_ = false;
-  bool ended_ = false;
-  bool delegating_renderer_ = false;
+  bool beginning_;
+  bool end_when_begin_returns_;
+  bool timed_out_;
+  bool scheduled_;
+  bool started_;
+  bool ended_;
+  bool delegating_renderer_;
 
-  int timeout_seconds_ = false;
+  int timeout_seconds_;
 
-  std::unique_ptr<LayerTreeTestDelegatingOutputSurfaceClient>
-      delegating_output_surface_client_;
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
   std::unique_ptr<base::Thread> impl_thread_;
diff --git a/cc/test/test_context_provider.cc b/cc/test/test_context_provider.cc
index 2634aff..31ef12e9 100644
--- a/cc/test/test_context_provider.cc
+++ b/cc/test/test_context_provider.cc
@@ -23,17 +23,13 @@
 
 // static
 scoped_refptr<TestContextProvider> TestContextProvider::Create() {
-  return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
-                                 base::MakeUnique<TestGLES2Interface>(),
-                                 TestWebGraphicsContext3D::Create());
+  return Create(TestWebGraphicsContext3D::Create());
 }
 
 // static
 scoped_refptr<TestContextProvider> TestContextProvider::CreateWorker() {
-  scoped_refptr<TestContextProvider> worker_context_provider(
-      new TestContextProvider(base::MakeUnique<TestContextSupport>(),
-                              base::MakeUnique<TestGLES2Interface>(),
-                              TestWebGraphicsContext3D::Create()));
+  scoped_refptr<TestContextProvider> worker_context_provider =
+      Create(TestWebGraphicsContext3D::Create());
   // Worker contexts are bound to the thread they are created on.
   if (!worker_context_provider->BindToCurrentThread())
     return nullptr;
@@ -44,8 +40,7 @@
 scoped_refptr<TestContextProvider> TestContextProvider::Create(
     std::unique_ptr<TestWebGraphicsContext3D> context) {
   DCHECK(context);
-  return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
-                                 base::MakeUnique<TestGLES2Interface>(),
+  return new TestContextProvider(base::MakeUnique<TestGLES2Interface>(),
                                  std::move(context));
 }
 
@@ -53,36 +48,23 @@
 scoped_refptr<TestContextProvider> TestContextProvider::Create(
     std::unique_ptr<TestGLES2Interface> gl) {
   DCHECK(gl);
-  return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
-                                 std::move(gl),
+  return new TestContextProvider(std::move(gl),
                                  TestWebGraphicsContext3D::Create());
 }
 
-// static
-scoped_refptr<TestContextProvider> TestContextProvider::Create(
-    std::unique_ptr<TestWebGraphicsContext3D> context,
-    std::unique_ptr<TestContextSupport> support) {
-  DCHECK(context);
-  DCHECK(support);
-  return new TestContextProvider(std::move(support),
-                                 base::MakeUnique<TestGLES2Interface>(),
-                                 std::move(context));
-}
-
 TestContextProvider::TestContextProvider(
-    std::unique_ptr<TestContextSupport> support,
     std::unique_ptr<TestGLES2Interface> gl,
     std::unique_ptr<TestWebGraphicsContext3D> context)
-    : support_(std::move(support)),
-      context3d_(std::move(context)),
+    : context3d_(std::move(context)),
       context_gl_(std::move(gl)),
+      bound_(false),
       weak_ptr_factory_(this) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   DCHECK(context3d_);
   DCHECK(context_gl_);
   context_thread_checker_.DetachFromThread();
   context_gl_->set_test_context(context3d_.get());
-  context3d_->set_test_support(support_.get());
+  context3d_->set_test_support(&support_);
 }
 
 TestContextProvider::~TestContextProvider() {
@@ -128,7 +110,7 @@
 }
 
 gpu::ContextSupport* TestContextProvider::ContextSupport() {
-  return support();
+  return &support_;
 }
 
 class GrContext* TestContextProvider::GrContext() {
diff --git a/cc/test/test_context_provider.h b/cc/test/test_context_provider.h
index d7c5627f..97c7abc 100644
--- a/cc/test/test_context_provider.h
+++ b/cc/test/test_context_provider.h
@@ -36,9 +36,6 @@
   static scoped_refptr<TestContextProvider> Create(
       std::unique_ptr<TestWebGraphicsContext3D> context);
   static scoped_refptr<TestContextProvider> Create(
-      std::unique_ptr<TestWebGraphicsContext3D> context,
-      std::unique_ptr<TestContextSupport> support);
-  static scoped_refptr<TestContextProvider> Create(
       std::unique_ptr<TestGLES2Interface> gl);
 
   bool BindToCurrentThread() override;
@@ -60,11 +57,10 @@
   // InitializeOnCurrentThread on the context returned from this method.
   TestWebGraphicsContext3D* UnboundTestContext3d();
 
-  TestContextSupport* support() { return support_.get(); }
+  TestContextSupport* support() { return &support_; }
 
  protected:
   explicit TestContextProvider(
-      std::unique_ptr<TestContextSupport> support,
       std::unique_ptr<TestGLES2Interface> gl,
       std::unique_ptr<TestWebGraphicsContext3D> context);
   ~TestContextProvider() override;
@@ -72,10 +68,11 @@
  private:
   void OnLostContext();
 
-  std::unique_ptr<TestContextSupport> support_;
+  TestContextSupport support_;
+
   std::unique_ptr<TestWebGraphicsContext3D> context3d_;
   std::unique_ptr<TestGLES2Interface> context_gl_;
-  bool bound_ = false;
+  bool bound_;
 
   base::ThreadChecker main_thread_checker_;
   base::ThreadChecker context_thread_checker_;
diff --git a/cc/test/test_delegating_output_surface.cc b/cc/test/test_delegating_output_surface.cc
index d626a3d..8f586cf 100644
--- a/cc/test/test_delegating_output_surface.cc
+++ b/cc/test/test_delegating_output_surface.cc
@@ -24,8 +24,7 @@
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     const RendererSettings& renderer_settings,
     base::SingleThreadTaskRunner* task_runner,
-    bool synchronous_composite,
-    bool force_disable_reclaim_resources)
+    bool synchronous_composite)
     : OutputSurface(std::move(compositor_context_provider),
                     std::move(worker_context_provider),
                     nullptr),
@@ -38,9 +37,6 @@
   if (!synchronous_composite) {
     begin_frame_source.reset(new DelayBasedBeginFrameSource(
         base::MakeUnique<DelayBasedTimeSource>(task_runner)));
-    begin_frame_source->SetAuthoritativeVSyncInterval(
-        base::TimeDelta::FromMilliseconds(1000.f /
-                                          renderer_settings.refresh_rate));
     scheduler.reset(new DisplayScheduler(
         begin_frame_source.get(), task_runner,
         display_output_surface->capabilities().max_frames_pending));
@@ -56,9 +52,8 @@
   capabilities_.delegated_rendering = true;
   // Since this OutputSurface and the Display are tightly coupled and in the
   // same process/thread, the LayerTreeHostImpl can reclaim resources from
-  // the Display. But we allow tests to disable this to mimic an out-of-process
-  // Display.
-  capabilities_.can_force_reclaim_resources = !force_disable_reclaim_resources;
+  // the Display.
+  capabilities_.can_force_reclaim_resources = true;
   capabilities_.delegated_sync_points_required =
       !context_shared_with_compositor;
 }
@@ -112,9 +107,6 @@
 }
 
 void TestDelegatingOutputSurface::SwapBuffers(CompositorFrame frame) {
-  if (test_client_)
-    test_client_->DisplayReceivedCompositorFrame(frame);
-
   if (delegated_surface_id_.is_null()) {
     delegated_surface_id_ = surface_id_allocator_->GenerateId();
     surface_factory_->Create(delegated_surface_id_);
@@ -130,7 +122,7 @@
 
   surface_factory_->SubmitCompositorFrame(
       delegated_surface_id_, std::move(frame),
-      base::Bind(&TestDelegatingOutputSurface::DidDrawCallback,
+      base::Bind(&TestDelegatingOutputSurface::DrawCallback,
                  weak_ptrs_.GetWeakPtr(), synchronous));
 
   for (std::unique_ptr<CopyOutputRequest>& copy_request : copy_requests_)
@@ -138,11 +130,11 @@
                                            std::move(copy_request));
   copy_requests_.clear();
 
-  if (synchronous)
+  if (!display_->has_scheduler())
     display_->DrawAndSwap();
 }
 
-void TestDelegatingOutputSurface::DidDrawCallback(bool synchronous) {
+void TestDelegatingOutputSurface::DrawCallback(bool synchronous) {
   // This is the frame ack to unthrottle the next frame, not actually a notice
   // that drawing is done.
   if (synchronous) {
@@ -194,16 +186,4 @@
   SetMemoryPolicy(policy);
 }
 
-void TestDelegatingOutputSurface::DisplayWillDrawAndSwap(
-    bool will_draw_and_swap,
-    const RenderPassList& render_passes) {
-  if (test_client_)
-    test_client_->DisplayWillDrawAndSwap(will_draw_and_swap, render_passes);
-}
-
-void TestDelegatingOutputSurface::DisplayDidDrawAndSwap() {
-  if (test_client_)
-    test_client_->DisplayDidDrawAndSwap();
-}
-
 }  // namespace cc
diff --git a/cc/test/test_delegating_output_surface.h b/cc/test/test_delegating_output_surface.h
index f5ac294..25ccb123 100644
--- a/cc/test/test_delegating_output_surface.h
+++ b/cc/test/test_delegating_output_surface.h
@@ -17,24 +17,13 @@
 #include "cc/surfaces/surface_manager.h"
 
 namespace cc {
+
 class CopyOutputRequest;
 
-class TestDelegatingOutputSurfaceClient {
- public:
-  virtual ~TestDelegatingOutputSurfaceClient() {}
-
-  virtual void DisplayReceivedCompositorFrame(const CompositorFrame& frame) = 0;
-  virtual void DisplayWillDrawAndSwap(bool will_draw_and_swap,
-                                      const RenderPassList& render_passes) = 0;
-  virtual void DisplayDidDrawAndSwap() = 0;
-};
-
 class TestDelegatingOutputSurface : public OutputSurface,
                                     public SurfaceFactoryClient,
                                     public DisplayClient {
  public:
-  // Pass true for |force_disable_reclaim_resources| to act like the Display
-  // is out-of-process and can't return resources synchronously.
   TestDelegatingOutputSurface(
       scoped_refptr<ContextProvider> compositor_context_provider,
       scoped_refptr<ContextProvider> worker_context_provider,
@@ -43,14 +32,9 @@
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       const RendererSettings& renderer_settings,
       base::SingleThreadTaskRunner* task_runner,
-      bool synchronous_composite,
-      bool force_disable_reclaim_resources);
+      bool synchronous_composite);
   ~TestDelegatingOutputSurface() override;
 
-  void SetClient(TestDelegatingOutputSurfaceClient* client) {
-    test_client_ = client;
-  }
-
   Display* display() const { return display_.get(); }
 
   // Will be submitted with the next SwapBuffers.
@@ -71,12 +55,9 @@
   // DisplayClient implementation.
   void DisplayOutputSurfaceLost() override;
   void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
-  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
-                              const RenderPassList& render_passes) override;
-  void DisplayDidDrawAndSwap() override;
 
  private:
-  void DidDrawCallback(bool synchronous);
+  void DrawCallback(bool synchronous);
 
   // TODO(danakj): These don't to be stored in unique_ptrs when OutputSurface
   // is owned/destroyed on the compositor thread.
@@ -91,7 +72,6 @@
   std::unique_ptr<Display> display_;
 
   bool bound_ = false;
-  TestDelegatingOutputSurfaceClient* test_client_ = nullptr;
 
   std::vector<std::unique_ptr<CopyOutputRequest>> copy_requests_;
 
diff --git a/cc/test/test_hooks.h b/cc/test/test_hooks.h
index ff0737f..f386091d 100644
--- a/cc/test/test_hooks.h
+++ b/cc/test/test_hooks.h
@@ -22,7 +22,6 @@
   TestHooks();
   ~TestHooks() override;
 
-  // Compositor thread hooks.
   virtual void CreateResourceAndRasterBufferProvider(
       LayerTreeHostImpl* host_impl,
       std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
@@ -46,33 +45,22 @@
       LayerTreeHostImpl::FrameData* frame_data,
       DrawResult draw_result);
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) {}
+  // Note that this is called asynchronously from the LayerTreeHostImpl
+  // performing its draw, so you should record state you want to use here
+  // in DrawLayersOnThread() instead. For that reason this method does not
+  // receive a LayerTreeHostImpl pointer.
+  virtual void SwapBuffersCompleteOnThread() {}
   virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void NotifyAllTileTasksCompleted(LayerTreeHostImpl* host_impl) {}
   virtual void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
                                               const Tile* tile) {}
-  virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
-                                       bool visible) {}
   virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
                              base::TimeTicks monotonic_time) {}
   virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
                                     bool has_unfinished_animation) {}
   virtual void WillAnimateLayers(LayerTreeHostImpl* host_impl,
                                  base::TimeTicks monotonic_time) {}
-
-  // Asynchronous compositor thread hooks.
-  // These are called asynchronously from the LayerTreeHostImpl performing its
-  // draw, so you should record state you want to use here in
-  // DrawLayersOnThread() instead. For that reason these methods do not receive
-  // a LayerTreeHostImpl pointer.
-  virtual void DisplayReceivedCompositorFrameOnThread(
-      const CompositorFrame& frame) {}
-  virtual void DisplayWillDrawAndSwapOnThread(
-      bool will_draw_and_swap,
-      const RenderPassList& render_passes) {}
-  virtual void DisplayDidDrawAndSwapOnThread() {}
-
-  // Main thread hooks.
   virtual void ApplyViewportDeltas(
       const gfx::Vector2dF& inner_delta,
       const gfx::Vector2dF& outer_delta,
@@ -91,6 +79,8 @@
   virtual void DidCommit() {}
   virtual void DidCommitAndDrawFrame() {}
   virtual void DidCompleteSwapBuffers() {}
+  virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
+                                       bool visible) {}
   virtual void ScheduleComposite() {}
   virtual void DidActivateSyncTree() {}
 
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc
index 4f0e3e61..2641c90 100644
--- a/cc/test/test_web_graphics_context_3d.cc
+++ b/cc/test/test_web_graphics_context_3d.cc
@@ -74,7 +74,6 @@
       weak_ptr_factory_(this) {
   CreateNamespace();
   set_support_image(true);
-  set_have_extension_egl_image(true);  // For stream textures.
 }
 
 TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 243e81da..b32ed4e 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -797,12 +797,11 @@
       !root_surface->layer_list().empty();
   bool hud_wants_to_draw_ = active_tree_->hud_layer() &&
                             active_tree_->hud_layer()->IsAnimatingHUDContents();
-  bool resources_must_be_resent =
-      output_surface_->capabilities().can_force_reclaim_resources;
   if (root_surface_has_contributing_layers &&
       root_surface_has_no_visible_damage &&
       !active_tree_->property_trees()->effect_tree.HasCopyRequests() &&
-      !resources_must_be_resent && !hud_wants_to_draw_) {
+      !output_surface_->capabilities().can_force_reclaim_resources &&
+      !hud_wants_to_draw_) {
     TRACE_EVENT0("cc",
                  "LayerTreeHostImpl::CalculateRenderPasses::EmptyDamageRect");
     frame->has_no_damage = true;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 087ecd0a..862ef2f8 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -7854,8 +7854,7 @@
           context_provider, TestContextProvider::CreateWorker(),
           FakeOutputSurface::Create3d(context_provider), nullptr, nullptr,
           RendererSettings(), base::ThreadTaskRunnerHandle::Get().get(),
-          true /* synchronous_composite */,
-          false /* force_disable_reclaim_resources */));
+          true /* synchronous_composite */));
 
   SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1));
 
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 27f4ab21..4fb8e69 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -47,7 +47,6 @@
 #include "cc/test/layer_internals_for_test.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/skia_common.h"
-#include "cc/test/test_delegating_output_surface.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/effect_node.h"
@@ -433,37 +432,25 @@
 
 class LayerTreeHostFreeWorkerContextResourcesTest : public LayerTreeHostTest {
  public:
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override {
-    auto mock_worker_context_support_owned =
-        base::MakeUnique<MockContextSupport>();
-    auto* mock_worker_context_support = mock_worker_context_support_owned.get();
-
-    auto mock_worker_context_provider = make_scoped_refptr(
-        new MockContextProvider(std::move(mock_worker_context_support_owned)));
-
-    // Workers are bound on the main thread.
-    mock_worker_context_provider->BindToCurrentThread();
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    auto output_surface = base::WrapUnique(
+        new testing::StrictMock<
+            MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface>(
+            delegating_renderer()));
 
     // At init, we expect one call to set visibility to true.
     testing::Expectation visibility_true =
-        EXPECT_CALL(*mock_worker_context_support,
-                    SetAggressivelyFreeResources(false))
+        EXPECT_CALL(*output_surface,
+                    SetWorkerContextShouldAggressivelyFreeResources(false))
             .Times(1);
 
     // After running, we should get exactly one call to
-    // DeleteCachedResources, along with SetAggressivelyFreeResources.
-    EXPECT_CALL(*mock_worker_context_provider, DeleteCachedResources())
-        .After(visibility_true);
-    EXPECT_CALL(*mock_worker_context_support,
-                SetAggressivelyFreeResources(true))
+    // FreeWorkerContextGpuResources.
+    EXPECT_CALL(*output_surface,
+                SetWorkerContextShouldAggressivelyFreeResources(true))
         .After(visibility_true)
         .WillOnce(testing::Invoke([this](bool is_visible) { EndTest(); }));
-
-    return LayerTreeHostTest::CreateDelegatingOutputSurface(
-        std::move(compositor_context_provider),
-        std::move(mock_worker_context_provider));
+    return std::move(output_surface);
   }
 
   void InitializeSettings(LayerTreeSettings* settings) override {
@@ -471,27 +458,27 @@
     settings->gpu_rasterization_forced = true;
   }
 
-  void BeginTest() override {}
-  void AfterTest() override {}
+  void BeginTest() override {
+    // Logic is handled in InitializedRendererOnThread to ensure that our
+    // LTHI is fully set up.
+  }
+
+  void AfterTest() override {
+    // Expectations handled via mock.
+  }
 
  private:
-  class MockContextProvider : public TestContextProvider {
+  class MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface
+      : public FakeOutputSurface {
    public:
-    explicit MockContextProvider(std::unique_ptr<TestContextSupport> support)
-        : TestContextProvider(std::move(support),
-                              base::MakeUnique<TestGLES2Interface>(),
-                              TestWebGraphicsContext3D::Create()) {}
-
-    MOCK_METHOD0(DeleteCachedResources, void());
-
-   private:
-    ~MockContextProvider() = default;
-  };
-
-  class MockContextSupport : public TestContextSupport {
-   public:
-    MOCK_METHOD1(SetAggressivelyFreeResources,
-                 void(bool aggressively_free_resources));
+    ~MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface() {}
+    explicit MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface(
+        bool delegated_rendering)
+        : FakeOutputSurface(TestContextProvider::Create(),
+                            TestContextProvider::CreateWorker(),
+                            delegated_rendering) {}
+    MOCK_METHOD1(SetWorkerContextShouldAggressivelyFreeResources,
+                 void(bool is_visible));
   };
 };
 
@@ -533,6 +520,7 @@
  public:
   void InitializeSettings(LayerTreeSettings* settings) override {
     LayerTreeHostFreeWorkerContextResourcesTest::InitializeSettings(settings);
+    settings->use_external_begin_frame_source = true;
     settings->using_synchronous_renderer_compositor = true;
   }
 };
@@ -2574,10 +2562,39 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLCDChange);
 
+// Verify that the BeginFrame notification is used to initiate rendering.
+class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
+ public:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->use_external_begin_frame_source = true;
+  }
+
+  void BeginTest() override {
+    // This will trigger a SetNeedsBeginFrame which will trigger a
+    // BeginFrame.
+    PostSetNeedsCommitToMainThread();
+  }
+
+  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                   LayerTreeHostImpl::FrameData* frame,
+                                   DrawResult draw_result) override {
+    EndTest();
+    return DRAW_SUCCESS;
+  }
+
+  void AfterTest() override {}
+
+ private:
+  base::TimeTicks frame_time_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFrameNotification);
+
 class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled
     : public LayerTreeHostTest {
  public:
   void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->use_external_begin_frame_source = true;
     settings->using_synchronous_renderer_compositor = true;
   }
 
@@ -2588,7 +2605,8 @@
     // once we return. End test while it's enabled.
     ImplThreadTaskRunner()->PostTask(
         FROM_HERE,
-        base::Bind(&LayerTreeHostTest::EndTest, base::Unretained(this)));
+        base::Bind(&LayerTreeHostTestBeginFrameNotification::EndTest,
+                   base::Unretained(this)));
   }
 
   void AfterTest() override {}
@@ -2602,6 +2620,10 @@
   LayerTreeHostTestAbortedCommitDoesntStall()
       : commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {}
 
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->use_external_begin_frame_source = true;
+  }
+
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void DidCommit() override {
@@ -2642,41 +2664,35 @@
   int commit_complete_count_;
 };
 
-class OnDrawOutputSurface : public TestDelegatingOutputSurface {
+class OnDrawOutputSurface : public OutputSurface {
  public:
-  explicit OnDrawOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider,
-      std::unique_ptr<OutputSurface> display_output_surface,
-      SharedBitmapManager* shared_bitmap_manager,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      const RendererSettings& renderer_settings,
-      base::SingleThreadTaskRunner* task_runner,
-      bool synchronous_composite,
-      bool force_disable_reclaim_resources,
-      base::Closure invalidate_callback)
-      : TestDelegatingOutputSurface(std::move(compositor_context_provider),
-                                    std::move(worker_context_provider),
-                                    std::move(display_output_surface),
-                                    shared_bitmap_manager,
-                                    gpu_memory_buffer_manager,
-                                    renderer_settings,
-                                    task_runner,
-                                    synchronous_composite,
-                                    force_disable_reclaim_resources),
-        invalidate_callback_(std::move(invalidate_callback)) {}
+  explicit OnDrawOutputSurface(base::Closure invalidate_callback)
+      : OutputSurface(TestContextProvider::Create(),
+                      TestContextProvider::CreateWorker(),
+                      nullptr),
+        invalidate_callback_(std::move(invalidate_callback)) {
+    capabilities_.delegated_rendering = true;
+  }
 
-  // TestDelegatingOutputSurface overrides.
+  // OutputSurface implementation.
+  void SwapBuffers(CompositorFrame frame) override { did_swap_ = true; }
+  uint32_t GetFramebufferCopyTextureFormat() override { return 0; }
   void Invalidate() override { invalidate_callback_.Run(); }
 
   void OnDraw(bool resourceless_software_draw) {
     gfx::Transform identity;
     gfx::Rect empty_rect;
+    // SwapBuffers happens inside of OnDraw.
     client_->OnDraw(identity, empty_rect, resourceless_software_draw);
+    if (did_swap_) {
+      did_swap_ = false;
+      client_->DidSwapBuffersComplete();
+    }
   }
 
  private:
-  const base::Closure invalidate_callback_;
+  bool did_swap_ = false;
+  base::Closure invalidate_callback_;
 };
 
 class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor
@@ -2687,21 +2703,11 @@
     settings->using_synchronous_renderer_compositor = true;
   }
 
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override {
-    auto on_draw_callback = base::Bind(
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    auto output_surface = base::MakeUnique<OnDrawOutputSurface>(base::Bind(
         &LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor::
             CallOnDraw,
-        base::Unretained(this));
-    auto output_surface = base::MakeUnique<OnDrawOutputSurface>(
-        compositor_context_provider, std::move(worker_context_provider),
-        CreateDisplayOutputSurface(compositor_context_provider),
-        shared_bitmap_manager(), gpu_memory_buffer_manager(),
-        layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
-        false /* synchronous_composite */,
-        false /* force_disable_reclaim_resources */,
-        std::move(on_draw_callback));
+        base::Unretained(this)));
     output_surface_ = output_surface.get();
     return std::move(output_surface);
   }
@@ -2837,20 +2843,10 @@
     client_.set_bounds(root_layer_->bounds());
   }
 
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override {
-    auto on_draw_callback =
-        base::Bind(&LayerTreeHostTestResourcelessSoftwareDraw::CallOnDraw,
-                   base::Unretained(this));
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
     auto output_surface = base::MakeUnique<OnDrawOutputSurface>(
-        compositor_context_provider, std::move(worker_context_provider),
-        CreateDisplayOutputSurface(compositor_context_provider),
-        shared_bitmap_manager(), gpu_memory_buffer_manager(),
-        layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
-        false /* synchronous_composite */,
-        false /* force_disable_reclaim_resources */,
-        std::move(on_draw_callback));
+        base::Bind(&LayerTreeHostTestResourcelessSoftwareDraw::CallOnDraw,
+                   base::Unretained(this)));
     output_surface_ = output_surface.get();
     return std::move(output_surface);
   }
@@ -4380,19 +4376,22 @@
       : first_output_surface_memory_limit_(4321234),
         second_output_surface_memory_limit_(1234321) {}
 
-  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider) override {
-    if (!first_context_provider_) {
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    if (!first_context_provider_.get()) {
       first_context_provider_ = TestContextProvider::Create();
-      compositor_context_provider = first_context_provider_;
     } else {
-      EXPECT_FALSE(second_context_provider_);
+      EXPECT_FALSE(second_context_provider_.get());
       second_context_provider_ = TestContextProvider::Create();
-      compositor_context_provider = second_context_provider_;
     }
 
-    auto output_surface =
-        FakeOutputSurface::Create3d(std::move(compositor_context_provider));
+    scoped_refptr<TestContextProvider> provider(second_context_provider_.get()
+                                                    ? second_context_provider_
+                                                    : first_context_provider_);
+    std::unique_ptr<FakeOutputSurface> output_surface;
+    if (delegating_renderer())
+      output_surface = FakeOutputSurface::CreateDelegating3d(provider);
+    else
+      output_surface = FakeOutputSurface::Create3d(provider);
     output_surface->SetMemoryPolicyToSetAtBind(
         base::WrapUnique(new ManagedMemoryPolicy(
             second_context_provider_.get() ? second_output_surface_memory_limit_
@@ -4528,7 +4527,7 @@
     }
   }
 
-  void DisplayDidDrawAndSwapOnThread() override { EndTest(); }
+  void SwapBuffersCompleteOnThread() override { EndTest(); }
 
   void AfterTest() override {
     // The pending swap promise should activate and swap.
@@ -4720,7 +4719,7 @@
             : base::Closure());
   }
 
-  void DisplayDidDrawAndSwapOnThread() override {
+  void SwapBuffersCompleteOnThread() override {
     if (num_swaps_++ >= 1) {
       // The commit changes layers so it should cause a swap.
       base::AutoLock lock(swap_promise_result_.lock);
@@ -5464,29 +5463,13 @@
 class LayerTreeHostTestSynchronousCompositeSwapPromise
     : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestSynchronousCompositeSwapPromise() = default;
+  LayerTreeHostTestSynchronousCompositeSwapPromise() : commit_count_(0) {}
 
   void InitializeSettings(LayerTreeSettings* settings) override {
     settings->single_thread_proxy_scheduler = false;
     settings->use_zero_copy = true;
   }
 
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override {
-    bool synchronous_composite =
-        !HasImplThread() &&
-        !layer_tree_host()->settings().single_thread_proxy_scheduler;
-    // Relaiming resources is parameterized for this test.
-    bool force_disable_reclaim_resources = !reclaim_resources_;
-    return base::MakeUnique<TestDelegatingOutputSurface>(
-        compositor_context_provider, std::move(worker_context_provider),
-        CreateDisplayOutputSurface(compositor_context_provider),
-        shared_bitmap_manager(), gpu_memory_buffer_manager(),
-        layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
-        synchronous_composite, force_disable_reclaim_resources);
-  }
-
   void BeginTest() override {
     // Successful composite.
     std::unique_ptr<SwapPromise> swap_promise0(
@@ -5494,7 +5477,7 @@
     layer_tree_host()->QueueSwapPromise(std::move(swap_promise0));
     layer_tree_host()->Composite(base::TimeTicks::Now());
 
-    // Fail to swap (no damage) if not reclaiming resources from the Display.
+    // Fail to swap (no damage).
     std::unique_ptr<SwapPromise> swap_promise1(
         new TestSwapPromise(&swap_promise_result_[1]));
     layer_tree_host()->QueueSwapPromise(std::move(swap_promise1));
@@ -5528,19 +5511,13 @@
       EXPECT_TRUE(swap_promise_result_[0].dtor_called);
     }
 
-    // Second swap promise fails to swap if not reclaiming resources from the
-    // Display.
+    // Second swap promise fails to swap.
     {
       base::AutoLock lock(swap_promise_result_[1].lock);
       EXPECT_TRUE(swap_promise_result_[1].did_activate_called);
-      if (!reclaim_resources_) {
-        EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
-        EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
-        EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
-      } else {
-        EXPECT_TRUE(swap_promise_result_[1].did_swap_called);
-        EXPECT_FALSE(swap_promise_result_[1].did_not_swap_called);
-      }
+      EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
+      EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
+      EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
       EXPECT_TRUE(swap_promise_result_[1].dtor_called);
     }
 
@@ -5555,20 +5532,11 @@
     }
   }
 
-  bool reclaim_resources_;
-  int commit_count_ = 0;
+  int commit_count_;
   TestSwapPromiseResult swap_promise_result_[3];
 };
 
-TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, NoReclaim) {
-  reclaim_resources_ = false;
-  RunTest(CompositorMode::SINGLE_THREADED, true);
-}
-
-TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, Reclaim) {
-  reclaim_resources_ = true;
-  RunTest(CompositorMode::SINGLE_THREADED, true);
-}
+SINGLE_THREAD_TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise);
 
 // Make sure page scale and top control deltas are applied to the client even
 // when the LayerTreeHost doesn't have a root layer.
@@ -5806,18 +5774,19 @@
 class LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy
     : public LayerTreeHostTestCrispUpAfterPinchEnds {
  protected:
-  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider) override {
-    scoped_refptr<TestContextProvider> display_context_provider =
-        TestContextProvider::Create();
-    TestWebGraphicsContext3D* context3d =
-        display_context_provider->UnboundTestContext3d();
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    std::unique_ptr<TestWebGraphicsContext3D> context3d =
+        TestWebGraphicsContext3D::Create();
+    context3d->set_support_image(true);
     context3d->set_support_sync_query(true);
 #if defined(OS_MACOSX)
     context3d->set_support_texture_rectangle(true);
 #endif
-    return LayerTreeTest::CreateDisplayOutputSurface(
-        std::move(display_context_provider));
+
+    if (delegating_renderer())
+      return FakeOutputSurface::CreateDelegating3d(std::move(context3d));
+    else
+      return FakeOutputSurface::Create3d(std::move(context3d));
   }
 };
 
@@ -6857,6 +6826,14 @@
 // frame's metadata.
 class LayerTreeHostTestPaintedDeviceScaleFactor : public LayerTreeHostTest {
  protected:
+  LayerTreeHostTestPaintedDeviceScaleFactor() = default;
+
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    auto ret = FakeOutputSurface::CreateDelegating3d();
+    fake_output_surface_ = ret.get();
+    return std::move(ret);
+  }
+
   void BeginTest() override {
     layer_tree_host()->SetPaintedDeviceScaleFactor(2.0f);
     EXPECT_EQ(1.0f, layer_tree_host()->device_scale_factor());
@@ -6868,13 +6845,16 @@
     EXPECT_EQ(1.0f, host_impl->active_tree()->device_scale_factor());
   }
 
-  void DisplayReceivedCompositorFrameOnThread(
-      const CompositorFrame& frame) override {
-    EXPECT_EQ(2.0f, frame.metadata.device_scale_factor);
+  void SwapBuffersCompleteOnThread() override {
+    EXPECT_EQ(
+        2.0f,
+        fake_output_surface_->last_sent_frame()->metadata.device_scale_factor);
     EndTest();
   }
 
   void AfterTest() override {}
+
+  FakeOutputSurface* fake_output_surface_ = nullptr;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPaintedDeviceScaleFactor);
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index 23d344fd..c9a0291 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -16,6 +16,7 @@
 #include "cc/layers/video_layer_impl.h"
 #include "cc/output/filter_operations.h"
 #include "cc/resources/single_release_callback.h"
+#include "cc/test/failure_output_surface.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
@@ -30,7 +31,6 @@
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/render_pass_test_utils.h"
 #include "cc/test/test_context_provider.h"
-#include "cc/test/test_delegating_output_surface.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/layer_tree_host.h"
@@ -80,35 +80,24 @@
     return TestWebGraphicsContext3D::Create();
   }
 
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override {
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
     if (times_to_fail_create_) {
       --times_to_fail_create_;
       ExpectCreateToFail();
-      auto test_compositor_context_provider = TestContextProvider::Create();
-      test_compositor_context_provider->UnboundTestContext3d()
-          ->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                                GL_INNOCENT_CONTEXT_RESET_ARB);
-      compositor_context_provider = std::move(test_compositor_context_provider);
+      return base::WrapUnique(new FailureOutputSurface(delegating_renderer()));
     }
-    return LayerTreeTest::CreateDelegatingOutputSurface(
-        std::move(compositor_context_provider),
-        std::move(worker_context_provider));
-  }
 
-  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider) override {
     std::unique_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
-    if (context_should_support_io_surface_) {
-      context3d->set_have_extension_io_surface(true);
-      context3d->set_have_extension_egl_image(true);
-    }
-
     base::AutoLock lock(context3d_lock_);
     context3d_ = context3d.get();
-    return LayerTreeTest::CreateDisplayOutputSurface(
-        TestContextProvider::Create(std::move(context3d)));
+
+    if (context_should_support_io_surface_) {
+      context3d_->set_have_extension_io_surface(true);
+      context3d_->set_have_extension_egl_image(true);
+    }
+
+    DCHECK(delegating_renderer());
+    return FakeOutputSurface::CreateDelegating3d(std::move(context3d));
   }
 
   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
@@ -189,15 +178,18 @@
     if (async_output_surface_creation_) {
       MainThreadTaskRunner()->PostTask(
           FROM_HERE, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
-                                    AsyncRequestNewOutputSurface,
+                                    CreateAndSetOutputSurface,
                                 base::Unretained(this)));
     } else {
-      AsyncRequestNewOutputSurface();
+      CreateAndSetOutputSurface();
     }
   }
 
-  void AsyncRequestNewOutputSurface() {
-    LayerTreeHostContextTest::RequestNewOutputSurface();
+  void CreateAndSetOutputSurface() {
+    std::unique_ptr<OutputSurface> surface(
+        LayerTreeHostContextTest::CreateOutputSurface());
+    CHECK(surface);
+    layer_tree_host()->SetOutputSurface(std::move(surface));
   }
 
   void DidInitializeOutputSurface() override {
@@ -373,8 +365,9 @@
     EndTest();
   }
 
-  void RequestNewOutputSurface() override {
-    ADD_FAILURE() << "RequestNewOutputSurface() should not be called";
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    EXPECT_TRUE(false);
+    return nullptr;
   }
 
   void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
@@ -401,10 +394,16 @@
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void RequestNewOutputSurface() override {
-    if (layer_tree_host()->visible()) {
-      setos_counter_++;
-      LayerTreeHostContextTest::RequestNewOutputSurface();
-    }
+    if (layer_tree_host()->visible())
+      CreateAndSetOutputSurface();
+  }
+
+  void CreateAndSetOutputSurface() {
+    std::unique_ptr<OutputSurface> surface =
+        LayerTreeHostContextTest::CreateOutputSurface();
+    CHECK(surface);
+    setos_counter_++;
+    layer_tree_host()->SetOutputSurface(std::move(surface));
   }
 
   void HideAndReleaseOutputSurface() {
@@ -464,6 +463,11 @@
     layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
   }
 
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    EXPECT_TRUE(false);
+    return nullptr;
+  }
+
   void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
 
   void AfterTest() override {}
@@ -496,20 +500,9 @@
     EXPECT_LE(num_requests_, 2);
     if (num_requests_ > 1)
       return;
-    LayerTreeHostContextTest::RequestNewOutputSurface();
-  }
-
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override {
     ExpectCreateToFail();
-    auto test_compositor_context_provider = TestContextProvider::Create();
-    test_compositor_context_provider->UnboundTestContext3d()
-        ->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                              GL_INNOCENT_CONTEXT_RESET_ARB);
-    return LayerTreeTest::CreateDelegatingOutputSurface(
-        std::move(test_compositor_context_provider),
-        std::move(worker_context_provider));
+    layer_tree_host()->SetOutputSurface(
+        base::WrapUnique(new FailureOutputSurface(false)));
   }
 
   void BeginTest() override {
@@ -562,7 +555,8 @@
 
   void CreateAndSetOutputSurface() {
     creating_output_ = true;
-    LayerTreeHostContextTest::RequestNewOutputSurface();
+    layer_tree_host()->SetOutputSurface(
+        LayerTreeHostContextTest::CreateOutputSurface());
   }
 
   void BeginTest() override {
@@ -594,7 +588,8 @@
   }
 
   void RequestNewOutputSurface() override {
-    LayerTreeHostContextTest::RequestNewOutputSurface();
+    layer_tree_host()->SetOutputSurface(
+        LayerTreeHostContextTest::CreateOutputSurface());
     EndTest();
   }
 
@@ -1041,14 +1036,14 @@
     return draw_result;
   }
 
-  void RequestNewOutputSurface() override {
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
     // This will get called twice:
     // First when we create the initial output surface...
     if (layer_tree_host()->source_frame_number() > 0) {
       // ... and then again after we forced the context to be lost.
       lost_context_ = true;
     }
-    LayerTreeHostContextTest::RequestNewOutputSurface();
+    return LayerTreeHostContextTest::CreateOutputSurface();
   }
 
   void DidCommitAndDrawFrame() override {
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 7177580c..623d403 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -11,13 +11,10 @@
 #include "cc/layers/layer_iterator.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
-#include "cc/output/direct_renderer.h"
-#include "cc/surfaces/display.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_picture_layer.h"
 #include "cc/test/layer_tree_test.h"
-#include "cc/test/test_delegating_output_surface.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "gpu/GLES2/gl2extchromium.h"
 
@@ -129,19 +126,19 @@
 
   void AfterTest() override { EXPECT_EQ(4u, callbacks_.size()); }
 
-  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider) override {
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
     if (!use_gl_renderer_) {
       return FakeOutputSurface::CreateSoftware(
           base::WrapUnique(new SoftwareOutputDevice));
     }
 
-    scoped_refptr<TestContextProvider> display_context_provider =
-        TestContextProvider::Create();
-    TestContextSupport* context_support = display_context_provider->support();
+    std::unique_ptr<FakeOutputSurface> output_surface =
+        FakeOutputSurface::Create3d(TestContextProvider::Create(),
+                                    TestContextProvider::CreateWorker());
+    TestContextSupport* context_support = static_cast<TestContextSupport*>(
+        output_surface->context_provider()->ContextSupport());
     context_support->set_out_of_order_callbacks(out_of_order_callbacks_);
-
-    return FakeOutputSurface::Create3d(std::move(display_context_provider));
+    return std::move(output_surface);
   }
 
   bool use_gl_renderer_;
@@ -466,17 +463,8 @@
     client_.set_bounds(root_->bounds());
   }
 
-  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider,
-      scoped_refptr<ContextProvider> worker_context_provider) override {
-    auto surface = LayerTreeHostCopyRequestTest::CreateDelegatingOutputSurface(
-        std::move(compositor_context_provider),
-        std::move(worker_context_provider));
-    display_ = surface->display();
-    return surface;
-  }
-
   void BeginTest() override {
+    did_draw_ = false;
     PostSetNeedsCommitToMainThread();
 
     copy_layer_->RequestCopyOfOutput(
@@ -492,53 +480,37 @@
     EndTest();
   }
 
-  void DisplayWillDrawAndSwapOnThread(
-      bool will_draw_and_swap,
-      const RenderPassList& render_passes) override {
-    EXPECT_TRUE(will_draw_and_swap) << did_swap_;
-    if (did_swap_) {
-      // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy
-      // completion. This can be removed when the extra commit is removed.
-      EXPECT_EQ(1u, render_passes.size());
-      return;
-    }
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+    Renderer* renderer = host_impl->renderer();
 
-    EXPECT_EQ(2u, render_passes.size());
-    // The root pass is the back of the list.
-    copy_layer_render_pass_id = render_passes[0]->id;
-    parent_render_pass_id = render_passes[1]->id;
-  }
-
-  void DisplayDidDrawAndSwapOnThread() override {
-    DirectRenderer* renderer = display_->renderer_for_testing();
+    LayerImpl* parent =
+        host_impl->active_tree()->LayerById(parent_layer_->id());
+    LayerImpl* copy_layer =
+        host_impl->active_tree()->LayerById(copy_layer_->id());
 
     // |parent| owns a surface, but it was hidden and not part of the copy
     // request so it should not allocate any resource.
-    EXPECT_FALSE(
-        renderer->HasAllocatedResourcesForTesting(parent_render_pass_id));
+    EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting(
+        parent->render_surface()->GetRenderPassId()));
 
-    // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy
-    // completion. This can be removed when the extra commit is removed.
-    if (did_swap_) {
-      EXPECT_FALSE(
-          renderer->HasAllocatedResourcesForTesting(copy_layer_render_pass_id));
+    // |copy_layer| should have been rendered to a texture since it was needed
+    // for a copy request.
+    if (did_draw_) {
+      // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy
+      // completion. This can be removed when the extra commit is removed.
+      EXPECT_FALSE(copy_layer->render_surface());
     } else {
-      // |copy_layer| should have been rendered to a texture since it was needed
-      // for a copy request.
-      EXPECT_TRUE(
-          renderer->HasAllocatedResourcesForTesting(copy_layer_render_pass_id));
+      EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
+          copy_layer->render_surface()->GetRenderPassId()));
     }
 
-    did_swap_ = true;
+    did_draw_ = true;
   }
 
-  void AfterTest() override { EXPECT_TRUE(did_swap_); }
+  void AfterTest() override { EXPECT_TRUE(did_draw_); }
 
-  RenderPassId parent_render_pass_id;
-  RenderPassId copy_layer_render_pass_id;
-  Display* display_ = nullptr;
-  bool did_swap_ = false;
   FakeContentLayerClient client_;
+  bool did_draw_;
   scoped_refptr<FakePictureLayer> root_;
   scoped_refptr<FakePictureLayer> grand_parent_layer_;
   scoped_refptr<FakePictureLayer> parent_layer_;
@@ -735,13 +707,18 @@
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
     LayerTreeHostTestAsyncTwoReadbacksWithoutDraw);
 
-class LayerTreeHostCopyRequestTestDeleteTexture
+class LayerTreeHostCopyRequestTestLostOutputSurface
     : public LayerTreeHostCopyRequestTest {
  protected:
-  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider) override {
-    display_context_provider_ = TestContextProvider::Create();
-    return FakeOutputSurface::Create3d(display_context_provider_);
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    if (!first_context_provider_) {
+      first_context_provider_ = TestContextProvider::Create();
+      return FakeOutputSurface::Create3d(first_context_provider_);
+    }
+
+    EXPECT_FALSE(second_context_provider_);
+    second_context_provider_ = TestContextProvider::Create();
+    return FakeOutputSurface::Create3d(second_context_provider_);
   }
 
   void SetupTree() override {
@@ -775,7 +752,7 @@
 
   void InsertCopyRequest() {
     copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateRequest(
-        base::Bind(&LayerTreeHostCopyRequestTestDeleteTexture::
+        base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
                        ReceiveCopyRequestOutputAndCommit,
                    base::Unretained(this))));
   }
@@ -785,59 +762,78 @@
     result_ = nullptr;
 
     ImplThreadTaskRunner()->PostTask(
-        FROM_HERE, base::Bind(&LayerTreeHostCopyRequestTestDeleteTexture::
+        FROM_HERE, base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
                                   CheckNumTexturesAfterReadbackDestroyed,
                               base::Unretained(this)));
   }
 
   void CheckNumTexturesAfterReadbackDestroyed() {
-    // After the copy we had |num_textures_after_readback_| many textures, but
-    // releasing the copy output request should cause the texture in the request
-    // to be destroyed by the compositor, so we should have 1 less by now.
-    EXPECT_EQ(num_textures_after_readback_ - 1,
-              display_context_provider_->TestContext3d()->NumTextures());
+    // After the loss we had |num_textures_after_loss_| many textures, but
+    // releasing the copy output request will cause the texture in the request
+    // to be released, so we should have 1 less by now.
+    EXPECT_EQ(num_textures_after_loss_ - 1,
+              first_context_provider_->TestContext3d()->NumTextures());
     EndTest();
   }
 
-  void DisplayDidDrawAndSwapOnThread() override {
+  void SwapBuffersCompleteOnThread() override {
     switch (num_swaps_++) {
       case 0:
-        // The layers have been drawn, so any textures required for drawing have
-        // been allocated.
+        // The layers have been drawn, so their textures have been allocated.
         EXPECT_FALSE(result_);
         num_textures_without_readback_ =
-            display_context_provider_->TestContext3d()->NumTextures();
+            first_context_provider_->TestContext3d()->NumTextures();
 
         // Request a copy of the layer. This will use another texture.
         MainThreadTaskRunner()->PostTask(
             FROM_HERE,
-            base::Bind(
-                &LayerTreeHostCopyRequestTestDeleteTexture::InsertCopyRequest,
-                base::Unretained(this)));
+            base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
+                           InsertCopyRequest,
+                       base::Unretained(this)));
         break;
       case 1:
         // We did a readback, so there will be a readback texture around now.
-        num_textures_after_readback_ =
-            display_context_provider_->TestContext3d()->NumTextures();
-        EXPECT_LT(num_textures_without_readback_, num_textures_after_readback_);
+        EXPECT_LT(num_textures_without_readback_,
+                  first_context_provider_->TestContext3d()->NumTextures());
+
+        // The copy request will be serviced and the result sent to
+        // ReceiveCopyRequestOutputAndCommit, which posts a new commit causing
+        // the test to advance to the next case.
+        break;
+      case 2:
+        // The readback texture is collected.
+        EXPECT_TRUE(result_);
+
+        // Lose the output surface.
+        first_context_provider_->TestContext3d()->loseContextCHROMIUM(
+            GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
+        break;
+      case 3:
+        // The output surface has been recreated.
+        EXPECT_TRUE(second_context_provider_);
+
+        num_textures_after_loss_ =
+            first_context_provider_->TestContext3d()->NumTextures();
 
         // Now destroy the CopyOutputResult, releasing the texture inside back
         // to the compositor. Then check the resulting number of allocated
         // textures.
         MainThreadTaskRunner()->PostTask(
-            FROM_HERE, base::Bind(&LayerTreeHostCopyRequestTestDeleteTexture::
-                                      DestroyCopyResultAndCheckNumTextures,
-                                  base::Unretained(this)));
+            FROM_HERE,
+            base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
+                           DestroyCopyResultAndCheckNumTextures,
+                       base::Unretained(this)));
         break;
     }
   }
 
   void AfterTest() override {}
 
-  scoped_refptr<TestContextProvider> display_context_provider_;
+  scoped_refptr<TestContextProvider> first_context_provider_;
+  scoped_refptr<TestContextProvider> second_context_provider_;
   int num_swaps_ = 0;
   size_t num_textures_without_readback_ = 0;
-  size_t num_textures_after_readback_ = 0;
+  size_t num_textures_after_loss_ = 0;
   FakeContentLayerClient client_;
   scoped_refptr<FakePictureLayer> root_;
   scoped_refptr<FakePictureLayer> copy_layer_;
@@ -845,47 +841,29 @@
 };
 
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
-    LayerTreeHostCopyRequestTestDeleteTexture);
+    LayerTreeHostCopyRequestTestLostOutputSurface);
 
 class LayerTreeHostCopyRequestTestCountTextures
     : public LayerTreeHostCopyRequestTest {
  protected:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    // Always allocate only a single texture at a time through ResourceProvider.
-    settings->renderer_settings.texture_id_allocation_chunk_size = 1;
-  }
-
-  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
-      scoped_refptr<ContextProvider> compositor_context_provider) override {
-    // These tests expect the LayerTreeHostImpl to share a context with
-    // the Display so that sync points are not needed and the texture counts
-    // are visible together.
-    // Since this test does not override CreateDelegatingOutputSurface, the
-    // |compositor_context_provider| will be a TestContextProvider.
-    display_context_provider_ =
-        static_cast<TestContextProvider*>(compositor_context_provider.get());
-    return FakeOutputSurface::Create3d(std::move(compositor_context_provider));
+  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+    context_provider_ = TestContextProvider::Create();
+    return FakeOutputSurface::Create3d(context_provider_);
   }
 
   void SetupTree() override {
-    // The layers in this test have solid color content, so they don't
-    // actually allocate any textures, making counting easier.
+    client_.set_fill_with_nonsolid_color(true);
 
-    root_ = FakePictureLayer::Create(&root_client_);
+    root_ = FakePictureLayer::Create(&client_);
     root_->SetBounds(gfx::Size(20, 20));
-    root_client_.set_bounds(root_->bounds());
 
-    copy_layer_ = FakePictureLayer::Create(&copy_client_);
+    copy_layer_ = FakePictureLayer::Create(&client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
-    copy_client_.set_bounds(copy_layer_->bounds());
-    // Doing a copy makes the layer have a render surface which can cause
-    // texture allocations. So get those allocations out of the way in the
-    // first frame by forcing it to have a render surface.
-    copy_layer_->SetForceRenderSurfaceForTesting(true);
     root_->AddChild(copy_layer_);
 
     layer_tree_host()->SetRootLayer(root_);
     LayerTreeHostCopyRequestTest::SetupTree();
+    client_.set_bounds(root_->bounds());
   }
 
   void BeginTest() override {
@@ -898,31 +876,27 @@
   void DidCommit() override {
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        // The layers have been pushed to the impl side and drawn. Any textures
-        // that are created in that process will have been allocated.
+        // The layers have been pushed to the impl side. The layer textures have
+        // been allocated.
         RequestCopy(copy_layer_.get());
         break;
     }
   }
 
-  void DisplayDidDrawAndSwapOnThread() override {
+  void SwapBuffersCompleteOnThread() override {
     switch (num_swaps_++) {
       case 0:
-        // The first frame has been drawn, so textures for drawing have been
-        // allocated.
+        // The layers have been drawn, so their textures have been allocated.
         num_textures_without_readback_ =
-            display_context_provider_->TestContext3d()->NumTextures();
+            context_provider_->TestContext3d()->NumTextures();
         break;
       case 1:
         // We did a readback, so there will be a readback texture around now.
         num_textures_with_readback_ =
-            display_context_provider_->TestContext3d()->NumTextures();
+            context_provider_->TestContext3d()->NumTextures();
         waited_sync_token_after_readback_ =
-            display_context_provider_->TestContext3d()
-                ->last_waited_sync_token();
+            context_provider_->TestContext3d()->last_waited_sync_token();
 
-        // End the test after main thread has a chance to hear about the
-        // readback.
         MainThreadTaskRunner()->PostTask(
             FROM_HERE,
             base::Bind(&LayerTreeHostCopyRequestTestCountTextures::DoEndTest,
@@ -933,13 +907,12 @@
 
   virtual void DoEndTest() { EndTest(); }
 
-  scoped_refptr<TestContextProvider> display_context_provider_;
+  scoped_refptr<TestContextProvider> context_provider_;
   int num_swaps_ = 0;
   size_t num_textures_without_readback_ = 0;
   size_t num_textures_with_readback_ = 0;
   gpu::SyncToken waited_sync_token_after_readback_;
-  FakeContentLayerClient root_client_;
-  FakeContentLayerClient copy_client_;
+  FakeContentLayerClient client_;
   scoped_refptr<FakePictureLayer> root_;
   scoped_refptr<FakePictureLayer> copy_layer_;
 };
diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc
index d8bde90..405d837 100644
--- a/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/cc/trees/layer_tree_host_unittest_damage.cc
@@ -197,7 +197,7 @@
     return draw_result;
   }
 
-  void DisplayDidDrawAndSwapOnThread() override {
+  void SwapBuffersCompleteOnThread() override {
     ++did_swap_;
     EXPECT_EQ(expect_swap_, did_swap_);
   }
diff --git a/chrome/VERSION b/chrome/VERSION
index 8d50071b..273d514 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=54
 MINOR=0
-BUILD=2819
+BUILD=2820
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java
index 24120eba..5ac4b9d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java
@@ -11,29 +11,22 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.content_public.browser.WebContents;
 
 /**
- * This class interacts with C++ to detect whether resources in web manifest of a WebAPK have been
- * updated.
+ * This class checks whether the WebAPK needs to be re-installed and sends a request to re-install
+ * the WebAPK if it needs to be re-installed.
  */
-public class ManifestUpgradeDetector extends EmptyTabObserver {
+public class ManifestUpgradeDetector implements ManifestUpgradeDetectorFetcher.Callback {
     /**
      * The names of <meta-data> in the WebAPK's AndroidManifest.xml whose values are needed to
      * determine whether a WebAPK needs to be upgraded but which are not present in
      * {@link WebappInfo}. The names must stay in sync with
      * {@linkorg.chromium.webapk.lib.runtime_library.HostBrowserLauncher}.
      */
-    private static final String META_DATA_START_URL = "org.chromium.webapk.shell_apk.startUrl";
+    public static final String META_DATA_START_URL = "org.chromium.webapk.shell_apk.startUrl";
 
-    /** Pointer to the native side ManifestUpgradeDetector. */
-    private long mNativePointer;
-
-    /** The tab that is being observed. */
+    /** The WebAPK's tab. */
     private final Tab mTab;
 
     private WebappInfo mWebappInfo;
@@ -41,10 +34,9 @@
     private String mStartUrl;
 
     /**
-     * A flag for whether metadata is set via {@link set*ForTesting()}, rather than set
-     * from WebAPK's AndroidManifest.xml.
+     * Fetches the WebAPK's Web Manifest from the web.
      */
-    private boolean mOverrideMetadataForTesting = false;
+    private ManifestUpgradeDetectorFetcher mFetcher;
 
     private static final String TAG = "cr_UpgradeDetector";
 
@@ -53,16 +45,6 @@
         mWebappInfo = info;
     }
 
-    @VisibleForTesting
-    public void setOverrideMetadataForTesting(boolean overrideMetadataForTesting) {
-        mOverrideMetadataForTesting = overrideMetadataForTesting;
-    }
-
-    @VisibleForTesting
-    public void setStartUrlForTesting(String startUrl) {
-        mStartUrl = startUrl;
-    }
-
     /**
      * Starts fetching the web manifest resources.
      */
@@ -72,21 +54,23 @@
             return;
         }
 
-        if (mNativePointer != 0) return;
+        if (mFetcher != null) return;
 
         getMetaDataFromAndroidManifest();
-        mNativePointer = nativeInitialize(mTab.getWebContents(),
-                mWebappInfo.scopeUri().toString(), mWebappInfo.webManifestUri().toString());
+        mFetcher = createFetcher(
+                mTab, mWebappInfo.scopeUri().toString(), mWebappInfo.webManifestUri().toString());
+        mFetcher.start(this);
+    }
 
-        mTab.addObserver(this);
-        nativeStart(mNativePointer);
+    /**
+     * Creates ManifestUpgradeDataFetcher.
+     */
+    protected ManifestUpgradeDetectorFetcher createFetcher(Tab tab, String scopeUrl,
+            String manifestUrl) {
+        return new ManifestUpgradeDetectorFetcher(tab, scopeUrl, manifestUrl);
     }
 
     private void getMetaDataFromAndroidManifest() {
-        if (mOverrideMetadataForTesting) {
-            // The metadata are set via {@link set*ForTesting()}.
-            return;
-        }
         try {
             ApplicationInfo appinfo =
                     ContextUtils.getApplicationContext().getPackageManager().getApplicationInfo(
@@ -101,54 +85,38 @@
      * Puts the object in a state where it is safe to be destroyed.
      */
     public void destroy() {
-        if (mNativePointer != 0) {
-            nativeDestroy(mNativePointer);
+        if (mFetcher != null) {
+            mFetcher.destroy();
         }
-        mNativePointer = 0;
-    }
-
-    @Override
-    public void onWebContentsSwapped(Tab tab, boolean didStartLoad,
-            boolean didFinishLoad) {
-        updatePointers();
-    }
-
-    @Override
-    public void onContentChanged(Tab tab) {
-        updatePointers();
-    }
-
-    /**
-     * Updates which WebContents the native ManifestUpgradeDetector is monitoring.
-     */
-    private void updatePointers() {
-        nativeReplaceWebContents(mNativePointer, mTab.getWebContents());
+        mFetcher = null;
     }
 
     /**
      * Called when the updated Web Manifest has been fetched.
      */
-    @CalledByNative
-    private void onDataAvailable(String startUrl, String scope, String name, String shortName,
+    @Override
+    public void onGotManifestData(String startUrl, String scopeUrl, String name, String shortName,
             int displayMode, int orientation, long themeColor, long backgroundColor) {
-        mTab.removeObserver(this);
-        destroy();
+        mFetcher.destroy();
+        mFetcher = null;
 
         // TODO(hanxi): crbug.com/627824. Validate whether the new WebappInfo is
         // WebAPK-compatible.
         final WebappInfo newInfo = WebappInfo.create(mWebappInfo.id(), startUrl,
-                scope, mWebappInfo.encodedIcon(), name, shortName, displayMode, orientation,
+                scopeUrl, mWebappInfo.encodedIcon(), name, shortName, displayMode, orientation,
                 mWebappInfo.source(), themeColor, backgroundColor, mWebappInfo.isIconGenerated(),
                 mWebappInfo.webApkPackageName(), mWebappInfo.webManifestUri().toString());
         if (requireUpgrade(newInfo)) {
             upgrade();
         }
+
+        onComplete();
     }
 
     /**
      * Checks whether the WebAPK needs to be upgraded provided the new Web Manifest info.
      */
-    protected boolean requireUpgrade(WebappInfo newInfo) {
+    private boolean requireUpgrade(WebappInfo newInfo) {
         boolean scopeMatch = mWebappInfo.scopeUri().equals(newInfo.scopeUri());
         if (!scopeMatch) {
             // Sometimes the scope doesn't match due to a missing "/" at the end of the scope URL.
@@ -173,12 +141,7 @@
         return false;
     }
 
-    private void upgrade() {}
+    protected void upgrade() {}
 
-    private native long nativeInitialize(WebContents webContents, String scope,
-            String webManifestUrl);
-    private native void nativeReplaceWebContents(long nativeManifestUpgradeDetector,
-            WebContents webContents);
-    private native void nativeDestroy(long nativeManifestUpgradeDetector);
-    private native void nativeStart(long nativeManifestUpgradeDetector);
+    protected void onComplete() {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcher.java
new file mode 100644
index 0000000..4c1e5c11
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcher.java
@@ -0,0 +1,96 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webapps;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * Downloads the Web Manifest if the web site still uses the {@link manifestUrl} passed to the
+ * constructor.
+ */
+public class ManifestUpgradeDetectorFetcher extends EmptyTabObserver {
+
+    /**
+     * Called once the Web Manifest has been downloaded.
+     */
+    public interface Callback {
+        public void onGotManifestData(String startUrl, String scopeUrl, String name,
+                String shortName, int displayMode, int orientation, long themeColor,
+                long backgroundColor);
+    }
+
+    /**
+     * Pointer to the native side ManifestUpgradeDetectorFetcher. The Java side owns the native side
+     * ManifestUpgradeDetectorFetcher.
+     */
+    private long mNativePointer;
+
+    /** The tab that is being observed. */
+    private final Tab mTab;
+
+    private Callback mCallback;
+
+    public ManifestUpgradeDetectorFetcher(Tab tab, String scopeUrl, String manifestUrl) {
+        mTab = tab;
+        mNativePointer = nativeInitialize(scopeUrl, manifestUrl);
+    }
+
+    /**
+     * Starts fetching the web manifest resources.
+     * @param callback Called once the Web Manifest has been downloaded.
+     */
+    public void start(Callback callback) {
+        mCallback = callback;
+        mTab.addObserver(this);
+        nativeStart(mNativePointer, mTab.getWebContents());
+    }
+
+    /**
+     * Puts the object in a state where it is safe to be destroyed.
+     */
+    public void destroy() {
+        mTab.removeObserver(this);
+        nativeDestroy(mNativePointer);
+        mNativePointer = 0;
+    }
+
+    @Override
+    public void onWebContentsSwapped(Tab tab, boolean didStartLoad,
+            boolean didFinishLoad) {
+        updatePointers();
+    }
+
+    @Override
+    public void onContentChanged(Tab tab) {
+        updatePointers();
+    }
+
+    /**
+     * Updates which WebContents the native ManifestUpgradeDetectorFetcher is monitoring.
+     */
+    private void updatePointers() {
+        nativeReplaceWebContents(mNativePointer, mTab.getWebContents());
+    }
+
+    /**
+     * Called when the updated Web Manifest has been fetched.
+     */
+    @CalledByNative
+    private void onDataAvailable(String startUrl, String scopeUrl, String name, String shortName,
+            int displayMode, int orientation, long themeColor, long backgroundColor) {
+        mCallback.onGotManifestData(startUrl, scopeUrl, name, shortName, displayMode, orientation,
+                themeColor, backgroundColor);
+    }
+
+    private native long nativeInitialize(String scope, String webManifestUrl);
+    private native void nativeReplaceWebContents(
+            long nativeManifestUpgradeDetectorFetcher, WebContents webContents);
+    private native void nativeDestroy(long nativeManifestUpgradeDetectorFetcher);
+    private native void nativeStart(
+            long nativeManifestUpgradeDetectorFetcher, WebContents webContents);
+}
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index cb1284d1..6f8c6db 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -940,6 +940,7 @@
   "java/src/org/chromium/chrome/browser/webapps/FullScreenActivity.java",
   "java/src/org/chromium/chrome/browser/webapps/FullScreenDelegateFactory.java",
   "java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java",
+  "java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcher.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkActivity0.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkActivity1.java",
@@ -1296,7 +1297,7 @@
   "javatests/src/org/chromium/chrome/browser/webapps/ActivityAssignerTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogTest.java",
-  "javatests/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java",
+  "javatests/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcherTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java",
   "javatests/src/org/chromium/chrome/browser/webapps/WebappAuthenticatorTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java",
@@ -1365,6 +1366,7 @@
   "junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java",
   "junit/src/org/chromium/chrome/browser/tabstate/TabStateUnitTest.java",
   "junit/src/org/chromium/chrome/browser/util/NonThreadSafeTest.java",
+  "junit/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java",
   "junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java",
   "junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java",
 ]
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcherTest.java
new file mode 100644
index 0000000..8430403
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcherTest.java
@@ -0,0 +1,133 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webapps;
+
+import android.content.Context;
+import android.os.Environment;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
+import org.chromium.chrome.test.util.browser.TabLoadObserver;
+import org.chromium.content.browser.test.util.CallbackHelper;
+import org.chromium.net.test.EmbeddedTestServer;
+
+/**
+ * Tests the ManifestUpgradeDetectorFetcher.
+ */
+public class ManifestUpgradeDetectorFetcherTest extends ChromeTabbedActivityTestBase {
+
+    private static final String PAGE_URL1 = "/chrome/test/data/webapps/manifest_test_page.html";
+    private static final String PAGE_URL2 = "/chrome/test/data/webapps/manifest_test_page2.html";
+
+    // Data for {@link PAGE_URL1}'s Web Manifest.
+    private static final String WEB_MANIFEST_URL1 = "/chrome/test/data/webapps/manifest.json";
+    private static final String WEB_MANIFEST_NAME1 = "Manifest test app";
+
+    // Data for {@link PAGE_URL2}'s Web Manifest.
+    private static final String WEB_MANIFEST_URL2 = "/chrome/test/data/webapps/manifest2.json";
+    private static final String WEB_MANIFEST_NAME2 = "Manifest test app2";
+
+    // Scope for {@link PAGE_URL1} and {@link PAGE_URL2}.
+    private static final String WEB_MANIFEST_SCOPE = "/chrome/test/data";
+
+    private EmbeddedTestServer mTestServer;
+    private Tab mTab;
+
+    // CallbackHelper which blocks until the {@link ManifestUpgradeDetectorFetcher.Callback}
+    // callback is called.
+    private static class CallbackWaiter
+            extends CallbackHelper implements ManifestUpgradeDetectorFetcher.Callback {
+        private String mName;
+
+        @Override
+        public void onGotManifestData(String startUrl, String scopeUrl, String name,
+                String shortName, int displayMode, int orientation, long themeColor,
+                long backgroundColor) {
+            assertNull(mName);
+            mName = name;
+            notifyCalled();
+        }
+
+        public String name() {
+            return mName;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Context context = getInstrumentation().getTargetContext();
+        mTestServer = EmbeddedTestServer.createAndStartFileServer(
+                context, Environment.getExternalStorageDirectory());
+        mTab = getActivity().getActivityTab();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mTestServer.stopAndDestroyServer();
+        super.tearDown();
+    }
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+        startMainActivityOnBlankPage();
+    }
+
+    /**
+     * Starts a ManifestUpgradeDetectorFetcher. Calls {@link callback} once the fetcher is done.
+     */
+    private void startManifestUpgradeDetectorFetcher(String scopeUrl, String manifestUrl,
+            final ManifestUpgradeDetectorFetcher.Callback callback) {
+        final ManifestUpgradeDetectorFetcher fetcher =
+                new ManifestUpgradeDetectorFetcher(mTab, scopeUrl, manifestUrl);
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                fetcher.start(callback);
+            }
+        });
+    }
+
+    /**
+     * Test starting ManifestUpgradeDetectorFetcher while a page with the desired manifest URL is
+     * loading.
+     */
+    @MediumTest
+    @Feature({"WebApk"})
+    public void testLaunchWithDesiredManifestUrl() throws Exception {
+        CallbackWaiter waiter = new CallbackWaiter();
+        startManifestUpgradeDetectorFetcher(mTestServer.getURL(WEB_MANIFEST_SCOPE),
+                mTestServer.getURL(WEB_MANIFEST_URL1), waiter);
+
+        TabLoadObserver tabLoadObserver = new TabLoadObserver(mTab);
+        tabLoadObserver.fullyLoadUrl(mTestServer.getURL(PAGE_URL1));
+        waiter.waitForCallback(0);
+
+        assertEquals(WEB_MANIFEST_NAME1, waiter.name());
+    }
+
+    /**
+     * Test starting ManifestUpgradeDetectorFetcher on page which uses a different manifest URL than
+     * the ManifestUpgradeDetectorFetcher is looking for. Check that the callback is only called
+     * once the user navigates to a page which uses the desired manifest URL.
+     */
+    @MediumTest
+    @Feature({"Webapps"})
+    public void testLaunchWithDifferentManifestUrl() throws Exception {
+        CallbackWaiter waiter = new CallbackWaiter();
+        startManifestUpgradeDetectorFetcher(mTestServer.getURL(WEB_MANIFEST_SCOPE),
+                mTestServer.getURL(WEB_MANIFEST_URL2), waiter);
+
+        TabLoadObserver tabLoadObserver = new TabLoadObserver(mTab);
+        tabLoadObserver.fullyLoadUrl(mTestServer.getURL(PAGE_URL1));
+        tabLoadObserver.fullyLoadUrl(mTestServer.getURL(PAGE_URL2));
+        waiter.waitForCallback(0);
+
+        assertEquals(WEB_MANIFEST_NAME2, waiter.name());
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java
deleted file mode 100644
index 44e6b27..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.webapps;
-
-import android.content.Context;
-import android.os.Environment;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import org.chromium.base.ThreadUtils;
-import org.chromium.blink_public.platform.WebDisplayMode;
-import org.chromium.chrome.browser.ShortcutHelper;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
-import org.chromium.chrome.test.util.browser.TabLoadObserver;
-import org.chromium.content.browser.test.util.CallbackHelper;
-import org.chromium.content_public.common.ScreenOrientationValues;
-import org.chromium.net.test.EmbeddedTestServer;
-import org.chromium.webapk.lib.common.WebApkConstants;
-
-/**
- * Tests the ManifestUpgradeDetector.
- */
-public class ManifestUpgradeDetectorTest extends ChromeTabbedActivityTestBase {
-    private static final String WEBAPK_ID = WebApkConstants.WEBAPK_ID_PREFIX + "webapp_id";
-
-    /** The following field values are declared in {@link WEBAPK_WEB_MANIFEST_URL}. */
-    private static final String WEBAPK_NAME = "Manifest test app";
-    private static final String WEBAPK_SHORT_NAME = "App";
-    private static final int WEBAPK_ORIENTATION = ScreenOrientationValues.LANDSCAPE;
-    private static final String WEBAPK_START_URL_PATH =
-            "/chrome/test/data/webapps/manifest_test_page.html";
-    private static final String WEBAPK_SCOPE_PATH = "/chrome/test/data/webapps/";
-    private static final String WEBAPK_WEB_MANIFEST_URL =
-            "/chrome/test/data/webapps/manifest.json";
-
-    private TestManifestUpgradeDetector mDetector;
-    private EmbeddedTestServer mTestServer;
-
-    /**
-     * A ManifestUpgradeDetector that verifies the Web Manifest fetching pipeline and the
-     * comparison are working correctly.
-     */
-    private static class TestManifestUpgradeDetector extends ManifestUpgradeDetector {
-        public boolean mIsUpgraded;
-        public String mStartUrl;
-        public CallbackHelper mCallbackHelper;
-
-        public TestManifestUpgradeDetector(Tab tab, WebappInfo info) {
-            super(tab, info);
-            mCallbackHelper = new CallbackHelper();
-        }
-
-        @Override
-        protected boolean requireUpgrade(WebappInfo newInfo) {
-            mIsUpgraded = super.requireUpgrade(newInfo);
-            mStartUrl = newInfo.uri().toString();
-            mCallbackHelper.notifyCalled();
-            return mIsUpgraded;
-        }
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        final Context context = getInstrumentation().getTargetContext();
-        mTestServer = EmbeddedTestServer.createAndStartFileServer(
-                context, Environment.getExternalStorageDirectory());
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mTestServer.stopAndDestroyServer();
-        super.tearDown();
-    }
-
-    @Override
-    public void startMainActivity() throws InterruptedException {
-        startMainActivityOnBlankPage();
-    }
-
-    /**
-     * Creates a WebappInfo with the properties in {@link WEBAPK_WEB_MANIFEST_URL}.
-     */
-    private WebappInfo createWebappInfo() {
-        return WebappInfo.create(WEBAPK_ID,
-                WEBAPK_START_URL_PATH,
-                mTestServer.getURL(WEBAPK_SCOPE_PATH),
-                null,
-                WEBAPK_NAME,
-                WEBAPK_SHORT_NAME,
-                WebDisplayMode.Standalone,
-                WEBAPK_ORIENTATION,
-                0,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                false,
-                "",
-                mTestServer.getURL(WEBAPK_WEB_MANIFEST_URL));
-    }
-
-    /**
-     * Navigates to {@link startUrl} and waits till the ManifestUpgradeDetector gets the Web
-     * Manifest data.
-     * @param info: the old Webapp info passed in to initialize the detector.
-     * @param startUrl: URL to navigate to and start URL of the old Webapp info.
-     */
-    private void waitUntilManifestDataAvailable(WebappInfo info, String startUrl) throws Exception {
-        final Tab tab = getActivity().getActivityTab();
-
-        mDetector = new TestManifestUpgradeDetector(tab, info);
-        mDetector.setOverrideMetadataForTesting(true);
-        mDetector.setStartUrlForTesting(startUrl);
-
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mDetector.start();
-            }
-        });
-
-        CallbackHelper callbackHelper = mDetector.mCallbackHelper;
-        int curCallCount = 0;
-        new TabLoadObserver(tab).fullyLoadUrl(startUrl);
-        callbackHelper.waitForCallback(curCallCount);
-    }
-
-    @MediumTest
-    public void testManifestDoesNotUpgrade() throws Exception {
-        waitUntilManifestDataAvailable(createWebappInfo(),
-                mTestServer.getURL(WEBAPK_START_URL_PATH));
-
-        assertFalse(mDetector.mIsUpgraded);
-    }
-
-    @MediumTest
-    public void testStartUrlChangeShouldReturnUpgradeTrue() throws Exception {
-        String currentStartUrl =
-                "/chrome/test/data/webapps/manifest_test_page_test_start_url_change.html";
-        waitUntilManifestDataAvailable(createWebappInfo(), mTestServer.getURL(currentStartUrl));
-
-        assertTrue(mDetector.mIsUpgraded);
-        assertEquals(mTestServer.getURL(WEBAPK_START_URL_PATH), mDetector.mStartUrl);
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java
new file mode 100644
index 0000000..4bb7346
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java
@@ -0,0 +1,159 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webapps;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.os.Bundle;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.blink_public.platform.WebDisplayMode;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.content_public.common.ScreenOrientationValues;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+import org.robolectric.res.builder.RobolectricPackageManager;
+
+/**
+ * Tests the ManifestUpgradeDetector.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ManifestUpgradeDetectorTest {
+
+    private static final String WEBAPK_START_URL = "/start_url.html";
+    private static final String WEBAPK_SCOPE_URL = "/";
+    private static final String WEBAPK_NAME = "Long Name";
+    private static final String WEBAPK_SHORT_NAME = "Short Name";
+    private static final int WEBAPK_DISPLAY_MODE = WebDisplayMode.Standalone;
+    private static final int WEBAPK_ORIENTATION = ScreenOrientationValues.LANDSCAPE;
+    private static final long WEBAPK_THEME_COLOR = 1L;
+    private static final long WEBAPK_BACKGROUND_COLOR = 2L;
+    private static final String WEBAPK_MANIFEST_URL = "manifest.java";
+    private static final String WEBAPK_PACKAGE_NAME = "package_name";
+
+    private RobolectricPackageManager mPackageManager;
+
+    /**
+     * Data from downloaded Web Manifest. Same as old Web Manifest data by default.
+     */
+    private static class FetchedData {
+        public String startUrl = WEBAPK_START_URL;
+        public String scopeUrl = WEBAPK_SCOPE_URL;
+        public String name = WEBAPK_NAME;
+        public String shortName = WEBAPK_SHORT_NAME;
+        public int displayMode = WEBAPK_DISPLAY_MODE;
+        public int orientation = WEBAPK_ORIENTATION;
+        public long themeColor = WEBAPK_THEME_COLOR;
+        public long backgroundColor = WEBAPK_BACKGROUND_COLOR;
+    }
+
+    /**
+     * ManifestUpgradeDetector subclass which:
+     * - Stubs out ManifestUpgradeDetectorFetcher.
+     * - Uses {@link fetchedData} passed into the constructor as the "Downloaded Manifest Data".
+     * - Tracks whether an upgraded WebAPK was requested.
+     * - Tracks whether "upgrade needed checking logic" has terminated.
+     */
+    private static class TestManifestUpgradeDetector extends ManifestUpgradeDetector {
+        public boolean mIsUpgraded;
+        public boolean mCompleted;
+        private FetchedData mFetchedData;
+
+        public TestManifestUpgradeDetector(Tab tab, WebappInfo info, FetchedData fetchedData) {
+            super(tab, info);
+            mFetchedData = fetchedData;
+        }
+
+        @Override
+        public ManifestUpgradeDetectorFetcher createFetcher(
+                Tab tab, String scopeUrl, String manifestUrl) {
+            ManifestUpgradeDetectorFetcher fetcher =
+                    Mockito.mock(ManifestUpgradeDetectorFetcher.class);
+            Answer<Void> mockStart = new Answer<Void>() {
+                public Void answer(InvocationOnMock invocation) throws Throwable {
+                    ManifestUpgradeDetectorFetcher.Callback callback =
+                            (ManifestUpgradeDetectorFetcher.Callback) invocation.getArguments()[0];
+                    callback.onGotManifestData(mFetchedData.startUrl, mFetchedData.scopeUrl,
+                            mFetchedData.name, mFetchedData.shortName, mFetchedData.displayMode,
+                            mFetchedData.orientation, mFetchedData.themeColor,
+                            mFetchedData.backgroundColor);
+                    return null;
+                }
+            };
+            Mockito.doAnswer(mockStart).when(fetcher).start(
+                    Mockito.any(ManifestUpgradeDetectorFetcher.Callback.class));
+            return fetcher;
+        }
+
+        @Override
+        protected void upgrade() {
+            mIsUpgraded = true;
+        }
+
+        @Override
+        protected void onComplete() {
+            mCompleted = true;
+        }
+    }
+
+    @Before
+    public void setUp() {
+        Context context = Robolectric.application;
+        ContextUtils.initApplicationContextForTests(context);
+        mPackageManager = (RobolectricPackageManager) context.getPackageManager();
+
+        setMetaData(WEBAPK_START_URL);
+    }
+
+    private TestManifestUpgradeDetector createDetector(FetchedData fetchedData) {
+        WebappInfo webappInfo = WebappInfo.create("", WEBAPK_START_URL, WEBAPK_SCOPE_URL, null,
+                WEBAPK_NAME, WEBAPK_SHORT_NAME, WEBAPK_DISPLAY_MODE, WEBAPK_ORIENTATION, 0,
+                WEBAPK_THEME_COLOR, WEBAPK_BACKGROUND_COLOR, false, WEBAPK_PACKAGE_NAME,
+                WEBAPK_MANIFEST_URL);
+        return new TestManifestUpgradeDetector(null, webappInfo, fetchedData);
+    }
+
+    private void setMetaData(String startUrl) {
+        Bundle bundle = new Bundle();
+        bundle.putString(ManifestUpgradeDetector.META_DATA_START_URL, startUrl);
+
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.metaData = bundle;
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = WEBAPK_PACKAGE_NAME;
+        packageInfo.applicationInfo = appInfo;
+        mPackageManager.addPackage(packageInfo);
+    }
+
+    @Test
+    public void testManifestDoesNotUpgrade() {
+        TestManifestUpgradeDetector detector = createDetector(new FetchedData());
+        detector.start();
+        Assert.assertTrue(detector.mCompleted);
+        Assert.assertFalse(detector.mIsUpgraded);
+    }
+
+    @Test
+    public void testStartUrlChangeShouldUpgrade() {
+        FetchedData fetchedData = new FetchedData();
+        fetchedData.startUrl = "/changed.html";
+        TestManifestUpgradeDetector detector = createDetector(fetchedData);
+        detector.start();
+        Assert.assertTrue(detector.mCompleted);
+        Assert.assertTrue(detector.mIsUpgraded);
+    }
+}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d64fedb..f7887bb 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -43,6 +43,7 @@
 #include "components/flags_ui/flags_storage.h"
 #include "components/flags_ui/flags_ui_switches.h"
 #include "components/nacl/common/nacl_switches.h"
+#include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
 #include "components/ntp_tiles/switches.h"
 #include "components/offline_pages/offline_page_feature.h"
@@ -1890,9 +1891,10 @@
 #if defined(OS_ANDROID)
     {"enable-ntp-snippets", IDS_FLAGS_ENABLE_NTP_SNIPPETS_NAME,
      IDS_FLAGS_ENABLE_NTP_SNIPPETS_DESCRIPTION, kOsAndroid,
-     FEATURE_WITH_VARIATIONS_VALUE_TYPE(chrome::android::kNTPSnippetsFeature,
-                                        kNTPSnippetsFeatureVariations,
-                                        ntp_snippets::kStudyName)},
+     FEATURE_WITH_VARIATIONS_VALUE_TYPE(
+         ntp_snippets::kContentSuggestionsFeature,
+         kNTPSnippetsFeatureVariations,
+         ntp_snippets::kStudyName)},
     {"enable-ntp-offline-page-suggestions",
      IDS_FLAGS_ENABLE_NTP_OFFLINE_PAGE_SUGGESTIONS_NAME,
      IDS_FLAGS_ENABLE_NTP_OFFLINE_PAGE_SUGGESTIONS_DESCRIPTION, kOsAndroid,
diff --git a/chrome/browser/after_startup_task_utils_android.cc b/chrome/browser/after_startup_task_utils_android.cc
index 925b6c19..a914f36 100644
--- a/chrome/browser/after_startup_task_utils_android.cc
+++ b/chrome/browser/after_startup_task_utils_android.cc
@@ -7,6 +7,8 @@
 #include "chrome/browser/after_startup_task_utils.h"
 #include "jni/AfterStartupTaskUtils_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace android {
 
 class AfterStartupTaskUtilsJNI {
diff --git a/chrome/browser/android/accessibility/font_size_prefs_android.cc b/chrome/browser/android/accessibility/font_size_prefs_android.cc
index ca2ab10..d0d446ce 100644
--- a/chrome/browser/android/accessibility/font_size_prefs_android.cc
+++ b/chrome/browser/android/accessibility/font_size_prefs_android.cc
@@ -12,6 +12,7 @@
 #include "components/prefs/pref_service.h"
 #include "jni/FontSizePrefs_jni.h"
 
+using base::android::JavaParamRef;
 using base::android::JavaRef;
 
 FontSizePrefsAndroid::FontSizePrefsAndroid(JNIEnv* env, jobject obj)
diff --git a/chrome/browser/android/appmenu/app_menu_drag_helper.cc b/chrome/browser/android/appmenu/app_menu_drag_helper.cc
index 1f018ea..07285eb 100644
--- a/chrome/browser/android/appmenu/app_menu_drag_helper.cc
+++ b/chrome/browser/android/appmenu/app_menu_drag_helper.cc
@@ -6,6 +6,8 @@
 #include "chrome/browser/android/appmenu/app_menu_drag_helper.h"
 #include "jni/AppMenuDragHelper_jni.h"
 
+using base::android::JavaParamRef;
+
 bool RegisterAppMenuDragHelper(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
index 9556e3f..03a1390 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -34,6 +34,8 @@
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace banners {
 
diff --git a/chrome/browser/android/banners/app_banner_manager_android.cc b/chrome/browser/android/banners/app_banner_manager_android.cc
index 5c8c44d..7a46174 100644
--- a/chrome/browser/android/banners/app_banner_manager_android.cc
+++ b/chrome/browser/android/banners/app_banner_manager_android.cc
@@ -18,6 +18,8 @@
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(banners::AppBannerManagerAndroid);
 
diff --git a/chrome/browser/android/blimp/blimp_client_context_factory_android.cc b/chrome/browser/android/blimp/blimp_client_context_factory_android.cc
index 3a4e3ef..a98137c 100644
--- a/chrome/browser/android/blimp/blimp_client_context_factory_android.cc
+++ b/chrome/browser/android/blimp/blimp_client_context_factory_android.cc
@@ -12,6 +12,8 @@
 #include "chrome/browser/profiles/profile_android.h"
 #include "jni/BlimpClientContextFactory_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace content {
 class BrowserContext;
 }
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc
index 47b3563..d9b0e1b 100644
--- a/chrome/browser/android/bookmarks/bookmark_bridge.cc
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc
@@ -38,6 +38,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ToJavaIntArray;
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
index 67637b8f..c0b724b6 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
@@ -24,6 +24,7 @@
 using base::android::AttachCurrentThread;
 using base::android::CheckException;
 using base::android::ConvertJavaStringToUTF16;
+using base::android::JavaParamRef;
 using bookmarks::BookmarkNode;
 using bookmarks::BookmarkPermanentNode;
 using content::BrowserThread;
diff --git a/chrome/browser/android/bottombar/overlay_panel_content.cc b/chrome/browser/android/bottombar/overlay_panel_content.cc
index 2e1146bb..95ee5d0 100644
--- a/chrome/browser/android/bottombar/overlay_panel_content.cc
+++ b/chrome/browser/android/bottombar/overlay_panel_content.cc
@@ -25,6 +25,7 @@
 #include "jni/OverlayPanelContent_jni.h"
 #include "net/url_request/url_fetcher_impl.h"
 
+using base::android::JavaParamRef;
 using content::ContentViewCore;
 
 namespace {
diff --git a/chrome/browser/android/browsing_data/browsing_data_counter_bridge.cc b/chrome/browser/android/browsing_data/browsing_data_counter_bridge.cc
index 1f8c05a..67ffe5d 100644
--- a/chrome/browser/android/browsing_data/browsing_data_counter_bridge.cc
+++ b/chrome/browser/android/browsing_data/browsing_data_counter_bridge.cc
@@ -13,6 +13,9 @@
 #include "components/browsing_data/core/browsing_data_utils.h"
 #include "jni/BrowsingDataCounterBridge_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 BrowsingDataCounterBridge::BrowsingDataCounterBridge(
     JNIEnv* env, const JavaParamRef<jobject>& obj, jint data_type)
     : jobject_(obj) {
diff --git a/chrome/browser/android/browsing_data/url_filter_bridge.cc b/chrome/browser/android/browsing_data/url_filter_bridge.cc
index 7b1e9ec..e9a19ad0 100644
--- a/chrome/browser/android/browsing_data/url_filter_bridge.cc
+++ b/chrome/browser/android/browsing_data/url_filter_bridge.cc
@@ -9,6 +9,8 @@
 #include "jni/UrlFilterBridge_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 UrlFilterBridge::UrlFilterBridge(
     const base::Callback<bool(const GURL&)>& url_filter)
     : url_filter_(url_filter),
diff --git a/chrome/browser/android/chrome_application.cc b/chrome/browser/android/chrome_application.cc
index 45cb459..a8c057a 100644
--- a/chrome/browser/android/chrome_application.cc
+++ b/chrome/browser/android/chrome_application.cc
@@ -25,6 +25,8 @@
 #include "net/url_request/url_request_context_getter.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace {
 
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 37bbe98f..db8d66b9 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -12,12 +12,14 @@
 #include "base/feature_list.h"
 #include "base/macros.h"
 #include "chrome/common/chrome_features.h"
+#include "components/ntp_snippets/features.h"
 #include "components/offline_pages/offline_page_feature.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "content/public/common/content_features.h"
 #include "jni/ChromeFeatureList_jni.h"
 
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 
 namespace chrome {
 namespace android {
@@ -35,11 +37,11 @@
     &kAllBookmarksFeature,
     &kAndroidPayIntegrationV1,
     &kImportantSitesInCBD,
+    &ntp_snippets::kContentSuggestionsFeature,
     &kNTPFakeOmniboxTextFeature,
     &kNTPMaterialDesign,
     &kNTPOfflinePagesFeature,
     &kNTPOfflinePageSuggestionsFeature,
-    &kNTPSnippetsFeature,
     &kNTPToolbarFeature,
     &kPhysicalWebFeature,
     &kPhysicalWebIgnoreOtherClientsFeature,
@@ -66,9 +68,6 @@
 const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kNTPSnippetsFeature{"NTPSnippets",
-                                        base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kNTPOfflinePageSuggestionsFeature{
     "NTPOfflinePageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index d0e8096..9be979d 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -17,7 +17,6 @@
 extern const base::Feature kImportantSitesInCBD;
 extern const base::Feature kNTPMaterialDesign;
 extern const base::Feature kNTPOfflinePagesFeature;
-extern const base::Feature kNTPSnippetsFeature;
 extern const base::Feature kNTPOfflinePageSuggestionsFeature;
 extern const base::Feature kNTPToolbarFeature;
 extern const base::Feature kNTPFakeOmniboxTextFeature;
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index c9c7d4f..b0d717c 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -94,7 +94,7 @@
 #include "chrome/browser/android/voice_search_tab_helper.h"
 #include "chrome/browser/android/warmup_manager.h"
 #include "chrome/browser/android/web_contents_factory.h"
-#include "chrome/browser/android/webapk/manifest_upgrade_detector.h"
+#include "chrome/browser/android/webapk/manifest_upgrade_detector_fetcher.h"
 #include "chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h"
 #include "chrome/browser/android/webapps/webapp_registry.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
@@ -271,7 +271,8 @@
     {"LaunchMetrics", metrics::RegisterLaunchMetrics},
     {"LayerTitleCache", chrome::android::RegisterLayerTitleCache},
     {"LogoBridge", RegisterLogoBridge},
-    {"ManifestUpgradeDetector", ManifestUpgradeDetector::Register},
+    {"ManifestUpgradeDetectorFetcher",
+     ManifestUpgradeDetectorFetcher::Register},
     {"MediaDrmCredentialManager",
      MediaDrmCredentialManager::RegisterMediaDrmCredentialManager},
     {"MostVisitedSites", MostVisitedSitesBridge::Register},
diff --git a/chrome/browser/android/compositor/compositor_view.cc b/chrome/browser/android/compositor/compositor_view.cc
index 3341b1d..acb5fc3 100644
--- a/chrome/browser/android/compositor/compositor_view.cc
+++ b/chrome/browser/android/compositor/compositor_view.cc
@@ -37,6 +37,8 @@
 #include "ui/android/window_android.h"
 #include "ui/gfx/android/java_bitmap.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/layer_title_cache.cc b/chrome/browser/android/compositor/layer_title_cache.cc
index cfe2eeb9..1cd7755e 100644
--- a/chrome/browser/android/compositor/layer_title_cache.cc
+++ b/chrome/browser/android/compositor/layer_title_cache.cc
@@ -18,6 +18,8 @@
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
index 2a1d59e..883f5c0 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -15,6 +15,8 @@
 #include "ui/android/view_android.h"
 #include "ui/gfx/android/java_bitmap.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.cc
index ddce855..beb69ef11 100644
--- a/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.cc
@@ -15,6 +15,8 @@
 #include "ui/android/view_android.h"
 #include "ui/gfx/android/java_bitmap.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/scene_layer/scene_layer.cc b/chrome/browser/android/compositor/scene_layer/scene_layer.cc
index 853cf7e..b5a7cd0 100644
--- a/chrome/browser/android/compositor/scene_layer/scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/scene_layer.cc
@@ -8,6 +8,9 @@
 #include "content/public/browser/android/compositor.h"
 #include "jni/SceneLayer_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.cc
index 4da7758..0b2f703 100644
--- a/chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.cc
@@ -13,6 +13,8 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/android/resources/resource_manager_impl.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.cc
index 4e96339..aaaabe1 100644
--- a/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.cc
@@ -13,6 +13,8 @@
 #include "jni/TabListSceneLayer_jni.h"
 #include "ui/android/resources/resource_manager_impl.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.cc
index d5ff192..45a450b 100644
--- a/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.cc
@@ -13,6 +13,8 @@
 #include "ui/android/resources/resource_manager_impl.h"
 #include "ui/gfx/transform.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.cc
index 85f9b0c..9a2de393 100644
--- a/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/toolbar_scene_layer.cc
@@ -14,6 +14,8 @@
 #include "ui/android/resources/resource_manager_impl.h"
 #include "ui/gfx/android/java_bitmap.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/compositor/tab_content_manager.cc b/chrome/browser/android/compositor/tab_content_manager.cc
index 537b3769..e14bbed9 100644
--- a/chrome/browser/android/compositor/tab_content_manager.cc
+++ b/chrome/browser/android/compositor/tab_content_manager.cc
@@ -32,6 +32,8 @@
 #include "ui/gfx/geometry/rect.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 namespace {
 
 const size_t kMaxReadbacks = 1;
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
index 6ef1b62..090ba40b 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -27,6 +27,7 @@
 #include "services/shell/public/cpp/interface_provider.h"
 #include "services/shell/public/cpp/interface_registry.h"
 
+using base::android::JavaParamRef;
 using content::WebContents;
 
 // This class manages the native behavior of the Contextual Search feature.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_tab_helper.cc b/chrome/browser/android/contextualsearch/contextual_search_tab_helper.cc
index 60c9011..66b4b6d 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_tab_helper.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_tab_helper.cc
@@ -12,6 +12,8 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "jni/ContextualSearchTabHelper_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 ContextualSearchTabHelper::ContextualSearchTabHelper(JNIEnv* env,
                                                      jobject obj,
diff --git a/chrome/browser/android/cookies/cookies_fetcher.cc b/chrome/browser/android/cookies/cookies_fetcher.cc
index b795c44..4fdf13f 100644
--- a/chrome/browser/android/cookies/cookies_fetcher.cc
+++ b/chrome/browser/android/cookies/cookies_fetcher.cc
@@ -15,6 +15,9 @@
 #include "net/cookies/cookie_store.h"
 #include "net/url_request/url_request_context.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 CookiesFetcher::CookiesFetcher(JNIEnv* env, jobject obj, Profile* profile) {
 }
 
diff --git a/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc b/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
index 868033b..a96d7db 100644
--- a/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
+++ b/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
@@ -22,6 +22,9 @@
 #include "net/base/network_change_notifier.h"
 #include "ui/base/l10n/l10n_util.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace {
 
 // Represents the IDs for string messages used by data use snackbar and
diff --git a/chrome/browser/android/dev_tools_server.cc b/chrome/browser/android/dev_tools_server.cc
index a7513b60..5eaf99c8 100644
--- a/chrome/browser/android/dev_tools_server.cc
+++ b/chrome/browser/android/dev_tools_server.cc
@@ -49,6 +49,7 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/base/resource/resource_bundle.h"
 
+using base::android::JavaParamRef;
 using content::DevToolsAgentHost;
 using content::RenderViewHost;
 using content::WebContents;
diff --git a/chrome/browser/android/document/document_web_contents_delegate.cc b/chrome/browser/android/document/document_web_contents_delegate.cc
index 339cc28d..2ef3d79 100644
--- a/chrome/browser/android/document/document_web_contents_delegate.cc
+++ b/chrome/browser/android/document/document_web_contents_delegate.cc
@@ -8,6 +8,8 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/DocumentWebContentsDelegate_jni.h"
 
+using base::android::JavaParamRef;
+
 DocumentWebContentsDelegate::DocumentWebContentsDelegate(JNIEnv* env,
                                                          jobject obj)
     : WebContentsDelegateAndroid(env, obj) {
diff --git a/chrome/browser/android/dom_distiller/distiller_ui_handle_android.cc b/chrome/browser/android/dom_distiller/distiller_ui_handle_android.cc
index a0ca40d..bf4c357b 100644
--- a/chrome/browser/android/dom_distiller/distiller_ui_handle_android.cc
+++ b/chrome/browser/android/dom_distiller/distiller_ui_handle_android.cc
@@ -12,6 +12,8 @@
 #include "ui/android/window_android.h"
 #include "url/gurl.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace dom_distiller {
 
 namespace android {
diff --git a/chrome/browser/android/download/chrome_download_delegate.cc b/chrome/browser/android/download/chrome_download_delegate.cc
index 5c9e7d6f..e8398e7 100644
--- a/chrome/browser/android/download/chrome_download_delegate.cc
+++ b/chrome/browser/android/download/chrome_download_delegate.cc
@@ -27,6 +27,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::WebContents;
 
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc
index c10ed11..89f8bfbd 100644
--- a/chrome/browser/android/download/download_controller.cc
+++ b/chrome/browser/android/download/download_controller.cc
@@ -32,6 +32,7 @@
 #include "ui/base/page_transition_types.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::BrowserContext;
 using content::BrowserThread;
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index 6fec5a6..fce1a417 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -22,6 +22,7 @@
 using base::android::JavaParamRef;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
 
 namespace {
 
diff --git a/chrome/browser/android/favicon_helper.cc b/chrome/browser/android/favicon_helper.cc
index d9205bff..273d339 100644
--- a/chrome/browser/android/favicon_helper.cc
+++ b/chrome/browser/android/favicon_helper.cc
@@ -35,6 +35,7 @@
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_rep.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::AttachCurrentThread;
diff --git a/chrome/browser/android/feature_utilities.cc b/chrome/browser/android/feature_utilities.cc
index 73d7cda..9e52e29 100644
--- a/chrome/browser/android/feature_utilities.cc
+++ b/chrome/browser/android/feature_utilities.cc
@@ -6,6 +6,8 @@
 
 #include "jni/FeatureUtilities_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace {
 bool document_mode_enabled = false;
 bool custom_tab_visible = false;
diff --git a/chrome/browser/android/feedback/connectivity_checker.cc b/chrome/browser/android/feedback/connectivity_checker.cc
index 13fd6241..9a4154c 100644
--- a/chrome/browser/android/feedback/connectivity_checker.cc
+++ b/chrome/browser/android/feedback/connectivity_checker.cc
@@ -23,6 +23,8 @@
 #include "net/url_request/url_request_status.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/feedback/screenshot_task.cc b/chrome/browser/android/feedback/screenshot_task.cc
index d4033c6..db79120e 100644
--- a/chrome/browser/android/feedback/screenshot_task.cc
+++ b/chrome/browser/android/feedback/screenshot_task.cc
@@ -17,6 +17,7 @@
 #include "ui/snapshot/snapshot.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using ui::WindowAndroid;
 
diff --git a/chrome/browser/android/find_in_page/find_in_page_bridge.cc b/chrome/browser/android/find_in_page/find_in_page_bridge.cc
index 5fc842b1..37451045 100644
--- a/chrome/browser/android/find_in_page/find_in_page_bridge.cc
+++ b/chrome/browser/android/find_in_page/find_in_page_bridge.cc
@@ -10,6 +10,8 @@
 #include "jni/FindInPageBridge_jni.h"
 
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 FindInPageBridge::FindInPageBridge(JNIEnv* env,
                                    jobject obj,
diff --git a/chrome/browser/android/foreign_session_helper.cc b/chrome/browser/android/foreign_session_helper.cc
index 0cfeba0..0722bf3 100644
--- a/chrome/browser/android/foreign_session_helper.cc
+++ b/chrome/browser/android/foreign_session_helper.cc
@@ -27,6 +27,7 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/ForeignSessionHelper_jni.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::AttachCurrentThread;
diff --git a/chrome/browser/android/history_report/history_report_jni_bridge.cc b/chrome/browser/android/history_report/history_report_jni_bridge.cc
index ee8d0a04..26ed8f56 100644
--- a/chrome/browser/android/history_report/history_report_jni_bridge.cc
+++ b/chrome/browser/android/history_report/history_report_jni_bridge.cc
@@ -28,6 +28,9 @@
 #include "content/public/browser/browser_thread.h"
 #include "jni/HistoryReportJniBridge_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace history_report {
 
 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
diff --git a/chrome/browser/android/intent_helper.cc b/chrome/browser/android/intent_helper.cc
index cee9e16..923995b 100644
--- a/chrome/browser/android/intent_helper.cc
+++ b/chrome/browser/android/intent_helper.cc
@@ -14,6 +14,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::ScopedJavaLocalRef;
 
 namespace chrome {
 namespace android {
diff --git a/chrome/browser/android/java_exception_reporter.cc b/chrome/browser/android/java_exception_reporter.cc
index 188805b..d76cb23 100644
--- a/chrome/browser/android/java_exception_reporter.cc
+++ b/chrome/browser/android/java_exception_reporter.cc
@@ -10,6 +10,8 @@
 #include "base/debug/dump_without_crashing.h"
 #include "jni/JavaExceptionReporter_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/large_icon_bridge.cc b/chrome/browser/android/large_icon_bridge.cc
index 81fdeda7..65e32ee5 100644
--- a/chrome/browser/android/large_icon_bridge.cc
+++ b/chrome/browser/android/large_icon_bridge.cc
@@ -22,6 +22,7 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/codec/png_codec.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::AttachCurrentThread;
diff --git a/chrome/browser/android/logo_bridge.cc b/chrome/browser/android/logo_bridge.cc
index a1e053d..e80a7a4a 100644
--- a/chrome/browser/android/logo_bridge.cc
+++ b/chrome/browser/android/logo_bridge.cc
@@ -25,6 +25,7 @@
 
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaByteArray;
 
diff --git a/chrome/browser/android/metrics/launch_metrics.cc b/chrome/browser/android/metrics/launch_metrics.cc
index 6c634ba..345dd31 100644
--- a/chrome/browser/android/metrics/launch_metrics.cc
+++ b/chrome/browser/android/metrics/launch_metrics.cc
@@ -19,6 +19,8 @@
 #include "jni/LaunchMetrics_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 namespace metrics {
 
 enum HomeScreenLaunch {
diff --git a/chrome/browser/android/metrics/uma_session_stats.cc b/chrome/browser/android/metrics/uma_session_stats.cc
index 37c3abdd..4b8c6ab 100644
--- a/chrome/browser/android/metrics/uma_session_stats.cc
+++ b/chrome/browser/android/metrics/uma_session_stats.cc
@@ -26,6 +26,7 @@
 #include "jni/UmaSessionStats_jni.h"
 
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::UserMetricsAction;
 
 namespace {
diff --git a/chrome/browser/android/metrics/uma_utils.cc b/chrome/browser/android/metrics/uma_utils.cc
index ebf6c4b..fe10318 100644
--- a/chrome/browser/android/metrics/uma_utils.cc
+++ b/chrome/browser/android/metrics/uma_utils.cc
@@ -10,6 +10,8 @@
 #include "components/metrics/metrics_reporting_default_state.h"
 #include "jni/UmaUtils_jni.h"
 
+using base::android::JavaParamRef;
+
 class PrefService;
 
 namespace chrome {
diff --git a/chrome/browser/android/metrics/variations_session.cc b/chrome/browser/android/metrics/variations_session.cc
index 068246f..348a3566 100644
--- a/chrome/browser/android/metrics/variations_session.cc
+++ b/chrome/browser/android/metrics/variations_session.cc
@@ -9,6 +9,8 @@
 #include "components/variations/service/variations_service.h"
 #include "jni/VariationsSession_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace {
 
 // Tracks whether VariationsService::OnAppEnterForeground() has been called
diff --git a/chrome/browser/android/net/external_estimate_provider_android.cc b/chrome/browser/android/net/external_estimate_provider_android.cc
index a966d0e..d81bd32 100644
--- a/chrome/browser/android/net/external_estimate_provider_android.cc
+++ b/chrome/browser/android/net/external_estimate_provider_android.cc
@@ -12,6 +12,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "jni/ExternalEstimateProviderAndroid_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/ntp/most_visited_sites_bridge.cc b/chrome/browser/android/ntp/most_visited_sites_bridge.cc
index 7951f94..802adee 100644
--- a/chrome/browser/android/ntp/most_visited_sites_bridge.cc
+++ b/chrome/browser/android/ntp/most_visited_sites_bridge.cc
@@ -34,6 +34,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaArrayOfStrings;
diff --git a/chrome/browser/android/ntp/new_tab_page_prefs.cc b/chrome/browser/android/ntp/new_tab_page_prefs.cc
index dd1f332..4c3d4672 100644
--- a/chrome/browser/android/ntp/new_tab_page_prefs.cc
+++ b/chrome/browser/android/ntp/new_tab_page_prefs.cc
@@ -15,6 +15,7 @@
 #include "jni/NewTabPagePrefs_jni.h"
 
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 
 static jlong Init(JNIEnv* env,
                   const JavaParamRef<jclass>& clazz,
diff --git a/chrome/browser/android/offline_pages/background_scheduler_bridge.cc b/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
index 6c9ceef..17243f0 100644
--- a/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
+++ b/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
@@ -13,7 +13,9 @@
 #include "components/offline_pages/background/request_coordinator.h"
 #include "jni/BackgroundSchedulerBridge_jni.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace offline_pages {
 namespace android {
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
index 44d9827..33e120f 100644
--- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
+++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
@@ -18,6 +18,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.cc b/chrome/browser/android/offline_pages/offline_page_bridge.cc
index 90673ca8..9400fe3 100644
--- a/chrome/browser/android/offline_pages/offline_page_bridge.cc
+++ b/chrome/browser/android/offline_pages/offline_page_bridge.cc
@@ -32,6 +32,7 @@
 
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 
diff --git a/chrome/browser/android/omnibox/answers_image_bridge.cc b/chrome/browser/android/omnibox/answers_image_bridge.cc
index 910f48d4..09a6791 100644
--- a/chrome/browser/android/omnibox/answers_image_bridge.cc
+++ b/chrome/browser/android/omnibox/answers_image_bridge.cc
@@ -19,6 +19,7 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ConvertUTF8ToJavaString;
 
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index 5eb606bf..8061733 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -60,7 +60,9 @@
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 using base::android::JavaRef;
+using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaIntArray;
 using bookmarks::BookmarkModel;
 using metrics::OmniboxEventProto;
diff --git a/chrome/browser/android/omnibox/omnibox_prerender.cc b/chrome/browser/android/omnibox/omnibox_prerender.cc
index b1b2708..2d4bd40 100644
--- a/chrome/browser/android/omnibox/omnibox_prerender.cc
+++ b/chrome/browser/android/omnibox/omnibox_prerender.cc
@@ -18,6 +18,7 @@
 #include "jni/OmniboxPrerender_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
 using predictors::AutocompleteActionPredictor;
 using predictors::AutocompleteActionPredictorFactory;
 
diff --git a/chrome/browser/android/password_ui_view_android.cc b/chrome/browser/android/password_ui_view_android.cc
index bc469ea..84db6852 100644
--- a/chrome/browser/android/password_ui_view_android.cc
+++ b/chrome/browser/android/password_ui_view_android.cc
@@ -25,6 +25,7 @@
 
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace {
diff --git a/chrome/browser/android/policy/policy_auditor.cc b/chrome/browser/android/policy/policy_auditor.cc
index 5fe17d3d..a60315e9 100644
--- a/chrome/browser/android/policy/policy_auditor.cc
+++ b/chrome/browser/android/policy/policy_auditor.cc
@@ -11,6 +11,8 @@
 #include "jni/PolicyAuditor_jni.h"
 #include "net/cert/cert_status_flags.h"
 
+using base::android::JavaParamRef;
+
 int GetCertificateFailure(JNIEnv* env,
                           const JavaParamRef<jclass>& obj,
                           const JavaParamRef<jobject>& java_web_contents) {
diff --git a/chrome/browser/android/precache/precache_launcher.cc b/chrome/browser/android/precache/precache_launcher.cc
index 74419a8..dad62cb 100644
--- a/chrome/browser/android/precache/precache_launcher.cc
+++ b/chrome/browser/android/precache/precache_launcher.cc
@@ -19,6 +19,7 @@
 #include "jni/PrecacheLauncher_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using precache::PrecacheManager;
 
 namespace {
diff --git a/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc b/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
index 8787577..3a9dca4 100644
--- a/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
+++ b/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
@@ -25,6 +25,8 @@
 
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaArrayOfStrings;
 using base::android::ToJavaIntArray;
 using ::i18n::addressinput::AddressField;
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index cc3e366d..8de0770 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -67,6 +67,7 @@
 using base::android::CheckException;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ScopedJavaGlobalRef;
 using content::BrowserThread;
diff --git a/chrome/browser/android/preferences/website_preference_bridge.cc b/chrome/browser/android/preferences/website_preference_bridge.cc
index cae923a..9de85d3f 100644
--- a/chrome/browser/android/preferences/website_preference_bridge.cc
+++ b/chrome/browser/android/preferences/website_preference_bridge.cc
@@ -47,6 +47,7 @@
 
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::JavaRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
diff --git a/chrome/browser/android/profiles/profile_downloader_android.cc b/chrome/browser/android/profiles/profile_downloader_android.cc
index 0a79c35..399b8f4 100644
--- a/chrome/browser/android/profiles/profile_downloader_android.cc
+++ b/chrome/browser/android/profiles/profile_downloader_android.cc
@@ -25,6 +25,9 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/image/image_skia.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace {
 
 // An account fetcher callback.
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc
index 32746fb..2d70930b 100644
--- a/chrome/browser/android/provider/chrome_browser_provider.cc
+++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -55,6 +55,7 @@
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::GetClass;
+using base::android::JavaParamRef;
 using base::android::MethodID;
 using base::android::JavaRef;
 using base::android::ScopedJavaGlobalRef;
diff --git a/chrome/browser/android/rappor/rappor_service_bridge.cc b/chrome/browser/android/rappor/rappor_service_bridge.cc
index 7fdcae7..a7a77b5 100644
--- a/chrome/browser/android/rappor/rappor_service_bridge.cc
+++ b/chrome/browser/android/rappor/rappor_service_bridge.cc
@@ -10,6 +10,8 @@
 #include "jni/RapporServiceBridge_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 namespace rappor {
 
 void SampleDomainAndRegistryFromURL(JNIEnv* env,
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.cc b/chrome/browser/android/recently_closed_tabs_bridge.cc
index 59bdd1b..e27a1229 100644
--- a/chrome/browser/android/recently_closed_tabs_bridge.cc
+++ b/chrome/browser/android/recently_closed_tabs_bridge.cc
@@ -19,6 +19,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace {
diff --git a/chrome/browser/android/rlz/revenue_stats.cc b/chrome/browser/android/rlz/revenue_stats.cc
index e68253a..e9fbbc6c 100644
--- a/chrome/browser/android/rlz/revenue_stats.cc
+++ b/chrome/browser/android/rlz/revenue_stats.cc
@@ -10,6 +10,8 @@
 #include "jni/RevenueStats_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 namespace chrome {
 namespace android {
 
diff --git a/chrome/browser/android/safe_browsing/safe_browsing_api_handler_bridge.cc b/chrome/browser/android/safe_browsing/safe_browsing_api_handler_bridge.cc
index a279b52..db19ef2 100644
--- a/chrome/browser/android/safe_browsing/safe_browsing_api_handler_bridge.cc
+++ b/chrome/browser/android/safe_browsing/safe_browsing_api_handler_bridge.cc
@@ -21,6 +21,7 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::GetApplicationContext;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaIntArray;
 using content::BrowserThread;
diff --git a/chrome/browser/android/service_tab_launcher.cc b/chrome/browser/android/service_tab_launcher.cc
index dc80eac..d8f219b 100644
--- a/chrome/browser/android/service_tab_launcher.cc
+++ b/chrome/browser/android/service_tab_launcher.cc
@@ -15,6 +15,8 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::GetApplicationContext;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 // Called by Java when the WebContents instance for a request Id is available.
 void OnWebContentsForRequestAvailable(
diff --git a/chrome/browser/android/sessions/session_tab_helper_android.cc b/chrome/browser/android/sessions/session_tab_helper_android.cc
index 7411543..140bb034 100644
--- a/chrome/browser/android/sessions/session_tab_helper_android.cc
+++ b/chrome/browser/android/sessions/session_tab_helper_android.cc
@@ -9,6 +9,8 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/SessionTabHelper_jni.h"
 
+using base::android::JavaParamRef;
+
 // static
 jint IdForTab(JNIEnv* env,
               const JavaParamRef<jclass>& clazz,
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index 52b8ae5..50c6cad 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -23,6 +23,8 @@
 #include "ui/gfx/color_analysis.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 using content::Manifest;
 
 namespace {
diff --git a/chrome/browser/android/signin/account_management_screen_helper.cc b/chrome/browser/android/signin/account_management_screen_helper.cc
index da22c15..512d18a 100644
--- a/chrome/browser/android/signin/account_management_screen_helper.cc
+++ b/chrome/browser/android/signin/account_management_screen_helper.cc
@@ -12,6 +12,8 @@
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "jni/AccountManagementScreenHelper_jni.h"
 
+using base::android::JavaParamRef;
+
 // static
 void AccountManagementScreenHelper::OpenAccountManagementScreen(
     Profile* profile,
diff --git a/chrome/browser/android/signin/account_tracker_service_android.cc b/chrome/browser/android/signin/account_tracker_service_android.cc
index 27a5ea4..127dc7c 100644
--- a/chrome/browser/android/signin/account_tracker_service_android.cc
+++ b/chrome/browser/android/signin/account_tracker_service_android.cc
@@ -12,6 +12,8 @@
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "jni/AccountTrackerService_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace signin {
 namespace android {
 
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc
index 21fc752..3da8310 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -46,6 +46,7 @@
 #include "jni/SigninManager_jni.h"
 #include "net/url_request/url_request_context_getter.h"
 
+using base::android::JavaParamRef;
 using bookmarks::BookmarkModel;
 
 namespace {
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index ede7480e..f61e979c 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -91,6 +91,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using content::BrowserThread;
 using content::GlobalRequestID;
 using content::NavigationController;
diff --git a/chrome/browser/android/tab_state.cc b/chrome/browser/android/tab_state.cc
index d98867a..d8cc808 100644
--- a/chrome/browser/android/tab_state.cc
+++ b/chrome/browser/android/tab_state.cc
@@ -30,6 +30,7 @@
 
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::NavigationController;
 using content::WebContents;
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index ea60eac..ddbee41 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -50,6 +50,7 @@
 #endif
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::BluetoothChooser;
 using content::FileChooserParams;
diff --git a/chrome/browser/android/url_utilities.cc b/chrome/browser/android/url_utilities.cc
index f945b61..c535912 100644
--- a/chrome/browser/android/url_utilities.cc
+++ b/chrome/browser/android/url_utilities.cc
@@ -14,6 +14,8 @@
 #include "url/gurl.h"
 
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace {
 
diff --git a/chrome/browser/android/warmup_manager.cc b/chrome/browser/android/warmup_manager.cc
index 0c7956a3..e3271e3c 100644
--- a/chrome/browser/android/warmup_manager.cc
+++ b/chrome/browser/android/warmup_manager.cc
@@ -12,6 +12,8 @@
 #include "jni/WarmupManager_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 static void PreconnectUrlAndSubresources(JNIEnv* env,
                                          const JavaParamRef<jclass>& clazz,
                                          const JavaParamRef<jobject>& jprofile,
diff --git a/chrome/browser/android/web_contents_factory.cc b/chrome/browser/android/web_contents_factory.cc
index d957e54..37a0799 100644
--- a/chrome/browser/android/web_contents_factory.cc
+++ b/chrome/browser/android/web_contents_factory.cc
@@ -12,6 +12,9 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/WebContentsFactory_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 static ScopedJavaLocalRef<jobject> CreateWebContents(
     JNIEnv* env,
     const JavaParamRef<jclass>& clazz,
diff --git a/chrome/browser/android/webapk/manifest_upgrade_detector.cc b/chrome/browser/android/webapk/manifest_upgrade_detector_fetcher.cc
similarity index 70%
rename from chrome/browser/android/webapk/manifest_upgrade_detector.cc
rename to chrome/browser/android/webapk/manifest_upgrade_detector_fetcher.cc
index 58a3a86a..cb82d2b 100644
--- a/chrome/browser/android/webapk/manifest_upgrade_detector.cc
+++ b/chrome/browser/android/webapk/manifest_upgrade_detector_fetcher.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/webapk/manifest_upgrade_detector.h"
+#include "chrome/browser/android/webapk/manifest_upgrade_detector_fetcher.h"
 
 #include <jni.h>
 
@@ -11,9 +11,12 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/manifest.h"
-#include "jni/ManifestUpgradeDetector_jni.h"
+#include "jni/ManifestUpgradeDetectorFetcher_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace {
 
 // Returns whether the given |url| is within the scope of the |scope| url.
@@ -26,75 +29,71 @@
 
 jlong Initialize(JNIEnv* env,
                  const JavaParamRef<jobject>& obj,
-                 const JavaParamRef<jobject>& java_web_contents,
                  const JavaParamRef<jstring>& java_scope_url,
                  const JavaParamRef<jstring>& java_web_manifest_url) {
-  content::WebContents* web_contents =
-      content::WebContents::FromJavaWebContents(java_web_contents);
   GURL scope(base::android::ConvertJavaStringToUTF8(env, java_scope_url));
   GURL web_manifest_url(base::android::ConvertJavaStringToUTF8(
       env, java_web_manifest_url));
-  ManifestUpgradeDetector* manifest_upgrade_detector =
-      new ManifestUpgradeDetector(env, obj, web_contents, scope,
-                                  web_manifest_url);
-  return reinterpret_cast<intptr_t>(manifest_upgrade_detector);
+  ManifestUpgradeDetectorFetcher* fetcher =
+      new ManifestUpgradeDetectorFetcher(env, obj, scope, web_manifest_url);
+  return reinterpret_cast<intptr_t>(fetcher);
 }
 
-ManifestUpgradeDetector::ManifestUpgradeDetector(
+ManifestUpgradeDetectorFetcher::ManifestUpgradeDetectorFetcher(
     JNIEnv* env,
     jobject obj,
-    content::WebContents* web_contents,
     const GURL& scope,
     const GURL& web_manifest_url)
-    : content::WebContentsObserver(web_contents),
-      started_(false),
+    : content::WebContentsObserver(nullptr),
       scope_(scope),
       web_manifest_url_(web_manifest_url),
       weak_ptr_factory_(this) {
   java_ref_.Reset(env, obj);
 }
 
-ManifestUpgradeDetector::~ManifestUpgradeDetector() {
+ManifestUpgradeDetectorFetcher::~ManifestUpgradeDetectorFetcher() {
 }
 
 // static
-bool ManifestUpgradeDetector::Register(JNIEnv* env) {
+bool ManifestUpgradeDetectorFetcher::Register(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
 
-void ManifestUpgradeDetector::ReplaceWebContents(
+void ManifestUpgradeDetectorFetcher::ReplaceWebContents(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jobject>& jweb_contents) {
+    const JavaParamRef<jobject>& java_web_contents) {
   content::WebContents* web_contents =
-      content::WebContents::FromJavaWebContents(jweb_contents);
+      content::WebContents::FromJavaWebContents(java_web_contents);
   content::WebContentsObserver::Observe(web_contents);
 }
 
-void ManifestUpgradeDetector::Destroy(JNIEnv* env,
-                                      const JavaParamRef<jobject>& obj) {
+void ManifestUpgradeDetectorFetcher::Destroy(JNIEnv* env,
+                                             const JavaParamRef<jobject>& obj) {
   delete this;
 }
 
-void ManifestUpgradeDetector::Start(JNIEnv* env,
-                                    const JavaParamRef<jobject>& obj) {
-  started_ = true;
+void ManifestUpgradeDetectorFetcher::Start(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& java_web_contents) {
+  ReplaceWebContents(env, obj, java_web_contents);
 }
 
-void ManifestUpgradeDetector::DidFinishLoad(
+void ManifestUpgradeDetectorFetcher::DidFinishLoad(
     content::RenderFrameHost* render_frame_host,
     const GURL& validated_url) {
   if (render_frame_host->GetParent())
     return;
-  if (!started_ || !IsInScope(validated_url, scope_))
+  if (!IsInScope(validated_url, scope_))
     return;
 
   web_contents()->GetManifest(
-      base::Bind(&ManifestUpgradeDetector::OnDidGetManifest,
+      base::Bind(&ManifestUpgradeDetectorFetcher::OnDidGetManifest,
                  weak_ptr_factory_.GetWeakPtr()));
 }
 
-void ManifestUpgradeDetector::OnDidGetManifest(
+void ManifestUpgradeDetectorFetcher::OnDidGetManifest(
     const GURL& manifest_url,
     const content::Manifest& manifest) {
   // If the manifest is empty, it means the current WebContents doesn't
@@ -108,8 +107,6 @@
   if (manifest.IsEmpty() || web_manifest_url_ != manifest_url)
     return;
 
-  started_ = false;
-
   ShortcutInfo info(GURL::EmptyGURL());
   info.UpdateFromManifest(manifest);
   info.manifest_url = manifest_url;
@@ -117,7 +114,7 @@
   OnDataAvailable(info);
 }
 
-void ManifestUpgradeDetector::OnDataAvailable(const ShortcutInfo& info) {
+void ManifestUpgradeDetectorFetcher::OnDataAvailable(const ShortcutInfo& info) {
   JNIEnv* env = base::android::AttachCurrentThread();
 
   ScopedJavaLocalRef<jstring> java_url =
@@ -129,7 +126,7 @@
   ScopedJavaLocalRef<jstring> java_short_name =
       base::android::ConvertUTF16ToJavaString(env, info.short_name);
 
-  Java_ManifestUpgradeDetector_onDataAvailable(
+  Java_ManifestUpgradeDetectorFetcher_onDataAvailable(
       env, java_ref_.obj(),
       java_url.obj(),
       java_scope.obj(),
diff --git a/chrome/browser/android/webapk/manifest_upgrade_detector.h b/chrome/browser/android/webapk/manifest_upgrade_detector_fetcher.h
similarity index 62%
rename from chrome/browser/android/webapk/manifest_upgrade_detector.h
rename to chrome/browser/android/webapk/manifest_upgrade_detector_fetcher.h
index 96db2e9..d1f66c2 100644
--- a/chrome/browser/android/webapk/manifest_upgrade_detector.h
+++ b/chrome/browser/android/webapk/manifest_upgrade_detector_fetcher.h
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_WEBAPK_MANIFEST_UPGRADE_DETECTOR_H_
-#define CHROME_BROWSER_ANDROID_WEBAPK_MANIFEST_UPGRADE_DETECTOR_H_
+#ifndef CHROME_BROWSER_ANDROID_WEBAPK_MANIFEST_UPGRADE_DETECTOR_FETCHER_H_
+#define CHROME_BROWSER_ANDROID_WEBAPK_MANIFEST_UPGRADE_DETECTOR_FETCHER_H_
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_weak_ref.h"
-#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -20,36 +19,35 @@
 class GURL;
 struct ShortcutInfo;
 
-// ManifestUpgradeDetector is the C++ counterpart of
-// org.chromium.chrome.browser's ManifestUpgradeDetector in Java. It is created
-// via a JNI (Initialize) call and MUST BE DESTROYED via Destroy().
-class ManifestUpgradeDetector : public content::WebContentsObserver {
+// ManifestUpgradeDetectorFetcher is the C++ counterpart of
+// org.chromium.chrome.browser's ManifestUpgradeDetectorFetcher in Java. It is
+// created via a JNI (Initialize) call and MUST BE DESTROYED via Destroy().
+class ManifestUpgradeDetectorFetcher : public content::WebContentsObserver {
  public:
-  ManifestUpgradeDetector(JNIEnv* env,
-                          jobject obj,
-                          content::WebContents* web_contents,
-                          const GURL& scope,
-                          const GURL& web_manifest_url);
+  ManifestUpgradeDetectorFetcher(JNIEnv* env,
+                                 jobject obj,
+                                 const GURL& scope,
+                                 const GURL& web_manifest_url);
 
   // Replaces the WebContents that is being observed.
   void ReplaceWebContents(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jobject>& jweb_contents);
+      const base::android::JavaParamRef<jobject>& java_web_contents);
 
   // Called by the Java counterpart to destroy its native half.
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
   // Called by the Java counterpart to start checking web manifest changes.
-  void Start(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  void Start(JNIEnv* env,
+             const base::android::JavaParamRef<jobject>& obj,
+             const base::android::JavaParamRef<jobject>& java_web_contents);
 
   // Registers JNI hooks.
   static bool Register(JNIEnv* env);
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(ManifestUpgradeDetectorTest,
-              OnDidGetManifestReturnsFalseWhenTheFetchedManifestUrlIsEmpty);
-  ~ManifestUpgradeDetector() override;
+  ~ManifestUpgradeDetectorFetcher() override;
 
   // content::WebContentsObserver:
   void DidFinishLoad(content::RenderFrameHost* render_frame_host,
@@ -64,18 +62,15 @@
   // Points to the Java object.
   base::android::ScopedJavaGlobalRef<jobject> java_ref_;
 
-  // A flag to indicate if the detection pipeline was started.
-  bool started_;
-
   // The detector will only fetch the URL within the scope of the WebAPK.
   const GURL scope_;
 
   // The WebAPK's Web Manifest URL that the detector is looking for.
   const GURL web_manifest_url_;
 
-  base::WeakPtrFactory<ManifestUpgradeDetector> weak_ptr_factory_;
+  base::WeakPtrFactory<ManifestUpgradeDetectorFetcher> weak_ptr_factory_;
 
-  DISALLOW_COPY_AND_ASSIGN(ManifestUpgradeDetector);
+  DISALLOW_COPY_AND_ASSIGN(ManifestUpgradeDetectorFetcher);
 };
 
-#endif  // CHROME_BROWSER_ANDROID_WEBAPK_MANIFEST_UPGRADE_DETECTOR_H_
+#endif  // CHROME_BROWSER_ANDROID_WEBAPK_MANIFEST_UPGRADE_DETECTOR_FETCHER_H_
diff --git a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc
index ba6732f..52e45492 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc
@@ -22,6 +22,8 @@
 #include "ui/gfx/color_analysis.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 using content::Manifest;
 
 jlong Initialize(JNIEnv* env,
diff --git a/chrome/browser/android/webapps/webapp_registry.cc b/chrome/browser/android/webapps/webapp_registry.cc
index 1d70965..df3fb330 100644
--- a/chrome/browser/android/webapps/webapp_registry.cc
+++ b/chrome/browser/android/webapps/webapp_registry.cc
@@ -14,6 +14,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "jni/WebappRegistry_jni.h"
 
+using base::android::JavaParamRef;
+
 void WebappRegistry::UnregisterWebappsForUrls(
     const base::Callback<bool(const GURL&)>& url_filter,
     const base::Closure& callback) {
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index 755fa6f..6b70e25c 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -43,6 +43,7 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 
diff --git a/chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.cc b/chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.cc
index f367c87..309c4b0 100644
--- a/chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.cc
+++ b/chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.cc
@@ -140,9 +140,7 @@
   no_show_checkbox_.reset(new views::Checkbox(
       l10n_util::GetStringUTF16(IDS_MULTIPROFILES_INTRO_NOSHOW_AGAIN)));
   no_show_checkbox_->SetChecked(true);
-  no_show_checkbox_->SetFontList(
-      ui::ResourceBundle::GetSharedInstance().GetFontList(
-      ui::ResourceBundle::MediumFont));
+  no_show_checkbox_->AdjustFontSize(ui::ResourceBundle::kMediumFontDelta);
   no_show_checkbox_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   grid_layout->StartRow(0, 0);
   grid_layout->AddView(no_show_checkbox_.get());
diff --git a/chrome/browser/dom_distiller/dom_distiller_service_factory_android.cc b/chrome/browser/dom_distiller/dom_distiller_service_factory_android.cc
index ed9971c..b2ea21f40 100644
--- a/chrome/browser/dom_distiller/dom_distiller_service_factory_android.cc
+++ b/chrome/browser/dom_distiller/dom_distiller_service_factory_android.cc
@@ -11,6 +11,7 @@
 #include "components/dom_distiller/core/dom_distiller_service_android.h"
 #include "jni/DomDistillerServiceFactory_jni.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace dom_distiller {
diff --git a/chrome/browser/dom_distiller/tab_utils_android.cc b/chrome/browser/dom_distiller/tab_utils_android.cc
index c3b943a2..d48bab9f 100644
--- a/chrome/browser/dom_distiller/tab_utils_android.cc
+++ b/chrome/browser/dom_distiller/tab_utils_android.cc
@@ -17,6 +17,9 @@
 #include "jni/DomDistillerTabUtils_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace android {
 
 void DistillCurrentPageAndView(JNIEnv* env,
diff --git a/chrome/browser/extensions/extension_bindings_apitest.cc b/chrome/browser/extensions/extension_bindings_apitest.cc
index 387576f..5006270 100644
--- a/chrome/browser/extensions/extension_bindings_apitest.cc
+++ b/chrome/browser/extensions/extension_bindings_apitest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/net/url_request_mock_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_test_utils.h"
@@ -208,5 +209,65 @@
   EXPECT_EQ("success", result);
 }
 
+class FramesExtensionBindingsApiTest : public ExtensionBindingsApiTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ExtensionBindingsApiTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kDisablePopupBlocking);
+  }
+};
+
+// This tests that web pages with iframes or child windows pointing at
+// chrome-extenison:// urls, both web_accessible and nonexistent pages, don't
+// get improper extensions bindings injected while they briefly still point at
+// about:blank and are still scriptable by their parent.
+//
+// The general idea is to load up 2 extensions, one which listens for external
+// messages ("receiver") and one which we'll try first faking messages from in
+// the web page's iframe, as well as actually send a message from later
+// ("sender").
+IN_PROC_BROWSER_TEST_F(FramesExtensionBindingsApiTest, FramesBeforeNavigation) {
+  // Load the sender and receiver extensions, and make sure they are ready.
+  ExtensionTestMessageListener sender_ready("sender_ready", true);
+  const Extension* sender = LoadExtension(
+      test_data_dir_.AppendASCII("bindings").AppendASCII("message_sender"));
+  ASSERT_NE(nullptr, sender);
+  ASSERT_TRUE(sender_ready.WaitUntilSatisfied());
+
+  ExtensionTestMessageListener receiver_ready("receiver_ready", false);
+  const Extension* receiver =
+      LoadExtension(test_data_dir_.AppendASCII("bindings")
+                        .AppendASCII("external_message_listener"));
+  ASSERT_NE(nullptr, receiver);
+  ASSERT_TRUE(receiver_ready.WaitUntilSatisfied());
+
+  // Load the web page which tries to impersonate the sender extension via
+  // scripting iframes/child windows before they finish navigating to pages
+  // within the sender extension.
+  ASSERT_TRUE(embedded_test_server()->Start());
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL(
+          "/extensions/api_test/bindings/frames_before_navigation.html"));
+
+  bool page_success = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      browser()->tab_strip_model()->GetWebContentsAt(0), "getResult()",
+      &page_success));
+  EXPECT_TRUE(page_success);
+
+  // Reply to |sender|, causing it to send a message over to |receiver|, and
+  // then ask |receiver| for the total message count. It should be 1 since
+  // |receiver| should not have received any impersonated messages.
+  sender_ready.Reply(receiver->id());
+  int message_count = 0;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+      ProcessManager::Get(profile())
+          ->GetBackgroundHostForExtension(receiver->id())
+          ->host_contents(),
+      "getMessageCountAfterReceivingRealSenderMessage()", &message_count));
+  EXPECT_EQ(1, message_count);
+}
+
 }  // namespace
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 2ecbf66..de6d7e72 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -347,6 +347,10 @@
     return GetURLForPath("www.chromium.org", "/chromium.org.html");
   }
 
+  GURL popup_opener_url() {
+    return GetURLForPath("www.chromium.org", "/popup_opener.html");
+  }
+
   GURL google_com_url() {
     return GetURLForPath("www.google.com", "/google.com.html");
   }
@@ -1018,6 +1022,43 @@
   EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
 }
 
+IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, FromPopup) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kDisablePopupBlocking);
+
+  InitializeTestServer();
+  scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
+
+  // This will let us wait for the chromium.org.html page to load in a popup.
+  ui_test_utils::UrlLoadObserver url_observer(
+      chromium_org_url(), content::NotificationService::AllSources());
+
+  // The page at popup_opener_url() should open chromium_org_url() as a popup.
+  ui_test_utils::NavigateToURL(browser(), popup_opener_url());
+  url_observer.Wait();
+
+  // Find the WebContents that committed the chromium_org_url().
+  // TODO(devlin) - it would be nice if UrlLoadObserver handled this for
+  // us, which it could pretty easily do.
+  content::WebContents* popup_contents = nullptr;
+  for (int i = 0; i < browser()->tab_strip_model()->count(); i++) {
+    content::WebContents* contents =
+        browser()->tab_strip_model()->GetWebContentsAt(i);
+    if (contents->GetLastCommittedURL() == chromium_org_url()) {
+      popup_contents = contents;
+      break;
+    }
+  }
+  ASSERT_NE(nullptr, popup_contents) << "Could not find WebContents for popup";
+
+  // Make sure the popup can connect and send messages to the extension.
+  content::RenderFrameHost* popup_frame = popup_contents->GetMainFrame();
+
+  EXPECT_EQ(OK, CanConnectAndSendMessagesToFrame(popup_frame, extension.get(),
+                                                 nullptr));
+  EXPECT_FALSE(AreAnyNonWebApisDefinedForFrame(popup_frame));
+}
+
 // Tests externally_connectable between a web page and an extension with a
 // TLS channel ID created for the origin.
 class ExternallyConnectableMessagingWithTlsChannelIdTest :
diff --git a/chrome/browser/history/android/sqlite_cursor.cc b/chrome/browser/history/android/sqlite_cursor.cc
index b720520..8bf9cc0 100644
--- a/chrome/browser/history/android/sqlite_cursor.cc
+++ b/chrome/browser/history/android/sqlite_cursor.cc
@@ -15,6 +15,7 @@
 #include "sql/statement.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::BrowserThread;
 
diff --git a/chrome/browser/invalidation/invalidation_service_factory_android.cc b/chrome/browser/invalidation/invalidation_service_factory_android.cc
index e42da0e..1b86424 100644
--- a/chrome/browser/invalidation/invalidation_service_factory_android.cc
+++ b/chrome/browser/invalidation/invalidation_service_factory_android.cc
@@ -12,6 +12,7 @@
 #include "components/invalidation/impl/profile_invalidation_provider.h"
 #include "jni/InvalidationServiceFactory_jni.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace invalidation {
diff --git a/chrome/browser/media/android/cdm/media_drm_credential_manager.cc b/chrome/browser/media/android/cdm/media_drm_credential_manager.cc
index c951e65..151784d0 100644
--- a/chrome/browser/media/android/cdm/media_drm_credential_manager.cc
+++ b/chrome/browser/media/android/cdm/media_drm_credential_manager.cc
@@ -20,6 +20,7 @@
 
 #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 
 namespace {
diff --git a/chrome/browser/media/android/remote/record_cast_action.cc b/chrome/browser/media/android/remote/record_cast_action.cc
index 7f9b5ad..37a556e 100644
--- a/chrome/browser/media/android/remote/record_cast_action.cc
+++ b/chrome/browser/media/android/remote/record_cast_action.cc
@@ -12,6 +12,7 @@
 #include "media/base/container_names.h"
 
 using base::UserMetricsAction;
+using base::android::JavaParamRef;
 using content::RecordAction;
 
 namespace {
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
index a95bdec..fa30672 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
@@ -23,6 +23,7 @@
 
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::AttachCurrentThread;
 using content::BrowserThread;
diff --git a/chrome/browser/media/android/router/media_router_android.cc b/chrome/browser/media/android/router/media_router_android.cc
index 7e1be79a..efe4cc9 100644
--- a/chrome/browser/media/android/router/media_router_android.cc
+++ b/chrome/browser/media/android/router/media_router_android.cc
@@ -29,6 +29,7 @@
 
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::AttachCurrentThread;
 
diff --git a/chrome/browser/media/android/router/media_router_dialog_controller_android.cc b/chrome/browser/media/android/router/media_router_dialog_controller_android.cc
index ced3e13..c2184cb 100644
--- a/chrome/browser/media/android/router/media_router_dialog_controller_android.cc
+++ b/chrome/browser/media/android/router/media_router_dialog_controller_android.cc
@@ -22,6 +22,8 @@
     media_router::MediaRouterDialogControllerAndroid);
 
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 using content::WebContents;
 
 namespace media_router {
diff --git a/chrome/browser/media/webrtc_video_quality_browsertest.cc b/chrome/browser/media/webrtc_video_quality_browsertest.cc
index 5662653..6203a80 100644
--- a/chrome/browser/media/webrtc_video_quality_browsertest.cc
+++ b/chrome/browser/media/webrtc_video_quality_browsertest.cc
@@ -53,15 +53,10 @@
     FILE_PATH_LITERAL("frame_analyzer");
 #endif
 
-static const base::FilePath::CharType kArgbToI420ConverterExecutable[] =
-#if defined(OS_WIN)
-    FILE_PATH_LITERAL("rgba_to_i420_converter.exe");
-#else
-    FILE_PATH_LITERAL("rgba_to_i420_converter");
-#endif
-
 static const base::FilePath::CharType kCapturedYuvFileName[] =
     FILE_PATH_LITERAL("captured_video.yuv");
+static const base::FilePath::CharType kCapturedWebmFileName[] =
+    FILE_PATH_LITERAL("captured_video.webm");
 static const base::FilePath::CharType kStatsFileName[] =
     FILE_PATH_LITERAL("stats.txt");
 static const char kMainWebrtcTestHtmlPage[] =
@@ -132,65 +127,50 @@
     command_line->AppendSwitch(switches::kUseGpuInTests);
   }
 
-  // Writes all frames we've captured so far by grabbing them from the
-  // javascript and writing them to the temporary work directory.
-  void WriteCapturedFramesToWorkingDir(content::WebContents* capturing_tab) {
-    int num_frames = 0;
-    std::string response =
-        ExecuteJavascript("getTotalNumberCapturedFrames()", capturing_tab);
-    ASSERT_TRUE(base::StringToInt(response, &num_frames)) <<
-        "Failed to retrieve frame count: got " << response;
-    ASSERT_NE(0, num_frames) << "Failed to capture any frames.";
-
-    for (int i = 0; i < num_frames; i++) {
-      std::string base64_encoded_frame =
-          ExecuteJavascript(base::StringPrintf("getOneCapturedFrame(%d)", i),
-                            capturing_tab);
-      std::string decoded_frame;
-      ASSERT_TRUE(base::Base64Decode(base64_encoded_frame, &decoded_frame))
-          << "Failed to decode frame data '" << base64_encoded_frame << "'.";
-
-      std::string file_name = base::StringPrintf("frame_%04d", i);
-      base::File frame_file(GetWorkingDir().AppendASCII(file_name),
-                            base::File::FLAG_CREATE | base::File::FLAG_WRITE);
-      size_t written = frame_file.Write(0, decoded_frame.c_str(),
-                                        decoded_frame.length());
-      ASSERT_EQ(decoded_frame.length(), written);
-    }
+  // Writes the captured video to a webm file.
+  void WriteCapturedWebmVideo(content::WebContents* capturing_tab,
+                              const base::FilePath& webm_video_filename) {
+    std::string base64_encoded_video =
+        ExecuteJavascript("getRecordedVideoAsBase64()", capturing_tab);
+    std::string recorded_video;
+    ASSERT_TRUE(base::Base64Decode(base64_encoded_video, &recorded_video));
+    base::File video_file(webm_video_filename,
+                          base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+    size_t written =
+        video_file.Write(0, recorded_video.c_str(), recorded_video.length());
+    ASSERT_EQ(recorded_video.length(), written);
   }
 
-  // Runs the RGBA to I420 converter on the video in |capture_video_filename|,
-  // which should contain frames of size |width| x |height|.
-  //
-  // The rgba_to_i420_converter is part of the webrtc_test_tools target which
-  // should be build prior to running this test. The resulting binary should
-  // live next to Chrome.
-  bool RunARGBtoI420Converter(int width,
-                              int height,
-                              const base::FilePath& captured_video_filename) {
-    base::FilePath path_to_converter =
-        GetBrowserDir().Append(kArgbToI420ConverterExecutable);
-
-    if (!base::PathExists(path_to_converter)) {
-      LOG(ERROR) << "Missing ARGB->I420 converter: should be in "
-          << path_to_converter.value()
-          << ". Try building the chromium_builder_webrtc target.";
+  // Runs ffmpeg on the captured webm video and writes it to a yuv video file.
+  bool RunWebmToI420Converter(const base::FilePath& webm_video_filename,
+                              const base::FilePath& yuv_video_filename,
+                              const int width,
+                              const int height) {
+    base::FilePath path_to_ffmpeg = test::GetToolForPlatform("ffmpeg");
+    if (!base::PathExists(path_to_ffmpeg)) {
+      LOG(ERROR) << "Missing ffmpeg: should be in " << path_to_ffmpeg.value();
       return false;
     }
 
-    base::CommandLine converter_command(path_to_converter);
-    converter_command.AppendSwitchPath("--frames_dir", GetWorkingDir());
-    converter_command.AppendSwitchPath("--output_file",
-                                       captured_video_filename);
-    converter_command.AppendSwitchASCII("--width", base::IntToString(width));
-    converter_command.AppendSwitchASCII("--height", base::IntToString(height));
-    converter_command.AppendSwitchASCII("--delete_frames", "true");
+    // Set up ffmpeg to output at a certain resolution (-s) and bitrate (-b:v).
+    // This is needed because WebRTC is free to start the call at a lower
+    // resolution before ramping up. Without these flags, ffmpeg would output a
+    // video in the inital lower resolution, causing the SSIM and PSNR results
+    // to become meaningless.
+    base::CommandLine ffmpeg_command(path_to_ffmpeg);
+    ffmpeg_command.AppendArg("-i");
+    ffmpeg_command.AppendArgPath(webm_video_filename);
+    ffmpeg_command.AppendArg("-s");
+    ffmpeg_command.AppendArg(base::StringPrintf("%dx%d", width, height));
+    ffmpeg_command.AppendArg("-b:v");
+    ffmpeg_command.AppendArg(base::StringPrintf("%d", 120 * width * height));
+    ffmpeg_command.AppendArgPath(yuv_video_filename);
 
     // We produce an output file that will later be used as an input to the
     // barcode decoder and frame analyzer tools.
-    DVLOG(0) << "Running " << converter_command.GetCommandLineString();
+    DVLOG(0) << "Running " << ffmpeg_command.GetCommandLineString();
     std::string result;
-    bool ok = base::GetAppOutput(converter_command, &result);
+    bool ok = base::GetAppOutputAndError(ffmpeg_command, &result);
     DVLOG(0) << "Output was:\n\n" << result;
     return ok;
   }
@@ -309,7 +289,8 @@
 
     HangUp(left_tab);
 
-    WriteCapturedFramesToWorkingDir(right_tab);
+    WriteCapturedWebmVideo(right_tab,
+                           GetWorkingDir().Append(kCapturedWebmFileName));
 
     // Shut everything down to avoid having the javascript race with the
     // analysis tools. For instance, dont have console log printouts interleave
@@ -317,9 +298,9 @@
     chrome::CloseWebContents(browser(), left_tab, false);
     chrome::CloseWebContents(browser(), right_tab, false);
 
-    ASSERT_TRUE(
-        RunARGBtoI420Converter(test_config_.width, test_config_.height,
-                               GetWorkingDir().Append(kCapturedYuvFileName)));
+    RunWebmToI420Converter(GetWorkingDir().Append(kCapturedWebmFileName),
+                           GetWorkingDir().Append(kCapturedYuvFileName),
+                           test_config_.width, test_config_.height);
 
     ASSERT_TRUE(CompareVideosAndPrintResult(
         MakeLabel(test_config_.test_name, video_codec), test_config_.width,
diff --git a/chrome/browser/net/spdyproxy/data_reduction_promo_infobar_delegate_android.cc b/chrome/browser/net/spdyproxy/data_reduction_promo_infobar_delegate_android.cc
index 57acc7b4..a570c62 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_promo_infobar_delegate_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_promo_infobar_delegate_android.cc
@@ -11,6 +11,8 @@
 #include "jni/DataReductionPromoInfoBarDelegate_jni.h"
 #include "ui/base/l10n/l10n_util.h"
 
+using base::android::JavaParamRef;
+
 // static
 void DataReductionPromoInfoBarDelegateAndroid::Create(
     content::WebContents* web_contents) {
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
index 013b5931..aeaef84 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
@@ -25,6 +25,7 @@
 
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using data_reduction_proxy::DataReductionProxySettings;
 
diff --git a/chrome/browser/notifications/notification_platform_bridge_android.cc b/chrome/browser/notifications/notification_platform_bridge_android.cc
index 4261433..3dd82ff 100644
--- a/chrome/browser/notifications/notification_platform_bridge_android.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_android.cc
@@ -35,6 +35,8 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace {
 
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index dc6c99b..cdb28959 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -21,6 +21,7 @@
 #include "components/image_fetcher/image_fetcher_impl.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
+#include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
 #include "components/ntp_snippets/ntp_snippets_database.h"
 #include "components/ntp_snippets/ntp_snippets_fetcher.h"
@@ -95,13 +96,12 @@
   Profile* profile = Profile::FromBrowserContext(context);
 
   // Create the ContentSuggestionsService.
-  State enabled = State::DISABLED;
-#if defined(OS_ANDROID)
-  if (base::FeatureList::IsEnabled(chrome::android::kNTPSnippetsFeature))
-    enabled = State::ENABLED;
-#endif  // OS_ANDROID
-  ContentSuggestionsService* service = new ContentSuggestionsService(enabled);
-  if (enabled == State::DISABLED)
+  State state =
+      base::FeatureList::IsEnabled(ntp_snippets::kContentSuggestionsFeature)
+          ? State::ENABLED
+          : State::DISABLED;
+  ContentSuggestionsService* service = new ContentSuggestionsService(state);
+  if (state == State::DISABLED)
     return service;
 
 // Create the OfflinePageSuggestionsProvider.
diff --git a/chrome/browser/password_manager/account_chooser_dialog_android.cc b/chrome/browser/password_manager/account_chooser_dialog_android.cc
index 5f27e2f..4891a58 100644
--- a/chrome/browser/password_manager/account_chooser_dialog_android.cc
+++ b/chrome/browser/password_manager/account_chooser_dialog_android.cc
@@ -31,6 +31,8 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace {
 
diff --git a/chrome/browser/password_manager/credential_manager_browsertest.cc b/chrome/browser/password_manager/credential_manager_browsertest.cc
index 9660f51e..2e8dc79 100644
--- a/chrome/browser/password_manager/credential_manager_browsertest.cc
+++ b/chrome/browser/password_manager/credential_manager_browsertest.cc
@@ -144,15 +144,11 @@
   "document.getElementById('password_field').value = 'trash';";
   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_password));
 
-  // Call the API with a delay to trigger the notification to the client. The
-  // delay ensures that parsing password forms won't happen again after the API
-  // call making the test flaky.
+  // Call the API to trigger the notification to the client.
   ASSERT_TRUE(content::ExecuteScript(
       RenderViewHost(),
-      "setTimeout( function() {"
-        "navigator.credentials.get({password: true})"
-        ".then(cred => window.location = '/password/done.html');"
-      "}, 1000)"));
+      "navigator.credentials.get({password: true})"
+      ".then(cred => window.location = '/password/done.html');"));
 
   NavigationObserver observer(WebContents());
   observer.SetPathToWaitFor("/password/done.html");
@@ -160,31 +156,23 @@
 
   std::unique_ptr<BubbleObserver> prompt_observer(
       new BubbleObserver(WebContents()));
-  // The autofill password manager shouldn't react to the successful login.
+  // The autofill password manager shouldn't react to the successful login
+  // because it was suppressed when the site got the credential back.
   EXPECT_FALSE(prompt_observer->IsShowingSavePrompt());
 }
 
 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, SaveViaAPIAndAutofill) {
   NavigateToFile("/password/password_form.html");
 
-  // Postpone a submit event for 1 second. Even for the static html page Chrome
-  // continues to parse and recreate the PasswordFormManager instances after the
-  // page load. Calling the API before this would make the test flaky. Clicking
-  // on the button emulates server analysing the credential and then saving and
-  // navigating to the landing page.
   ASSERT_TRUE(content::ExecuteScript(
       RenderViewHost(),
       "document.getElementById('input_submit_button').addEventListener('click',"
       "function(event) {"
-        "setTimeout( function() {"
-          "var c = new PasswordCredential({ id: 'user', password: 'API' });"
-          "navigator.credentials.store(c);"
-          "document.getElementById('testform').submit();"
-        "}, 1000 );"
-        "event.preventDefault();"
+        "var c = new PasswordCredential({ id: 'user', password: 'API' });"
+        "navigator.credentials.store(c);"
       "});"));
-  // Fill the password and click the button to submit the page later. The API
-  // should suppress the autofill password manager.
+  // Fill the password and click the button to submit the page. The API should
+  // suppress the autofill password manager.
   NavigationObserver form_submit_observer(WebContents());
   ASSERT_TRUE(content::ExecuteScript(
       RenderViewHost(),
@@ -232,21 +220,12 @@
 
   NavigateToFile("/password/password_form.html");
 
-  // Postpone a submit event for 1 second. Even for the static html page Chrome
-  // continues to parse and recreate the PasswordFormManager instances after the
-  // page load. Calling the API before this would make the test flaky. Clicking
-  // on the button emulates server analysing the credential and then saving and
-  // navigating to the landing page.
   ASSERT_TRUE(content::ExecuteScript(
       RenderViewHost(),
       "document.getElementById('input_submit_button').addEventListener('click',"
       "function(event) {"
-        "setTimeout( function() {"
-          "var c = new PasswordCredential({ id: 'user', password: 'API' });"
-          "navigator.credentials.store(c);"
-          "document.getElementById('testform').submit();"
-        "}, 1000 );"
-        "event.preventDefault();"
+        "var c = new PasswordCredential({ id: 'user', password: 'API' });"
+        "navigator.credentials.store(c);"
       "});"));
   // Fill the new password and click the button to submit the page later. The
   // API should suppress the autofill password manager and overwrite the
diff --git a/chrome/browser/permissions/permission_update_infobar_delegate_android.cc b/chrome/browser/permissions/permission_update_infobar_delegate_android.cc
index 453bc8c..e1c22fa1 100644
--- a/chrome/browser/permissions/permission_update_infobar_delegate_android.cc
+++ b/chrome/browser/permissions/permission_update_infobar_delegate_android.cc
@@ -20,6 +20,8 @@
 #include "ui/android/window_android.h"
 #include "ui/base/l10n/l10n_util.h"
 
+using base::android::JavaParamRef;
+
 // static
 infobars::InfoBar* PermissionUpdateInfoBarDelegate::Create(
     content::WebContents* web_contents,
diff --git a/chrome/browser/platform_util_android.cc b/chrome/browser/platform_util_android.cc
index 816e20e..1880a8e 100644
--- a/chrome/browser/platform_util_android.cc
+++ b/chrome/browser/platform_util_android.cc
@@ -12,6 +12,8 @@
 #include "ui/android/view_android.h"
 #include "url/gurl.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace platform_util {
 
 // TODO: crbug/115682 to track implementation of the following methods.
diff --git a/chrome/browser/prerender/external_prerender_handler_android.cc b/chrome/browser/prerender/external_prerender_handler_android.cc
index 9f60ba0..012c9017 100644
--- a/chrome/browser/prerender/external_prerender_handler_android.cc
+++ b/chrome/browser/prerender/external_prerender_handler_android.cc
@@ -19,6 +19,7 @@
 #include "net/base/network_change_notifier.h"
 
 using base::android::ConvertJavaStringToUTF16;
+using base::android::JavaParamRef;
 
 namespace prerender {
 
diff --git a/chrome/browser/profiles/profile_android.cc b/chrome/browser/profiles/profile_android.cc
index 2ec4bbb..2a49844 100644
--- a/chrome/browser/profiles/profile_android.cc
+++ b/chrome/browser/profiles/profile_android.cc
@@ -11,6 +11,8 @@
 #include "jni/Profile_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace {
 const char kProfileAndroidKey[] = "profile_android";
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc
index cd5b4409..42021753 100644
--- a/chrome/browser/push_messaging/push_messaging_browsertest.cc
+++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -420,7 +420,7 @@
   RequestAndDenyPermission();
 
   ASSERT_TRUE(RunScript("documentSubscribePush()", &script_result));
-  EXPECT_EQ("PermissionDeniedError - Registration failed - permission denied",
+  EXPECT_EQ("NotAllowedError - Registration failed - permission denied",
             script_result);
 }
 
@@ -470,7 +470,7 @@
   RequestAndAcceptPermission();
 
   ASSERT_TRUE(RunScript("documentSubscribePush()", &script_result));
-  EXPECT_EQ("PermissionDeniedError - Registration failed - permission denied",
+  EXPECT_EQ("NotAllowedError - Registration failed - permission denied",
             script_result);
 }
 
@@ -1086,7 +1086,7 @@
   RequestAndDenyPermission();
 
   ASSERT_TRUE(RunScript("documentSubscribePush()", &script_result));
-  EXPECT_EQ("PermissionDeniedError - Registration failed - permission denied",
+  EXPECT_EQ("NotAllowedError - Registration failed - permission denied",
             script_result);
 
   ASSERT_TRUE(RunScript("permissionState()", &script_result));
diff --git a/chrome/browser/resources/chromeos/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
index 8eefdfb..717722b 100644
--- a/chrome/browser/resources/chromeos/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
@@ -342,6 +342,26 @@
     "//content/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
+    "//ui/keyboard:resources",
+  ]
+
+  data = [
+    "$root_out_dir/chrome_100_percent.pak",
+    "$root_out_dir/chrome_200_percent.pak",
+    "$root_out_dir/locales/en-US.pak",
+    "$root_out_dir/locales/fr.pak",
+    "$root_out_dir/resources.pak",
+    "$root_out_dir/resources/chromeos/chromevox/",
+    "$root_out_dir/test_data/chrome/browser/resources/chromeos/chromevox/",
+
+    # Surprisingly, the test uses data from the original location, not the
+    # copied one.
+    "//chrome/browser/resources/chromeos/chromevox/",
+    "//chrome/test/data/webui/test_api.js",
+    "//chrome/third_party/chromevox/",
+    "//chrome/third_party/mock4js/",
+    "//third_party/accessibility-audit/axs_testing.js",
+    "//third_party/chaijs/chai.js",
   ]
 }
 
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
index ecd5810..9bb0912 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
@@ -425,7 +425,7 @@
   ],
 
   ready: function() {
-    this.elementReadyTimeMs_ = performance.now();
+    this.elementReadyTimeMs_ = window.performance.now();
     this.showSinkList_();
 
     Polymer.RenderStatus.afterNextRender(this, function() {
@@ -519,7 +519,7 @@
     });
 
     if (initialAction == media_router.MediaRouterUserAction.CLOSE) {
-      var timeToClose = performance.now() - this.elementReadyTimeMs_;
+      var timeToClose = window.performance.now() - this.elementReadyTimeMs_;
       this.fire('report-initial-action-close', {
         timeMs: timeToClose,
       });
@@ -1320,7 +1320,7 @@
         sinksToShow.length != 0) {
       // Only set |populatedSinkListSeenTimeMs_| if it has not already been set.
       if (this.populatedSinkListSeenTimeMs_ == -1)
-        this.populatedSinkListSeenTimeMs_ = performance.now();
+        this.populatedSinkListSeenTimeMs_ = window.performance.now();
     } else {
       // Reset |populatedSinkListLastSeen_| if the sink list isn't being shown
       // or if there aren't any sinks available for display.
@@ -2225,7 +2225,7 @@
         });
 
         var timeToSelectSink =
-            performance.now() - this.populatedSinkListSeenTimeMs_;
+            window.performance.now() - this.populatedSinkListSeenTimeMs_;
         this.fire('report-sink-click-time', {timeMs: timeToSelectSink});
       }
       if (!this.launchingSinkAwaitingRouteClose_) {
diff --git a/chrome/browser/resources/media_router/externs.js b/chrome/browser/resources/media_router/externs.js
index bbfb4b8..9e7ccd8 100644
--- a/chrome/browser/resources/media_router/externs.js
+++ b/chrome/browser/resources/media_router/externs.js
@@ -2,18 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/**
- * @fileoverview Externs to be declared to properly compile JS code.
- * @externs
- */
-
-var performance = {};
-
-/**
- * @return {number}
- */
-performance.now = function() {};
-
 /** @interface */
 var InputDeviceCapabilities;
 
diff --git a/chrome/browser/resources/settings/search_settings.js b/chrome/browser/resources/settings/search_settings.js
index 4d195ce..f001427 100644
--- a/chrome/browser/resources/settings/search_settings.js
+++ b/chrome/browser/resources/settings/search_settings.js
@@ -100,7 +100,7 @@
    * ensures that <settings-section> instances become visible if any matches
    * occurred under their subtree.
    *
-   * @param {!settings.SearchRequest} request
+   * @param {!SearchRequest} request
    * @param {!Node} root The root of the sub-tree to be searched
    * @private
    */
@@ -167,11 +167,11 @@
   /**
    * @constructor
    *
-   * @param {!settings.SearchRequest} request
+   * @param {!SearchRequest} request
    * @param {!Node} node
    */
   function Task(request, node) {
-    /** @protected {!settings.SearchRequest} */
+    /** @protected {!SearchRequest} */
     this.request = request;
 
     /** @protected {!Node} */
@@ -193,7 +193,7 @@
    * @constructor
    * @extends {Task}
    *
-   * @param {!settings.SearchRequest} request
+   * @param {!SearchRequest} request
    * @param {!Node} node
    */
   function RenderTask(request, node) {
@@ -227,7 +227,7 @@
    * @constructor
    * @extends {Task}
    *
-   * @param {!settings.SearchRequest} request
+   * @param {!SearchRequest} request
    * @param {!Node} node
    */
   function SearchAndHighlightTask(request, node) {
@@ -247,7 +247,7 @@
    * @constructor
    * @extends {Task}
    *
-   * @param {!settings.SearchRequest} request
+   * @param {!SearchRequest} request
    * @param {!Node} page
    */
   function TopLevelSearchTask(request, page) {
@@ -454,25 +454,11 @@
     },
   };
 
-  /** @interface */
-  var SearchManager = function() {};
-
-  SearchManager.prototype = {
-    /**
-     * @param {string} text The text to search for.
-     * @param {!Node} page
-     * @return {!Promise<!settings.SearchRequest>} A signal indicating that
-     *     searching finished.
-     */
-    search: function(text, page) {}
-  };
-
   /**
    * @constructor
-   * @implements {SearchManager}
    */
-  var SearchManagerImpl = function() {
-    /** @private {?settings.SearchRequest} */
+  var SearchManager = function() {
+    /** @private {?SearchRequest} */
     this.activeRequest_ = null;
 
     /** @private {!TaskQueue} */
@@ -483,15 +469,20 @@
       this.activeRequest_ = null;
     }.bind(this));
   };
-  cr.addSingletonGetter(SearchManagerImpl);
+  cr.addSingletonGetter(SearchManager);
 
-  SearchManagerImpl.prototype = {
-    /** @override */
+  SearchManager.prototype = {
+    /**
+     * @param {string} text The text to search for.
+     * @param {!Node} page
+     * @return {!Promise<!SearchRequest>} A signal indicating that searching
+     *     finished.
+     */
     search: function(text, page) {
       // Creating a new request only if the |text| changed.
       if (!this.activeRequest_ || !this.activeRequest_.isSame(text)) {
         // Resolving previous search request without marking it as
-        // 'finished', if any, and dropping all pending tasks.
+        // 'finisthed', if any, and droping all pending tasks.
         this.queue_.reset();
         if (this.activeRequest_)
           this.activeRequest_.resolver.resolve(this.activeRequest_);
@@ -508,20 +499,10 @@
 
   /** @return {!SearchManager} */
   function getSearchManager() {
-    return SearchManagerImpl.getInstance();
-  }
-
-  /**
-   * Sets the SearchManager singleton instance, useful for testing.
-   * @param {!SearchManager} searchManager
-   */
-  function setSearchManagerForTesting(searchManager) {
-    SearchManagerImpl.instance_ = searchManager;
+    return SearchManager.getInstance();
   }
 
   return {
     getSearchManager: getSearchManager,
-    setSearchManagerForTesting: setSearchManagerForTesting,
-    SearchRequest: SearchRequest,
   };
 });
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index 5b4e489..e18bfb2 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -1,6 +1,5 @@
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/html/promise_resolver.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="/about_page/about_page.html">
 <link rel="import" href="/advanced_page/advanced_page.html">
@@ -40,20 +39,20 @@
         -webkit-margin-start: 16px;
       }
 
-      #noSearchResults {
+      #no-search-results {
         align-items: center;
         display: flex;
         flex-direction: column;
         margin-top: 80px;
       }
 
-      #noSearchResults div:first-child {
+      #no-search-results div:first-child {
         font-size: 120%;
         margin-bottom: 10px;
       }
     </style>
     <content select="paper-icon-button"></content>
-    <div id="noSearchResults" hidden$="[[!showNoResultsFound_]]">
+    <div id="no-search-results" hidden$="[[!showNoResultsFound_]]">
       <div>$i18n{searchNoResults}</div>
       <div>$i18nRaw{searchNoResultsHelp}</div>
     </div>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js
index 30eb7448..c840fbe 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.js
+++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -206,7 +206,6 @@
 
   /**
    * @param {string} query
-   * @return {!Promise} A promise indicating that searching finished.
    */
   searchContents: function(query) {
     this.ensureInDefaultSearchPage_();
@@ -215,30 +214,26 @@
     // Trigger rendering of the basic and advanced pages and search once ready.
     this.showPages_ = {about: false, basic: true, advanced: true};
 
-    return new Promise(function(resolve, reject) {
-      setTimeout(function() {
-        var whenSearchDone = settings.getSearchManager().search(
-            query, assert(this.$$('settings-basic-page')));
-        assert(
-            whenSearchDone ===
-                settings.getSearchManager().search(
-                    query, assert(this.$$('settings-advanced-page'))));
+    setTimeout(function() {
+      settings.getSearchManager().search(
+          query, assert(this.$$('settings-basic-page')));
+    }.bind(this), 0);
+    setTimeout(function() {
+      settings.getSearchManager().search(
+          query, assert(this.$$('settings-advanced-page'))).then(
+          function(request) {
+            if (!request.finished) {
+              // Nothing to do here. A previous search request was canceled
+              // because a new search request was issued before the first one
+              // completed.
+              return;
+            }
 
-        whenSearchDone.then(function(request) {
-          resolve();
-          if (!request.finished) {
-            // Nothing to do here. A previous search request was canceled
-            // because a new search request was issued before the first one
-            // completed.
-            return;
-          }
-
-          this.toolbarSpinnerActive = false;
-          this.showNoResultsFound_ =
-              !request.isSame('') && !request.didFindMatches();
-        }.bind(this));
-      }.bind(this), 0);
-    }.bind(this));
+            this.toolbarSpinnerActive = false;
+            this.showNoResultsFound_ =
+                !request.isSame('') && !request.didFindMatches();
+          }.bind(this));
+    }.bind(this), 0);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/settings_page/main_page_behavior.js b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
index e17f8809..c6844a9 100644
--- a/chrome/browser/resources/settings/settings_page/main_page_behavior.js
+++ b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
@@ -41,10 +41,7 @@
 
   /** @override */
   attached: function() {
-    if (this.domHost && this.domHost.parentNode.tagName == 'PAPER-HEADER-PANEL')
-      this.scroller = this.domHost.parentNode.$.mainContainer;
-    else
-      this.scroller = document.body; // Used in unit tests.
+    this.scroller = this.domHost && this.domHost.parentNode.$.mainContainer;
   },
 
   /**
diff --git a/chrome/browser/search_engines/template_url_service_android.cc b/chrome/browser/search_engines/template_url_service_android.cc
index fa47ef5..f56f756 100644
--- a/chrome/browser/search_engines/template_url_service_android.cc
+++ b/chrome/browser/search_engines/template_url_service_android.cc
@@ -22,6 +22,9 @@
 #include "jni/TemplateUrlService_jni.h"
 #include "net/base/url_util.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace {
 
 Profile* GetOriginalProfile() {
diff --git a/chrome/browser/signin/oauth2_token_service_delegate_android.cc b/chrome/browser/signin/oauth2_token_service_delegate_android.cc
index fbf23f8..39638d96 100644
--- a/chrome/browser/signin/oauth2_token_service_delegate_android.cc
+++ b/chrome/browser/signin/oauth2_token_service_delegate_android.cc
@@ -25,6 +25,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::BrowserThread;
 
diff --git a/chrome/browser/speech/tts_android.cc b/chrome/browser/speech/tts_android.cc
index 3d22831..18a4e1be 100644
--- a/chrome/browser/speech/tts_android.cc
+++ b/chrome/browser/speech/tts_android.cc
@@ -15,6 +15,7 @@
 #include "jni/TtsPlatformImpl_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 
 // static
 TtsPlatformImpl* TtsPlatformImpl::GetInstance() {
diff --git a/chrome/browser/spellchecker/spellchecker_session_bridge_android.cc b/chrome/browser/spellchecker/spellchecker_session_bridge_android.cc
index 30958b0..3392176 100644
--- a/chrome/browser/spellchecker/spellchecker_session_bridge_android.cc
+++ b/chrome/browser/spellchecker/spellchecker_session_bridge_android.cc
@@ -14,6 +14,8 @@
 #include "content/public/browser/render_process_host.h"
 #include "jni/SpellCheckerSessionBridge_jni.h"
 
+using base::android::JavaParamRef;
+
 SpellCheckerSessionBridge::SpellCheckerSessionBridge(int render_process_id)
     : render_process_id_(render_process_id) {}
 
diff --git a/chrome/browser/ssl/security_state_model_android.cc b/chrome/browser/ssl/security_state_model_android.cc
index c7eea43..b861e67 100644
--- a/chrome/browser/ssl/security_state_model_android.cc
+++ b/chrome/browser/ssl/security_state_model_android.cc
@@ -9,6 +9,8 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/SecurityStateModel_jni.h"
 
+using base::android::JavaParamRef;
+
 // static
 bool RegisterSecurityStateModelAndroid(JNIEnv* env) {
   return RegisterNativesImpl(env);
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_feedback_reporter_android.cc b/chrome/browser/supervised_user/child_accounts/child_account_feedback_reporter_android.cc
index eeb6da0..01fd20ef 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_feedback_reporter_android.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_feedback_reporter_android.cc
@@ -12,6 +12,8 @@
 #include "ui/android/window_android.h"
 #include "url/gurl.h"
 
+using base::android::ScopedJavaLocalRef;
+
 void ReportChildAccountFeedback(content::WebContents* web_contents,
                                 const std::string& description,
                                 const GURL& url) {
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service_android.cc b/chrome/browser/supervised_user/child_accounts/child_account_service_android.cc
index 6d23de9..7d0e932 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service_android.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service_android.cc
@@ -9,6 +9,8 @@
 #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
 #include "jni/ChildAccountService_jni.h"
 
+using base::android::JavaParamRef;
+
 jboolean IsChildAccountDetectionEnabled(JNIEnv* env,
                                         const JavaParamRef<jclass>& jcaller) {
   return ChildAccountService::IsChildAccountDetectionEnabled();
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index 0b8bf444..8ecf44bc 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -46,6 +46,7 @@
 using base::android::CheckException;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::BrowserThread;
 
diff --git a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
index 7590656..01592b4 100644
--- a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
+++ b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view.cc
@@ -20,6 +20,9 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/geometry/rect.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace autofill {
 
 namespace {
diff --git a/chrome/browser/ui/android/autofill/autofill_logger_android.cc b/chrome/browser/ui/android/autofill/autofill_logger_android.cc
index 451630f..04be3a5 100644
--- a/chrome/browser/ui/android/autofill/autofill_logger_android.cc
+++ b/chrome/browser/ui/android/autofill/autofill_logger_android.cc
@@ -6,6 +6,8 @@
 
 #include "jni/AutofillLogger_jni.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace autofill {
 
 void AutofillLoggerAndroid::DidFillOrPreviewField(
diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
index 02bcfdd2..11f2514 100644
--- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
+++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
@@ -23,6 +23,9 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/geometry/rect_f.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace autofill {
 
 AutofillPopupViewAndroid::AutofillPopupViewAndroid(
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
index 9229486..46c905f 100644
--- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
+++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
@@ -12,6 +12,9 @@
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace autofill {
 
 CardUnmaskPromptView* CreateCardUnmaskPromptView(
diff --git a/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc b/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc
index 7d9a0d0..576f1d0 100644
--- a/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc
+++ b/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc
@@ -17,6 +17,8 @@
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
 
+using base::android::JavaParamRef;
+
 namespace autofill {
 
 // static
diff --git a/chrome/browser/ui/android/autofill/password_generation_popup_view_android.cc b/chrome/browser/ui/android/autofill/password_generation_popup_view_android.cc
index a0f48c6..3558643 100644
--- a/chrome/browser/ui/android/autofill/password_generation_popup_view_android.cc
+++ b/chrome/browser/ui/android/autofill/password_generation_popup_view_android.cc
@@ -19,6 +19,9 @@
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/range/range.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace autofill {
 
 PasswordGenerationPopupViewAndroid::PasswordGenerationPopupViewAndroid(
diff --git a/chrome/browser/ui/android/bluetooth_chooser_android.cc b/chrome/browser/ui/android/bluetooth_chooser_android.cc
index 66c752e1..a74e7088 100644
--- a/chrome/browser/ui/android/bluetooth_chooser_android.cc
+++ b/chrome/browser/ui/android/bluetooth_chooser_android.cc
@@ -20,6 +20,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 BluetoothChooserAndroid::BluetoothChooserAndroid(
diff --git a/chrome/browser/ui/android/certificate_viewer_android.cc b/chrome/browser/ui/android/certificate_viewer_android.cc
index fa227701..f900c50 100644
--- a/chrome/browser/ui/android/certificate_viewer_android.cc
+++ b/chrome/browser/ui/android/certificate_viewer_android.cc
@@ -12,6 +12,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 void ShowCertificateViewer(content::WebContents* web_contents,
diff --git a/chrome/browser/ui/android/chrome_http_auth_handler.cc b/chrome/browser/ui/android/chrome_http_auth_handler.cc
index 768558dac..fd484e8 100644
--- a/chrome/browser/ui/android/chrome_http_auth_handler.cc
+++ b/chrome/browser/ui/android/chrome_http_auth_handler.cc
@@ -20,6 +20,7 @@
 using base::android::CheckException;
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 ChromeHttpAuthHandler::ChromeHttpAuthHandler(const base::string16& authority,
diff --git a/chrome/browser/ui/android/connection_info_popup_android.cc b/chrome/browser/ui/android/connection_info_popup_android.cc
index 081e50c..b0bf613 100644
--- a/chrome/browser/ui/android/connection_info_popup_android.cc
+++ b/chrome/browser/ui/android/connection_info_popup_android.cc
@@ -29,6 +29,7 @@
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::GetClass;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using content::CertStore;
 using content::WebContents;
diff --git a/chrome/browser/ui/android/context_menu_helper.cc b/chrome/browser/ui/android/context_menu_helper.cc
index 968180f..5d6b16c 100644
--- a/chrome/browser/ui/android/context_menu_helper.cc
+++ b/chrome/browser/ui/android/context_menu_helper.cc
@@ -24,6 +24,7 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ContextMenuHelper);
 
diff --git a/chrome/browser/ui/android/infobars/autofill_save_card_infobar.cc b/chrome/browser/ui/android/infobars/autofill_save_card_infobar.cc
index d78132d1..27d79ba 100644
--- a/chrome/browser/ui/android/infobars/autofill_save_card_infobar.cc
+++ b/chrome/browser/ui/android/infobars/autofill_save_card_infobar.cc
@@ -19,6 +19,8 @@
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace autofill {
 
 std::unique_ptr<infobars::InfoBar> CreateSaveCardInfoBarMobile(
diff --git a/chrome/browser/ui/android/infobars/confirm_infobar.cc b/chrome/browser/ui/android/infobars/confirm_infobar.cc
index 6f86df2..321eead 100644
--- a/chrome/browser/ui/android/infobars/confirm_infobar.cc
+++ b/chrome/browser/ui/android/infobars/confirm_infobar.cc
@@ -26,6 +26,9 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/image/image.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 // InfoBarService -------------------------------------------------------------
 
 std::unique_ptr<infobars::InfoBar> InfoBarService::CreateConfirmInfoBar(
diff --git a/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc b/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc
index be51215..d7c5329 100644
--- a/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc
+++ b/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/android/download/download_overwrite_infobar_delegate.h"
 #include "jni/DownloadOverwriteInfoBar_jni.h"
 
+using base::android::ScopedJavaLocalRef;
 using chrome::android::DownloadOverwriteInfoBarDelegate;
 
 // static
diff --git a/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc b/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
index 86bc042..a050021 100644
--- a/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
+++ b/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
@@ -13,6 +13,8 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/GeneratedPasswordSavedInfoBarDelegate_jni.h"
 
+using base::android::JavaParamRef;
+
 // static
 void GeneratedPasswordSavedInfoBarDelegateAndroid::Create(
     content::WebContents* web_contents) {
diff --git a/chrome/browser/ui/android/infobars/infobar_android.cc b/chrome/browser/ui/android/infobars/infobar_android.cc
index 5715cf4..ddf6d3c7 100644
--- a/chrome/browser/ui/android/infobars/infobar_android.cc
+++ b/chrome/browser/ui/android/infobars/infobar_android.cc
@@ -15,6 +15,7 @@
 #include "components/infobars/core/infobar_delegate.h"
 #include "jni/InfoBar_jni.h"
 
+using base::android::JavaParamRef;
 
 // InfoBarAndroid -------------------------------------------------------------
 
diff --git a/chrome/browser/ui/android/infobars/infobar_container_android.cc b/chrome/browser/ui/android/infobars/infobar_container_android.cc
index 2f88a69..34ec186 100644
--- a/chrome/browser/ui/android/infobars/infobar_container_android.cc
+++ b/chrome/browser/ui/android/infobars/infobar_container_android.cc
@@ -14,6 +14,7 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/InfoBarContainer_jni.h"
 
+using base::android::JavaParamRef;
 
 // InfoBarContainerAndroid ----------------------------------------------------
 
diff --git a/chrome/browser/ui/android/infobars/save_password_infobar.cc b/chrome/browser/ui/android/infobars/save_password_infobar.cc
index e4659fc0..0c518ac 100644
--- a/chrome/browser/ui/android/infobars/save_password_infobar.cc
+++ b/chrome/browser/ui/android/infobars/save_password_infobar.cc
@@ -11,6 +11,8 @@
 #include "base/memory/ptr_util.h"
 #include "jni/SavePasswordInfoBar_jni.h"
 
+using base::android::JavaParamRef;
+
 SavePasswordInfoBar::SavePasswordInfoBar(
     std::unique_ptr<SavePasswordInfoBarDelegate> delegate)
     : ConfirmInfoBar(std::move(delegate)) {}
diff --git a/chrome/browser/ui/android/infobars/simple_confirm_infobar_builder.cc b/chrome/browser/ui/android/infobars/simple_confirm_infobar_builder.cc
index 36963bb..6869e49b 100644
--- a/chrome/browser/ui/android/infobars/simple_confirm_infobar_builder.cc
+++ b/chrome/browser/ui/android/infobars/simple_confirm_infobar_builder.cc
@@ -20,6 +20,8 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/vector_icons_public.h"
 
+using base::android::JavaParamRef;
+
 namespace {
 
 // Delegate for a simple ConfirmInfoBar triggered via JNI.
diff --git a/chrome/browser/ui/android/infobars/translate_infobar.cc b/chrome/browser/ui/android/infobars/translate_infobar.cc
index 21678b2..83aae0c7 100644
--- a/chrome/browser/ui/android/infobars/translate_infobar.cc
+++ b/chrome/browser/ui/android/infobars/translate_infobar.cc
@@ -17,6 +17,9 @@
 #include "components/translate/core/browser/translate_infobar_delegate.h"
 #include "jni/TranslateInfoBar_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 // ChromeTranslateClient
 // ----------------------------------------------------------
 
diff --git a/chrome/browser/ui/android/infobars/update_password_infobar.cc b/chrome/browser/ui/android/infobars/update_password_infobar.cc
index 771119c..cc3185e 100644
--- a/chrome/browser/ui/android/infobars/update_password_infobar.cc
+++ b/chrome/browser/ui/android/infobars/update_password_infobar.cc
@@ -13,6 +13,8 @@
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "jni/UpdatePasswordInfoBar_jni.h"
 
+using base::android::JavaParamRef;
+
 UpdatePasswordInfoBar::UpdatePasswordInfoBar(
     std::unique_ptr<UpdatePasswordInfoBarDelegate> delegate)
     : ConfirmInfoBar(std::move(delegate)) {}
diff --git a/chrome/browser/ui/android/javascript_app_modal_dialog_android.cc b/chrome/browser/ui/android/javascript_app_modal_dialog_android.cc
index 886df67..1942a72 100644
--- a/chrome/browser/ui/android/javascript_app_modal_dialog_android.cc
+++ b/chrome/browser/ui/android/javascript_app_modal_dialog_android.cc
@@ -22,6 +22,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 
diff --git a/chrome/browser/ui/android/omnibox/omnibox_url_emphasizer.cc b/chrome/browser/ui/android/omnibox/omnibox_url_emphasizer.cc
index fe2cb4f..edbcbb6 100644
--- a/chrome/browser/ui/android/omnibox/omnibox_url_emphasizer.cc
+++ b/chrome/browser/ui/android/omnibox/omnibox_url_emphasizer.cc
@@ -11,6 +11,9 @@
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "jni/OmniboxUrlEmphasizer_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 // static
 ScopedJavaLocalRef<jintArray> ParseForEmphasizeComponents(
     JNIEnv* env,
diff --git a/chrome/browser/ui/android/omnibox/omnibox_view_util.cc b/chrome/browser/ui/android/omnibox/omnibox_view_util.cc
index c80cccd..22c00e5 100644
--- a/chrome/browser/ui/android/omnibox/omnibox_view_util.cc
+++ b/chrome/browser/ui/android/omnibox/omnibox_view_util.cc
@@ -8,6 +8,9 @@
 #include "components/omnibox/browser/omnibox_view.h"
 #include "jni/OmniboxViewUtil_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 // static
 ScopedJavaLocalRef<jstring> SanitizeTextForPaste(
     JNIEnv* env,
diff --git a/chrome/browser/ui/android/snackbars/auto_signin_prompt_controller.cc b/chrome/browser/ui/android/snackbars/auto_signin_prompt_controller.cc
index 85cf421..432d017 100644
--- a/chrome/browser/ui/android/snackbars/auto_signin_prompt_controller.cc
+++ b/chrome/browser/ui/android/snackbars/auto_signin_prompt_controller.cc
@@ -14,6 +14,8 @@
 #include "jni/AutoSigninSnackbarController_jni.h"
 #include "ui/base/l10n/l10n_util.h"
 
+using base::android::ScopedJavaLocalRef;
+
 void ShowAutoSigninPrompt(content::WebContents* web_contents,
                           const base::string16& username) {
   base::string16 message = l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/ui/android/ssl_client_certificate_request.cc b/chrome/browser/ui/android/ssl_client_certificate_request.cc
index 55f5a44..0b5d9d3c 100644
--- a/chrome/browser/ui/android/ssl_client_certificate_request.cc
+++ b/chrome/browser/ui/android/ssl_client_certificate_request.cc
@@ -29,6 +29,9 @@
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace chrome {
 
 namespace {
diff --git a/chrome/browser/ui/android/tab_model/single_tab_model.cc b/chrome/browser/ui/android/tab_model/single_tab_model.cc
index b99af80..567c949 100644
--- a/chrome/browser/ui/android/tab_model/single_tab_model.cc
+++ b/chrome/browser/ui/android/tab_model/single_tab_model.cc
@@ -10,6 +10,8 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/SingleTabModel_jni.h"
 
+using base::android::JavaParamRef;
+
 static void PermanentlyBlockAllNewWindows(
     JNIEnv* env,
     const JavaParamRef<jclass>& clazz,
diff --git a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc
index ce6aad7..dd8f5cc 100644
--- a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc
+++ b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc
@@ -23,6 +23,8 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 using content::WebContents;
 
 namespace {
diff --git a/chrome/browser/ui/android/toolbar/toolbar_model_android.cc b/chrome/browser/ui/android/toolbar/toolbar_model_android.cc
index c53fca1..c43698f 100644
--- a/chrome/browser/ui/android/toolbar/toolbar_model_android.cc
+++ b/chrome/browser/ui/android/toolbar/toolbar_model_android.cc
@@ -18,6 +18,7 @@
 #include "jni/ToolbarModel_jni.h"
 #include "net/cert/x509_certificate.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 ToolbarModelAndroid::ToolbarModelAndroid(JNIEnv* env, jobject jdelegate)
diff --git a/chrome/browser/ui/android/website_settings_popup_android.cc b/chrome/browser/ui/android/website_settings_popup_android.cc
index 0706ef7..9281918 100644
--- a/chrome/browser/ui/android/website_settings_popup_android.cc
+++ b/chrome/browser/ui/android/website_settings_popup_android.cc
@@ -26,6 +26,7 @@
 
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 
 // static
 static jlong Init(JNIEnv* env,
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.h b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.h
index 115cb2f..af151567 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.h
+++ b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.h
@@ -10,13 +10,16 @@
 #include <memory>
 
 #import "base/mac/scoped_nsobject.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
+#include "chrome/browser/ui/avatar_button_error_controller.h"
+#include "chrome/browser/ui/avatar_button_error_controller_delegate.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/has_weak_browser_pointer.h"
 #include "components/signin/core/browser/signin_header_helper.h"
 
 @class BaseBubbleController;
 class Browser;
-class ProfileAttributesUpdateObserver;
+class ProfileUpdateObserver;
 
 // This view controller manages the button that sits in the top of the
 // window frame when using multi-profiles, and shows information about the
@@ -28,12 +31,13 @@
   // The avatar button. Child classes are responsible for implementing it.
   base::scoped_nsobject<NSButton> button_;
 
+  // Observer that listens for updates to the ProfileAttributesStorage as well
+  // as AvatarButtonErrorController.
+  std::unique_ptr<ProfileUpdateObserver> profileObserver_;
+
  @private
   // The menu controller, if the menu is open.
   BaseBubbleController* menuController_;
-
-  // Observer that listens for updates to the ProfileAttributesStorage.
-  std::unique_ptr<ProfileAttributesUpdateObserver> profileAttributesObserver_;
 }
 
 // The avatar button view.
@@ -56,4 +60,33 @@
 - (BOOL)isCtrlPressed;
 @end
 
+class ProfileUpdateObserver : public ProfileAttributesStorage::Observer,
+                              public AvatarButtonErrorControllerDelegate {
+ public:
+  ProfileUpdateObserver(Profile* profile,
+                        AvatarBaseController* avatarController);
+  ~ProfileUpdateObserver() override;
+
+  // ProfileAttributesStorage::Observer:
+  void OnProfileAdded(const base::FilePath& profile_path) override;
+  void OnProfileWasRemoved(const base::FilePath& profile_path,
+                           const base::string16& profile_name) override;
+  void OnProfileNameChanged(const base::FilePath& profile_path,
+                            const base::string16& old_profile_name) override;
+  void OnProfileSupervisedUserIdChanged(
+      const base::FilePath& profile_path) override;
+
+  // AvatarButtonErrorControllerDelegate:
+  void OnAvatarErrorChanged() override;
+
+  bool HasAvatarError();
+
+ private:
+  AvatarButtonErrorController errorController_;
+  Profile* profile_;
+  AvatarBaseController* avatarController_;  // Weak; owns this.
+
+  DISALLOW_COPY_AND_ASSIGN(ProfileUpdateObserver);
+};
+
 #endif  // CHROME_BROWSER_UI_COCOA_PROFILES_AVATAR_BASE_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
index ef503f0..8a39e73 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
@@ -22,7 +21,6 @@
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.h"
 #import "chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h"
-#include "components/signin/core/browser/signin_error_controller.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
 
@@ -45,85 +43,68 @@
 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent;
 
 // Displays an error icon if any accounts associated with this profile have an
-// auth error.
-- (void)updateErrorStatus:(BOOL)hasError;
+// auth error or sync error.
+- (void)setErrorStatus:(BOOL)hasError;
 @end
 
-class ProfileAttributesUpdateObserver
-    : public ProfileAttributesStorage::Observer,
-      public SigninErrorController::Observer {
- public:
-  ProfileAttributesUpdateObserver(Profile* profile,
-                                  AvatarBaseController* avatarController)
-      : profile_(profile),
-        avatarController_(avatarController) {
-    g_browser_process->profile_manager()->
-        GetProfileAttributesStorage().AddObserver(this);
+ProfileUpdateObserver::ProfileUpdateObserver(
+    Profile* profile,
+    AvatarBaseController* avatarController)
+    : errorController_(this, profile),
+      profile_(profile),
+      avatarController_(avatarController) {
+  g_browser_process->profile_manager()
+      ->GetProfileAttributesStorage()
+      .AddObserver(this);
+}
 
-    // Subscribe to authentication error changes so that the avatar button
-    // can update itself.
-    SigninErrorController* errorController =
-        profiles::GetSigninErrorController(profile_);
-    if (errorController)
-      errorController->AddObserver(this);
-  }
+ProfileUpdateObserver::~ProfileUpdateObserver() {
+  g_browser_process->profile_manager()
+      ->GetProfileAttributesStorage()
+      .RemoveObserver(this);
+}
 
-  ~ProfileAttributesUpdateObserver() override {
-    g_browser_process->profile_manager()->
-        GetProfileAttributesStorage().RemoveObserver(this);
-    SigninErrorController* errorController =
-        profiles::GetSigninErrorController(profile_);
-    if (errorController)
-      errorController->RemoveObserver(this);
-  }
+void ProfileUpdateObserver::OnProfileAdded(const base::FilePath& profile_path) {
+  [avatarController_ updateAvatarButtonAndLayoutParent:YES];
+}
 
-  // ProfileAttributesStorage::Observer:
-  void OnProfileAdded(const base::FilePath& profile_path) override {
+void ProfileUpdateObserver::OnProfileWasRemoved(
+    const base::FilePath& profile_path,
+    const base::string16& profile_name) {
+  // If deleting the active profile, don't bother updating the avatar
+  // button, as the browser window is being closed anyway.
+  if (profile_->GetPath() != profile_path)
     [avatarController_ updateAvatarButtonAndLayoutParent:YES];
-  }
+}
 
-  void OnProfileWasRemoved(const base::FilePath& profile_path,
-                           const base::string16& profile_name) override {
-    // If deleting the active profile, don't bother updating the avatar
-    // button, as the browser window is being closed anyway.
-    if (profile_->GetPath() != profile_path)
-      [avatarController_ updateAvatarButtonAndLayoutParent:YES];
-  }
+void ProfileUpdateObserver::OnProfileNameChanged(
+    const base::FilePath& profile_path,
+    const base::string16& old_profile_name) {
+  if (profile_->GetPath() == profile_path)
+    [avatarController_ updateAvatarButtonAndLayoutParent:YES];
+}
 
-  void OnProfileNameChanged(const base::FilePath& profile_path,
-                            const base::string16& old_profile_name) override {
-    if (profile_->GetPath() == profile_path)
-      [avatarController_ updateAvatarButtonAndLayoutParent:YES];
-  }
+void ProfileUpdateObserver::OnProfileSupervisedUserIdChanged(
+    const base::FilePath& profile_path) {
+  if (profile_->GetPath() == profile_path)
+    [avatarController_ updateAvatarButtonAndLayoutParent:YES];
+}
 
-  void OnProfileSupervisedUserIdChanged(
-      const base::FilePath& profile_path) override {
-    if (profile_->GetPath() == profile_path)
-      [avatarController_ updateAvatarButtonAndLayoutParent:YES];
-  }
+void ProfileUpdateObserver::OnAvatarErrorChanged() {
+  [avatarController_ setErrorStatus:errorController_.HasAvatarError()];
+}
 
-  // SigninErrorController::Observer:
-  void OnErrorChanged() override {
-    SigninErrorController* errorController =
-        profiles::GetSigninErrorController(profile_);
-    if (errorController)
-      [avatarController_ updateErrorStatus:errorController->HasError()];
-  }
-
- private:
-  Profile* profile_;
-  AvatarBaseController* avatarController_;  // Weak; owns this.
-
-  DISALLOW_COPY_AND_ASSIGN(ProfileAttributesUpdateObserver);
-};
+bool ProfileUpdateObserver::HasAvatarError() {
+  return errorController_.HasAvatarError();
+}
 
 @implementation AvatarBaseController
 
 - (id)initWithBrowser:(Browser*)browser {
   if ((self = [super init])) {
     browser_ = browser;
-    profileAttributesObserver_.reset(
-        new ProfileAttributesUpdateObserver(browser_->profile(), self));
+    profileObserver_.reset(
+        new ProfileUpdateObserver(browser_->profile(), self));
   }
   return self;
 }
@@ -255,7 +236,7 @@
   NOTREACHED();
 }
 
-- (void)updateErrorStatus:(BOOL)hasError {
+- (void)setErrorStatus:(BOOL)hasError {
 }
 
 - (BaseBubbleController*)menuController {
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
index 2377b86d..0796752 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
@@ -18,15 +18,18 @@
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/profiles/avatar_button.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/signin/core/browser/signin_error_controller.h"
+#include "components/signin/core/common/profile_management_switches.h"
 #include "grit/theme_resources.h"
 #import "ui/base/cocoa/appkit_utils.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/nine_image_painter_factory.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/image/image_skia_util_mac.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/vector_icons_public.h"
 
 namespace {
 
@@ -143,7 +146,7 @@
 
 @interface AvatarButtonController (Private)
 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent;
-- (void)updateErrorStatus:(BOOL)hasError;
+- (void)setErrorStatus:(BOOL)hasError;
 - (void)dealloc;
 - (void)themeDidChangeNotification:(NSNotification*)aNotification;
 @end
@@ -163,11 +166,6 @@
         [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]);
     [avatarButton setCell:cell.get()];
 
-    // Check if the account already has an authentication error.
-    SigninErrorController* errorController =
-        profiles::GetSigninErrorController(browser->profile());
-    hasError_ = errorController && errorController->HasError();
-
     [avatarButton setWantsLayer:YES];
     [self setView:avatarButton];
 
@@ -180,6 +178,9 @@
     [avatarButton setAction:@selector(buttonClicked:)];
     [avatarButton setRightAction:@selector(buttonRightClicked:)];
 
+    // Check if the account already has an authentication or sync error and
+    // initialize the avatar button UI.
+    hasError_ = profileObserver_->HasAvatarError();
     [self updateAvatarButtonAndLayoutParent:NO];
 
     NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
@@ -260,12 +261,15 @@
     [button setImage:GetImageFromResourceID(IDR_AVATAR_NATIVE_BUTTON_AVATAR)];
     [button setImagePosition:NSImageOnly];
   } else if (hasError_) {
-    [button setDefaultImage:GetImageFromResourceID(
-        IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR)];
+    NSImage* errorIcon =
+        switches::IsMaterialDesignUserMenu()
+            ? NSImageFromImageSkia(gfx::CreateVectorIcon(
+                  gfx::VectorIconId::SYNC_PROBLEM, 13, gfx::kGoogleRed700))
+            : GetImageFromResourceID(IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR);
+    [button setDefaultImage:errorIcon];
     [button setHoverImage:nil];
     [button setPressedImage:nil];
-    [button setImage:GetImageFromResourceID(
-        IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR)];
+    [button setImage:errorIcon];
     [button setImagePosition:NSImageRight];
   } else {
     [button setDefaultImage:nil];
@@ -296,7 +300,7 @@
   }
 }
 
-- (void)updateErrorStatus:(BOOL)hasError {
+- (void)setErrorStatus:(BOOL)hasError {
   hasError_ = hasError;
   [self updateAvatarButtonAndLayoutParent:YES];
 }
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
index 1e3e745..26572c6e 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
@@ -26,7 +26,7 @@
 
 // Defined in the AvatarButtonController implementation.
 @interface AvatarButtonController (ExposedForTesting)
-- (void)updateErrorStatus:(BOOL)hasError;
+- (void)setErrorStatus:(BOOL)hasError;
 @end
 
 // Subclassing AvatarButtonController to be able to control the state of
@@ -102,7 +102,7 @@
   testing_profile_manager()->CreateTestingProfile("batman");
 
   EXPECT_EQ(0, [button() image].size.width);
-  [controller() updateErrorStatus:true];
+  [controller() setErrorStatus:true];
 
   ASSERT_FALSE([view() isHidden]);
   EXPECT_NSEQ(@"Person 1", [button() title]);
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
index 2b8dbf2e..433ef2f 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -32,6 +32,8 @@
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/signin/signin_ui_util.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/sync/sync_ui_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -51,6 +53,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
@@ -931,10 +934,11 @@
 // Builds the regular profile chooser view.
 - (void)buildProfileChooserViewWithProfileView:(NSView*)currentProfileView
                                   tutorialView:(NSView*)tutorialView
+                                 syncErrorView:(NSView*)syncErrorView
                                  otherProfiles:(NSArray*)otherProfiles
                                      atYOffset:(CGFloat)yOffset
                                    inContainer:(NSView*)container
-                                   showLock:(bool)showLock;
+                                      showLock:(bool)showLock;
 
 // Builds the profile chooser view.
 - (NSView*)buildProfileChooserView;
@@ -957,6 +961,12 @@
                      linkAction:(SEL)linkAction
                    buttonAction:(SEL)buttonAction;
 
+// Builds a header for signin and sync error surfacing on the user menu.
+- (NSView*)buildSyncErrorViewIfNeeded;
+- (NSView*)buildSyncErrorViewWithContent:(int)contentStringId
+                          buttonStringId:(int)buttonStringId
+                            buttonAction:(SEL)buttonAction;
+
 // Builds a tutorial card to introduce an upgrade user to the new avatar menu if
 // needed. |tutorial_shown| indicates if the tutorial has already been shown in
 // the previous active view. |avatar_item| refers to the current profile.
@@ -1165,11 +1175,32 @@
   [self initMenuContentsWithView:profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL];
 }
 
+- (IBAction)showSignoutView:(id)sender {
+  chrome::ShowSettingsSubPage(browser_, chrome::kSignOutSubPage);
+}
+
+- (IBAction)showSignoutSigninView:(id)sender {
+  if (ProfileSyncServiceFactory::GetForProfile(browser_->profile()))
+    ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS);
+  SigninManagerFactory::GetForProfile(browser_->profile())
+      ->SignOut(signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS,
+                signin_metrics::SignoutDelete::IGNORE_METRIC);
+  [self showSigninUIForMode:profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN];
+}
+
 - (IBAction)showAccountReauthenticationView:(id)sender {
   DCHECK(!isGuestSession_);
   [self showSigninUIForMode:profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH];
 }
 
+- (IBAction)showUpdateChromeView:(id)sender {
+  chrome::OpenUpdateChromeDialog(browser_);
+}
+
+- (IBAction)showSyncPassphraseSetupView:(id)sender {
+  chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage);
+}
+
 - (IBAction)removeAccount:(id)sender {
   DCHECK(!accountIdToRemove_.empty());
   ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile())
@@ -1404,10 +1435,11 @@
 
 - (void)buildProfileChooserViewWithProfileView:(NSView*)currentProfileView
                                   tutorialView:(NSView*)tutorialView
+                                 syncErrorView:(NSView*)syncErrorView
                                  otherProfiles:(NSArray*)otherProfiles
                                      atYOffset:(CGFloat)yOffset
                                    inContainer:(NSView*)container
-                                   showLock:(bool)showLock {
+                                      showLock:(bool)showLock {
   if (switches::IsMaterialDesignUserMenu())
     yOffset += kRelatedControllVerticalSpacing;
 
@@ -1451,13 +1483,22 @@
   }
 
   if (viewMode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
-    NSView* currentProfileAccountsView = [self
-        createCurrentProfileAccountsView:NSMakeRect(0, yOffset,
-                                                    GetFixedMenuWidth(), 0)];
-    [container addSubview:currentProfileAccountsView];
-    yOffset = NSMaxY([currentProfileAccountsView frame]);
+    const AvatarMenu::Item& item =
+        avatarMenu_->GetItemAt(avatarMenu_->GetActiveProfileIndex());
+    if (item.signed_in) {
+      NSView* currentProfileAccountsView = [self
+          createCurrentProfileAccountsView:NSMakeRect(0, yOffset,
+                                                      GetFixedMenuWidth(), 0)];
+      [container addSubview:currentProfileAccountsView];
+      yOffset = NSMaxY([currentProfileAccountsView frame]);
 
-    yOffset = [self addSeparatorToContainer:container atYOffset: yOffset];
+      yOffset = [self addSeparatorToContainer:container atYOffset:yOffset];
+    } else {
+      // This is the case when the user selects the sign out option in the user
+      // menu upon encountering unrecoverable errors. Afterwards, the profile
+      // chooser view is shown instead of the account management view.
+      viewMode_ = profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER;
+    }
   }
 
   // Active profile card.
@@ -1471,6 +1512,13 @@
     yOffset = NSMaxY([currentProfileView frame]) + verticalSpacing;
   }
 
+  if (syncErrorView) {
+    yOffset = [self addSeparatorToContainer:container atYOffset:yOffset];
+    [syncErrorView setFrameOrigin:NSMakePoint(0, yOffset)];
+    [container addSubview:syncErrorView];
+    yOffset = NSMaxY([syncErrorView frame]);
+  }
+
   if (tutorialView) {
     [tutorialView setFrameOrigin:NSMakePoint(0, yOffset)];
     [container addSubview:tutorialView];
@@ -1488,6 +1536,7 @@
       [[NSView alloc] initWithFrame:NSZeroRect]);
 
   NSView* tutorialView = nil;
+  NSView* syncErrorView = nil;
   NSView* currentProfileView = nil;
   base::scoped_nsobject<NSMutableArray> otherProfiles(
       [[NSMutableArray alloc] init]);
@@ -1507,7 +1556,9 @@
   for (int i = avatarMenu_->GetNumberOfItems() - 1; i >= 0; --i) {
     const AvatarMenu::Item& item = avatarMenu_->GetItemAt(i);
     if (item.active) {
-      if (viewMode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
+      if (switches::IsMaterialDesignUserMenu()) {
+        syncErrorView = [self buildSyncErrorViewIfNeeded];
+      } else if (viewMode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
         tutorialView = [self buildTutorialViewIfNeededForItem:item];
       }
       currentProfileView =
@@ -1537,10 +1588,11 @@
   } else {
     [self buildProfileChooserViewWithProfileView:currentProfileView
                                     tutorialView:tutorialView
+                                   syncErrorView:syncErrorView
                                    otherProfiles:otherProfiles.get()
                                        atYOffset:yOffset
                                      inContainer:container
-                                     showLock:showLock];
+                                        showLock:showLock];
   }
 
   return container.autorelease();
@@ -1803,6 +1855,93 @@
   return container.autorelease();
 }
 
+- (NSView*)buildSyncErrorViewIfNeeded {
+  int contentStringId, buttonStringId;
+  SEL buttonAction;
+  sync_ui_util::AvatarSyncErrorType error =
+      sync_ui_util::GetMessagesForAvatarSyncError(
+          browser_->profile(), &contentStringId, &buttonStringId);
+  switch (error) {
+    case sync_ui_util::MANAGED_USER_UNRECOVERABLE_ERROR:
+      buttonAction = @selector(showSignoutView:);
+      break;
+    case sync_ui_util::UNRECOVERABLE_ERROR:
+      buttonAction = @selector(showSignoutSigninView:);
+      break;
+    case sync_ui_util::AUTH_ERROR:
+      buttonAction = @selector(showAccountReauthenticationView:);
+      break;
+    case sync_ui_util::UPGRADE_CLIENT_ERROR:
+      buttonAction = @selector(showUpdateChromeView:);
+      break;
+    case sync_ui_util::PASSPHRASE_ERROR:
+      buttonAction = @selector(showSyncPassphraseSetupView:);
+      break;
+    case sync_ui_util::NO_SYNC_ERROR:
+      return nil;
+    default:
+      NOTREACHED();
+  }
+  return [self buildSyncErrorViewWithContent:contentStringId
+                              buttonStringId:buttonStringId
+                                buttonAction:buttonAction];
+}
+
+- (NSView*)buildSyncErrorViewWithContent:(int)contentStringId
+                          buttonStringId:(int)buttonStringId
+                            buttonAction:(SEL)buttonAction {
+  base::scoped_nsobject<NSView> container(
+      [[NSView alloc] initWithFrame:NSMakeRect(0, 0, GetFixedMenuWidth(), 0)]);
+  CGFloat iconSize = 20.0;
+  CGFloat xOffset = kHorizontalSpacing + iconSize + 12.0;
+  CGFloat availableWidth = GetFixedMenuWidth() - xOffset - kHorizontalSpacing;
+  CGFloat yOffset = 20.0;
+
+  // Adds an action button for resolving the error at the bottom.
+  base::scoped_nsobject<NSButton> resolveErrorButton(
+      [[BlueLabelButton alloc] initWithFrame:NSZeroRect]);
+  [resolveErrorButton setTitle:l10n_util::GetNSString(buttonStringId)];
+  [resolveErrorButton setTarget:self];
+  [resolveErrorButton setAction:buttonAction];
+  [resolveErrorButton setAlignment:NSCenterTextAlignment];
+  [resolveErrorButton sizeToFit];
+  [resolveErrorButton setFrameOrigin:NSMakePoint(xOffset, yOffset)];
+  [container addSubview:resolveErrorButton];
+  yOffset = NSMaxY([resolveErrorButton frame]) + kVerticalSpacing;
+
+  // Adds the error message content.
+  NSTextField* contentLabel =
+      BuildLabel(l10n_util::GetNSString(contentStringId),
+                 NSMakePoint(xOffset, yOffset), nil);
+  [contentLabel setFrameSize:NSMakeSize(availableWidth, 0)];
+  [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:contentLabel];
+  [container addSubview:contentLabel];
+  yOffset = NSMaxY([contentLabel frame]) + 4;
+
+  // Adds the title for the error card.
+  NSTextField* titleLabel =
+      BuildLabel(l10n_util::GetNSString(IDS_SYNC_ERROR_USER_MENU_TITLE),
+                 NSMakePoint(xOffset, yOffset),
+                 skia::SkColorToCalibratedNSColor(gfx::kGoogleRed700));
+  [titleLabel setFrameSize:NSMakeSize(availableWidth, 0)];
+  [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:titleLabel];
+  [container addSubview:titleLabel];
+  yOffset = NSMaxY([titleLabel frame]);
+
+  // Adds the sync problem icon.
+  base::scoped_nsobject<NSImageView> syncProblemIcon([[NSImageView alloc]
+      initWithFrame:NSMakeRect(kHorizontalSpacing, yOffset - iconSize, iconSize,
+                               iconSize)]);
+  [syncProblemIcon setImage:NSImageFromImageSkia(gfx::CreateVectorIcon(
+                                gfx::VectorIconId::SYNC_PROBLEM, iconSize,
+                                gfx::kGoogleRed700))];
+  [container addSubview:syncProblemIcon];
+
+  [container
+      setFrameSize:NSMakeSize(GetFixedMenuWidth(), yOffset + kVerticalSpacing)];
+  return container.autorelease();
+}
+
 - (NSView*)createCurrentProfileView:(const AvatarMenu::Item&)item {
   base::scoped_nsobject<NSView> container([[NSView alloc]
       initWithFrame:NSZeroRect]);
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.cc b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
index 68e8bdc..f7980ea 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/android/chrome_feature_list.h"
 #include "chrome/browser/ntp_snippets/content_suggestions_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/ntp_snippet.h"
 #include "components/ntp_snippets/switches.h"
 #include "content/public/browser/web_ui.h"
@@ -230,7 +231,7 @@
   SendHosts();
 
   SendBoolean("flag-snippets", base::FeatureList::IsEnabled(
-                                   chrome::android::kNTPSnippetsFeature));
+                                   ntp_snippets::kContentSuggestionsFeature));
 
   SendBoolean("flag-offline-page-suggestions",
               base::FeatureList::IsEnabled(
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 35a62491..450c826 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1004,8 +1004,8 @@
       'browser/android/warmup_manager.h',
       'browser/android/web_contents_factory.cc',
       'browser/android/web_contents_factory.h',
-      'browser/android/webapk/manifest_upgrade_detector.cc',
-      'browser/android/webapk/manifest_upgrade_detector.h',
+      'browser/android/webapk/manifest_upgrade_detector_fetcher.cc',
+      'browser/android/webapk/manifest_upgrade_detector_fetcher.h',
       'browser/android/webapps/add_to_homescreen_data_fetcher.cc',
       'browser/android/webapps/add_to_homescreen_data_fetcher.h',
       'browser/android/webapps/add_to_homescreen_dialog_helper.cc',
@@ -2136,7 +2136,7 @@
       'android/java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java',
       'android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java',
       'android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelper.java',
-      'android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetector.java',
+      'android/java/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorFetcher.java',
       'android/java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java',
     ],
     'chrome_browser_mdns_sources': [
diff --git a/chrome/test/data/extensions/api_test/bindings/external_message_listener/background.js b/chrome/test/data/extensions/api_test/bindings/external_message_listener/background.js
new file mode 100644
index 0000000..b5dce1a
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bindings/external_message_listener/background.js
@@ -0,0 +1,32 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var messagesReceived = [];
+
+// Have we received the real message from the sender extension?
+var receivedRealSenderMessage = false;
+
+// Has the c++ code in the browser test asked us for the total count of messages
+// we've received?
+var sendCountAfterSenderMessage = false;
+
+function getMessageCountAfterReceivingRealSenderMessage() {
+  if (receivedRealSenderMessage) {
+    window.domAutomationController.send(messagesReceived.length);
+  } else {
+    sendCountAfterSenderMessage = true;
+  }
+}
+
+chrome.runtime.onMessageExternal.addListener(function(msg, sender, respond) {
+  messagesReceived.push({msg:msg, sender:sender});
+  if (msg == 'from_sender') {
+    receivedRealSenderMessage = true;
+    if (sendCountAfterSenderMessage) {
+      window.domAutomationController.send(messagesReceived.length);
+    }
+  }
+});
+
+chrome.test.sendMessage('receiver_ready');
\ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/bindings/external_message_listener/manifest.json b/chrome/test/data/extensions/api_test/bindings/external_message_listener/manifest.json
new file mode 100644
index 0000000..032e576d
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bindings/external_message_listener/manifest.json
@@ -0,0 +1,11 @@
+{
+  "name": "External Message Listener (id mlmdejkkkhmhchpmepehbcncoalclded)",
+  "version": "0.1",
+   "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxvZCeDtPe+NIpnq7VtLOb/0bs+QlmF7cOvDzqgwniGEla8Z903Pq/oV8f649IQrvqfz+osvJxvqODzKiGU7a9g1cLu/fSVZXyhlGf7fCQjBYdPC7iFbFkTqSoeUOLCZzXYmxg/2t5WIWq8pLZgz043KjuzuS68pLRltHBRGeG+SWPu+cyfeNcFNPwlOjk6QCD/EUUG/QVeobACekF2/hh4TkRW5iU/vcJ+84aygr3r4hsvIoIEVMtlatHpzqAt/X01zsXJ5d9jH5DI5wnjUVPJKpA31QLkKu0Rq3s/79eTEEiZqSAFFA/1mMPs90u5iUyiYx3U5vNml/P+r6b31f0QIDAQAB",
+  "manifest_version": 2,
+  "permissions": ["tabs"],
+  "background": {
+    "persistent": true,
+    "scripts": ["background.js"]
+   }
+}
diff --git a/chrome/test/data/extensions/api_test/bindings/frames_before_navigation.html b/chrome/test/data/extensions/api_test/bindings/frames_before_navigation.html
new file mode 100644
index 0000000..8528b1d7
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bindings/frames_before_navigation.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<html>
+<body>
+<iframe id="frame1" src="chrome-extension://ficgdghpakbhhkmdjamiedmcoobamkoo/public.html"></iframe>
+<iframe id="frame2" src="chrome-extension://ficgdghpakbhhkmdjamiedmcoobamkoo/nonexistent.html"></iframe>
+<script>
+
+// We expect that chrome.runtime.id will not be set in this frame, and that
+// either chrome.runtime.sendMessage is not defined or we're able to call it
+// (but elsewhere in the browser_test that uses this page we check that the
+// message was not actually sent, or at least didn't incorrectly seem to come
+// from the extension ficgdghpakbhhkmdjamiedmcoobamkoo).
+function testFrame(win) {
+  var haveId = true;
+  var didRun = false;
+  try {
+    haveId = win.eval('typeof chrome.runtime != "undefined" && ' +
+                      'typeof chrome.runtime.id != "undefined"');
+    win.eval('typeof chrome.runtime != "undefined" ' +
+             '&& chrome.runtime.sendMessage(' +
+             '"mlmdejkkkhmhchpmepehbcncoalclded", "evil")');
+    didRun = true;
+  } catch (e) {
+    console.log('caught exception: ' + e);
+  }
+  return didRun && !haveId;
+}
+
+// Test the two frames (actual page and nonexistent page) that were included in
+// the original html document.
+var frame1Success = testFrame(document.getElementById('frame1').contentWindow);
+var frame2Success = testFrame(document.getElementById('frame2').contentWindow);
+
+// Now test two frames that get dynamically created and added to the DOM, again
+// one actual page and one nonexistent.
+var frame3 = document.createElement('iframe');
+frame3.src = 'chrome-extension://ficgdghpakbhhkmdjamiedmcoobamkoo/public.html';
+document.body.appendChild(frame3);
+var frame3Success = testFrame(frame3.contentWindow);
+
+var frame4 = document.createElement('iframe');
+frame4.src =
+    'chrome-extension://ficgdghpakbhhkmdjamiedmcoobamkoo/nonexistent.html';
+document.body.appendChild(frame4);
+var frame4Success = testFrame(frame4.contentWindow);
+
+// Finally, test against two newly opened windows.
+var newWin1 = window.open(
+    'chrome-extension://ficgdghpakbhhkmdjamiedmcoobamkoo/public.html');
+var newWindow1Success = testFrame(newWin1);
+
+var newWin2 = window.open(
+    'chrome-extension://ficgdghpakbhhkmdjamiedmcoobamkoo/nonexistent.html');
+var newWindow2Success = testFrame(newWin2);
+
+function getResult() {
+  if (!frame1Success)
+    console.log("frame1Success is false!");
+  if (!frame2Success)
+    console.log("frame2Success is false!");
+  if (!frame3Success)
+    console.log("frame3Success is false!");
+  if (!frame4Success)
+    console.log("frame4Success is false!");
+  if (!newWindow1Success)
+    console.log("newWindow1Success is false!");
+  if (!newWindow2Success)
+    console.log("newWindow2Success is false!");
+
+  window.domAutomationController.send(
+      frame1Success && frame2Success && frame3Success &&
+      frame4Success && newWindow1Success && newWindow2Success);
+}
+
+</script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/bindings/message_sender/background.js b/chrome/test/data/extensions/api_test/bindings/message_sender/background.js
new file mode 100644
index 0000000..c323550d
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bindings/message_sender/background.js
@@ -0,0 +1,7 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.test.sendMessage('sender_ready', function(id) {
+  chrome.runtime.sendMessage(id, 'from_sender');
+});
diff --git a/chrome/test/data/extensions/api_test/bindings/message_sender/manifest.json b/chrome/test/data/extensions/api_test/bindings/message_sender/manifest.json
new file mode 100644
index 0000000..2e49eab
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bindings/message_sender/manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "Message Sender (id ficgdghpakbhhkmdjamiedmcoobamkoo)",
+  "version": "0.1",
+   "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydrsgsTfyyY3zLW+j9ZNb0/Ej0yIKlysp5Scz549wyvpTZIeNqYrq9wt5W6Lcfe9jthuxlLRzKiPP/kk/B8CZCsyet9XbLxnKCJUJUMv/8iih0wC+7tmzqfcDPjBrjv5VT0IAGBaupIDvJbSnf8efGI1U2c3teXZrpk320asfL26x+xezQOPWTcbrY4KINH11AZK8slB0WsWy2pxoel8O7uPRDDy4uqGX27J6oU3WdU5A4/L8j8UQCFcgAuQu/0Cu8WoLuJ4z3CdObQCBXCnmvyIKMpgmqa3Yk5oJRPBqOFkwMnJRFivnTjrBss/M9Jft3WzkHx4Wn9mDzDXQLltOQIDAQAB",
+  "manifest_version": 2,
+  "background": {
+    "persistent": true,
+    "scripts": ["background.js"]
+   },
+  "web_accessible_resources": [
+    "public.html"
+  ]
+}
diff --git a/chrome/test/data/extensions/api_test/bindings/message_sender/public.html b/chrome/test/data/extensions/api_test/bindings/message_sender/public.html
new file mode 100644
index 0000000..781a483
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bindings/message_sender/public.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+Hello World
+</body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/messaging/externally_connectable/sites/popup_opener.html b/chrome/test/data/extensions/api_test/messaging/externally_connectable/sites/popup_opener.html
new file mode 100644
index 0000000..6b11de5
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/messaging/externally_connectable/sites/popup_opener.html
@@ -0,0 +1,9 @@
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<script>
+var url = location.href.replace('popup_opener.html', 'chromium.org.html');
+window.open(url, '_blank');
+</script>
diff --git a/chrome/test/data/webapps/manifest2.json b/chrome/test/data/webapps/manifest2.json
new file mode 100644
index 0000000..2739c7dd
--- /dev/null
+++ b/chrome/test/data/webapps/manifest2.json
@@ -0,0 +1,14 @@
+{
+  "name": "Manifest test app2",
+  "short_name": "App",
+  "icons": [
+    {
+      "src": "image-512px.png",
+      "sizes": "512x512",
+      "type": "image/png"
+    }
+  ],
+  "start_url": "manifest_test_page2.html",
+  "display": "standalone",
+  "orientation": "landscape"
+}
diff --git a/chrome/test/data/webapps/manifest_test_page2.html b/chrome/test/data/webapps/manifest_test_page2.html
new file mode 100644
index 0000000..fdc7d68
--- /dev/null
+++ b/chrome/test/data/webapps/manifest_test_page2.html
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <title>Web app banner test page</title>
+    <link rel="manifest" href="manifest2.json" />
+  </head>
+  <body>
+    Do-nothing page with a manifest.
+  </body>
+</html>
diff --git a/chrome/test/data/webapps/manifest_test_page_test_start_url_change.html b/chrome/test/data/webapps/manifest_test_page_test_start_url_change.html
deleted file mode 100644
index 3fa2aa0..0000000
--- a/chrome/test/data/webapps/manifest_test_page_test_start_url_change.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
-  <head>
-    <title>Web manifest upgrade detector test page</title>
-    <link rel="manifest" href="manifest.json" />
-  </head>
-  <body>
-    Do-nothing page with a manifest.
-  </body>
-</html>
diff --git a/chrome/test/data/webrtc/video_extraction.js b/chrome/test/data/webrtc/video_extraction.js
index 95f83bd..3d8d4d2a 100644
--- a/chrome/test/data/webrtc/video_extraction.js
+++ b/chrome/test/data/webrtc/video_extraction.js
@@ -5,10 +5,10 @@
  */
 
 /**
- * The gStartedAt when the capturing begins. Used for timeout adjustments.
+ * FPS at which we would like to sample.
  * @private
  */
-var gStartedAt = 0;
+var gFps = 30;
 
 /**
  * The duration of the all frame capture in milliseconds.
@@ -17,23 +17,16 @@
 var gCaptureDuration = 0;
 
 /**
- * The time interval at which the video is sampled.
+ * The recorded video encoded in Base64.
  * @private
  */
-var gFrameCaptureInterval = 0;
+var gVideoBase64 = '';
 
 /**
- * The global array of frames. Frames are pushed, i.e. this should be treated as
- * a queue and we should read from the start.
+ * Chunks of the video recorded by MediaRecorded as they become available.
  * @private
  */
-var gFrames = [];
-
-/**
- * We need to skip the first two frames due to timing issues.
- * @private
- */
-var gHasThrownAwayFirstTwoFrames = false;
+var gChunks = [];
 
 /**
  * A string to be returned to the test about the current status of capture.
@@ -44,44 +37,47 @@
  * Starts the frame capturing.
  *
  * @param {!Object} The video tag from which the height and width parameters are
-                    to be extracted.
- * @param {Number} The frame rate at which we would like to capture frames.
+ *                  to be extracted.
  * @param {Number} The duration of the frame capture in seconds.
  */
-function startFrameCapture(videoTag, frameRate, duration) {
-  gFrameCaptureInterval = 1000 / frameRate;
-  gCaptureDuration = 1000 * duration;
-  inputElement = document.getElementById("local-view");
+function startFrameCapture(videoTag, duration) {
+  var inputElement = document.getElementById('local-view');
   var width = inputElement.videoWidth;
   var height = inputElement.videoHeight;
 
-  // The WebRTC code is free to start in VGA, so make sure that the output video
-  // tag scales up to whatever the input size is (otherwise the video quality
-  // comparison will go poorly.
-  videoTag.width = width;
-  videoTag.height = height;
+  // |videoBitsPerSecond| is set to a large number to indicate VP8 to throw as
+  // little information away as possible.
+  var mediaRecorderOptions = {'videoBitsPerSecond': 4 * width * height * gFps};
+  var stream = getStreamFromElement_(videoTag);
+  gCaptureDuration = 1000 * duration;
 
-  if (width == 0 || height == 0) {
-    // Video must be playing at this point since this function is invoked from
-    // onplay on the <video> tag. See http://crbug.com/625943.
-    gCapturingStatus = 'failed-video-was-0x0-after-onplay'
-    return;
+  var mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions);
+
+  mediaRecorder.ondataavailable = function(recording) {
+    gChunks.push(recording.data);
+  }
+  mediaRecorder.onstop = function() {
+    var videoBlob = new Blob(gChunks, {type: "video/webm"});
+    gChunks = [];
+    var reader = new FileReader();
+    reader.onloadend = function() {
+      gVideoBase64 = reader.result.substr(reader.result.indexOf(',') + 1);
+      gCapturingStatus = 'done-capturing';
+      debug('done-capturing');
+    }
+    reader.readAsDataURL(videoBlob);
   }
 
-  console.log('Received width is: ' + width + ', received height is: ' + height
-              + ', capture interval is: ' + gFrameCaptureInterval +
-              ', duration is: ' + gCaptureDuration);
+  mediaRecorder.start();
+  setTimeout(function() { mediaRecorder.stop(); }, gCaptureDuration);
   gCapturingStatus = 'still-capturing';
+}
 
-  var remoteCanvas = document.createElement('canvas');
-  remoteCanvas.width = width;
-  remoteCanvas.height = height;
-  document.body.appendChild(remoteCanvas);
-
-  gStartedAt = new Date().getTime();
-  gFrames = [];
-  setTimeout(function() { shoot_(videoTag, remoteCanvas, width, height); },
-             gFrameCaptureInterval);
+/**
+ * Returns the video recorded by RecordMedia encoded in Base64.
+ */
+function getRecordedVideoAsBase64() {
+  silentReturnToTest(gVideoBase64);
 }
 
 /**
@@ -92,111 +88,15 @@
 }
 
 /**
- * Retrieves the number of captured frames.
- */
-function getTotalNumberCapturedFrames() {
-  returnToTest(gFrames.length.toString());
-}
-
-/**
- * Retrieves one captured frame in ARGB format as a base64-encoded string.
- *
- * Also updates the page's progress bar.
- *
- * @param frameIndex A frame index in the range 0 to total-1 where total is
- *     given by getTotalNumberCapturedFrames.
- */
-function getOneCapturedFrame(frameIndex) {
-  var codedFrame = convertArrayBufferToBase64String_(gFrames[frameIndex]);
-  updateProgressBar_(frameIndex);
-  silentReturnToTest(codedFrame);
-}
-
-/**
+ * Returns the stream from the input element to be attached to MediaRecorder.
  * @private
- *
- * @param {ArrayBuffer} buffer An array buffer to convert to a base 64 string.
- * @return {String} A base 64 string.
  */
-function convertArrayBufferToBase64String_(buffer) {
-  var binary = '';
-  var bytes = new Uint8Array(buffer);
-  for (var i = 0; i < bytes.byteLength; i++) {
-    binary += String.fromCharCode(bytes[i]);
-  }
-  return window.btoa(binary);
-}
-
-/**
- * The function which is called at the end of every gFrameCaptureInterval. Gets
- * the current frame from the video and extracts the data from it. Then it saves
- * it in the frames array and adjusts the capture interval (timers in JavaScript
- * aren't precise).
- *
- * @private
- *
- * @param {!Object} The video whose frames are to be captured.
- * @param {Canvas} The canvas on which the image will be captured.
- * @param {Number} The width of the video/canvas area to be captured.
- * @param {Number} The height of the video area to be captured.
- */
-function shoot_(video, canvas, width, height) {
-  // The first two captured frames have big difference between the ideal time
-  // interval between two frames and the real one. As a consequence this affects
-  // enormously the interval adjustment for subsequent frames. That's why we
-  // have to reset the time after the first two frames and get rid of these two
-  // frames.
-  if (gFrames.length == 1 && !gHasThrownAwayFirstTwoFrames) {
-    gStartedAt = new Date().getTime();
-    gHasThrownAwayFirstTwoFrames = true;
-    gFrames = [];
-  }
-
-  // We capture the whole video frame.
-  var img = captureFrame_(video, canvas.getContext('2d'), width, height);
-  gFrames.push(img.data.buffer);
-
-  // Adjust the timer and try to account for timer incorrectness.
-  var currentTime = new Date().getTime();
-  var idealTime = gFrames.length * gFrameCaptureInterval;
-  var realTimeElapsed = currentTime - gStartedAt;
-  var diff = realTimeElapsed - idealTime;
-
-  if (realTimeElapsed < gCaptureDuration) {
-    // If duration isn't over shoot_ again.
-    setTimeout(function() { shoot_(video, canvas, width, height); },
-               gFrameCaptureInterval - diff);
+function getStreamFromElement_(element) {
+  if (element.srcObject !== undefined) {
+    return element.srcObject;
+  } else if (element.src !== undefined) {
+    return element.src;
   } else {
-    // Done capturing!
-    gCapturingStatus = 'done-capturing';
-    prepareProgressBar_();
+    failTest('Error extracting stream from element.');
   }
 }
-
-/**
- * @private
- */
-function captureFrame_(video, context, width, height) {
-  context.drawImage(video, 0, 0, width, height);
-  return context.getImageData(0, 0, width, height);
-}
-
-/**
- * @private
- */
-function prepareProgressBar_() {
-  document.body.innerHTML =
-    '<html><body>' +
-    '<p id="progressBar" style="position: absolute; top: 50%; left: 40%;">' +
-    'Preparing to send frames.</p>' +
-    '</body></html>';
-}
-
-/**
- * @private
- */
-function updateProgressBar_(currentFrame) {
-  progressBar.innerHTML =
-    'Transferring captured frames: ' + '(' + currentFrame + '/' +
-    gFrames.length + ')';
-}
diff --git a/chrome/test/data/webrtc/webrtc_video_quality_test.html b/chrome/test/data/webrtc/webrtc_video_quality_test.html
index 3e9b902..06404ba 100644
--- a/chrome/test/data/webrtc/webrtc_video_quality_test.html
+++ b/chrome/test/data/webrtc/webrtc_video_quality_test.html
@@ -21,12 +21,11 @@
         <video id="local-view" autoplay="autoplay"></video>
       </td>
       <td>
-        <!-- startFrameCapture() takes 3 parameters:
+        <!-- startFrameCapture() takes 2 parameters:
              1. reference to remote video tag.
-             2. fps: fps at which we would like to sample.
-             3. duration: The duration of the capturing. -->
+             2. duration: The duration of the capturing. -->
         <video id="remote-view" autoplay="autoplay"
-            onplay="startFrameCapture(this, 30, 5)"></video>
+            onplay="startFrameCapture(this, 5)"></video>
       </td>
     </tr>
   </table>
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index cc407ba..26f76c0 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -724,27 +724,3 @@
   });
   mocha.run();
 });
-
-/**
- * Test fixture for chrome/browser/resources/settings/settings_main/.
- * @constructor
- * @extends {CrSettingsBrowserTest}
-*/
-function CrSettingsMainPageTest() {}
-
-CrSettingsMainPageTest.prototype = {
-  __proto__: CrSettingsBrowserTest.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://md-settings/settings_main/settings_main.html',
-
-  /** @override */
-  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
-    'settings_main_test.js',
-  ]),
-};
-
-TEST_F('CrSettingsMainPageTest', 'All', function() {
-  settings_main_page.registerTests();
-  mocha.run();
-});
diff --git a/chrome/test/data/webui/settings/settings_main_test.js b/chrome/test/data/webui/settings/settings_main_test.js
deleted file mode 100644
index 0ae1912e..0000000
--- a/chrome/test/data/webui/settings/settings_main_test.js
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('settings_main_page', function() {
-  /**
-   * @implements {SearchManager}
-   */
-  var TestSearchManager = function() {
-    /** @private {boolean} */
-    this.matchesFound_ = true;
-
-    /** @private {?settings.SearchRequest} */
-    this.searchRequest_ = null;
-  }
-
-  TestSearchManager.prototype = {
-    /**
-     * @param {boolean} matchesFound
-     */
-    setMatchesFound: function(matchesFound) {
-      this.matchesFound_ = matchesFound;
-    },
-
-    /** @override */
-    search: function(text, page) {
-      if (this.searchRequest_ == null || !this.searchRequest_.isSame(text)) {
-        this.searchRequest_ = new settings.SearchRequest(text);
-        this.searchRequest_.finished = true;
-        this.searchRequest_.updateMatches(this.matchesFound_);
-        this.searchRequest_.resolver.resolve(this.searchRequest_);
-      }
-      return this.searchRequest_.resolver.promise;
-    },
-  };
-
-  function registerTests() {
-    var settingsPrefs = null;
-
-    suiteSetup(function() {
-      settingsPrefs = document.createElement('settings-prefs');
-    });
-
-    suite('SearchTests', function() {
-      /** @type {?TestSearchManager} */
-      var searchManager = null;
-
-      /** @type {?SettingsMainElement} */
-      var settingsMain = null;
-
-      // TODO(tommycli): Remove once settings.navigateTo is no longer a stub.
-      settings.navigateTo = function(route) {
-        settingsMain.currentRoute = route;
-      };
-
-      setup(function() {
-        searchManager = new TestSearchManager();
-        settings.setSearchManagerForTesting(searchManager);
-        PolymerTest.clearBody();
-        settingsMain = document.createElement('settings-main');
-        settingsMain.prefs = settingsPrefs.prefs;
-        settingsMain.toolbarSpinnerActive = false;
-        document.body.appendChild(settingsMain);
-      });
-
-      teardown(function() { settingsMain.remove(); });
-
-      test('no results page shows and hides', function() {
-        var noSearchResults = settingsMain.$.noSearchResults;
-        assertTrue(!!noSearchResults);
-        assertTrue(noSearchResults.hidden);
-
-        searchManager.setMatchesFound(false);
-        return settingsMain.searchContents('Query1').then(function() {
-          assertFalse(noSearchResults.hidden);
-
-          searchManager.setMatchesFound(true);
-          return settingsMain.searchContents('Query2');
-        }).then(function() {
-          assertTrue(noSearchResults.hidden);
-        });
-      });
-
-      // Ensure that when the user clears the search box, the "no results" page
-      // is hidden.
-      test('no results page hides on clear', function() {
-        var noSearchResults = settingsMain.$.noSearchResults;
-        assertTrue(!!noSearchResults);
-        assertTrue(noSearchResults.hidden);
-        searchManager.setMatchesFound(false);
-
-        // Clearing the search box is effectively a search for the empty string.
-        return settingsMain.searchContents('').then(function() {
-          assertTrue(noSearchResults.hidden);
-        });
-      });
-    });
-  }
-
-  return {
-    registerTests: registerTests,
-  };
-});
diff --git a/components/autofill/core/browser/autofill_regex_constants.cc b/components/autofill/core/browser/autofill_regex_constants.cc
index 6f507e9..e5587be 100644
--- a/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/components/autofill/core/browser/autofill_regex_constants.cc
@@ -185,11 +185,22 @@
     "|Срок действия карты"  // ru
     "|年|有效期";  // zh-CN
 
-// The "yy" portion of the regex is just looking for two adjacent y's.
+// Used to match a expiration date field with a two digit year.
+// The following conditions must be met:
+//  - Exactly two adjacent y's.
+//  - (optional) Exactly two adjacent m's before the y's.
+//    - (optional) Separated by white-space and/or a dash or slash.
+//  - (optional) Prepended with some text similar to "Expiration Date".
+// Tested in components/autofill/core/common/autofill_regexes_unittest.cc
 const char kExpirationDate2DigitYearRe[] =
-    "(?:exp.*date.*|mm\\s*[-/]\\s*)[^y]yy([^y]|$)";
+    "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yy(?:[^y]|$)";
+// Used to match a expiration date field with a four digit year.
+// Same requirements as |kExpirationDate2DigitYearRe| except:
+//  - Exactly four adjacent y's.
+// Tested in components/autofill/core/common/autofill_regexes_unittest.cc
 const char kExpirationDate4DigitYearRe[] =
-    "^mm\\s*[-/]\\syyyy$";
+    "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yyyy(?:[^y]|$)";
+// Used to match expiration date fields that do not specify a year length.
 const char kExpirationDateRe[] =
     "expir|exp.*date|^expfield$"
     "|gueltig|gültig"  // de-DE
diff --git a/components/autofill/core/browser/credit_card_field.cc b/components/autofill/core/browser/credit_card_field.cc
index dc4145a..f53c686 100644
--- a/components/autofill/core/browser/credit_card_field.cc
+++ b/components/autofill/core/browser/credit_card_field.cc
@@ -60,11 +60,13 @@
 
   switch (type) {
     case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: {
-      static int kMinimum2YearCcExpLength = strlen("12/14");
+      // A date with a 2 digit year can fit in a minimum of 4 chars (MMYY)
+      static constexpr int kMinimum2YearCcExpLength = 4;
       return max_length >= kMinimum2YearCcExpLength;
     }
     case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
-      static int kMinimum4YearCcExpLength = strlen("12/2014");
+      // A date with a 4 digit year can fit in a minimum of 6 chars (MMYYYY)
+      static constexpr int kMinimum4YearCcExpLength = 6;
       return max_length >= kMinimum4YearCcExpLength;
     }
     default:
@@ -434,7 +436,7 @@
     return true;
   }
 
-  // If that fails, look for just MM/YY(YY).
+  // If that fails, look for just MM and/or YY(YY).
   scanner->RewindTo(month_year_saved_cursor);
   if (ParseFieldSpecifics(scanner,
                           base::ASCIIToUTF16("^mm$"),
diff --git a/components/autofill/core/browser/credit_card_field_unittest.cc b/components/autofill/core/browser/credit_card_field_unittest.cc
index 609ff17..b6cf575 100644
--- a/components/autofill/core/browser/credit_card_field_unittest.cc
+++ b/components/autofill/core/browser/credit_card_field_unittest.cc
@@ -277,136 +277,118 @@
 }
 
 TEST_F(CreditCardFieldTest, ParseExpField) {
-  FormFieldData field;
-  field.form_control_type = "text";
+  typedef struct {
+    const std::string label;
+    const int max_length;
+    const ServerFieldType expected_prediction;
+  } TestCase;
 
-  field.label = ASCIIToUTF16("Name on Card");
-  field.name = ASCIIToUTF16("name_on_card");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("name1")));
+  TestCase test_cases[] = {
+    // General label, no maxlength.
+    {"Expiration Date", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+    // General label, maxlength 4.
+    {"Expiration Date", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+    // General label, maxlength 5.
+    {"Expiration Date", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+    // General label, maxlength 6.
+    {"Expiration Date", 6, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+    // General label, maxlength 7.
+    {"Expiration Date", 7, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+    // General label, large maxlength.
+    {"Expiration Date", 12, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
 
-  field.label = ASCIIToUTF16("Card Number");
-  field.name = ASCIIToUTF16("card_number");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("number2")));
+    // Unsupported maxlength, general label.
+    {"Expiration Date", 3, UNKNOWN_TYPE},
+    // Unsupported maxlength, two digit year label.
+    {"Expiration Date (MM/YY)", 3, UNKNOWN_TYPE},
+    // Unsupported maxlength, four digit year label.
+    {"Expiration Date (MM/YYYY)", 3, UNKNOWN_TYPE},
 
-  field.label = ASCIIToUTF16("Expiration Date (MM/YYYY)");
-  field.name = ASCIIToUTF16("cc_exp");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3")));
+    // Two digit year, simple label.
+    {"MM / YY", 0, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+    // Two digit year, with slash (MM/YY).
+    {"Expiration Date (MM/YY)", 0, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+    // Two digit year, no slash (MMYY).
+    {"Expiration Date (MMYY)", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+    // Two digit year, with slash and maxlength (MM/YY).
+    {"Expiration Date (MM/YY)", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+    // Two digit year, with slash and large maxlength (MM/YY).
+    {"Expiration Date (MM/YY)", 12, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
 
-  Parse();
-  ASSERT_NE(nullptr, field_.get());
-  AddClassifications();
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME_FULL,
-            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER,
-            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
-            field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
-}
+    // Four digit year, simple label.
+    {"MM / YYYY", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+    // Four digit year, with slash (MM/YYYY).
+    {"Expiration Date (MM/YYYY)", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+    // Four digit year, no slash (MMYYYY).
+    {"Expiration Date (MMYYYY)", 6, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+    // Four digit year, with slash and maxlength (MM/YYYY).
+    {"Expiration Date (MM/YYYY)", 7, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+    // Four digit year, with slash and large maxlength (MM/YYYY).
+    {"Expiration Date (MM/YYYY)", 12, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
 
-TEST_F(CreditCardFieldTest, ParseExpField2DigitYear) {
-  FormFieldData field;
-  field.form_control_type = "text";
+    // Four digit year label with restrictive maxlength (4).
+    {"Expiration Date (MM/YYYY)", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+    // Four digit year label with restrictive maxlength (5).
+    {"Expiration Date (MM/YYYY)", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+  };
 
-  field.label = ASCIIToUTF16("Name on Card");
-  field.name = ASCIIToUTF16("name_on_card");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("name1")));
+  for (const TestCase &test_case : test_cases) {
+    // Clean up after previous test cases.
+    list_.clear();
+    field_.reset();
+    field_candidates_map_.clear();
 
-  field.label = ASCIIToUTF16("Card Number");
-  field.name = ASCIIToUTF16("card_number");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("number2")));
+    FormFieldData field;
+    field.form_control_type = "text";
 
-  field.label = ASCIIToUTF16("Expiration Date (MM/YY)");
-  field.name = ASCIIToUTF16("cc_exp");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3")));
+    field.label = ASCIIToUTF16("Name on Card");
+    field.name = ASCIIToUTF16("name_on_card");
+    list_.push_back(new AutofillField(field, ASCIIToUTF16("name1")));
 
-  Parse();
-  ASSERT_NE(nullptr, field_.get());
-  AddClassifications();
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME_FULL,
-            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER,
-            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
-            field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
-}
+    field.label = ASCIIToUTF16("Card Number");
+    field.name = ASCIIToUTF16("card_number");
+    list_.push_back(new AutofillField(field, ASCIIToUTF16("num2")));
 
-TEST_F(CreditCardFieldTest, ParseExpField2DigitYearDueToMaxLength) {
-  FormFieldData field;
-  field.form_control_type = "text";
+    field.label = ASCIIToUTF16(test_case.label);
+    if (test_case.max_length != 0) {
+      field.max_length = test_case.max_length;
+    }
+    field.name = ASCIIToUTF16("cc_exp");
+    list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3")));
 
-  field.label = ASCIIToUTF16("Name on Card");
-  field.name = ASCIIToUTF16("name_on_card");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("name1")));
+    Parse();
 
-  field.label = ASCIIToUTF16("Card Number");
-  field.name = ASCIIToUTF16("card_number");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("number2")));
+    // Assists in identifing which case has failed.
+    SCOPED_TRACE(test_case.expected_prediction);
+    SCOPED_TRACE(test_case.max_length);
+    SCOPED_TRACE(test_case.label);
 
-  field.label = ASCIIToUTF16("Expiration Date");
-  field.name = ASCIIToUTF16("cc_exp");
-  field.max_length = 6;  // Cannot fit YYYY-MM.
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3")));
+    if (test_case.expected_prediction == UNKNOWN_TYPE) {
+      // Expect failure and continue to next test case.
+      // The expiry date is a required field for credit card forms, and thus the
+      // parse sets |field_| to nullptr.
+      EXPECT_EQ(nullptr, field_.get());
+      continue;
+    }
 
-  Parse();
-  ASSERT_NE(nullptr, field_.get());
-  AddClassifications();
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME_FULL,
-            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER,
-            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
-            field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
-}
+    // Ensure that the form was determined as valid.
+    ASSERT_NE(nullptr, field_.get());
+    AddClassifications();
+    ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+                field_candidates_map_.end());
+    EXPECT_EQ(CREDIT_CARD_NAME_FULL,
+              field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
 
-TEST_F(CreditCardFieldTest, ParseExpField4DigitYear) {
-  FormFieldData field;
-  field.form_control_type = "text";
+    ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("num2")) !=
+                field_candidates_map_.end());
+    EXPECT_EQ(CREDIT_CARD_NUMBER,
+              field_candidates_map_[ASCIIToUTF16("num2")].BestHeuristicType());
 
-  field.label = ASCIIToUTF16("Name on Card");
-  field.name = ASCIIToUTF16("name_on_card");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("name1")));
-
-  field.label = ASCIIToUTF16("Card Number");
-  field.name = ASCIIToUTF16("card_number");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("number2")));
-
-  field.label = ASCIIToUTF16("MM / YYYY");
-  field.name = ASCIIToUTF16("cc_exp");
-  list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3")));
-
-  Parse();
-  ASSERT_NE(nullptr, field_.get());
-  AddClassifications();
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME_FULL,
-            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER,
-            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
-  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
-              field_candidates_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
-            field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
+    ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
+                field_candidates_map_.end());
+    EXPECT_EQ(test_case.expected_prediction,
+              field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
+  }
 }
 
 TEST_F(CreditCardFieldTest, ParseCreditCardHolderNameWithCCFullName) {
diff --git a/components/autofill/core/common/autofill_regexes_unittest.cc b/components/autofill/core/common/autofill_regexes_unittest.cc
index ff8cbd13..bf1c425 100644
--- a/components/autofill/core/common/autofill_regexes_unittest.cc
+++ b/components/autofill/core/common/autofill_regexes_unittest.cc
@@ -16,7 +16,7 @@
 
 namespace autofill {
 
-TEST(AutofillRegexesTest, AutofillRegexes) {
+TEST(AutofillRegexesTest, SampleRegexes) {
   struct TestCase {
     const char* const input;
     const char* const pattern;
@@ -66,4 +66,150 @@
   }
 }
 
+TEST(AutofillRegexesTest, ExpirationDate2DigitYearRegexes) {
+  struct TestCase {
+    const char* const input;
+  };
+
+  const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
+
+  const TestCase kPositiveCases[] = {
+    // Simple two year cases
+    {"mm / yy"},
+    {"mm/ yy"},
+    {"mm /yy"},
+    {"mm/yy"},
+    {"mm - yy"},
+    {"mm- yy"},
+    {"mm -yy"},
+    {"mm-yy"},
+    {"mmyy"},
+    // Complex two year cases
+    {"Expiration Date (MM / YY)"},
+    {"Expiration Date (MM/YY)"},
+    {"Expiration Date (MM - YY)"},
+    {"Expiration Date (MM-YY)"},
+    {"Expiration Date MM / YY"},
+    {"Expiration Date MM/YY"},
+    {"Expiration Date MM - YY"},
+    {"Expiration Date MM-YY"},
+    {"expiration date yy"},
+    {"Exp Date     (MM / YY)"},
+  };
+
+  for (size_t i = 0; i < arraysize(kPositiveCases); ++i) {
+    const TestCase& test_case = kPositiveCases[i];
+    SCOPED_TRACE(test_case.input);
+    EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),pattern));
+  }
+
+  const TestCase kNegativeCases[] = {
+    {""},
+    {"Look, ma' -- an invalid string!"},
+    {"mmfavouritewordyy"},
+    {"mm a yy"},
+    {"mm a yyyy"},
+    // Simple four year cases
+    {"mm / yyyy"},
+    {"mm/ yyyy"},
+    {"mm /yyyy"},
+    {"mm/yyyy"},
+    {"mm - yyyy"},
+    {"mm- yyyy"},
+    {"mm -yyyy"},
+    {"mm-yyyy"},
+    {"mmyyyy"},
+    // Complex four year cases
+    {"Expiration Date (MM / YYYY)"},
+    {"Expiration Date (MM/YYYY)"},
+    {"Expiration Date (MM - YYYY)"},
+    {"Expiration Date (MM-YYYY)"},
+    {"Expiration Date MM / YYYY"},
+    {"Expiration Date MM/YYYY"},
+    {"Expiration Date MM - YYYY"},
+    {"Expiration Date MM-YYYY"},
+    {"expiration date yyyy"},
+    {"Exp Date     (MM / YYYY)"},
+  };
+
+  for (size_t i = 0; i < arraysize(kNegativeCases); ++i) {
+    const TestCase& test_case = kNegativeCases[i];
+    SCOPED_TRACE(test_case.input);
+    EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+  }
+}
+
+TEST(AutofillRegexesTest, ExpirationDate4DigitYearRegexes) {
+  struct TestCase {
+    const char* const input;
+  };
+
+  const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
+
+  const TestCase kPositiveCases[] = {
+    // Simple four year cases
+    {"mm / yyyy"},
+    {"mm/ yyyy"},
+    {"mm /yyyy"},
+    {"mm/yyyy"},
+    {"mm - yyyy"},
+    {"mm- yyyy"},
+    {"mm -yyyy"},
+    {"mm-yyyy"},
+    {"mmyyyy"},
+    // Complex four year cases
+    {"Expiration Date (MM / YYYY)"},
+    {"Expiration Date (MM/YYYY)"},
+    {"Expiration Date (MM - YYYY)"},
+    {"Expiration Date (MM-YYYY)"},
+    {"Expiration Date MM / YYYY"},
+    {"Expiration Date MM/YYYY"},
+    {"Expiration Date MM - YYYY"},
+    {"Expiration Date MM-YYYY"},
+    {"expiration date yyyy"},
+    {"Exp Date     (MM / YYYY)"},
+  };
+
+  for (size_t i = 0; i < arraysize(kPositiveCases); ++i) {
+    const TestCase& test_case = kPositiveCases[i];
+    SCOPED_TRACE(test_case.input);
+    EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),pattern));
+  }
+
+  const TestCase kNegativeCases[] = {
+    {""},
+    {"Look, ma' -- an invalid string!"},
+    {"mmfavouritewordyy"},
+    {"mm a yy"},
+    {"mm a yyyy"},
+    // Simple two year cases
+    {"mm / yy"},
+    {"mm/ yy"},
+    {"mm /yy"},
+    {"mm/yy"},
+    {"mm - yy"},
+    {"mm- yy"},
+    {"mm -yy"},
+    {"mm-yy"},
+    {"mmyy"},
+    // Complex two year cases
+    {"Expiration Date (MM / YY)"},
+    {"Expiration Date (MM/YY)"},
+    {"Expiration Date (MM - YY)"},
+    {"Expiration Date (MM-YY)"},
+    {"Expiration Date MM / YY"},
+    {"Expiration Date MM/YY"},
+    {"Expiration Date MM - YY"},
+    {"Expiration Date MM-YY"},
+    {"expiration date yy"},
+    {"Exp Date     (MM / YY)"},
+  };
+
+  for (size_t i = 0; i < arraysize(kNegativeCases); ++i) {
+    const TestCase& test_case = kNegativeCases[i];
+    SCOPED_TRACE(test_case.input);
+    EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+  }
+}
+
 }  // namespace autofill
diff --git a/components/dom_distiller/content/browser/distillable_page_utils_android.cc b/components/dom_distiller/content/browser/distillable_page_utils_android.cc
index 8ba1281..f0890f68 100644
--- a/components/dom_distiller/content/browser/distillable_page_utils_android.cc
+++ b/components/dom_distiller/content/browser/distillable_page_utils_android.cc
@@ -14,6 +14,7 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/DistillablePageUtils_jni.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 
 namespace dom_distiller {
diff --git a/components/dom_distiller/core/distilled_page_prefs_android.cc b/components/dom_distiller/core/distilled_page_prefs_android.cc
index 64bfc2bf..269e8702 100644
--- a/components/dom_distiller/core/distilled_page_prefs_android.cc
+++ b/components/dom_distiller/core/distilled_page_prefs_android.cc
@@ -8,6 +8,8 @@
 #include "components/dom_distiller/core/dom_distiller_service.h"
 #include "jni/DistilledPagePrefs_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace dom_distiller {
 
 namespace android {
diff --git a/components/dom_distiller/core/dom_distiller_service_android.cc b/components/dom_distiller/core/dom_distiller_service_android.cc
index cdf7289..0f4b131 100644
--- a/components/dom_distiller/core/dom_distiller_service_android.cc
+++ b/components/dom_distiller/core/dom_distiller_service_android.cc
@@ -13,6 +13,7 @@
 #include "jni/DomDistillerService_jni.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace dom_distiller {
diff --git a/components/dom_distiller/core/url_utils_android.cc b/components/dom_distiller/core/url_utils_android.cc
index fc387869..cd07cdc 100644
--- a/components/dom_distiller/core/url_utils_android.cc
+++ b/components/dom_distiller/core/url_utils_android.cc
@@ -13,6 +13,9 @@
 #include "net/base/url_util.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace dom_distiller {
 
 namespace url_utils {
diff --git a/components/domain_reliability/quic_error_mapping.cc b/components/domain_reliability/quic_error_mapping.cc
index cc0b84d3..1e8a965 100644
--- a/components/domain_reliability/quic_error_mapping.cc
+++ b/components/domain_reliability/quic_error_mapping.cc
@@ -236,6 +236,10 @@
   // Stream frame overlaps with buffered data.
   { net::QUIC_OVERLAPPING_STREAM_DATA,
     "quic.overlapping_stream_data" },
+  // Stream frames arrived too discontiguously so that stream sequencer buffer
+  // has too many gaps.
+  { net::QUIC_TOO_MANY_FRAME_GAPS,
+    "quic.too_many_frame_gaps" },
 
   // No error. Used as bound while iterating.
   { net::QUIC_LAST_ERROR, "quic.last_error"}
diff --git a/components/external_video_surface/browser/android/external_video_surface_container_impl.cc b/components/external_video_surface/browser/android/external_video_surface_container_impl.cc
index cac766d..9b7295f0 100644
--- a/components/external_video_surface/browser/android/external_video_surface_container_impl.cc
+++ b/components/external_video_surface/browser/android/external_video_surface_container_impl.cc
@@ -10,6 +10,7 @@
 #include "ui/gfx/geometry/rect_f.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using content::ContentViewCore;
 
 namespace external_video_surface {
diff --git a/components/gcm_driver/gcm_driver_android.cc b/components/gcm_driver/gcm_driver_android.cc
index 40e204d..3354c22 100644
--- a/components/gcm_driver/gcm_driver_android.cc
+++ b/components/gcm_driver/gcm_driver_android.cc
@@ -20,6 +20,7 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::JavaByteArrayToByteVector;
+using base::android::JavaParamRef;
 
 namespace gcm {
 
diff --git a/components/invalidation/impl/invalidation_service_android.cc b/components/invalidation/impl/invalidation_service_android.cc
index c2fdabc..c0704a5 100644
--- a/components/invalidation/impl/invalidation_service_android.cc
+++ b/components/invalidation/impl/invalidation_service_android.cc
@@ -14,6 +14,7 @@
 
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 
 namespace invalidation {
 
diff --git a/components/navigation_interception/navigation_params_android.cc b/components/navigation_interception/navigation_params_android.cc
index be90ef7..c761d15 100644
--- a/components/navigation_interception/navigation_params_android.cc
+++ b/components/navigation_interception/navigation_params_android.cc
@@ -8,6 +8,7 @@
 #include "jni/NavigationParams_jni.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
 
 namespace navigation_interception {
 
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index 22ea5ae..d601cdd 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -24,6 +24,8 @@
     "content_suggestions_provider.h",
     "content_suggestions_service.cc",
     "content_suggestions_service.h",
+    "features.cc",
+    "features.h",
     "ntp_snippet.cc",
     "ntp_snippet.h",
     "ntp_snippets_constants.cc",
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc
new file mode 100644
index 0000000..7645601
--- /dev/null
+++ b/components/ntp_snippets/features.cc
@@ -0,0 +1,12 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/ntp_snippets/features.h"
+
+namespace ntp_snippets {
+
+const base::Feature kContentSuggestionsFeature{
+    "NTPSnippets", base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace ntp_snippets
diff --git a/components/ntp_snippets/features.h b/components/ntp_snippets/features.h
new file mode 100644
index 0000000..0f86f5ca
--- /dev/null
+++ b/components/ntp_snippets/features.h
@@ -0,0 +1,16 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NTP_SNIPPETS_FEATURES_H_
+#define COMPONENTS_NTP_SNIPPETS_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace ntp_snippets {
+
+extern const base::Feature kContentSuggestionsFeature;
+
+}  // namespace ntp_snippets
+
+#endif  // COMPONENTS_NTP_SNIPPETS_FEATURES_H_
diff --git a/components/offline_pages/background/request_coordinator.cc b/components/offline_pages/background/request_coordinator.cc
index f8d9eba..b32cfa2f 100644
--- a/components/offline_pages/background/request_coordinator.cc
+++ b/components/offline_pages/background/request_coordinator.cc
@@ -69,6 +69,32 @@
                                 weak_ptr_factory_.GetWeakPtr()));
   return true;
 }
+void RequestCoordinator::GetQueuedRequests(
+    const std::string& client_namespace,
+    const QueuedRequestCallback& callback) {
+  // Get all matching requests from the request queue, send them to our
+  // callback.  We bind the namespace and callback to the front of the callback
+  // param set.
+  queue_->GetRequests(base::Bind(&RequestCoordinator::GetQueuedRequestsCallback,
+                                 weak_ptr_factory_.GetWeakPtr(),
+                                 client_namespace, callback));
+}
+
+// For each request matching the client_namespace, return the ClientId.
+void RequestCoordinator::GetQueuedRequestsCallback(
+    const std::string& client_namespace,
+    const QueuedRequestCallback& callback,
+    RequestQueue::GetRequestsResult result,
+    const std::vector<SavePageRequest>& requests) {
+  std::vector<ClientId> client_ids;
+
+  for (const auto& request : requests) {
+    if (client_namespace == request.client_id().name_space)
+      client_ids.push_back(request.client_id());
+  }
+
+  callback.Run(client_ids);
+}
 
 void RequestCoordinator::RemoveRequests(
     const std::vector<ClientId>& client_ids) {
diff --git a/components/offline_pages/background/request_coordinator.h b/components/offline_pages/background/request_coordinator.h
index 24c2183..1be33930 100644
--- a/components/offline_pages/background/request_coordinator.h
+++ b/components/offline_pages/background/request_coordinator.h
@@ -55,6 +55,17 @@
   // TODO(petewil): Add code to cancel an in-progress pre-render.
   void RemoveRequests(const std::vector<ClientId>& client_ids);
 
+  // Callback that receives the response for GetQueuedRequests.  Client must
+  // copy the result right away, it goes out of scope at the end of the
+  // callback.
+  typedef base::Callback<void(const std::vector<ClientId>&)>
+      QueuedRequestCallback;
+
+  // For a client namespace, get the ClientId of all requests for that
+  // namespace.
+  void GetQueuedRequests(const std::string& client_namespace,
+                         const QueuedRequestCallback& callback);
+
   // Starts processing of one or more queued save page later requests.
   // Returns whether processing was started and that caller should expect
   // a callback. If processing was already active, returns false.
@@ -100,9 +111,18 @@
   }
 
  private:
+  // Receives the results of a get from the request queue, and turns that into
+  // ClientId objects for the caller of GetQueuedRequests.
+  void GetQueuedRequestsCallback(const std::string& client_namespace,
+                                 const QueuedRequestCallback& callback,
+                                 RequestQueue::GetRequestsResult result,
+                                 const std::vector<SavePageRequest>& requests);
+
+  // Receives the result of add requests to the request queue.
   void AddRequestResultCallback(RequestQueue::AddRequestResult result,
                                 const SavePageRequest& request);
 
+  // Receives the result of update and delete requests to the request queue.
   void UpdateRequestCallback(RequestQueue::UpdateRequestResult result);
 
   // Callback from the request picker when it has chosen our next request.
diff --git a/components/offline_pages/background/request_coordinator_unittest.cc b/components/offline_pages/background/request_coordinator_unittest.cc
index eb59471a..68b9bac 100644
--- a/components/offline_pages/background/request_coordinator_unittest.cc
+++ b/components/offline_pages/background/request_coordinator_unittest.cc
@@ -29,12 +29,15 @@
 
 namespace {
 // put test constants here
-const GURL kUrl("http://universe.com/everything");
-const ClientId kClientId("bookmark", "42");
-const int kRequestId2(2);
+const GURL kUrl1("http://universe.com/everything");
 const GURL kUrl2("http://universe.com/toinfinityandbeyond");
-const ClientId kClientId2("bookmark", "43");
-const int kRequestId(1);
+const std::string kClientNamespace("bookmark");
+const std::string kId1("42");
+const std::string kId2("life*universe+everything");
+const ClientId kClientId1(kClientNamespace, kId1);
+const ClientId kClientId2(kClientNamespace, kId2);
+const int kRequestId1(1);
+const int kRequestId2(2);
 const long kTestTimeoutSeconds = 1;
 const long kTestTimeBudgetSeconds = 200;
 const int kBatteryPercentageHigh = 75;
@@ -75,7 +78,7 @@
 class OfflinerStub : public Offliner {
  public:
   OfflinerStub()
-      : request_(kRequestId, kUrl, kClientId, base::Time::Now(),
+      : request_(kRequestId1, kUrl1, kClientId1, base::Time::Now(),
                  kUserRequested),
         enable_callback_(false),
         cancel_called_(false) {}
@@ -141,7 +144,7 @@
     return coordinator_->is_busy();
   }
 
-  // Empty callback function
+  // Empty callback function.
   void EmptyCallbackFunction(bool result) {
   }
 
@@ -150,7 +153,7 @@
     waiter_.Signal();
   }
 
-  // Callback for Add requests
+  // Callback for Add requests.
   void AddRequestDone(RequestQueue::AddRequestResult result,
                       const SavePageRequest& request);
 
@@ -158,6 +161,9 @@
   void GetRequestsDone(RequestQueue::GetRequestsResult result,
                        const std::vector<SavePageRequest>& requests);
 
+  // Callback for getting request statuses.
+  void GetQueuedRequestsDone(const std::vector<ClientId>& client_ids);
+
   void SendOfflinerDoneCallback(const SavePageRequest& request,
                                 Offliner::RequestStatus status);
 
@@ -169,6 +175,10 @@
     return last_requests_;
   }
 
+  const std::vector<ClientId>& last_client_ids() const {
+    return last_client_ids_;
+  }
+
   void EnableOfflinerCallback(bool enable) {
     offliner_->enable_callback(enable);
   }
@@ -198,6 +208,7 @@
  private:
   RequestQueue::GetRequestsResult last_get_requests_result_;
   std::vector<SavePageRequest> last_requests_;
+  std::vector<ClientId> last_client_ids_;
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
   base::ThreadTaskRunnerHandle task_runner_handle_;
   std::unique_ptr<RequestCoordinator> coordinator_;
@@ -241,6 +252,12 @@
   last_requests_ = requests;
 }
 
+void RequestCoordinatorTest::GetQueuedRequestsDone(
+    const std::vector<ClientId>& client_ids) {
+  last_client_ids_ = client_ids;
+  waiter_.Signal();
+}
+
 void RequestCoordinatorTest::AddRequestDone(
     RequestQueue::AddRequestResult result,
     const SavePageRequest& request) {}
@@ -263,7 +280,7 @@
 
 TEST_F(RequestCoordinatorTest, StartProcessingWithRequestInProgress) {
   // Put the request on the queue.
-  EXPECT_TRUE(coordinator()->SavePageLater(kUrl, kClientId, kUserRequested));
+  EXPECT_TRUE(coordinator()->SavePageLater(kUrl1, kClientId1, kUserRequested));
 
   // Set up for the call to StartProcessing by building arguments.
   DeviceConditions device_conditions(false, 75,
@@ -286,7 +303,7 @@
 }
 
 TEST_F(RequestCoordinatorTest, SavePageLater) {
-  EXPECT_TRUE(coordinator()->SavePageLater(kUrl, kClientId, kUserRequested));
+  EXPECT_TRUE(coordinator()->SavePageLater(kUrl1, kClientId1, kUserRequested));
 
   // Expect that a request got placed on the queue.
   coordinator()->queue()->GetRequests(
@@ -298,8 +315,8 @@
 
   // Check the request queue is as expected.
   EXPECT_EQ(1UL, last_requests().size());
-  EXPECT_EQ(kUrl, last_requests()[0].url());
-  EXPECT_EQ(kClientId, last_requests()[0].client_id());
+  EXPECT_EQ(kUrl1, last_requests()[0].url());
+  EXPECT_EQ(kClientId1, last_requests()[0].client_id());
 
   // Expect that the scheduler got notified.
   SchedulerStub* scheduler_stub = reinterpret_cast<SchedulerStub*>(
@@ -314,7 +331,7 @@
 TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
   // Add a request to the queue, wait for callbacks to finish.
   offline_pages::SavePageRequest request(
-      kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
+      kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
   coordinator()->queue()->AddRequest(
       request,
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -354,7 +371,7 @@
 TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
   // Add a request to the queue, wait for callbacks to finish.
   offline_pages::SavePageRequest request(
-      kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
+      kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
   coordinator()->queue()->AddRequest(
       request,
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -411,7 +428,7 @@
 TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingImmediately) {
   // Add a request to the queue, wait for callbacks to finish.
   offline_pages::SavePageRequest request(
-      kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
+      kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
   coordinator()->queue()->AddRequest(
       request,
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -445,7 +462,7 @@
 TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingLater) {
   // Add a request to the queue, wait for callbacks to finish.
   offline_pages::SavePageRequest request(
-      kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
+      kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
   coordinator()->queue()->AddRequest(
       request,
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -484,7 +501,7 @@
 TEST_F(RequestCoordinatorTest, PrerendererTimeout) {
   // Build a request to use with the pre-renderer, and put it on the queue.
   offline_pages::SavePageRequest request(
-      kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
+      kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
   coordinator()->queue()->AddRequest(
       request,
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -527,18 +544,18 @@
 }
 
 TEST_F(RequestCoordinatorTest, TimeBudgetExceeded) {
-  // Build a request to use with the pre-renderer, and put it on the queue.
+  // Build two requests to use with the pre-renderer, and put it on the queue.
   offline_pages::SavePageRequest request1(
-      kRequestId, kUrl, kClientId, base::Time::Now(), kUserRequested);
+      kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
   offline_pages::SavePageRequest request2(
-      kRequestId + 1, kUrl, kClientId, base::Time::Now(), kUserRequested);
+      kRequestId1 + 1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
   request2.set_attempt_count(kAttemptCount);
   coordinator()->queue()->AddRequest(
       request1,
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
                  base::Unretained(this)));
-    coordinator()->queue()->AddRequest(
-      request1,
+  coordinator()->queue()->AddRequest(
+      request1,  // TODO(petewil): This is a bug, should be request2.
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
                  base::Unretained(this)));
   PumpLoop();
@@ -572,4 +589,35 @@
   EXPECT_EQ(1UL, last_requests().size());
 }
 
+TEST_F(RequestCoordinatorTest, GetQueuedRequests) {
+  // Add two requests to the queue.
+  offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
+                                          base::Time::Now(), kUserRequested);
+  offline_pages::SavePageRequest request2(kRequestId1 + 1, kUrl2, kClientId2,
+                                          base::Time::Now(), kUserRequested);
+  coordinator()->queue()->AddRequest(
+      request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+                           base::Unretained(this)));
+  coordinator()->queue()->AddRequest(
+      request2, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+                           base::Unretained(this)));
+  PumpLoop();
+
+  // Start the async status fetching.
+  coordinator()->GetQueuedRequests(
+      kClientNamespace,
+      base::Bind(&RequestCoordinatorTest::GetQueuedRequestsDone,
+                 base::Unretained(this)));
+  PumpLoop();
+
+  // Wait for async get to finish.
+  WaitForCallback();
+  PumpLoop();
+
+  // Check that the statuses found in the callback match what we expect.
+  EXPECT_EQ(2UL, last_client_ids().size());
+  EXPECT_EQ(kId1, last_client_ids().at(0).id);
+  EXPECT_EQ(kId2, last_client_ids().at(1).id);
+}
+
 }  // namespace offline_pages
diff --git a/components/policy/core/browser/android/android_combined_policy_provider.cc b/components/policy/core/browser/android/android_combined_policy_provider.cc
index 8ace29b..7f1aeecf 100644
--- a/components/policy/core/browser/android/android_combined_policy_provider.cc
+++ b/components/policy/core/browser/android/android_combined_policy_provider.cc
@@ -10,6 +10,7 @@
 #include "jni/CombinedPolicyProvider_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 
 namespace {
 
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index 1876a68..b0763bc 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -57,7 +57,7 @@
     Validation successful
   </message>
   <message name="IDS_POLICY_VALIDATION_BAD_INITIAL_SIGNATURE" desc="Message indicating a bad signature on policy validation using the initial key.">
-    Bad intial signature
+    Bad initial signature
   </message>
   <message name="IDS_POLICY_VALIDATION_BAD_SIGNATURE" desc="Message indicating a bad signature on policy validation.">
     Bad signature
diff --git a/components/safe_json/json_sanitizer_android.cc b/components/safe_json/json_sanitizer_android.cc
index f7f007b..12dd2503 100644
--- a/components/safe_json/json_sanitizer_android.cc
+++ b/components/safe_json/json_sanitizer_android.cc
@@ -14,6 +14,8 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "jni/JsonSanitizer_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace safe_json {
 
 namespace {
diff --git a/components/search_provider_logos.gypi b/components/search_provider_logos.gypi
index 3b5f777..a46b767 100644
--- a/components/search_provider_logos.gypi
+++ b/components/search_provider_logos.gypi
@@ -26,6 +26,8 @@
         'search_provider_logos/logo_common.h',
         'search_provider_logos/logo_tracker.cc',
         'search_provider_logos/logo_tracker.h',
+        'search_provider_logos/switches.cc',
+        'search_provider_logos/switches.h',
       ],
     },
   ],
diff --git a/components/search_provider_logos/BUILD.gn b/components/search_provider_logos/BUILD.gn
index 84db250..3191df25 100644
--- a/components/search_provider_logos/BUILD.gn
+++ b/components/search_provider_logos/BUILD.gn
@@ -12,6 +12,8 @@
     "logo_common.h",
     "logo_tracker.cc",
     "logo_tracker.h",
+    "switches.cc",
+    "switches.h",
   ]
 
   public_deps = [
diff --git a/components/search_provider_logos/google_logo_api.cc b/components/search_provider_logos/google_logo_api.cc
index 02c127d..40fc1e8 100644
--- a/components/search_provider_logos/google_logo_api.cc
+++ b/components/search_provider_logos/google_logo_api.cc
@@ -79,9 +79,17 @@
 
   // Default parsing failure to be true.
   *parsing_failed = true;
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response_sp);
-  if (!value.get())
+
+  int error_code;
+  std::string error_string;
+  int error_line;
+  int error_col;
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
+      response_sp, 0, &error_code, &error_string, &error_line, &error_col);
+  if (!value) {
+    LOG(WARNING) << error_string << " at " << error_line << ":" << error_col;
     return nullptr;
+  }
   // The important data lives inside several nested dictionaries:
   // {"update": {"logo": { "mime_type": ..., etc } } }
   const base::DictionaryValue* outer_dict;
diff --git a/components/search_provider_logos/logo_tracker.cc b/components/search_provider_logos/logo_tracker.cc
index 1e384139..eb86eb6 100644
--- a/components/search_provider_logos/logo_tracker.cc
+++ b/components/search_provider_logos/logo_tracker.cc
@@ -7,12 +7,15 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_clock.h"
+#include "components/search_provider_logos/switches.h"
 #include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
@@ -23,8 +26,6 @@
 
 const int64_t kMaxDownloadBytes = 1024 * 1024;
 
-//const int kDecodeLogoTimeoutSeconds = 30;
-
 // Returns whether the metadata for the cached logo indicates that the logo is
 // OK to show, i.e. it's not expired or it's allowed to be shown temporarily
 // after expiration.
@@ -208,14 +209,19 @@
   DCHECK(!fetcher_);
   DCHECK(!is_idle_);
 
-  GURL url;
   std::string fingerprint;
   if (cached_logo_ && !cached_logo_->metadata.fingerprint.empty() &&
       cached_logo_->metadata.expiration_time >= clock_->Now()) {
     fingerprint = cached_logo_->metadata.fingerprint;
   }
-  url = append_queryparams_func_.Run(
-      logo_url_, fingerprint, wants_cta_, transparent_);
+  GURL url;
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kGoogleDoodleUrl)) {
+    url = GURL(command_line->GetSwitchValueASCII(switches::kGoogleDoodleUrl));
+  } else {
+    url = append_queryparams_func_.Run(
+        logo_url_, fingerprint, wants_cta_, transparent_);
+  }
 
   fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
   fetcher_->SetRequestContext(request_context_getter_.get());
@@ -295,7 +301,7 @@
     }
   }
 
-  DCHECK(download_outcome != kDownloadOutcomeNotTracked);
+  DCHECK_NE(kDownloadOutcomeNotTracked, download_outcome);
   ReturnToIdle(download_outcome);
 }
 
@@ -303,7 +309,16 @@
   DCHECK(!is_idle_);
   std::unique_ptr<net::URLFetcher> cleanup_fetcher(fetcher_.release());
 
-  if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200)) {
+  if (!source->GetStatus().is_success()) {
+    ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
+    return;
+  }
+
+  int response_code = source->GetResponseCode();
+  if (response_code != net::HTTP_OK &&
+      response_code != net::URLFetcher::RESPONSE_CODE_INVALID) {
+    // RESPONSE_CODE_INVALID is returned when fetching from a file: URL
+    // (for testing). In all other cases we would have had a non-success status.
     ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
     return;
   }
diff --git a/components/search_provider_logos/switches.cc b/components/search_provider_logos/switches.cc
new file mode 100644
index 0000000..32679db
--- /dev/null
+++ b/components/search_provider_logos/switches.cc
@@ -0,0 +1,14 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/search_provider_logos/switches.h"
+
+namespace search_provider_logos {
+namespace switches {
+
+// Overrides the URL used to fetch the current Google Doodle.
+const char kGoogleDoodleUrl[] = "google-doodle-url";
+
+}  // namespace switches
+}  // namespace search_provider_logos
diff --git a/components/search_provider_logos/switches.h b/components/search_provider_logos/switches.h
new file mode 100644
index 0000000..385690f
--- /dev/null
+++ b/components/search_provider_logos/switches.h
@@ -0,0 +1,16 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SEARCH_PROVIDER_LOGOS_SWITCHES_H_
+#define COMPONENTS_SEARCH_PROVIDER_LOGOS_SWITCHES_H_
+
+namespace search_provider_logos {
+namespace switches {
+
+extern const char kGoogleDoodleUrl[];
+
+}  // namespace switches
+}  // namespace search_provider_logos
+
+#endif  // COMPONENTS_SEARCH_PROVIDER_LOGOS_SWITCHES_H_
diff --git a/components/signin/core/browser/child_account_info_fetcher_android.cc b/components/signin/core/browser/child_account_info_fetcher_android.cc
index 1321588..dbb6e6a8 100644
--- a/components/signin/core/browser/child_account_info_fetcher_android.cc
+++ b/components/signin/core/browser/child_account_info_fetcher_android.cc
@@ -10,6 +10,8 @@
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "jni/ChildAccountInfoFetcher_jni.h"
 
+using base::android::JavaParamRef;
+
 // static
 void ChildAccountInfoFetcherAndroid::StartFetchingChildAccountInfo(
     AccountFetcherService* service,
diff --git a/components/sync/android/model_type_helper.cc b/components/sync/android/model_type_helper.cc
index e3215a19..46ca7e9 100644
--- a/components/sync/android/model_type_helper.cc
+++ b/components/sync/android/model_type_helper.cc
@@ -11,6 +11,9 @@
 #include "components/sync/base/model_type.h"
 #include "jni/ModelTypeHelper_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace syncer {
 
 static ScopedJavaLocalRef<jstring> ModelTypeToNotificationType(
diff --git a/components/sync/test/fake_server/android/fake_server_helper_android.cc b/components/sync/test/fake_server/android/fake_server_helper_android.cc
index 75801f55..1f4491a 100644
--- a/components/sync/test/fake_server/android/fake_server_helper_android.cc
+++ b/components/sync/test/fake_server/android/fake_server_helper_android.cc
@@ -28,6 +28,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 FakeServerHelperAndroid::FakeServerHelperAndroid(JNIEnv* env, jobject obj) {}
 
 FakeServerHelperAndroid::~FakeServerHelperAndroid() {}
diff --git a/components/test_runner/BUILD.gn b/components/test_runner/BUILD.gn
index cc2fa4e..6b2bad0 100644
--- a/components/test_runner/BUILD.gn
+++ b/components/test_runner/BUILD.gn
@@ -36,6 +36,8 @@
     "mock_content_settings_client.h",
     "mock_credential_manager_client.cc",
     "mock_credential_manager_client.h",
+    "mock_grammar_check.cc",
+    "mock_grammar_check.h",
     "mock_screen_orientation_client.cc",
     "mock_screen_orientation_client.h",
     "mock_spell_check.cc",
diff --git a/components/test_runner/mock_grammar_check.cc b/components/test_runner/mock_grammar_check.cc
new file mode 100644
index 0000000..9125766
--- /dev/null
+++ b/components/test_runner/mock_grammar_check.cc
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/test_runner/mock_grammar_check.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "components/test_runner/test_common.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+
+namespace test_runner {
+
+bool MockGrammarCheck::CheckGrammarOfString(
+    const blink::WebString& text,
+    std::vector<blink::WebTextCheckingResult>* results) {
+  DCHECK(results);
+  base::string16 string_text = text;
+  if (std::find_if(string_text.begin(), string_text.end(), IsASCIIAlpha) ==
+      string_text.end())
+    return true;
+
+  // Find matching grammatical errors from known ones. This function has to
+  // check all errors because the given text may consist of two or more
+  // sentences that have grammatical errors.
+  static const struct {
+    const char* text;
+    int location;
+    int length;
+  } kGrammarErrors[] = {
+        {"I have a issue.", 7, 1},
+        {"I have an grape.", 7, 2},
+        {"I have an kiwi.", 7, 2},
+        {"I have an muscat.", 7, 2},
+        {"You has the right.", 4, 3},
+        {"apple orange zz.", 0, 16},
+        {"apple zz orange.", 0, 16},
+        {"apple,zz,orange.", 0, 16},
+        {"orange,zz,apple.", 0, 16},
+        {"the the adlj adaasj sdklj. there there", 4, 3},
+        {"the the adlj adaasj sdklj. there there", 33, 5},
+        {"zz apple orange.", 0, 16},
+    };
+  for (size_t i = 0; i < arraysize(kGrammarErrors); ++i) {
+    size_t offset = 0;
+    base::string16 error(
+        kGrammarErrors[i].text,
+        kGrammarErrors[i].text + strlen(kGrammarErrors[i].text));
+    while ((offset = string_text.find(error, offset)) != base::string16::npos) {
+      results->push_back(
+          blink::WebTextCheckingResult(blink::WebTextDecorationTypeGrammar,
+                                       offset + kGrammarErrors[i].location,
+                                       kGrammarErrors[i].length));
+      offset += kGrammarErrors[i].length;
+    }
+  }
+  return false;
+}
+
+}  // namespace test_runner
diff --git a/components/test_runner/mock_grammar_check.h b/components/test_runner/mock_grammar_check.h
new file mode 100644
index 0000000..2642141d
--- /dev/null
+++ b/components/test_runner/mock_grammar_check.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_TEST_RUNNER_MOCK_GRAMMAR_CHECK_H_
+#define COMPONENTS_TEST_RUNNER_MOCK_GRAMMAR_CHECK_H_
+
+#include <vector>
+
+namespace blink {
+class WebString;
+struct WebTextCheckingResult;
+}
+
+namespace test_runner {
+
+// A mock implementation of a grammar-checker used for WebKit tests. This class
+// only implements the minimal functionarities required by WebKit tests, i.e.
+// this class just compares the given string with known grammar mistakes in
+// webkit tests and adds grammar markers on them. Even though this is sufficent
+// for webkit tests, this class is not suitable for any other usages.
+class MockGrammarCheck {
+ public:
+  static bool CheckGrammarOfString(const blink::WebString&,
+                                   std::vector<blink::WebTextCheckingResult>*);
+};
+
+}  // namespace test_runner
+
+#endif  // COMPONENTS_TEST_RUNNER_MOCK_GRAMMAR_CHECK_H_
diff --git a/components/test_runner/spell_check_client.cc b/components/test_runner/spell_check_client.cc
index 75825f6..68c663a 100644
--- a/components/test_runner/spell_check_client.cc
+++ b/components/test_runner/spell_check_client.cc
@@ -10,6 +10,7 @@
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "components/test_runner/mock_grammar_check.h"
 #include "components/test_runner/test_runner.h"
 #include "components/test_runner/web_task.h"
 #include "components/test_runner/web_test_delegate.h"
@@ -65,6 +66,8 @@
       offset += misspelled_position + misspelled_length;
     }
   }
+  if (mask & blink::WebTextCheckingTypeGrammar)
+    MockGrammarCheck::CheckGrammarOfString(text, &results);
   web_results->assign(results);
 }
 
@@ -119,6 +122,8 @@
       text = text.substr(misspelled_position + misspelled_length);
       offset += misspelled_position + misspelled_length;
     }
+    MockGrammarCheck::CheckGrammarOfString(last_requested_text_check_string_,
+                                           &results);
   }
   last_requested_text_checking_completion_->didFinishCheckingText(results);
   last_requested_text_checking_completion_ = 0;
diff --git a/components/test_runner/test_runner.gyp b/components/test_runner/test_runner.gyp
index 5efc749..b99001d 100644
--- a/components/test_runner/test_runner.gyp
+++ b/components/test_runner/test_runner.gyp
@@ -65,6 +65,8 @@
         'mock_content_settings_client.h',
         'mock_credential_manager_client.cc',
         'mock_credential_manager_client.h',
+        'mock_grammar_check.cc',
+        'mock_grammar_check.h',
         'mock_screen_orientation_client.cc',
         'mock_screen_orientation_client.h',
         'mock_spell_check.cc',
diff --git a/components/variations/android/variations_associated_data_android.cc b/components/variations/android/variations_associated_data_android.cc
index 42e5ae18..1dd8096 100644
--- a/components/variations/android/variations_associated_data_android.cc
+++ b/components/variations/android/variations_associated_data_android.cc
@@ -13,6 +13,8 @@
 
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace variations {
 
diff --git a/content/app/android/child_process_service_impl.cc b/content/app/android/child_process_service_impl.cc
index 551efe9..d4772047 100644
--- a/content/app/android/child_process_service_impl.cc
+++ b/content/app/android/child_process_service_impl.cc
@@ -25,6 +25,7 @@
 using base::android::AttachCurrentThread;
 using base::android::CheckException;
 using base::android::JavaIntArrayToIntVector;
+using base::android::JavaParamRef;
 
 namespace content {
 
diff --git a/content/app/android/content_main.cc b/content/app/android/content_main.cc
index 5b51323..1c82788b 100644
--- a/content/app/android/content_main.cc
+++ b/content/app/android/content_main.cc
@@ -18,6 +18,7 @@
 #include "jni/ContentMain_jni.h"
 
 using base::LazyInstance;
+using base::android::JavaParamRef;
 
 namespace content {
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index cdb5bbbd8..e34d36a0 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -21,6 +21,7 @@
 #include "ui/accessibility/ax_text_utils.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace content {
diff --git a/content/browser/android/background_sync_network_observer_android.cc b/content/browser/android/background_sync_network_observer_android.cc
index 05d46ecd..e87d1fd 100644
--- a/content/browser/android/background_sync_network_observer_android.cc
+++ b/content/browser/android/background_sync_network_observer_android.cc
@@ -7,6 +7,8 @@
 #include "base/android/context_utils.h"
 #include "jni/BackgroundSyncNetworkObserver_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace content {
 
 // static
diff --git a/content/browser/android/browser_startup_controller.cc b/content/browser/android/browser_startup_controller.cc
index 7b59452..98b90ba 100644
--- a/content/browser/android/browser_startup_controller.cc
+++ b/content/browser/android/browser_startup_controller.cc
@@ -10,6 +10,8 @@
 
 #include "jni/BrowserStartupController_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace content {
 
 bool BrowserMayStartAsynchronously() {
diff --git a/content/browser/android/child_process_launcher_android.cc b/content/browser/android/child_process_launcher_android.cc
index f7e8437a..43bd5c8 100644
--- a/content/browser/android/child_process_launcher_android.cc
+++ b/content/browser/android/child_process_launcher_android.cc
@@ -30,6 +30,7 @@
 #include "ui/gl/android/surface_texture.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using base::android::ToJavaArrayOfStrings;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
diff --git a/content/browser/android/content_video_view.cc b/content/browser/android/content_video_view.cc
index e0d1a12..86f6755 100644
--- a/content/browser/android/content_video_view.cc
+++ b/content/browser/android/content_video_view.cc
@@ -15,7 +15,9 @@
 
 using base::android::AttachCurrentThread;
 using base::android::CheckException;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
 using base::UserMetricsAction;
 using content::RecordAction;
 
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 9e8bde5..72b524f 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -72,6 +72,7 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using blink::WebGestureEvent;
 using blink::WebInputEvent;
diff --git a/content/browser/android/content_view_render_view.cc b/content/browser/android/content_view_render_view.cc
index 857fb6b..9fb49fc0 100644
--- a/content/browser/android/content_view_render_view.cc
+++ b/content/browser/android/content_view_render_view.cc
@@ -24,6 +24,7 @@
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/geometry/size.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace content {
diff --git a/content/browser/android/content_view_statics.cc b/content/browser/android/content_view_statics.cc
index f5e7267..81c3e35 100644
--- a/content/browser/android/content_view_statics.cc
+++ b/content/browser/android/content_view_statics.cc
@@ -19,6 +19,8 @@
 
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace {
 
diff --git a/content/browser/android/date_time_chooser_android.cc b/content/browser/android/date_time_chooser_android.cc
index 35d7038..1b079b0 100644
--- a/content/browser/android/date_time_chooser_android.cc
+++ b/content/browser/android/date_time_chooser_android.cc
@@ -22,7 +22,7 @@
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::JavaRef;
-
+using base::android::ScopedJavaLocalRef;
 
 namespace {
 
diff --git a/content/browser/android/interface_provider_android_impl.cc b/content/browser/android/interface_provider_android_impl.cc
index 949bdfd1..c6f9910 100644
--- a/content/browser/android/interface_provider_android_impl.cc
+++ b/content/browser/android/interface_provider_android_impl.cc
@@ -17,6 +17,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 
 namespace content {
diff --git a/content/browser/android/interface_registry_android_impl.cc b/content/browser/android/interface_registry_android_impl.cc
index 02f67b7..d4c9070be 100644
--- a/content/browser/android/interface_registry_android_impl.cc
+++ b/content/browser/android/interface_registry_android_impl.cc
@@ -18,6 +18,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 
 namespace content {
diff --git a/content/browser/android/interstitial_page_delegate_android.cc b/content/browser/android/interstitial_page_delegate_android.cc
index ee4bba84..a88bc0d 100644
--- a/content/browser/android/interstitial_page_delegate_android.cc
+++ b/content/browser/android/interstitial_page_delegate_android.cc
@@ -11,6 +11,7 @@
 #include "jni/InterstitialPageDelegateAndroid_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace content {
diff --git a/content/browser/android/load_url_params.cc b/content/browser/android/load_url_params.cc
index 2f08725..98c6819 100644
--- a/content/browser/android/load_url_params.cc
+++ b/content/browser/android/load_url_params.cc
@@ -12,6 +12,8 @@
 #include "jni/LoadUrlParams_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+
 namespace content {
 
 bool RegisterLoadUrlParams(JNIEnv* env) {
diff --git a/content/browser/android/popup_touch_handle_drawable.cc b/content/browser/android/popup_touch_handle_drawable.cc
index bca147b..01113f3f 100644
--- a/content/browser/android/popup_touch_handle_drawable.cc
+++ b/content/browser/android/popup_touch_handle_drawable.cc
@@ -7,6 +7,8 @@
 #include "content/public/browser/android/content_view_core.h"
 #include "jni/PopupTouchHandleDrawable_jni.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace content {
 
 // static
diff --git a/content/browser/android/tracing_controller_android.cc b/content/browser/android/tracing_controller_android.cc
index 35545aad..9a35987 100644
--- a/content/browser/android/tracing_controller_android.cc
+++ b/content/browser/android/tracing_controller_android.cc
@@ -12,6 +12,9 @@
 #include "content/public/browser/tracing_controller.h"
 #include "jni/TracingControllerAndroid_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace content {
 
 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
diff --git a/content/browser/android/web_contents_observer_proxy.cc b/content/browser/android/web_contents_observer_proxy.cc
index e1f7cc7..f34cc45 100644
--- a/content/browser/android/web_contents_observer_proxy.cc
+++ b/content/browser/android/web_contents_observer_proxy.cc
@@ -18,6 +18,7 @@
 #include "jni/WebContentsObserverProxy_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
diff --git a/content/browser/bluetooth/bluetooth_allowed_devices_map.cc b/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
index 1e8f79b..b4516642 100644
--- a/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
+++ b/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
@@ -4,41 +4,24 @@
 
 #include "content/browser/bluetooth/bluetooth_allowed_devices_map.h"
 
+#include <string>
 #include <vector>
 
-#include "base/base64.h"
 #include "base/logging.h"
 #include "base/optional.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "content/browser/bluetooth/bluetooth_blacklist.h"
-#include "crypto/random.h"
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
 
 using device::BluetoothUUID;
 
 namespace content {
 
-namespace {
-const size_t kIdLength = 16 /* 128bits */;
-
-std::string GetBase64Id() {
-  std::string bytes(
-      kIdLength + 1 /* to avoid bytes being reallocated by WriteInto */, '\0');
-
-  crypto::RandBytes(
-      base::WriteInto(&bytes /* str */, kIdLength + 1 /* length_with_null */),
-      kIdLength);
-
-  base::Base64Encode(bytes, &bytes);
-
-  return bytes;
-}
-}  // namespace
-
 BluetoothAllowedDevicesMap::BluetoothAllowedDevicesMap() {}
 BluetoothAllowedDevicesMap::~BluetoothAllowedDevicesMap() {}
 
-const std::string& BluetoothAllowedDevicesMap::AddDevice(
+const WebBluetoothDeviceId& BluetoothAllowedDevicesMap::AddDevice(
     const url::Origin& origin,
     const std::string& device_address,
     const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) {
@@ -59,7 +42,7 @@
 
     return origin_to_device_address_to_id_map_[origin][device_address];
   }
-  const std::string device_id = GenerateDeviceId();
+  const WebBluetoothDeviceId device_id = GenerateUniqueDeviceId();
   VLOG(1) << "Id generated for device: " << device_id;
 
   origin_to_device_address_to_id_map_[origin][device_address] = device_id;
@@ -75,8 +58,13 @@
 void BluetoothAllowedDevicesMap::RemoveDevice(
     const url::Origin& origin,
     const std::string& device_address) {
-  const std::string device_id = GetDeviceId(origin, device_address);
-  DCHECK(!device_id.empty());
+  const WebBluetoothDeviceId* device_id_ptr =
+      GetDeviceId(origin, device_address);
+  DCHECK(device_id_ptr != nullptr);
+
+  // We make a copy because we are going to remove the original value from its
+  // map.
+  WebBluetoothDeviceId device_id = *device_id_ptr;
 
   // 1. Remove from all three maps.
   CHECK(origin_to_device_address_to_id_map_[origin].erase(device_address));
@@ -94,26 +82,26 @@
   CHECK(device_id_set_.erase(device_id));
 }
 
-const std::string& BluetoothAllowedDevicesMap::GetDeviceId(
+const WebBluetoothDeviceId* BluetoothAllowedDevicesMap::GetDeviceId(
     const url::Origin& origin,
     const std::string& device_address) {
   auto address_map_iter = origin_to_device_address_to_id_map_.find(origin);
   if (address_map_iter == origin_to_device_address_to_id_map_.end()) {
-    return base::EmptyString();
+    return nullptr;
   }
 
   const auto& device_address_to_id_map = address_map_iter->second;
 
   auto id_iter = device_address_to_id_map.find(device_address);
   if (id_iter == device_address_to_id_map.end()) {
-    return base::EmptyString();
+    return nullptr;
   }
-  return id_iter->second;
+  return &(id_iter->second);
 }
 
 const std::string& BluetoothAllowedDevicesMap::GetDeviceAddress(
     const url::Origin& origin,
-    const std::string& device_id) {
+    const WebBluetoothDeviceId& device_id) {
   auto id_map_iter = origin_to_device_id_to_address_map_.find(origin);
   if (id_map_iter == origin_to_device_id_to_address_map_.end()) {
     return base::EmptyString();
@@ -129,7 +117,7 @@
 
 bool BluetoothAllowedDevicesMap::IsOriginAllowedToAccessService(
     const url::Origin& origin,
-    const std::string& device_id,
+    const WebBluetoothDeviceId& device_id,
     const BluetoothUUID& service_uuid) const {
   if (BluetoothBlacklist::Get().IsExcluded(service_uuid)) {
     return false;
@@ -149,11 +137,11 @@
              : ContainsKey(id_iter->second, service_uuid);
 }
 
-std::string BluetoothAllowedDevicesMap::GenerateDeviceId() {
-  std::string device_id = GetBase64Id();
+WebBluetoothDeviceId BluetoothAllowedDevicesMap::GenerateUniqueDeviceId() {
+  WebBluetoothDeviceId device_id = WebBluetoothDeviceId::Create();
   while (ContainsKey(device_id_set_, device_id)) {
     LOG(WARNING) << "Generated repeated id.";
-    device_id = GetBase64Id();
+    device_id = WebBluetoothDeviceId::Create();
   }
   return device_id;
 }
diff --git a/content/browser/bluetooth/bluetooth_allowed_devices_map.h b/content/browser/bluetooth/bluetooth_allowed_devices_map.h
index 396f7293..86dadd2 100644
--- a/content/browser/bluetooth/bluetooth_allowed_devices_map.h
+++ b/content/browser/bluetooth/bluetooth_allowed_devices_map.h
@@ -2,15 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_
-#define CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_
+#ifndef CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_H_
+#define CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_H_
 
-#include <map>
 #include <memory>
-#include <set>
+#include <string>
+#include <unordered_map>
 #include <unordered_set>
 #include <vector>
 
+#include "base/optional.h"
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
 #include "url/origin.h"
@@ -37,7 +39,7 @@
   // devices for that origin. Generates and returns a device id. Because
   // unique origins generate the same hash, unique origins are not supported.
   // Calling this function with a unique origin will CHECK-fail.
-  const std::string& AddDevice(
+  const WebBluetoothDeviceId& AddDevice(
       const url::Origin& origin,
       const std::string& device_address,
       const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options);
@@ -47,34 +49,39 @@
   void RemoveDevice(const url::Origin& origin,
                     const std::string& device_address);
 
-  // Returns the Bluetooth Device's id for |origin|. Returns an empty string
-  // if |origin| is not allowed to access the device.
-  const std::string& GetDeviceId(const url::Origin& origin,
-                                 const std::string& device_address);
+  // Returns the Bluetooth Device's id for |origin| if |origin| is allowed to
+  // access the device.
+  const WebBluetoothDeviceId* GetDeviceId(const url::Origin& origin,
+                                          const std::string& device_address);
 
   // For |device_id| in |origin|, returns the Bluetooth device's address. If
   // there is no such |device_id| in |origin|, returns an empty string.
   const std::string& GetDeviceAddress(const url::Origin& origin,
-                                      const std::string& device_id);
+                                      const WebBluetoothDeviceId& device_id);
 
   // Returns true if the origin has previously been granted access to
   // the service.
   bool IsOriginAllowedToAccessService(
       const url::Origin& origin,
-      const std::string& device_id,
+      const WebBluetoothDeviceId& device_id,
       const device::BluetoothUUID& service_uuid) const;
 
  private:
-  typedef std::map<std::string, std::string> DeviceAddressToIdMap;
-  typedef std::map<std::string, std::string> DeviceIdToAddressMap;
-  typedef std::map<
-      std::string,
-      std::unordered_set<device::BluetoothUUID, device::BluetoothUUIDHash>>
+  typedef std::unordered_map<std::string, WebBluetoothDeviceId>
+      DeviceAddressToIdMap;
+  typedef std::unordered_map<WebBluetoothDeviceId,
+                             std::string,
+                             WebBluetoothDeviceIdHash>
+      DeviceIdToAddressMap;
+  typedef std::unordered_map<
+      WebBluetoothDeviceId,
+      std::unordered_set<device::BluetoothUUID, device::BluetoothUUIDHash>,
+      WebBluetoothDeviceIdHash>
       DeviceIdToServicesMap;
 
   // Returns an id guaranteed to be unique for the map. The id is randomly
   // generated so that an origin can't guess the id used in another origin.
-  std::string GenerateDeviceId();
+  WebBluetoothDeviceId GenerateUniqueDeviceId();
   void AddUnionOfServicesTo(
       const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options,
       std::unordered_set<device::BluetoothUUID, device::BluetoothUUIDHash>*
@@ -92,9 +99,10 @@
       origin_to_device_id_to_services_map_;
 
   // Keep track of all device_ids in the map.
-  std::set<std::string> device_id_set_;
+  std::unordered_set<WebBluetoothDeviceId, WebBluetoothDeviceIdHash>
+      device_id_set_;
 };
 
 }  //  namespace content
 
-#endif  // CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_
+#endif  // CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_H_
diff --git a/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc b/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc
index 58b98d9..1c4b18e 100644
--- a/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc
+++ b/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc
@@ -5,6 +5,7 @@
 #include "content/browser/bluetooth/bluetooth_allowed_devices_map.h"
 
 #include "base/strings/string_util.h"
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -53,46 +54,46 @@
 TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceToMap) {
   BluetoothAllowedDevicesMap allowed_devices_map;
 
-  const std::string& device_id = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress1, empty_options_);
 
   // Test that we can retrieve the device address/id.
   EXPECT_EQ(device_id,
-            allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
+            *allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
   EXPECT_EQ(kDeviceAddress1,
             allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id));
 }
 
 TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceToMapTwice) {
   BluetoothAllowedDevicesMap allowed_devices_map;
-  const std::string& device_id1 = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id1 = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress1, empty_options_);
-  const std::string& device_id2 = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id2 = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress1, empty_options_);
 
   EXPECT_EQ(device_id1, device_id2);
 
   // Test that we can retrieve the device address/id.
   EXPECT_EQ(device_id1,
-            allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
+            *allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
   EXPECT_EQ(kDeviceAddress1,
             allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id1));
 }
 
 TEST_F(BluetoothAllowedDevicesMapTest, AddTwoDevicesFromSameOriginToMap) {
   BluetoothAllowedDevicesMap allowed_devices_map;
-  const std::string& device_id1 = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id1 = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress1, empty_options_);
-  const std::string& device_id2 = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id2 = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress2, empty_options_);
 
   EXPECT_NE(device_id1, device_id2);
 
   // Test that we can retrieve the device address/id.
   EXPECT_EQ(device_id1,
-            allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
+            *allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
   EXPECT_EQ(device_id2,
-            allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress2));
+            *allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress2));
 
   EXPECT_EQ(kDeviceAddress1,
             allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id1));
@@ -102,18 +103,18 @@
 
 TEST_F(BluetoothAllowedDevicesMapTest, AddTwoDevicesFromTwoOriginsToMap) {
   BluetoothAllowedDevicesMap allowed_devices_map;
-  const std::string& device_id1 = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id1 = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress1, empty_options_);
-  const std::string& device_id2 = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id2 = allowed_devices_map.AddDevice(
       kTestOrigin2, kDeviceAddress2, empty_options_);
 
   EXPECT_NE(device_id1, device_id2);
 
   // Test that the wrong origin doesn't have access to the device.
 
-  EXPECT_EQ(base::EmptyString(),
+  EXPECT_EQ(nullptr,
             allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress2));
-  EXPECT_EQ(base::EmptyString(),
+  EXPECT_EQ(nullptr,
             allowed_devices_map.GetDeviceId(kTestOrigin2, kDeviceAddress1));
 
   EXPECT_EQ(base::EmptyString(),
@@ -123,9 +124,9 @@
 
   // Test that we can retrieve the device address/id.
   EXPECT_EQ(device_id1,
-            allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
+            *allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
   EXPECT_EQ(device_id2,
-            allowed_devices_map.GetDeviceId(kTestOrigin2, kDeviceAddress2));
+            *allowed_devices_map.GetDeviceId(kTestOrigin2, kDeviceAddress2));
 
   EXPECT_EQ(kDeviceAddress1,
             allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id1));
@@ -135,9 +136,9 @@
 
 TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceFromTwoOriginsToMap) {
   BluetoothAllowedDevicesMap allowed_devices_map;
-  const std::string& device_id1 = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id1 = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress1, empty_options_);
-  const std::string& device_id2 = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id2 = allowed_devices_map.AddDevice(
       kTestOrigin2, kDeviceAddress1, empty_options_);
 
   EXPECT_NE(device_id1, device_id2);
@@ -151,13 +152,15 @@
 
 TEST_F(BluetoothAllowedDevicesMapTest, AddRemoveAddDeviceToMap) {
   BluetoothAllowedDevicesMap allowed_devices_map;
-  const std::string device_id_first_time = allowed_devices_map.AddDevice(
-      kTestOrigin1, kDeviceAddress1, empty_options_);
+  const WebBluetoothDeviceId device_id_first_time =
+      allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress1,
+                                    empty_options_);
 
   allowed_devices_map.RemoveDevice(kTestOrigin1, kDeviceAddress1);
 
-  const std::string device_id_second_time = allowed_devices_map.AddDevice(
-      kTestOrigin1, kDeviceAddress1, empty_options_);
+  const WebBluetoothDeviceId device_id_second_time =
+      allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress1,
+                                    empty_options_);
 
   EXPECT_NE(device_id_first_time, device_id_second_time);
 }
@@ -165,15 +168,15 @@
 TEST_F(BluetoothAllowedDevicesMapTest, RemoveDeviceFromMap) {
   BluetoothAllowedDevicesMap allowed_devices_map;
 
-  const std::string& device_id = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId device_id = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress1, empty_options_);
 
   allowed_devices_map.RemoveDevice(kTestOrigin1, kDeviceAddress1);
 
+  EXPECT_EQ(nullptr,
+            allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
   EXPECT_EQ(base::EmptyString(),
-            allowed_devices_map.GetDeviceId(kTestOrigin1, device_id));
-  EXPECT_EQ(base::EmptyString(), allowed_devices_map.GetDeviceAddress(
-                                     kTestOrigin1, kDeviceAddress1));
+            allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id));
 }
 
 TEST_F(BluetoothAllowedDevicesMapTest, AllowedServices_OneOriginOneDevice) {
@@ -197,7 +200,7 @@
   options->optional_services.push_back(kHeartRateUUID);
 
   // Add to map.
-  const std::string device_id1 =
+  const WebBluetoothDeviceId device_id1 =
       allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress1, options);
 
   // Access allowed services.
@@ -229,7 +232,7 @@
   options2->filters.push_back(scanFilter1.Clone());
   options2->filters.push_back(scanFilter2.Clone());
 
-  const std::string device_id2 =
+  const WebBluetoothDeviceId device_id2 =
       allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress1, options2);
 
   // Access allowed services.
@@ -277,9 +280,9 @@
   options2->optional_services.push_back(kBloodPressureUUID);
 
   // Add devices to map.
-  const std::string& device_id1 =
+  const WebBluetoothDeviceId& device_id1 =
       allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress1, options1);
-  const std::string& device_id2 =
+  const WebBluetoothDeviceId& device_id2 =
       allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress2, options2);
 
   // Access allowed services.
@@ -334,9 +337,9 @@
   options2->optional_services.push_back(kBloodPressureUUID);
 
   // Add devices to map.
-  const std::string& device_id1 =
+  const WebBluetoothDeviceId& device_id1 =
       allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress1, options1);
-  const std::string& device_id2 =
+  const WebBluetoothDeviceId& device_id2 =
       allowed_devices_map.AddDevice(kTestOrigin2, kDeviceAddress1, options2);
 
   // Access allowed services.
@@ -395,7 +398,7 @@
   options1->optional_services.push_back(kBatteryServiceUUID);
 
   // Add to map.
-  const std::string device_id1 =
+  const WebBluetoothDeviceId device_id1 =
       allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress1, options1);
 
   // Setup second request.
@@ -410,7 +413,7 @@
   options2->optional_services.push_back(kBloodPressureUUID);
 
   // Add to map again.
-  const std::string device_id2 =
+  const WebBluetoothDeviceId device_id2 =
       allowed_devices_map.AddDevice(kTestOrigin1, kDeviceAddress1, options2);
 
   EXPECT_EQ(device_id1, device_id2);
@@ -428,13 +431,10 @@
 TEST_F(BluetoothAllowedDevicesMapTest, CorrectIdFormat) {
   BluetoothAllowedDevicesMap allowed_devices_map;
 
-  const std::string& device_id = allowed_devices_map.AddDevice(
+  const WebBluetoothDeviceId& device_id = allowed_devices_map.AddDevice(
       kTestOrigin1, kDeviceAddress1, empty_options_);
 
-  EXPECT_TRUE(device_id.size() == 24)
-      << "Expected Lenghth of a 128bit string encoded to Base64.";
-  EXPECT_TRUE((device_id[22] == '=') && (device_id[23] == '='))
-      << "Expected padding characters for a 128bit string encoded to Base64.";
+  EXPECT_TRUE(WebBluetoothDeviceId::IsValid(device_id.str()));
 }
 
 }  // namespace content
diff --git a/content/browser/bluetooth/frame_connected_bluetooth_devices.cc b/content/browser/bluetooth/frame_connected_bluetooth_devices.cc
index 16457923..7187609 100644
--- a/content/browser/bluetooth/frame_connected_bluetooth_devices.cc
+++ b/content/browser/bluetooth/frame_connected_bluetooth_devices.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/bluetooth/frame_connected_bluetooth_devices.h"
 
+#include "base/optional.h"
 #include "base/strings/string_util.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/web_contents.h"
@@ -23,7 +24,7 @@
 }
 
 bool FrameConnectedBluetoothDevices::IsConnectedToDeviceWithId(
-    const std::string& device_id) {
+    const WebBluetoothDeviceId& device_id) {
   auto connection_iter = device_id_to_connection_map_.find(device_id);
   if (connection_iter == device_id_to_connection_map_.end()) {
     return false;
@@ -39,7 +40,7 @@
 }
 
 void FrameConnectedBluetoothDevices::Insert(
-    const std::string& device_id,
+    const WebBluetoothDeviceId& device_id,
     std::unique_ptr<device::BluetoothGattConnection> connection) {
   auto connection_iter = device_id_to_connection_map_.find(device_id);
   if (connection_iter != device_id_to_connection_map_.end()) {
@@ -74,7 +75,7 @@
 }
 
 void FrameConnectedBluetoothDevices::CloseConnectionToDeviceWithId(
-    const std::string& device_id) {
+    const WebBluetoothDeviceId& device_id) {
   auto connection_iter = device_id_to_connection_map_.find(device_id);
   if (connection_iter == device_id_to_connection_map_.end()) {
     return;
@@ -85,17 +86,18 @@
   DecrementDevicesConnectedCount();
 }
 
-std::string FrameConnectedBluetoothDevices::CloseConnectionToDeviceWithAddress(
+base::Optional<WebBluetoothDeviceId>
+FrameConnectedBluetoothDevices::CloseConnectionToDeviceWithAddress(
     const std::string& device_address) {
   auto device_address_iter = device_address_to_id_map_.find(device_address);
   if (device_address_iter == device_address_to_id_map_.end()) {
-    return std::string();
+    return base::nullopt;
   }
-  std::string device_id = device_address_iter->second;
+  WebBluetoothDeviceId device_id = device_address_iter->second;
   CHECK(device_address_to_id_map_.erase(device_address));
   CHECK(device_id_to_connection_map_.erase(device_id));
   DecrementDevicesConnectedCount();
-  return device_id;
+  return base::make_optional(device_id);
 }
 
 void FrameConnectedBluetoothDevices::IncrementDevicesConnectedCount() {
diff --git a/content/browser/bluetooth/frame_connected_bluetooth_devices.h b/content/browser/bluetooth/frame_connected_bluetooth_devices.h
index bf76e55..4168059 100644
--- a/content/browser/bluetooth/frame_connected_bluetooth_devices.h
+++ b/content/browser/bluetooth/frame_connected_bluetooth_devices.h
@@ -9,6 +9,8 @@
 #include <string>
 #include <unordered_map>
 
+#include "base/optional.h"
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
 #include "content/common/content_export.h"
 #include "url/origin.h"
 
@@ -35,22 +37,22 @@
   ~FrameConnectedBluetoothDevices();
 
   // Returns true if the map holds a connection to |device_id|.
-  bool IsConnectedToDeviceWithId(const std::string& device_id);
+  bool IsConnectedToDeviceWithId(const WebBluetoothDeviceId& device_id);
 
   // If a connection doesn't exist already for |device_id|, adds a connection to
   // the map and increases the WebContents count of connected devices.
-  void Insert(const std::string& device_id,
+  void Insert(const WebBluetoothDeviceId& device_id,
               std::unique_ptr<device::BluetoothGattConnection> connection);
 
   // Deletes the BluetoothGattConnection for |device_id| and decrements the
   // WebContents count of connected devices if |device_id| had a connection.
-  void CloseConnectionToDeviceWithId(const std::string& device_id);
+  void CloseConnectionToDeviceWithId(const WebBluetoothDeviceId& device_id);
 
   // Deletes the BluetoothGattConnection for |device_address| and decrements the
   // WebContents count of connected devices if |device_address| had a
   // connection. Returns the device_id of the device associated with the
   // connection.
-  std::string CloseConnectionToDeviceWithAddress(
+  base::Optional<WebBluetoothDeviceId> CloseConnectionToDeviceWithAddress(
       const std::string& device_address);
 
  private:
@@ -64,12 +66,14 @@
 
   // Keeps the BluetoothGattConnection objects alive so that connections don't
   // get closed.
-  std::unordered_map<std::string,
-                     std::unique_ptr<device::BluetoothGattConnection>>
+  std::unordered_map<WebBluetoothDeviceId,
+                     std::unique_ptr<device::BluetoothGattConnection>,
+                     WebBluetoothDeviceIdHash>
       device_id_to_connection_map_;
 
   // Keeps track of which device addresses correspond to which ids.
-  std::unordered_map<std::string, std::string> device_address_to_id_map_;
+  std::unordered_map<std::string, WebBluetoothDeviceId>
+      device_address_to_id_map_;
 
   DISALLOW_COPY_AND_ASSIGN(FrameConnectedBluetoothDevices);
 };
diff --git a/content/browser/bluetooth/frame_connected_bluetooth_devices_unittest.cc b/content/browser/bluetooth/frame_connected_bluetooth_devices_unittest.cc
index 644a04d..66b018a 100644
--- a/content/browser/bluetooth/frame_connected_bluetooth_devices_unittest.cc
+++ b/content/browser/bluetooth/frame_connected_bluetooth_devices_unittest.cc
@@ -30,11 +30,11 @@
 
 namespace {
 
-constexpr char kDeviceId0[] = "0";
+const WebBluetoothDeviceId kDeviceId0("000000000000000000000A==");
 constexpr char kDeviceAddress0[] = "0";
 constexpr char kDeviceName0[] = "Device0";
 
-constexpr char kDeviceId1[] = "1";
+const WebBluetoothDeviceId kDeviceId1("111111111111111111111A==");
 constexpr char kDeviceAddress1[] = "1";
 constexpr char kDeviceName1[] = "Device1";
 
@@ -255,7 +255,7 @@
   EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice());
   EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
 
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0),
+  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(),
             kDeviceId0);
 
   EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice());
@@ -269,9 +269,9 @@
   EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice());
   EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
 
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0),
+  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(),
             kDeviceId0);
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0), "");
+  EXPECT_FALSE(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0));
 
   EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice());
   EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
@@ -285,7 +285,7 @@
   EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice());
   EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
 
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0),
+  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(),
             kDeviceId0);
 
   EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice());
@@ -300,9 +300,9 @@
   EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice());
   EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
 
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0),
+  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(),
             kDeviceId0);
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0), "");
+  EXPECT_FALSE(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0));
 
   EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice());
   EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
@@ -316,14 +316,14 @@
   EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
   EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId1));
 
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0),
+  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(),
             kDeviceId0);
 
   EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice());
   EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
   EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId1));
 
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress1),
+  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress1).value(),
             kDeviceId1);
 
   EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice());
@@ -338,14 +338,14 @@
   EXPECT_TRUE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
   EXPECT_TRUE(map1_->IsConnectedToDeviceWithId(kDeviceId1));
 
-  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0),
+  EXPECT_EQ(map0_->CloseConnectionToDeviceWithAddress(kDeviceAddress0).value(),
             kDeviceId0);
 
   EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice());
   EXPECT_FALSE(map0_->IsConnectedToDeviceWithId(kDeviceId0));
   EXPECT_TRUE(map1_->IsConnectedToDeviceWithId(kDeviceId1));
 
-  EXPECT_EQ(map1_->CloseConnectionToDeviceWithAddress(kDeviceAddress1),
+  EXPECT_EQ(map1_->CloseConnectionToDeviceWithAddress(kDeviceAddress1).value(),
             kDeviceId1);
 
   EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice());
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.cc b/content/browser/bluetooth/web_bluetooth_service_impl.cc
index 6db050b1..974eb1db 100644
--- a/content/browser/bluetooth/web_bluetooth_service_impl.cc
+++ b/content/browser/bluetooth/web_bluetooth_service_impl.cc
@@ -20,6 +20,7 @@
 #include "content/browser/bluetooth/bluetooth_metrics.h"
 #include "content/browser/bluetooth/frame_connected_bluetooth_devices.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
@@ -237,13 +238,11 @@
                                             device::BluetoothDevice* device) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!device->IsGattConnected()) {
-    std::string device_id =
+    base::Optional<WebBluetoothDeviceId> device_id =
         connected_devices_->CloseConnectionToDeviceWithAddress(
             device->GetAddress());
-    if (!device_id.empty()) {
-      if (client_) {
-        client_->GattServerDisconnected(device_id);
-      }
+    if (device_id && client_) {
+      client_->GattServerDisconnected(device_id.value());
     }
   }
 }
@@ -331,7 +330,7 @@
 }
 
 void WebBluetoothServiceImpl::RemoteServerConnect(
-    const mojo::String& device_id,
+    const WebBluetoothDeviceId& device_id,
     const RemoteServerConnectCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT);
@@ -365,24 +364,23 @@
                  weak_ptr_factory_.GetWeakPtr(), device_id, start_time,
                  callback),
       base::Bind(&WebBluetoothServiceImpl::OnCreateGATTConnectionFailed,
-                 weak_ptr_factory_.GetWeakPtr(), device_id, start_time,
-                 callback));
+                 weak_ptr_factory_.GetWeakPtr(), start_time, callback));
 }
 
 void WebBluetoothServiceImpl::RemoteServerDisconnect(
-    const mojo::String& device_id) {
+    const WebBluetoothDeviceId& device_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RecordWebBluetoothFunctionCall(
       UMAWebBluetoothFunction::REMOTE_GATT_SERVER_DISCONNECT);
 
   if (connected_devices_->IsConnectedToDeviceWithId(device_id)) {
-    VLOG(1) << "Disconnecting device: " << device_id;
+    VLOG(1) << "Disconnecting device: " << device_id.str();
     connected_devices_->CloseConnectionToDeviceWithId(device_id);
   }
 }
 
 void WebBluetoothServiceImpl::RemoteServerGetPrimaryServices(
-    const mojo::String& device_id,
+    const WebBluetoothDeviceId& device_id,
     blink::mojom::WebBluetoothGATTQueryQuantity quantity,
     const base::Optional<BluetoothUUID>& services_uuid,
     const RemoteServerGetPrimaryServicesCallback& callback) {
@@ -691,7 +689,7 @@
 }
 
 void WebBluetoothServiceImpl::RemoteServerGetPrimaryServicesImpl(
-    const mojo::String& device_id,
+    const WebBluetoothDeviceId& device_id,
     blink::mojom::WebBluetoothGATTQueryQuantity quantity,
     const base::Optional<BluetoothUUID>& services_uuid,
     const RemoteServerGetPrimaryServicesCallback& callback,
@@ -763,7 +761,7 @@
     return;
   }
 
-  const std::string device_id_for_origin =
+  const WebBluetoothDeviceId device_id_for_origin =
       allowed_devices_map_.AddDevice(GetOrigin(), device_address, options);
 
   VLOG(1) << "Device: " << device->GetNameForDisplay();
@@ -800,7 +798,7 @@
 }
 
 void WebBluetoothServiceImpl::OnCreateGATTConnectionSuccess(
-    const std::string& device_id,
+    const WebBluetoothDeviceId& device_id,
     base::TimeTicks start_time,
     const RemoteServerConnectCallback& callback,
     std::unique_ptr<device::BluetoothGattConnection> connection) {
@@ -813,7 +811,6 @@
 }
 
 void WebBluetoothServiceImpl::OnCreateGATTConnectionFailed(
-    const std::string& device_id,
     base::TimeTicks start_time,
     const RemoteServerConnectCallback& callback,
     device::BluetoothDevice::ConnectErrorCode error_code) {
@@ -885,7 +882,7 @@
 }
 
 CacheQueryResult WebBluetoothServiceImpl::QueryCacheForDevice(
-    const std::string& device_id) {
+    const WebBluetoothDeviceId& device_id) {
   const std::string& device_address =
       allowed_devices_map_.GetDeviceAddress(GetOrigin(), device_id);
   if (device_address.empty()) {
@@ -915,15 +912,15 @@
     return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER);
   }
 
-  const std::string& device_id =
+  const WebBluetoothDeviceId* device_id =
       allowed_devices_map_.GetDeviceId(GetOrigin(), device_iter->second);
   // Kill the renderer if origin is not allowed to access the device.
-  if (device_id.empty()) {
+  if (device_id == nullptr) {
     CrashRendererAndClosePipe(bad_message::BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN);
     return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER);
   }
 
-  CacheQueryResult result = QueryCacheForDevice(device_id);
+  CacheQueryResult result = QueryCacheForDevice(*device_id);
   if (result.outcome != CacheQueryOutcome::SUCCESS) {
     return result;
   }
@@ -932,7 +929,7 @@
   if (result.service == nullptr) {
     result.outcome = CacheQueryOutcome::NO_SERVICE;
   } else if (!allowed_devices_map_.IsOriginAllowedToAccessService(
-                 GetOrigin(), device_id, result.service->GetUUID())) {
+                 GetOrigin(), *device_id, result.service->GetUUID())) {
     CrashRendererAndClosePipe(bad_message::BDH_SERVICE_NOT_ALLOWED_FOR_ORIGIN);
     return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER);
   }
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.h b/content/browser/bluetooth/web_bluetooth_service_impl.h
index 8fc73cb..94b2fb0 100644
--- a/content/browser/bluetooth/web_bluetooth_service_impl.h
+++ b/content/browser/bluetooth/web_bluetooth_service_impl.h
@@ -98,13 +98,13 @@
   void RequestDevice(blink::mojom::WebBluetoothRequestDeviceOptionsPtr options,
                      const RequestDeviceCallback& callback) override;
   void RemoteServerConnect(
-      const mojo::String& device_id,
+      const WebBluetoothDeviceId& device_id,
       const RemoteServerConnectCallback& callback) override;
-  void RemoteServerDisconnect(const mojo::String& device_id) override;
+  void RemoteServerDisconnect(const WebBluetoothDeviceId& device_id) override;
   void RemoteServerGetPrimaryServices(
-      const mojo::String& device_id,
+      const WebBluetoothDeviceId& device_id,
       blink::mojom::WebBluetoothGATTQueryQuantity quantity,
-      const base::Optional<device::BluetoothUUID>& services_uuid,
+      const base::Optional<device::BluetoothUUID>& service_uuid,
       const RemoteServerGetPrimaryServicesCallback& callback) override;
   void RemoteServiceGetCharacteristics(
       const mojo::String& service_instance_id,
@@ -133,7 +133,7 @@
   // Should only be run after the services have been discovered for
   // |device_address|.
   void RemoteServerGetPrimaryServicesImpl(
-      const mojo::String& device_id,
+      const WebBluetoothDeviceId& device_id,
       blink::mojom::WebBluetoothGATTQueryQuantity quantity,
       const base::Optional<device::BluetoothUUID>& services_uuid,
       const RemoteServerGetPrimaryServicesCallback& callback,
@@ -149,12 +149,11 @@
 
   // Callbacks for BluetoothDevice::CreateGattConnection.
   void OnCreateGATTConnectionSuccess(
-      const std::string& device_id,
+      const WebBluetoothDeviceId& device_id,
       base::TimeTicks start_time,
       const RemoteServerConnectCallback& callback,
       std::unique_ptr<device::BluetoothGattConnection> connection);
   void OnCreateGATTConnectionFailed(
-      const std::string& device_id,
       base::TimeTicks start_time,
       const RemoteServerConnectCallback& callback,
       device::BluetoothDevice::ConnectErrorCode error_code);
@@ -196,7 +195,7 @@
 
   // Queries the platform cache for a Device with |device_id| for |origin|.
   // Fills in the |outcome| field and the |device| field if successful.
-  CacheQueryResult QueryCacheForDevice(const std::string& device_id);
+  CacheQueryResult QueryCacheForDevice(const WebBluetoothDeviceId& device_id);
 
   // Queries the platform cache for a Service with |service_instance_id|. Fills
   // in the |outcome| field, and |device| and |service| fields if successful.
diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h
index ff10fdd..082fdf6e1 100644
--- a/content/browser/browser_child_process_host_impl.h
+++ b/content/browser/browser_child_process_host_impl.h
@@ -33,7 +33,6 @@
 
 namespace shell {
 class InterfaceProvider;
-class InterfaceRegistry;
 }
 
 namespace content {
diff --git a/content/browser/device_sensors/sensor_manager_android.cc b/content/browser/device_sensors/sensor_manager_android.cc
index fcef4e1..7c293c9 100644
--- a/content/browser/device_sensors/sensor_manager_android.cc
+++ b/content/browser/device_sensors/sensor_manager_android.cc
@@ -15,6 +15,7 @@
 #include "jni/DeviceSensors_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 
 namespace {
 
diff --git a/content/browser/frame_host/navigation_controller_android.cc b/content/browser/frame_host/navigation_controller_android.cc
index 905757c65..2d89750 100644
--- a/content/browser/frame_host/navigation_controller_android.cc
+++ b/content/browser/frame_host/navigation_controller_android.cc
@@ -22,6 +22,8 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 namespace {
 
 // static
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 797e4eb..1a55641 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -566,6 +566,8 @@
                                 OnDidCommitProvisionalLoad(msg))
     IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateState, OnUpdateState)
     IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_CancelInitialHistoryLoad,
+                        OnCancelInitialHistoryLoad)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DocumentOnLoadCompleted,
                         OnDocumentOnLoadCompleted)
     IPC_MESSAGE_HANDLER(FrameHostMsg_BeforeUnload_ACK, OnBeforeUnloadACK)
@@ -972,6 +974,16 @@
   OpenURL(params, GetSiteInstance());
 }
 
+void RenderFrameHostImpl::OnCancelInitialHistoryLoad() {
+  // A Javascript navigation interrupted the initial history load.  Check if an
+  // initial subframe cross-process navigation needs to be canceled as a result.
+  // TODO(creis, clamy): Cancel any cross-process navigation in PlzNavigate.
+  if (GetParent() && !frame_tree_node_->has_committed_real_load() &&
+      frame_tree_node_->render_manager()->pending_frame_host()) {
+    frame_tree_node_->render_manager()->CancelPending();
+  }
+}
+
 void RenderFrameHostImpl::OnDocumentOnLoadCompleted(
     FrameMsg_UILoadMetricsReportType::Value report_type,
     base::TimeTicks ui_timestamp) {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 2d5e1f94..4baadd4 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -648,6 +648,7 @@
   void OnDetach();
   void OnFrameFocused();
   void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
+  void OnCancelInitialHistoryLoad();
   void OnDocumentOnLoadCompleted(
       FrameMsg_UILoadMetricsReportType::Value report_type,
       base::TimeTicks ui_timestamp);
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index e6f7b81f..6e33a629 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -2317,6 +2317,7 @@
 }
 
 void RenderFrameHostManager::CancelPending() {
+  CHECK(pending_render_frame_host_);
   TRACE_EVENT1("navigation", "RenderFrameHostManager::CancelPending",
                "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
   render_frame_host_->ClearPendingWebUI();
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index 663ea40..dd08ac2 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -515,6 +515,9 @@
   bool InitRenderView(RenderViewHostImpl* render_view_host,
     RenderFrameProxyHost* proxy);
 
+  // Terminates and deletes the pending RenderFrameHost.
+  void CancelPending();
+
  private:
   friend class NavigatorTestWithBrowserSideNavigation;
   friend class RenderFrameHostManagerTest;
@@ -710,10 +713,6 @@
   void DiscardUnusedFrame(
       std::unique_ptr<RenderFrameHostImpl> render_frame_host);
 
-  // Helper method to terminate the pending RenderFrameHost. The frame may be
-  // deleted immediately, or it may be kept around in hopes of later reuse.
-  void CancelPending();
-
   // Clears pending_render_frame_host_, returning it to the caller for disposal.
   std::unique_ptr<RenderFrameHostImpl> UnsetPendingRenderFrameHost();
 
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index d027355..f394db3 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -62,7 +62,6 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/interface_provider.h"
-#include "services/shell/public/cpp/interface_registry.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/events/latency_info.h"
 #include "ui/gl/gl_switches.h"
diff --git a/content/browser/media/session/media_session_delegate_android.cc b/content/browser/media/session/media_session_delegate_android.cc
index ddcd286..32ce8f6 100644
--- a/content/browser/media/session/media_session_delegate_android.cc
+++ b/content/browser/media/session/media_session_delegate_android.cc
@@ -8,6 +8,8 @@
 #include "base/android/jni_android.h"
 #include "jni/MediaSessionDelegate_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace content {
 
 // static
diff --git a/content/browser/renderer_host/ime_adapter_android.cc b/content/browser/renderer_host/ime_adapter_android.cc
index 6948868..a712e54 100644
--- a/content/browser/renderer_host/ime_adapter_android.cc
+++ b/content/browser/renderer_host/ime_adapter_android.cc
@@ -35,6 +35,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF16;
+using base::android::JavaParamRef;
 
 namespace content {
 namespace {
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index bbe183a1..fb886d5 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -23,6 +23,7 @@
 #include "content/public/test/test_mojo_service.mojom.h"
 #include "content/public/test/test_utils.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/shell/public/cpp/interface_registry.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 // IPC messages for testing ---------------------------------------------------
diff --git a/content/browser/speech/speech_recognizer_impl_android.cc b/content/browser/speech/speech_recognizer_impl_android.cc
index 5337da1c..136e9d1f 100644
--- a/content/browser/speech/speech_recognizer_impl_android.cc
+++ b/content/browser/speech/speech_recognizer_impl_android.cc
@@ -26,6 +26,7 @@
 using base::android::ConvertUTF8ToJavaString;
 using base::android::GetApplicationContext;
 using base::android::JavaFloatArrayToFloatVector;
+using base::android::JavaParamRef;
 
 namespace content {
 
diff --git a/content/browser/time_zone_monitor_android.cc b/content/browser/time_zone_monitor_android.cc
index b2239913..1207a8ed 100644
--- a/content/browser/time_zone_monitor_android.cc
+++ b/content/browser/time_zone_monitor_android.cc
@@ -8,6 +8,8 @@
 #include "base/android/jni_android.h"
 #include "jni/TimeZoneMonitor_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace content {
 
 TimeZoneMonitorAndroid::TimeZoneMonitorAndroid() : TimeZoneMonitor() {
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index dea8a24..3d74b30 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -43,7 +43,6 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/interface_provider.h"
-#include "services/shell/public/cpp/interface_registry.h"
 #include "ui/base/ui_base_switches.h"
 
 #if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 7e0b569..f929fbf6 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -47,6 +47,7 @@
 using base::android::ConvertUTF16ToJavaString;
 using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaIntArray;
 
 namespace content {
diff --git a/content/child/push_messaging/push_provider.cc b/content/child/push_messaging/push_provider.cc
index 1969914..440ba3c3 100644
--- a/content/child/push_messaging/push_provider.cc
+++ b/content/child/push_messaging/push_provider.cc
@@ -183,7 +183,7 @@
 
   blink::WebPushError::ErrorType error_type =
       status == PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
-          ? blink::WebPushError::ErrorTypePermissionDenied
+          ? blink::WebPushError::ErrorTypeNotAllowed
           : blink::WebPushError::ErrorTypeAbort;
 
   callbacks->onError(blink::WebPushError(
diff --git a/content/common/DEPS b/content/common/DEPS
index dbb43fb..b4078bbc 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -24,6 +24,7 @@
   "+third_party/WebKit/public/platform/WebStorageArea.h",
   "+third_party/WebKit/public/platform/linux/WebFallbackFont.h",
   "+third_party/WebKit/public/platform/linux/WebFontRenderStyle.h",
+  "+third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h",
   "+third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionData.h",
   "+third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationData.h",
   "+third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h",
diff --git a/content/common/android/media_metadata_android.cc b/content/common/android/media_metadata_android.cc
index 0e4179d..20e4fa7 100644
--- a/content/common/android/media_metadata_android.cc
+++ b/content/common/android/media_metadata_android.cc
@@ -12,6 +12,8 @@
 #include "content/public/common/media_metadata.h"
 #include "jni/MediaMetadata_jni.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace content {
 
 namespace {
diff --git a/content/common/android/resource_request_body_android.cc b/content/common/android/resource_request_body_android.cc
index 3f91c9a..e890370 100644
--- a/content/common/android/resource_request_body_android.cc
+++ b/content/common/android/resource_request_body_android.cc
@@ -15,6 +15,8 @@
 #include "content/public/common/resource_request_body.h"
 #include "jni/ResourceRequestBody_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace content {
 
 namespace {
diff --git a/content/common/bluetooth/OWNERS b/content/common/bluetooth/OWNERS
new file mode 100644
index 0000000..e1158f6c
--- /dev/null
+++ b/content/common/bluetooth/OWNERS
@@ -0,0 +1,8 @@
+jyasskin@chromium.org
+ortuno@chromium.org
+scheib@chromium.org
+
+# Changes to IPC serialization require a security review to avoid introducing
+# new sandbox escapes.
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/content/common/bluetooth/PRESUBMIT.py b/content/common/bluetooth/PRESUBMIT.py
new file mode 100644
index 0000000..5af5a08
--- /dev/null
+++ b/content/common/bluetooth/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit script.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+  results = []
+  results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+  return results
diff --git a/content/common/bluetooth/typemaps.gni b/content/common/bluetooth/typemaps.gni
new file mode 100644
index 0000000..552e6cfe
--- /dev/null
+++ b/content/common/bluetooth/typemaps.gni
@@ -0,0 +1,5 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+typemaps = [ "//content/common/bluetooth/web_bluetooth_device_id.typemap" ]
diff --git a/content/common/bluetooth/web_bluetooth_device_id.cc b/content/common/bluetooth/web_bluetooth_device_id.cc
new file mode 100644
index 0000000..823ed0f
--- /dev/null
+++ b/content/common/bluetooth/web_bluetooth_device_id.cc
@@ -0,0 +1,87 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
+
+#include "base/base64.h"
+#include "base/strings/string_util.h"
+#include "crypto/random.h"
+
+namespace content {
+
+namespace {
+
+enum { kDeviceIdLength = 16 /* 128 bits */ };
+
+}  // namespace
+
+WebBluetoothDeviceId::WebBluetoothDeviceId() {}
+
+WebBluetoothDeviceId::WebBluetoothDeviceId(std::string device_id)
+    : device_id_(std::move(device_id)) {
+  CHECK(IsValid(device_id_));
+}
+
+WebBluetoothDeviceId::~WebBluetoothDeviceId() {}
+
+const std::string& WebBluetoothDeviceId::str() const {
+  CHECK(IsValid(device_id_));
+  return device_id_;
+}
+
+// static
+WebBluetoothDeviceId WebBluetoothDeviceId::Create() {
+  std::string bytes(
+      kDeviceIdLength + 1 /* to avoid bytes being reallocated by WriteInto */,
+      '\0');
+
+  crypto::RandBytes(base::WriteInto(&bytes /* str */,
+                                    kDeviceIdLength + 1 /* length_with_null */),
+                    kDeviceIdLength);
+
+  base::Base64Encode(bytes, &bytes);
+
+  return WebBluetoothDeviceId(std::move(bytes));
+}
+
+// static
+bool WebBluetoothDeviceId::IsValid(const std::string& device_id) {
+  std::string decoded;
+  if (!base::Base64Decode(device_id, &decoded)) {
+    return false;
+  }
+
+  if (decoded.size() != kDeviceIdLength) {
+    return false;
+  }
+
+  // When base64-encoding a 128bit string, only the two MSB are used for
+  // the 3rd-to-last character. Because of this, the 3rd-to-last character
+  // can only be one of this four characters.
+  if (!(device_id[device_id.size() - 3] == 'A' ||
+        device_id[device_id.size() - 3] == 'Q' ||
+        device_id[device_id.size() - 3] == 'g' ||
+        device_id[device_id.size() - 3] == 'w')) {
+    return false;
+  }
+
+  return true;
+}
+
+bool WebBluetoothDeviceId::operator==(
+    const WebBluetoothDeviceId& device_id) const {
+  return str() == device_id.str();
+}
+
+bool WebBluetoothDeviceId::operator!=(
+    const WebBluetoothDeviceId& device_id) const {
+  return !(*this == device_id);
+}
+
+std::ostream& operator<<(std::ostream& out,
+                         const WebBluetoothDeviceId& device_id) {
+  return out << device_id.str();
+}
+
+}  // namespace content
diff --git a/content/common/bluetooth/web_bluetooth_device_id.h b/content/common/bluetooth/web_bluetooth_device_id.h
new file mode 100644
index 0000000..2de12a0
--- /dev/null
+++ b/content/common/bluetooth/web_bluetooth_device_id.h
@@ -0,0 +1,58 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_BLUETOOTH_WEB_BLUETOOTH_DEVICE_ID_H_
+#define CONTENT_COMMON_BLUETOOTH_WEB_BLUETOOTH_DEVICE_ID_H_
+
+#include <string>
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Used to uniquely identify a Bluetooth Device for an Origin.
+// A WebBluetoothDeviceId is generated by base64-encoding a 128bit
+// string.
+class CONTENT_EXPORT WebBluetoothDeviceId {
+ public:
+  // Default constructor that creates an invalid id. We implement it so that
+  // instances of this class in a container, e.g. std::unordered_map, can be
+  // accessed through the [] operator. Trying to call any function of the
+  // resulting object will DCHECK-fail.
+  WebBluetoothDeviceId();
+
+  // DCHECKS that |device_id| is valid.
+  explicit WebBluetoothDeviceId(std::string device_id);
+  ~WebBluetoothDeviceId();
+
+  // Returns the string that represents this WebBluetoothDeviceId.
+  const std::string& str() const;
+
+  // The returned WebBluetoothDeviceId is generated by creating a random 128bit
+  // string and base64-encoding it.
+  static WebBluetoothDeviceId Create();
+
+  // Returns true if base64-decoding |device_id| results in a 128bit string.
+  static bool IsValid(const std::string& device_id);
+
+  bool operator==(const WebBluetoothDeviceId& device_id) const;
+  bool operator!=(const WebBluetoothDeviceId& device_id) const;
+
+ private:
+  std::string device_id_;
+};
+
+// This is required by gtest to print a readable output on test failures.
+CONTENT_EXPORT std::ostream& operator<<(std::ostream& out,
+                                        const WebBluetoothDeviceId& device_id);
+
+struct WebBluetoothDeviceIdHash {
+  size_t operator()(const WebBluetoothDeviceId& device_id) const {
+    return std::hash<std::string>()(device_id.str());
+  }
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_BLUETOOTH_WEB_BLUETOOTH_DEVICE_ID_H_
diff --git a/content/common/bluetooth/web_bluetooth_device_id.typemap b/content/common/bluetooth/web_bluetooth_device_id.typemap
new file mode 100644
index 0000000..7f07b52
--- /dev/null
+++ b/content/common/bluetooth/web_bluetooth_device_id.typemap
@@ -0,0 +1,11 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom =
+    "//third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom"
+public_headers = [ "//content/common/bluetooth/web_bluetooth_device_id.h" ]
+traits_headers =
+    [ "//content/common/bluetooth/web_bluetooth_device_id_struct_traits.h" ]
+type_mappings =
+    [ "blink.mojom.WebBluetoothDeviceId=content::WebBluetoothDeviceId" ]
diff --git a/content/common/bluetooth/web_bluetooth_device_id_struct_traits.h b/content/common/bluetooth/web_bluetooth_device_id_struct_traits.h
new file mode 100644
index 0000000..82fa21b
--- /dev/null
+++ b/content/common/bluetooth/web_bluetooth_device_id_struct_traits.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BLUETOOTH_WEB_BLUETOOTH_DEVICE_ID_STRUCT_TRAITS_H_
+#define CONTENT_BROWSER_BLUETOOTH_WEB_BLUETOOTH_DEVICE_ID_STRUCT_TRAITS_H_
+
+#include <string>
+
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<blink::mojom::WebBluetoothDeviceId,
+                    content::WebBluetoothDeviceId> {
+  static const std::string& device_id(
+      const content::WebBluetoothDeviceId& device_id) {
+    return device_id.str();
+  }
+
+  static bool Read(blink::mojom::WebBluetoothDeviceIdDataView input,
+                   content::WebBluetoothDeviceId* output) {
+    std::string result;
+
+    if (!input.ReadDeviceId(&result))
+      return false;
+    if (!content::WebBluetoothDeviceId::IsValid(result))
+      return false;
+
+    *output = content::WebBluetoothDeviceId(std::move(result));
+    return true;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // CONTENT_BROWSER_BLUETOOTH_WEB_BLUETOOTH_DEVICE_ID_STRUCT_TRAITS_H_
diff --git a/content/common/bluetooth/web_bluetooth_device_id_unittest.cc b/content/common/bluetooth/web_bluetooth_device_id_unittest.cc
new file mode 100644
index 0000000..44f7daaf
--- /dev/null
+++ b/content/common/bluetooth/web_bluetooth_device_id_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
+
+#include "base/base64.h"
+#include "base/strings/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::WebBluetoothDeviceId;
+
+namespace {
+
+const char kValidDeviceId1[] = "123456789012345678901A==";
+const char kValidDeviceId2[] = "AbCdEfGhIjKlMnOpQrS+/Q==";
+const char kInvalidLongDeviceId[] = "12345678901234567890123=";
+const char kInvalidShortDeviceId[] = "12345678901234567890";
+const char kInvalidCharacterDeviceId[] = "123456789012345678901*==";
+// A base64 string should have a length of a multiple of 4.
+const char kInvalidLengthDeviceId[] = "123456789012345678901";
+
+}  // namespace
+
+TEST(WebBluetoothDeviceIdTest, DefaultConstructor) {
+  WebBluetoothDeviceId default_id1;
+  WebBluetoothDeviceId default_id2;
+  WebBluetoothDeviceId valid_id(kValidDeviceId1);
+
+  ASSERT_DEATH_IF_SUPPORTED(default_id1.str(), "");
+  ASSERT_DEATH_IF_SUPPORTED(default_id2.str(), "");
+  ASSERT_TRUE(WebBluetoothDeviceId::IsValid(valid_id.str()));
+
+  EXPECT_DEATH_IF_SUPPORTED([&]() { return default_id1 == default_id2; }(), "");
+  EXPECT_DEATH_IF_SUPPORTED([&]() { return default_id1 != default_id2; }(), "");
+
+  EXPECT_DEATH_IF_SUPPORTED([&]() { return default_id1 == valid_id; }(), "");
+  EXPECT_DEATH_IF_SUPPORTED([&]() { return valid_id == default_id1; }(), "");
+
+  EXPECT_DEATH_IF_SUPPORTED([&]() { return default_id1 != valid_id; }(), "");
+  EXPECT_DEATH_IF_SUPPORTED([&]() { return valid_id != default_id1; }(), "");
+}
+
+TEST(WebBluetoothDeviceIdTest, StrConstructor) {
+  WebBluetoothDeviceId valid1(kValidDeviceId1);
+  WebBluetoothDeviceId valid2(kValidDeviceId2);
+
+  EXPECT_TRUE(valid1 == valid1);
+  EXPECT_TRUE(valid2 == valid2);
+
+  EXPECT_TRUE(valid1 != valid2);
+
+  EXPECT_DEATH_IF_SUPPORTED(WebBluetoothDeviceId(""), "");
+  EXPECT_DEATH_IF_SUPPORTED(
+      [&]() { return WebBluetoothDeviceId(kInvalidLongDeviceId); }(), "");
+  EXPECT_DEATH_IF_SUPPORTED(
+      [&]() { return WebBluetoothDeviceId(kInvalidShortDeviceId); }(), "");
+  EXPECT_DEATH_IF_SUPPORTED(
+      [&]() { return WebBluetoothDeviceId(kInvalidCharacterDeviceId); }(), "");
+  EXPECT_DEATH_IF_SUPPORTED(
+      [&]() { return WebBluetoothDeviceId(kInvalidLengthDeviceId); }(), "");
+}
+
+TEST(WebBluetoothDeviceIdTest, IsValid_Valid) {
+  EXPECT_TRUE(WebBluetoothDeviceId::IsValid(kValidDeviceId1));
+  EXPECT_TRUE(WebBluetoothDeviceId::IsValid(kValidDeviceId2));
+}
+
+TEST(WebBluetoothDeviceIdTest, IsValid_Invalid) {
+  EXPECT_FALSE(WebBluetoothDeviceId::IsValid(""));
+  EXPECT_FALSE(WebBluetoothDeviceId::IsValid(kInvalidLongDeviceId));
+  EXPECT_FALSE(WebBluetoothDeviceId::IsValid(kInvalidShortDeviceId));
+  EXPECT_FALSE(WebBluetoothDeviceId::IsValid(kInvalidCharacterDeviceId));
+  EXPECT_FALSE(WebBluetoothDeviceId::IsValid(kInvalidLengthDeviceId));
+}
+
+TEST(WebBluetoothDeviceIdTest, Create) {
+  // Tests that Create generates a valid Device Id.
+  EXPECT_TRUE(
+      WebBluetoothDeviceId::IsValid(WebBluetoothDeviceId::Create().str()));
+}
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 96a3043..5a649f33 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -1087,6 +1087,11 @@
 // Requests that the given URL be opened in the specified manner.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_OpenURL, FrameHostMsg_OpenURL_Params)
 
+// If a cross-process navigation was started for the initial history load in
+// this subframe, this tries to cancel it to allow a client redirect to happen
+// instead.
+IPC_MESSAGE_ROUTED0(FrameHostMsg_CancelInitialHistoryLoad)
+
 // Notifies the browser that a frame finished loading.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_DidFinishLoad,
                     GURL /* validated_url */)
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 0874e15..c16e64a 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -255,6 +255,8 @@
       'common/appcache_messages.h',
       'common/ax_content_node_data.cc',
       'common/ax_content_node_data.h',
+      'common/bluetooth/web_bluetooth_device_id.cc',
+      'common/bluetooth/web_bluetooth_device_id.h',
       'common/browser_plugin/browser_plugin_constants.cc',
       'common/browser_plugin/browser_plugin_constants.h',
       'common/browser_plugin/browser_plugin_messages.h',
diff --git a/content/content_common_mojo_bindings.gyp b/content/content_common_mojo_bindings.gyp
index de48c54..ce0a991 100644
--- a/content/content_common_mojo_bindings.gyp
+++ b/content/content_common_mojo_bindings.gyp
@@ -18,8 +18,11 @@
           'common/render_frame_message_filter.mojom',
           'common/service_worker/embedded_worker_setup.mojom',
           'common/storage_partition_service.mojom',
+          '../third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom',
         ],
         'mojom_typemaps': [
+          'common/bluetooth/web_bluetooth_device_id.typemap',
+          '../device/bluetooth/public/interfaces/bluetooth_uuid.typemap',
           '../skia/public/interfaces/skbitmap.typemap',
           '../ui/gfx/geometry/mojo/geometry.typemap',
           '../url/mojo/gurl.typemap',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 08ef649c..d7e6323 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -669,6 +669,7 @@
       'child/worker_thread_registry_unittest.cc',
       'common/android/address_parser_unittest.cc',
       'common/android/gin_java_bridge_value_unittest.cc',
+      'common/bluetooth/web_bluetooth_device_id_unittest.cc',
       'common/common_param_traits_unittest.cc',
       'common/cross_site_document_classifier_unittest.cc',
       'common/cursors/webcursor_unittest.cc',
diff --git a/content/public/browser/browser_child_process_host_delegate.h b/content/public/browser/browser_child_process_host_delegate.h
index 6d8e9adc..323cd8e1 100644
--- a/content/public/browser/browser_child_process_host_delegate.h
+++ b/content/public/browser/browser_child_process_host_delegate.h
@@ -10,7 +10,6 @@
 
 namespace shell {
 class InterfaceProvider;
-class InterfaceRegistry;
 }
 
 namespace content {
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 28fde53..de2843d4 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -18,7 +18,6 @@
 #include "content/common/content_export.h"
 #include "ipc/ipc_channel_proxy.h"
 #include "ipc/ipc_sender.h"
-#include "services/shell/public/cpp/interface_registry.h"
 #include "ui/gfx/native_widget_types.h"
 
 class GURL;
diff --git a/content/public/browser/utility_process_host.h b/content/public/browser/utility_process_host.h
index 0c22796..2f49727 100644
--- a/content/public/browser/utility_process_host.h
+++ b/content/public/browser/utility_process_host.h
@@ -19,7 +19,6 @@
 
 namespace shell {
 class InterfaceProvider;
-class InterfaceRegistry;
 }
 
 namespace content {
diff --git a/content/renderer/android/synchronous_compositor_output_surface.h b/content/renderer/android/synchronous_compositor_output_surface.h
index de8f1f0f..6a8f83a2 100644
--- a/content/renderer/android/synchronous_compositor_output_surface.h
+++ b/content/renderer/android/synchronous_compositor_output_surface.h
@@ -143,10 +143,6 @@
     void DisplayOutputSurfaceLost() override {}
     void DisplaySetMemoryPolicy(
         const cc::ManagedMemoryPolicy& policy) override {}
-    void DisplayWillDrawAndSwap(
-        bool will_draw_and_swap,
-        const cc::RenderPassList& render_passes) override {}
-    void DisplayDidDrawAndSwap() override {}
   };
 
   // TODO(danakj): These don't to be stored in unique_ptrs when OutputSurface
diff --git a/content/renderer/bluetooth/web_bluetooth_impl.cc b/content/renderer/bluetooth/web_bluetooth_impl.cc
index ef89b10..549d5cf 100644
--- a/content/renderer/bluetooth/web_bluetooth_impl.cc
+++ b/content/renderer/bluetooth/web_bluetooth_impl.cc
@@ -12,6 +12,7 @@
 #include "base/optional.h"
 #include "content/child/mojo/type_converters.h"
 #include "content/child/thread_safe_sender.h"
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
 #include "content/renderer/bluetooth/bluetooth_type_converters.h"
 #include "ipc/ipc_message.h"
 #include "mojo/public/cpp/bindings/array.h"
@@ -57,19 +58,20 @@
     blink::WebBluetoothRemoteGATTServerConnectCallbacks* callbacks) {
   // TODO(crbug.com/495270): After the Bluetooth Tree is implemented, there will
   // only be one object per device. But for now we replace the previous object.
-  connected_devices_[device_id.utf8()] = device;
+  WebBluetoothDeviceId device_id_obj = WebBluetoothDeviceId(device_id.utf8());
+  connected_devices_[device_id_obj] = device;
 
   GetWebBluetoothService().RemoteServerConnect(
-      mojo::String::From(device_id),
+      std::move(device_id_obj),
       base::Bind(&WebBluetoothImpl::OnConnectComplete, base::Unretained(this),
                  base::Passed(base::WrapUnique(callbacks))));
 }
 
 void WebBluetoothImpl::disconnect(const blink::WebString& device_id) {
-  connected_devices_.erase(device_id.utf8());
+  WebBluetoothDeviceId device_id_obj = WebBluetoothDeviceId(device_id.utf8());
+  connected_devices_.erase(device_id_obj);
 
-  GetWebBluetoothService().RemoteServerDisconnect(
-      mojo::String::From(device_id));
+  GetWebBluetoothService().RemoteServerDisconnect(std::move(device_id_obj));
 }
 
 void WebBluetoothImpl::getPrimaryServices(
@@ -80,7 +82,7 @@
   DCHECK(blink::mojom::IsKnownEnumValue(
       static_cast<blink::mojom::WebBluetoothGATTQueryQuantity>(quantity)));
   GetWebBluetoothService().RemoteServerGetPrimaryServices(
-      mojo::String::From(device_id),
+      WebBluetoothDeviceId(device_id.utf8()),
       static_cast<blink::mojom::WebBluetoothGATTQueryQuantity>(quantity),
       services_uuid.isEmpty()
           ? base::nullopt
@@ -188,7 +190,7 @@
       uuids[i] = blink::WebString::fromUTF8(device->uuids[i]);
 
     callbacks->onSuccess(base::WrapUnique(new blink::WebBluetoothDeviceInit(
-        blink::WebString::fromUTF8(device->id),
+        blink::WebString::fromUTF8(device->id.str()),
         device->name.is_null() ? blink::WebString()
                                : blink::WebString::fromUTF8(device->name),
         uuids)));
@@ -197,7 +199,8 @@
   }
 }
 
-void WebBluetoothImpl::GattServerDisconnected(const mojo::String& device_id) {
+void WebBluetoothImpl::GattServerDisconnected(
+    const WebBluetoothDeviceId& device_id) {
   auto device_iter = connected_devices_.find(device_id);
   if (device_iter != connected_devices_.end()) {
     // Remove device from the map before calling dispatchGattServerDisconnected
diff --git a/content/renderer/bluetooth/web_bluetooth_impl.h b/content/renderer/bluetooth/web_bluetooth_impl.h
index e1257d0..00658dd 100644
--- a/content/renderer/bluetooth/web_bluetooth_impl.h
+++ b/content/renderer/bluetooth/web_bluetooth_impl.h
@@ -16,6 +16,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "content/common/bluetooth/web_bluetooth_device_id.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h"
@@ -88,7 +89,7 @@
   void RemoteCharacteristicValueChanged(
       const mojo::String& characteristic_instance_id,
       mojo::Array<uint8_t> value) override;
-  void GattServerDisconnected(const mojo::String& device_id) override;
+  void GattServerDisconnected(const WebBluetoothDeviceId& device_id) override;
 
   // Callbacks for WebBluetoothService calls:
   void OnRequestDeviceComplete(
@@ -142,7 +143,9 @@
   // Map of device_ids to WebBluetoothDevices. Added in connect() and removed in
   // disconnect(). This means a device may not actually be connected while in
   // this map, but that it will definitely be removed when the page navigates.
-  std::unordered_map<std::string, blink::WebBluetoothDevice*>
+  std::unordered_map<WebBluetoothDeviceId,
+                     blink::WebBluetoothDevice*,
+                     WebBluetoothDeviceIdHash>
       connected_devices_;
 
   // Binding associated with |web_bluetooth_service_|.
diff --git a/content/renderer/categorized_worker_pool.cc b/content/renderer/categorized_worker_pool.cc
index 41814b4..fa7de93 100644
--- a/content/renderer/categorized_worker_pool.cc
+++ b/content/renderer/categorized_worker_pool.cc
@@ -152,7 +152,7 @@
   // Use background priority for background thread.
   base::SimpleThread::Options thread_options;
 #if !defined(OS_MACOSX)
-  thread_options.set_priority(base::ThreadPriority::BACKGROUND);
+  thread_options.priority = base::ThreadPriority::BACKGROUND;
 #endif
 
   std::unique_ptr<base::SimpleThread> thread(new CategorizedWorkerPoolThread(
diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc
index 3246db3..47c1e21 100644
--- a/content/renderer/gpu/render_widget_compositor_unittest.cc
+++ b/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -14,16 +14,14 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/output/copy_output_request.h"
+#include "cc/test/failure_output_surface.h"
 #include "cc/test/fake_external_begin_frame_source.h"
-#include "cc/test/fake_output_surface.h"
-#include "cc/test/test_context_provider.h"
 #include "cc/trees/layer_tree_host.h"
 #include "components/scheduler/renderer/renderer_scheduler.h"
 #include "content/public/test/mock_render_thread.h"
 #include "content/renderer/render_widget.h"
 #include "content/test/fake_compositor_dependencies.h"
 #include "content/test/fake_renderer_scheduler.h"
-#include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
@@ -82,20 +80,18 @@
             RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
         fallback);
     last_create_was_fallback_ = fallback;
-
     bool success = num_failures_ >= num_failures_before_success_;
-    if (!success && use_null_output_surface_)
-      return nullptr;
-
-    auto context_provider = cc::TestContextProvider::Create();
-    if (!success) {
-      context_provider->UnboundTestContext3d()->loseContextCHROMIUM(
-          GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
+    if (success) {
+      std::unique_ptr<cc::TestWebGraphicsContext3D> context =
+          cc::TestWebGraphicsContext3D::Create();
+      // Image support required for synchronous compositing.
+      context->set_support_image(true);
+      // Create delegating surface so that max_pending_frames = 1.
+      return cc::FakeOutputSurface::CreateDelegating3d(std::move(context));
     }
-
-    // Create delegating surface so that max_pending_frames = 1.
-    return cc::FakeOutputSurface::CreateDelegating3d(
-        std::move(context_provider));
+    return use_null_output_surface_
+               ? nullptr
+               : base::WrapUnique(new cc::FailureOutputSurface(true));
   }
 
   std::unique_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource()
diff --git a/content/renderer/push_messaging/push_messaging_dispatcher.cc b/content/renderer/push_messaging/push_messaging_dispatcher.cc
index 75e6e103..7c89a76 100644
--- a/content/renderer/push_messaging/push_messaging_dispatcher.cc
+++ b/content/renderer/push_messaging/push_messaging_dispatcher.cc
@@ -138,7 +138,7 @@
 
   blink::WebPushError::ErrorType error_type =
       status == PUSH_REGISTRATION_STATUS_PERMISSION_DENIED
-          ? blink::WebPushError::ErrorTypePermissionDenied
+          ? blink::WebPushError::ErrorTypeNotAllowed
           : blink::WebPushError::ErrorTypeAbort;
 
   callbacks->onError(blink::WebPushError(
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 1386b37..e52952d0 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4958,11 +4958,21 @@
   // FrameNavigationEntry.  If none is found, fall back to the default url.
   if (SiteIsolationPolicy::UseSubframeNavigationEntries() &&
       info.isHistoryNavigationInNewChildFrame && is_content_initiated) {
-    OpenURL(url, IsHttpPost(info.urlRequest),
-            GetRequestBodyForWebURLRequest(info.urlRequest), referrer,
-            info.defaultPolicy, info.replacesCurrentHistoryItem, true);
-    // Suppress the load in Blink but mark the frame as loading.
-    return blink::WebNavigationPolicyHandledByClient;
+    // Don't do this if |info| also says it is a client redirect, in which case
+    // JavaScript on the page is trying to interrupt the history navigation.
+    if (!info.isClientRedirect) {
+      OpenURL(url, IsHttpPost(info.urlRequest),
+              GetRequestBodyForWebURLRequest(info.urlRequest), referrer,
+              info.defaultPolicy, info.replacesCurrentHistoryItem, true);
+      // Suppress the load in Blink but mark the frame as loading.
+      return blink::WebNavigationPolicyHandledByClient;
+    } else {
+      // Client redirects during an initial history load should attempt to
+      // cancel the history navigation.  They will create a provisional document
+      // loader, causing the history load to be ignored in NavigateInternal, and
+      // this IPC will try to cancel any cross-process history load.
+      Send(new FrameHostMsg_CancelInitialHistoryLoad(routing_id_));
+    }
   }
 
   // Use the frame's original request's URL rather than the document's URL for
@@ -5568,11 +5578,21 @@
                         : blink::WebFrameLoadType::BackForward;
         should_load_request = true;
 
+        // If this navigation is to a history item for a new child frame, we
+        // should cancel it if we were interrupted by a Javascript navigation
+        // that has already committed or has started a provisional loader.
+        if (request_params.is_history_navigation_in_new_child &&
+            (!current_history_item_.isNull() ||
+             frame_->provisionalDataSource())) {
+          should_load_request = false;
+          has_history_navigation_in_frame = false;
+        }
+
         // Generate the request for the load from the HistoryItem.
         // PlzNavigate: use the data sent by the browser for the url and the
         // HTTP state. The restoration of user state such as scroll position
         // will be done based on the history item during the load.
-        if (!browser_side_navigation) {
+        if (!browser_side_navigation && should_load_request) {
           request = frame_->requestFromHistoryItem(item_for_history_navigation,
                                                    cache_policy);
         }
diff --git a/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc b/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc
index 30481ee..098021d 100644
--- a/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc
+++ b/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc
@@ -23,6 +23,8 @@
 #include "jni/LinkerTests_jni.h"
 #include "third_party/re2/src/re2/re2.h"
 
+using base::android::JavaParamRef;
+
 namespace content {
 
 namespace {
diff --git a/content/shell/android/shell_manager.cc b/content/shell/android/shell_manager.cc
index f7cfd63..ea782c5 100644
--- a/content/shell/android/shell_manager.cc
+++ b/content/shell/android/shell_manager.cc
@@ -16,6 +16,7 @@
 #include "jni/ShellManager_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace {
diff --git a/content/shell/browser/layout_test/layout_test_android.cc b/content/shell/browser/layout_test/layout_test_android.cc
index 62ac49d..45bc77f 100644
--- a/content/shell/browser/layout_test/layout_test_android.cc
+++ b/content/shell/browser/layout_test/layout_test_android.cc
@@ -18,6 +18,8 @@
 #include "jni/ShellLayoutTestUtils_jni.h"
 #include "url/gurl.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace {
 
 base::FilePath GetTestFilesDirectory(JNIEnv* env) {
diff --git a/content/shell/browser/shell_android.cc b/content/shell/browser/shell_android.cc
index 8cc8a8a..111aff1 100644
--- a/content/shell/browser/shell_android.cc
+++ b/content/shell/browser/shell_android.cc
@@ -18,6 +18,8 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace content {
 
diff --git a/content/shell/browser/shell_mojo_test_utils_android.cc b/content/shell/browser/shell_mojo_test_utils_android.cc
index d152d4c..0dbec57 100644
--- a/content/shell/browser/shell_mojo_test_utils_android.cc
+++ b/content/shell/browser/shell_mojo_test_utils_android.cc
@@ -18,6 +18,9 @@
 #include "services/shell/public/cpp/interface_provider.h"
 #include "services/shell/public/cpp/interface_registry.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace {
 
 struct TestEnvironment {
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index 0caf15c..d27892c 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -264,8 +264,7 @@
         std::move(compositor_context_provider),
         std::move(worker_context_provider), std::move(display_output_surface),
         deps->GetSharedBitmapManager(), deps->GetGpuMemoryBufferManager(),
-        settings.renderer_settings, task_runner, synchronous_composite,
-        false /* force_disable_reclaim_resources */);
+        settings.renderer_settings, task_runner, synchronous_composite);
     output_surfaces_[routing_id] = output_surface.get();
     return std::move(output_surface);
   }
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
index 2bc0b91..2741e7c 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -179,6 +179,11 @@
                 @Override
                 public void run() {
                     if (mNativeBluetoothDeviceAndroid != 0) {
+                        // When the device disconnects is deletes
+                        // mBluetoothGatt, so we need to check it's not null.
+                        if (mBluetoothGatt == null) {
+                            return;
+                        }
                         // TODO(crbug.com/576906): Update or replace existing GATT objects if they
                         //                         change after initial discovery.
                         for (Wrappers.BluetoothGattServiceWrapper service :
diff --git a/device/bluetooth/android/wrappers.cc b/device/bluetooth/android/wrappers.cc
index 6ad8b7a..4ad3bc2 100644
--- a/device/bluetooth/android/wrappers.cc
+++ b/device/bluetooth/android/wrappers.cc
@@ -9,6 +9,7 @@
 #include "jni/Wrappers_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_adapter_android.cc b/device/bluetooth/bluetooth_adapter_android.cc
index 780ced05..d877899 100644
--- a/device/bluetooth/bluetooth_adapter_android.cc
+++ b/device/bluetooth/bluetooth_adapter_android.cc
@@ -21,6 +21,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 
 namespace {
 // The poll interval in ms when there is no active discovery. This
diff --git a/device/bluetooth/bluetooth_device_android.cc b/device/bluetooth/bluetooth_device_android.cc
index ac48b1bf..ca182ca18 100644
--- a/device/bluetooth/bluetooth_device_android.cc
+++ b/device/bluetooth/bluetooth_device_android.cc
@@ -16,6 +16,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::AppendJavaStringArrayToStringVector;
+using base::android::JavaParamRef;
 
 namespace device {
 namespace {
diff --git a/device/bluetooth/bluetooth_device_unittest.cc b/device/bluetooth/bluetooth_device_unittest.cc
index 2232c7ce..bbfde53d 100644
--- a/device/bluetooth/bluetooth_device_unittest.cc
+++ b/device/bluetooth/bluetooth_device_unittest.cc
@@ -590,6 +590,117 @@
 }
 #endif  // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_MACOSX)
 
+#if defined(OS_ANDROID)
+// macOS: Not applicable: This can never happen because when
+// the device gets destroyed the CBPeripheralDelegate is also destroyed
+// and no more events are dispatched.
+TEST_F(BluetoothTest, GattServicesDiscovered_AfterDeleted) {
+  // Tests that we don't crash if services are discovered after
+  // the device object is deleted.
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
+  InitWithFakeAdapter();
+  StartLowEnergyDiscoverySession();
+  BluetoothDevice* device = SimulateLowEnergyDevice(3);
+  device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED),
+                               GetConnectErrorCallback(Call::NOT_EXPECTED));
+  ResetEventCounts();
+  SimulateGattConnection(device);
+  EXPECT_EQ(1, gatt_discovery_attempts_);
+
+  RememberDeviceForSubsequentAction(device);
+  DeleteDevice(device);
+
+  std::vector<std::string> services;
+  services.push_back("00000000-0000-1000-8000-00805f9b34fb");
+  services.push_back("00000001-0000-1000-8000-00805f9b34fb");
+  SimulateGattServicesDiscovered(nullptr /* use remembered device */, services);
+}
+#endif  // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+// macOS: Not applicable: This can never happen because when
+// the device gets destroyed the CBPeripheralDelegate is also destroyed
+// and no more events are dispatched.
+TEST_F(BluetoothTest, GattServicesDiscoveredError_AfterDeleted) {
+  // Tests that we don't crash if there was an error discoverying services
+  // after the device object is deleted.
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
+  InitWithFakeAdapter();
+  StartLowEnergyDiscoverySession();
+  BluetoothDevice* device = SimulateLowEnergyDevice(3);
+  device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED),
+                               GetConnectErrorCallback(Call::NOT_EXPECTED));
+  ResetEventCounts();
+  SimulateGattConnection(device);
+  EXPECT_EQ(1, gatt_discovery_attempts_);
+
+  RememberDeviceForSubsequentAction(device);
+  DeleteDevice(device);
+
+  SimulateGattServicesDiscoveryError(nullptr /* use remembered device */);
+}
+#endif  // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
+TEST_F(BluetoothTest, GattServicesDiscovered_AfterDisconnection) {
+  // Tests that we don't crash there was an error discovering services after
+  // the device disconnects.
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
+  InitWithFakeAdapter();
+  StartLowEnergyDiscoverySession();
+  BluetoothDevice* device = SimulateLowEnergyDevice(3);
+  device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED),
+                               GetConnectErrorCallback(Call::NOT_EXPECTED));
+  ResetEventCounts();
+  SimulateGattConnection(device);
+  EXPECT_EQ(1, gatt_discovery_attempts_);
+
+  SimulateGattDisconnection(device);
+
+  std::vector<std::string> services;
+  services.push_back("00000000-0000-1000-8000-00805f9b34fb");
+  services.push_back("00000001-0000-1000-8000-00805f9b34fb");
+  SimulateGattServicesDiscovered(device, services);
+
+  EXPECT_FALSE(device->IsGattServicesDiscoveryComplete());
+  EXPECT_EQ(0u, device->GetGattServices().size());
+}
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
+
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
+TEST_F(BluetoothTest, GattServicesDiscoveredError_AfterDisconnection) {
+  // Tests that we don't crash if services are discovered after
+  // the device disconnects.
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
+  InitWithFakeAdapter();
+  StartLowEnergyDiscoverySession();
+  BluetoothDevice* device = SimulateLowEnergyDevice(3);
+  device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED),
+                               GetConnectErrorCallback(Call::NOT_EXPECTED));
+  ResetEventCounts();
+  SimulateGattConnection(device);
+  EXPECT_EQ(1, gatt_discovery_attempts_);
+
+  SimulateGattDisconnection(device);
+
+  SimulateGattServicesDiscoveryError(device);
+  EXPECT_FALSE(device->IsGattServicesDiscoveryComplete());
+  EXPECT_EQ(0u, device->GetGattServices().size());
+}
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
+
 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_MACOSX)
 TEST_F(BluetoothTest, GetGattServices_and_GetGattService) {
   if (!PlatformSupportsLowEnergy()) {
diff --git a/device/bluetooth/bluetooth_low_energy_device_mac.mm b/device/bluetooth/bluetooth_low_energy_device_mac.mm
index 6995dbe..e335e5fb 100644
--- a/device/bluetooth/bluetooth_low_energy_device_mac.mm
+++ b/device/bluetooth/bluetooth_low_energy_device_mac.mm
@@ -244,6 +244,12 @@
             << ": " << error.code << ")";
     return;
   }
+
+  if (!IsGattConnected()) {
+    // Don't create services if the device disconnected.
+    return;
+  }
+
   for (CBService* cb_service in GetPeripheral().services) {
     BluetoothRemoteGattServiceMac* gatt_service =
         GetBluetoothRemoteGattService(cb_service);
@@ -276,6 +282,12 @@
             << ": " << error.code << ")";
     return;
   }
+
+  if (!IsGattConnected()) {
+    // Don't create characteristics if the device disconnected.
+    return;
+  }
+
   BluetoothRemoteGattServiceMac* gatt_service =
       GetBluetoothRemoteGattService(cb_service);
   DCHECK(gatt_service);
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
index a269ff8..18c5e12d 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
@@ -21,6 +21,7 @@
 #include "jni/ChromeBluetoothRemoteGattCharacteristic_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
index 32e753f..62a405a 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
@@ -19,6 +19,7 @@
 #include "jni/ChromeBluetoothRemoteGattDescriptor_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 
 namespace device {
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_android.cc b/device/bluetooth/bluetooth_remote_gatt_service_android.cc
index 38c477e..730983655 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_service_android.cc
@@ -14,6 +14,7 @@
 #include "jni/ChromeBluetoothRemoteGattService_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 
 namespace device {
 
diff --git a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
index be9ba8a..636e67c8 100644
--- a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
+++ b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
@@ -302,6 +302,8 @@
         final FakeBluetoothGatt mGatt;
         private Wrappers.BluetoothGattCallbackWrapper mGattCallback;
 
+        static FakeBluetoothDevice sRememberedDevice;
+
         public FakeBluetoothDevice(FakeBluetoothAdapter adapter, String address, String name) {
             super(null);
             mAdapter = adapter;
@@ -310,6 +312,12 @@
             mGatt = new FakeBluetoothGatt(this);
         }
 
+        // Implements BluetoothTestAndroid::RememberDeviceForSubsequentAction.
+        @CalledByNative("FakeBluetoothDevice")
+        private static void rememberDeviceForSubsequentAction(ChromeBluetoothDevice chromeDevice) {
+            sRememberedDevice = (FakeBluetoothDevice) chromeDevice.mDevice;
+        }
+
         // Create a call to onConnectionStateChange on the |chrome_device| using parameters
         // |status| & |connected|.
         @CalledByNative("FakeBluetoothDevice")
@@ -326,7 +334,13 @@
         @CalledByNative("FakeBluetoothDevice")
         private static void servicesDiscovered(
                 ChromeBluetoothDevice chromeDevice, int status, String uuidsSpaceDelimited) {
-            FakeBluetoothDevice fakeDevice = (FakeBluetoothDevice) chromeDevice.mDevice;
+            if (chromeDevice == null && sRememberedDevice == null) {
+                throw new IllegalArgumentException("rememberDevice wasn't called previously.");
+            }
+
+            FakeBluetoothDevice fakeDevice = (chromeDevice == null)
+                    ? sRememberedDevice
+                    : (FakeBluetoothDevice) chromeDevice.mDevice;
 
             if (status == android.bluetooth.BluetoothGatt.GATT_SUCCESS) {
                 fakeDevice.mGatt.mServices.clear();
diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h
index b91359d..cdb85a6 100644
--- a/device/bluetooth/test/bluetooth_test.h
+++ b/device/bluetooth/test/bluetooth_test.h
@@ -112,6 +112,13 @@
   // name kTestDeviceName, no advertised UUIDs and address kTestDeviceAddress3.
   virtual BluetoothDevice* SimulateClassicDevice();
 
+  // Remembers |device|'s platform specific object to be used in a
+  // subsequent call to methods such as SimulateGattServicesDiscovered that
+  // accept a nullptr value to select this remembered characteristic. This
+  // enables tests where the platform attempts to reference device
+  // objects after the Chrome objects have been deleted, e.g. with DeleteDevice.
+  virtual void RememberDeviceForSubsequentAction(BluetoothDevice* device) {}
+
   // Simulates success of implementation details of CreateGattConnection.
   virtual void SimulateGattConnection(BluetoothDevice* device) {}
 
diff --git a/device/bluetooth/test/bluetooth_test_android.cc b/device/bluetooth/test/bluetooth_test_android.cc
index 2756f242..3f12f8c8 100644
--- a/device/bluetooth/test/bluetooth_test_android.cc
+++ b/device/bluetooth/test/bluetooth_test_android.cc
@@ -21,6 +21,7 @@
 #include "jni/Fakes_jni.h"
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace device {
@@ -85,6 +86,16 @@
   return observer.last_device();
 }
 
+void BluetoothTestAndroid::RememberDeviceForSubsequentAction(
+    BluetoothDevice* device) {
+  BluetoothDeviceAndroid* device_android =
+      static_cast<BluetoothDeviceAndroid*>(device);
+
+  Java_FakeBluetoothDevice_rememberDeviceForSubsequentAction(
+      base::android::AttachCurrentThread(),
+      device_android->GetJavaObject().obj());
+}
+
 void BluetoothTestAndroid::SimulateLocationServicesOff() {
   Java_Fakes_setLocationServicesState(
       AttachCurrentThread(), true /* hasPermission */, false /* isEnabled */);
@@ -133,17 +144,19 @@
 void BluetoothTestAndroid::SimulateGattServicesDiscovered(
     BluetoothDevice* device,
     const std::vector<std::string>& uuids) {
-  BluetoothDeviceAndroid* device_android =
-      static_cast<BluetoothDeviceAndroid*>(device);
-  JNIEnv* env = base::android::AttachCurrentThread();
+  BluetoothDeviceAndroid* device_android = nullptr;
+  if (device) {
+    device_android = static_cast<BluetoothDeviceAndroid*>(device);
+  }
 
   // Join UUID strings into a single string.
   std::ostringstream uuids_space_delimited;
   std::copy(uuids.begin(), uuids.end(),
             std::ostream_iterator<std::string>(uuids_space_delimited, " "));
 
+  JNIEnv* env = base::android::AttachCurrentThread();
   Java_FakeBluetoothDevice_servicesDiscovered(
-      env, device_android->GetJavaObject().obj(),
+      env, device_android ? device_android->GetJavaObject().obj() : nullptr,
       0,  // android.bluetooth.BluetoothGatt.GATT_SUCCESS
       base::android::ConvertUTF8ToJavaString(env, uuids_space_delimited.str())
           .obj());
@@ -151,11 +164,14 @@
 
 void BluetoothTestAndroid::SimulateGattServicesDiscoveryError(
     BluetoothDevice* device) {
-  BluetoothDeviceAndroid* device_android =
-      static_cast<BluetoothDeviceAndroid*>(device);
+  BluetoothDeviceAndroid* device_android = nullptr;
+  if (device) {
+    device_android = static_cast<BluetoothDeviceAndroid*>(device);
+  }
 
   Java_FakeBluetoothDevice_servicesDiscovered(
-      AttachCurrentThread(), device_android->GetJavaObject().obj(),
+      AttachCurrentThread(),
+      device_android ? device_android->GetJavaObject().obj() : nullptr,
       0x00000101,  // android.bluetooth.BluetoothGatt.GATT_FAILURE
       nullptr);
 }
diff --git a/device/bluetooth/test/bluetooth_test_android.h b/device/bluetooth/test/bluetooth_test_android.h
index d8dfaeb..fa2ce9d 100644
--- a/device/bluetooth/test/bluetooth_test_android.h
+++ b/device/bluetooth/test/bluetooth_test_android.h
@@ -31,6 +31,7 @@
   void InitWithFakeAdapter() override;
   bool DenyPermission() override;
   BluetoothDevice* SimulateLowEnergyDevice(int device_ordinal) override;
+  void RememberDeviceForSubsequentAction(BluetoothDevice* device) override;
   void SimulateGattConnection(BluetoothDevice* device) override;
   void SimulateGattConnectionError(BluetoothDevice* device,
                                    BluetoothDevice::ConnectErrorCode) override;
diff --git a/device/gamepad/gamepad_platform_data_fetcher_android.cc b/device/gamepad/gamepad_platform_data_fetcher_android.cc
index 9a14515..2a45658 100644
--- a/device/gamepad/gamepad_platform_data_fetcher_android.cc
+++ b/device/gamepad/gamepad_platform_data_fetcher_android.cc
@@ -22,6 +22,7 @@
 using base::android::CheckException;
 using base::android::ClearException;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 using blink::WebGamepad;
 using blink::WebGamepads;
diff --git a/device/geolocation/location_api_adapter_android.cc b/device/geolocation/location_api_adapter_android.cc
index 55a19c4..693fb90 100644
--- a/device/geolocation/location_api_adapter_android.cc
+++ b/device/geolocation/location_api_adapter_android.cc
@@ -16,6 +16,7 @@
 using base::android::AttachCurrentThread;
 using base::android::CheckException;
 using base::android::ClearException;
+using base::android::JavaParamRef;
 using device::AndroidLocationApiAdapter;
 
 static void NewLocationAvailable(JNIEnv* env,
diff --git a/device/power_save_blocker/power_save_blocker_android.cc b/device/power_save_blocker/power_save_blocker_android.cc
index 2f091055..947123d 100644
--- a/device/power_save_blocker/power_save_blocker_android.cc
+++ b/device/power_save_blocker/power_save_blocker_android.cc
@@ -15,6 +15,7 @@
 namespace device {
 
 using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
 
 class PowerSaveBlocker::Delegate
     : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
diff --git a/device/usb/usb_device_handle_android.cc b/device/usb/usb_device_handle_android.cc
index 5b13f8f..5041f60 100644
--- a/device/usb/usb_device_handle_android.cc
+++ b/device/usb/usb_device_handle_android.cc
@@ -9,6 +9,8 @@
 #include "device/usb/usb_device.h"
 #include "jni/ChromeUsbConnection_jni.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace device {
 
 // static
diff --git a/device/vr/android/cardboard/cardboard_vr_device.cc b/device/vr/android/cardboard/cardboard_vr_device.cc
index 7017611..c2a0a50a 100644
--- a/device/vr/android/cardboard/cardboard_vr_device.cc
+++ b/device/vr/android/cardboard/cardboard_vr_device.cc
@@ -20,6 +20,7 @@
 #include "ui/gfx/transform_util.h"
 
 using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
 
 namespace device {
 
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 5e27be4d..a03d931 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -1987,7 +1987,8 @@
   bucket->DeductToken();
 }
 
-bool WebRequestInternalAddEventListenerFunction::RunSync() {
+ExtensionFunction::ResponseAction
+WebRequestInternalAddEventListenerFunction::Run() {
   // Argument 0 is the callback, which we don't use here.
   ExtensionWebRequestEventRouter::RequestFilter filter;
   base::DictionaryValue* value = NULL;
@@ -1997,7 +1998,7 @@
   EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
                               !error_.empty());
   if (!error_.empty())
-    return false;
+    return RespondNow(Error(error_));
 
   int extra_info_spec = 0;
   if (HasOptionalArgument(2)) {
@@ -2032,8 +2033,7 @@
          (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) &&
         !extension->permissions_data()->HasAPIPermission(
             APIPermission::kWebRequestBlocking)) {
-      error_ = keys::kBlockingPermissionRequired;
-      return false;
+      return RespondNow(Error(keys::kBlockingPermissionRequired));
     }
 
     // We allow to subscribe to patterns that are broader than the host
@@ -2049,8 +2049,7 @@
             ->withheld_permissions()
             .explicit_hosts()
             .is_empty()) {
-      error_ = keys::kHostPermissionsRequired;
-      return false;
+      return RespondNow(Error(keys::kHostPermissionsRequired));
     }
   }
 
@@ -2070,16 +2069,14 @@
                                        profile_id(), extension_id_safe()));
   }
 
-  return true;
+  return RespondNow(NoArguments());
 }
 
-void WebRequestInternalEventHandledFunction::RespondWithError(
+void WebRequestInternalEventHandledFunction::OnError(
     const std::string& event_name,
     const std::string& sub_event_name,
     uint64_t request_id,
-    std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
-    const std::string& error) {
-  error_ = error;
+    std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response) {
   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
       profile_id(),
       extension_id_safe(),
@@ -2089,7 +2086,8 @@
       response.release());
 }
 
-bool WebRequestInternalEventHandledFunction::RunSync() {
+ExtensionFunction::ResponseAction
+WebRequestInternalEventHandledFunction::Run() {
   std::string event_name;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
 
@@ -2117,9 +2115,8 @@
     if (value->HasKey("cancel")) {
       // Don't allow cancel mixed with other keys.
       if (value->size() != 1) {
-        RespondWithError(event_name, sub_event_name, request_id,
-                         std::move(response), keys::kInvalidBlockingResponse);
-        return false;
+        OnError(event_name, sub_event_name, request_id, std::move(response));
+        return RespondNow(Error(keys::kInvalidBlockingResponse));
       }
 
       bool cancel = false;
@@ -2133,11 +2130,8 @@
                                                    &new_url_str));
       response->new_url = GURL(new_url_str);
       if (!response->new_url.is_valid()) {
-        RespondWithError(event_name, sub_event_name, request_id,
-                         std::move(response),
-                         ErrorUtils::FormatErrorMessage(
-                             keys::kInvalidRedirectUrl, new_url_str));
-        return false;
+        OnError(event_name, sub_event_name, request_id, std::move(response));
+        return RespondNow(Error(keys::kInvalidRedirectUrl, new_url_str));
       }
     }
 
@@ -2146,10 +2140,8 @@
     if (has_request_headers || has_response_headers) {
       if (has_request_headers && has_response_headers) {
         // Allow only one of the keys, not both.
-        RespondWithError(event_name, sub_event_name, request_id,
-                         std::move(response),
-                         keys::kInvalidHeaderKeyCombination);
-        return false;
+        OnError(event_name, sub_event_name, request_id, std::move(response));
+        return RespondNow(Error(keys::kInvalidHeaderKeyCombination));
       }
 
       base::ListValue* headers_value = NULL;
@@ -2174,22 +2166,16 @@
         if (!FromHeaderDictionary(header_value, &name, &value)) {
           std::string serialized_header;
           base::JSONWriter::Write(*header_value, &serialized_header);
-          RespondWithError(event_name, sub_event_name, request_id,
-                           std::move(response),
-                           ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
-                                                          serialized_header));
-          return false;
+          OnError(event_name, sub_event_name, request_id, std::move(response));
+          return RespondNow(Error(keys::kInvalidHeader, serialized_header));
         }
         if (!net::HttpUtil::IsValidHeaderName(name)) {
-          RespondWithError(event_name, sub_event_name, request_id,
-                           std::move(response), keys::kInvalidHeaderName);
-          return false;
+          OnError(event_name, sub_event_name, request_id, std::move(response));
+          return RespondNow(Error(keys::kInvalidHeaderName));
         }
         if (!net::HttpUtil::IsValidHeaderValue(value)) {
-          RespondWithError(
-              event_name, sub_event_name, request_id, std::move(response),
-              ErrorUtils::FormatErrorMessage(keys::kInvalidHeaderValue, name));
-          return false;
+          OnError(event_name, sub_event_name, request_id, std::move(response));
+          return RespondNow(Error(keys::kInvalidHeaderValue, name));
         }
         if (has_request_headers)
           request_headers->SetHeader(name, value);
@@ -2222,7 +2208,7 @@
       profile_id(), extension_id_safe(), event_name, sub_event_name, request_id,
       response.release());
 
-  return true;
+  return RespondNow(NoArguments());
 }
 
 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
@@ -2250,12 +2236,13 @@
       base::Bind(&WarningService::NotifyWarningsOnUI, profile_id(), warnings));
 
   // Continue gracefully.
-  RunSync();
+  RunWithValidation()->Execute();
 }
 
-bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
+ExtensionFunction::ResponseAction
+WebRequestHandlerBehaviorChangedFunction::Run() {
   helpers::ClearCacheOnNavigation();
-  return true;
+  return RespondNow(NoArguments());
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index ff9def33..de5784b 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -476,7 +476,7 @@
   DISALLOW_COPY_AND_ASSIGN(ExtensionWebRequestEventRouter);
 };
 
-class WebRequestInternalFunction : public SyncIOThreadExtensionFunction {
+class WebRequestInternalFunction : public IOThreadExtensionFunction {
  public:
   WebRequestInternalFunction() {}
 
@@ -498,7 +498,7 @@
   ~WebRequestInternalAddEventListenerFunction() override {}
 
   // ExtensionFunction:
-  bool RunSync() override;
+  ResponseAction Run() override;
 };
 
 class WebRequestInternalEventHandledFunction
@@ -510,19 +510,18 @@
  protected:
   ~WebRequestInternalEventHandledFunction() override {}
 
-  // Unblocks the network request and sets |error_| such that the developer
-  // console will show the respective error message. Use this function to handle
-  // incorrect requests from the extension that cannot be detected by the schema
+ private:
+  // Unblocks the network request. Use this function when handling incorrect
+  // requests from the extension that cannot be detected by the schema
   // validator.
-  void RespondWithError(
+  void OnError(
       const std::string& event_name,
       const std::string& sub_event_name,
       uint64_t request_id,
-      std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
-      const std::string& error);
+      std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response);
 
   // ExtensionFunction:
-  bool RunSync() override;
+  ResponseAction Run() override;
 };
 
 class WebRequestHandlerBehaviorChangedFunction
@@ -540,7 +539,7 @@
   // Handle quota exceeded gracefully: Only warn the user but still execute the
   // function.
   void OnQuotaExceeded(const std::string& error) override;
-  bool RunSync() override;
+  ResponseAction Run() override;
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc
index 49a005b..255f2c63 100644
--- a/extensions/browser/extension_function.cc
+++ b/extensions/browser/extension_function.cc
@@ -641,20 +641,3 @@
 bool SyncExtensionFunction::ValidationFailure(SyncExtensionFunction* function) {
   return false;
 }
-
-SyncIOThreadExtensionFunction::SyncIOThreadExtensionFunction() {
-}
-
-SyncIOThreadExtensionFunction::~SyncIOThreadExtensionFunction() {
-}
-
-ExtensionFunction::ResponseAction SyncIOThreadExtensionFunction::Run() {
-  return RespondNow(RunSync() ? ArgumentList(std::move(results_))
-                              : Error(error_));
-}
-
-// static
-bool SyncIOThreadExtensionFunction::ValidationFailure(
-    SyncIOThreadExtensionFunction* function) {
-  return false;
-}
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index d6a0ad4..9627b08b 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -700,30 +700,4 @@
   DISALLOW_COPY_AND_ASSIGN(SyncExtensionFunction);
 };
 
-class SyncIOThreadExtensionFunction : public IOThreadExtensionFunction {
- public:
-  SyncIOThreadExtensionFunction();
-
- protected:
-  ~SyncIOThreadExtensionFunction() override;
-
-  // Deprecated: Override IOThreadExtensionFunction and implement Run() instead.
-  //
-  // SyncIOThreadExtensionFunctions implement this method. Return true to
-  // respond immediately with success, false to respond immediately with an
-  // error.
-  virtual bool RunSync() = 0;
-
-  // ValidationFailure override to match RunSync().
-  static bool ValidationFailure(SyncIOThreadExtensionFunction* function);
-
- private:
-  // If you're hitting a compile error here due to "final" - great! You're
-  // doing the right thing, you just need to extend IOThreadExtensionFunction
-  // instead of SyncIOExtensionFunction.
-  ResponseAction Run() final;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncIOThreadExtensionFunction);
-};
-
 #endif  // EXTENSIONS_BROWSER_EXTENSION_FUNCTION_H_
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc
index cf6432f..f611dde 100644
--- a/extensions/renderer/script_context.cc
+++ b/extensions/renderer/script_context.cc
@@ -4,8 +4,6 @@
 
 #include "extensions/renderer/script_context.h"
 
-#include <memory>
-
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -109,12 +107,13 @@
       effective_context_type_(effective_context_type),
       safe_builtins_(this),
       isolate_(v8_context->GetIsolate()),
-      url_(web_frame_ ? GetDataSourceURLForFrame(web_frame_) : GURL()),
       runner_(new Runner(this)) {
   VLOG(1) << "Created context:\n" << GetDebugString();
   gin::PerContextData* gin_data = gin::PerContextData::From(v8_context);
   CHECK(gin_data);
   gin_data->set_runner(runner_.get());
+  if (web_frame_)
+    url_ = GetAccessCheckedFrameURL(web_frame_);
 }
 
 ScriptContext::~ScriptContext() {
@@ -282,6 +281,22 @@
 }
 
 // static
+GURL ScriptContext::GetAccessCheckedFrameURL(const blink::WebFrame* frame) {
+  const blink::WebURL& weburl = frame->document().url();
+  if (weburl.isEmpty()) {
+    blink::WebDataSource* data_source = frame->provisionalDataSource()
+                                            ? frame->provisionalDataSource()
+                                            : frame->dataSource();
+    if (data_source &&
+        frame->getSecurityOrigin().canAccess(
+            blink::WebSecurityOrigin::create(data_source->request().url()))) {
+      return GURL(data_source->request().url());
+    }
+  }
+  return GURL(weburl);
+}
+
+// static
 GURL ScriptContext::GetEffectiveDocumentURL(const blink::WebFrame* frame,
                                             const GURL& document_url,
                                             bool match_about_blank) {
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h
index bbfd2f6..dd97ac9 100644
--- a/extensions/renderer/script_context.h
+++ b/extensions/renderer/script_context.h
@@ -5,6 +5,7 @@
 #ifndef EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_
 #define EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_
 
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
@@ -157,6 +158,13 @@
   // The returned URL may be invalid.
   static GURL GetDataSourceURLForFrame(const blink::WebFrame* frame);
 
+  // Similar to GetDataSourceURLForFrame, but only returns the data source URL
+  // if the frame's document url is empty and the frame has a security origin
+  // that allows access to the data source url.
+  // TODO(asargent/devlin) - there may be places that should switch to using
+  // this instead of GetDataSourceURLForFrame.
+  static GURL GetAccessCheckedFrameURL(const blink::WebFrame* frame);
+
   // Returns the first non-about:-URL in the document hierarchy above and
   // including |frame|. The document hierarchy is only traversed if
   // |document_url| is an about:-URL and if |match_about_blank| is true.
diff --git a/extensions/renderer/script_context_set.cc b/extensions/renderer/script_context_set.cc
index adefb38..276acae 100644
--- a/extensions/renderer/script_context_set.cc
+++ b/extensions/renderer/script_context_set.cc
@@ -140,8 +140,14 @@
     // Isolated worlds (content script).
     extension_id = ScriptInjection::GetHostIdForIsolatedWorld(world_id);
   } else {
-    // Extension pages (chrome-extension:// URLs).
-    GURL frame_url = ScriptContext::GetDataSourceURLForFrame(frame);
+    // For looking up the extension associated with this frame, we either want
+    // to use the current url or possibly the data source url (which this frame
+    // may be navigating to shortly), depending on the security origin of the
+    // frame. We don't always want to use the data source url because some
+    // frames (eg iframes and windows created via window.open) briefly contain
+    // an about:blank script context that is scriptable by their parent/opener
+    // before they finish navigating.
+    GURL frame_url = ScriptContext::GetAccessCheckedFrameURL(frame);
     frame_url = ScriptContext::GetEffectiveDocumentURL(frame, frame_url,
                                                        use_effective_url);
     extension_id =
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index f4b237f..179c600 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -11012,14 +11012,14 @@
   gfx::RectF contents_rect(mem[0], mem[1], mem[2], mem[3]);
   gfx::RectF bounds_rect(mem[4], mem[5], mem[6], mem[7]);
 
+  // TODO(erikchen): Pass through filter effects. https://crbug.com/581526.
+  ca_layer_filter_effects_.clear();
   ui::CARendererLayerParams params = ui::CARendererLayerParams(
       ca_layer_shared_state_->is_clipped, ca_layer_shared_state_->clip_rect,
       ca_layer_shared_state_->sorting_context_id,
       ca_layer_shared_state_->transform, image, contents_rect,
       gfx::ToEnclosingRect(bounds_rect), c.background_color, c.edge_aa_mask,
       ca_layer_shared_state_->opacity, filter);
-  params.filter_effects.swap(ca_layer_filter_effects_);
-
   if (!surface_->ScheduleCALayer(params)) {
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glScheduleCALayerCHROMIUM",
                        "failed to schedule CALayer");
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index 1bcf70e..39d226f 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -51,7 +51,8 @@
       : browser_(nullptr),
         devtools_client_(HeadlessDevToolsClient::Create()),
         web_contents_(nullptr),
-        processed_page_ready_(false) {}
+        processed_page_ready_(false),
+        browser_context_(nullptr) {}
   ~HeadlessShell() override {}
 
   void OnStart(HeadlessBrowser* browser) {
@@ -85,7 +86,7 @@
     }
     web_contents_->RemoveObserver(this);
     web_contents_ = nullptr;
-    browser_context_.reset();
+    browser_context_->Close();
     browser_->Shutdown();
   }
 
@@ -285,7 +286,7 @@
   HeadlessWebContents* web_contents_;
   bool processed_page_ready_;
   std::unique_ptr<net::FileStream> screenshot_file_stream_;
-  std::unique_ptr<HeadlessBrowserContext> browser_context_;
+  HeadlessBrowserContext* browser_context_;
 
   DISALLOW_COPY_AND_ASSIGN(HeadlessShell);
 };
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index 7bc310c2..458103d 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/guid.h"
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "content/public/browser/browser_thread.h"
@@ -20,6 +21,7 @@
 #include "headless/public/util/black_hole_protocol_handler.h"
 #include "headless/public/util/in_memory_protocol_handler.h"
 #include "net/url_request/url_request_context.h"
+#include "ui/aura/window_tree_host.h"
 
 namespace headless {
 
@@ -78,18 +80,19 @@
 
 HeadlessBrowserContextImpl::HeadlessBrowserContextImpl(
     HeadlessBrowserImpl* browser,
-    HeadlessBrowserContextOptions context_options)
+    std::unique_ptr<HeadlessBrowserContextOptions> context_options)
     : browser_(browser),
       context_options_(std::move(context_options)),
-      resource_context_(new HeadlessResourceContext) {
+      resource_context_(new HeadlessResourceContext),
+      id_(base::GenerateGUID()) {
   InitWhileIOAllowed();
 }
 
 HeadlessBrowserContextImpl::~HeadlessBrowserContextImpl() {
-  auto all_web_contents = GetAllWebContents();
-  for (auto* web_contents : all_web_contents) {
-    web_contents->Close();
-  }
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // Destroy all web contents before shutting down storage partitions.
+  web_contents_map_.clear();
 
   ShutdownStoragePartitions();
 
@@ -105,15 +108,41 @@
   return reinterpret_cast<HeadlessBrowserContextImpl*>(browser_context);
 }
 
+// static
+std::unique_ptr<HeadlessBrowserContextImpl> HeadlessBrowserContextImpl::Create(
+    HeadlessBrowserContext::Builder* builder) {
+  return base::WrapUnique(new HeadlessBrowserContextImpl(
+      builder->browser_, std::move(builder->options_)));
+}
+
 HeadlessWebContents::Builder
 HeadlessBrowserContextImpl::CreateWebContentsBuilder() {
   DCHECK(browser_->BrowserMainThread()->BelongsToCurrentThread());
   return HeadlessWebContents::Builder(this);
 }
 
+std::vector<HeadlessWebContents*>
+HeadlessBrowserContextImpl::GetAllWebContents() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  std::vector<HeadlessWebContents*> result;
+  result.reserve(web_contents_map_.size());
+
+  for (const auto& web_contents_pair : web_contents_map_) {
+    result.push_back(web_contents_pair.second.get());
+  }
+
+  return result;
+}
+
+void HeadlessBrowserContextImpl::Close() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  browser_->DestroyBrowserContext(this);
+}
+
 void HeadlessBrowserContextImpl::InitWhileIOAllowed() {
-  if (!context_options_.user_data_dir().empty()) {
-    path_ = context_options_.user_data_dir();
+  if (!context_options_->user_data_dir().empty()) {
+    path_ = context_options_->user_data_dir();
   } else {
     PathService::Get(base::DIR_EXE, &path_);
   }
@@ -182,8 +211,8 @@
               content::BrowserThread::IO),
           content::BrowserThread::GetTaskRunnerForThread(
               content::BrowserThread::FILE),
-          protocol_handlers, context_options_.TakeProtocolHandlers(),
-          std::move(request_interceptors), &context_options_));
+          protocol_handlers, context_options_->TakeProtocolHandlers(),
+          std::move(request_interceptors), context_options_.get()));
   resource_context_->set_url_request_context_getter(url_request_context_getter);
   return url_request_context_getter.get();
 }
@@ -209,38 +238,59 @@
   return nullptr;
 }
 
-std::vector<HeadlessWebContents*>
-HeadlessBrowserContextImpl::GetAllWebContents() {
-  std::vector<HeadlessWebContents*> result;
+HeadlessWebContents* HeadlessBrowserContextImpl::CreateWebContents(
+    HeadlessWebContents::Builder* builder) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  result.reserve(web_contents_map_.size());
+  std::unique_ptr<HeadlessWebContentsImpl> headless_web_contents =
+      HeadlessWebContentsImpl::Create(builder,
+                                      browser()->window_tree_host()->window());
 
-  for (const auto& web_contents_pair : web_contents_map_) {
-    result.push_back(web_contents_pair.second);
+  if (!headless_web_contents) {
+    return nullptr;
   }
 
+  HeadlessWebContents* result = headless_web_contents.get();
+
+  RegisterWebContents(std::move(headless_web_contents));
+
   return result;
 }
 
 void HeadlessBrowserContextImpl::RegisterWebContents(
-    HeadlessWebContentsImpl* web_contents) {
-  web_contents_map_[web_contents->GetDevtoolsAgentHostId()] = web_contents;
+    std::unique_ptr<HeadlessWebContentsImpl> web_contents) {
+  DCHECK(web_contents);
+  web_contents_map_[web_contents->GetDevToolsAgentHostId()] =
+      std::move(web_contents);
 }
 
-void HeadlessBrowserContextImpl::UnregisterWebContents(
+void HeadlessBrowserContextImpl::DestroyWebContents(
     HeadlessWebContentsImpl* web_contents) {
-  auto it = web_contents_map_.find(web_contents->GetDevtoolsAgentHostId());
+  auto it = web_contents_map_.find(web_contents->GetDevToolsAgentHostId());
   DCHECK(it != web_contents_map_.end());
   web_contents_map_.erase(it);
 }
 
+HeadlessWebContents*
+HeadlessBrowserContextImpl::GetWebContentsForDevToolsAgentHostId(
+    const std::string& devtools_agent_host_id) {
+  auto find_it = web_contents_map_.find(devtools_agent_host_id);
+  if (find_it == web_contents_map_.end())
+    return nullptr;
+  return find_it->second.get();
+}
+
 HeadlessBrowserImpl* HeadlessBrowserContextImpl::browser() const {
   return browser_;
 }
 
 const HeadlessBrowserContextOptions* HeadlessBrowserContextImpl::options()
     const {
-  return &context_options_;
+  return context_options_.get();
+}
+
+const std::string& HeadlessBrowserContextImpl::Id() const {
+  return id_;
 }
 
 HeadlessBrowserContext::Builder::Builder(HeadlessBrowserImpl* browser)
@@ -307,8 +357,7 @@
   return *this;
 }
 
-std::unique_ptr<HeadlessBrowserContext>
-HeadlessBrowserContext::Builder::Build() {
+HeadlessBrowserContext* HeadlessBrowserContext::Builder::Build() {
   if (!mojo_bindings_.empty()) {
     std::unique_ptr<InMemoryProtocolHandler> headless_mojom_protocol_handler(
         new InMemoryProtocolHandler());
@@ -333,8 +382,7 @@
     }
   }
 
-  return base::WrapUnique(
-      new HeadlessBrowserContextImpl(browser_, std::move(*options_)));
+  return browser_->CreateBrowserContext(this);
 }
 
 HeadlessBrowserContext::Builder::MojoBindings::MojoBindings() {}
diff --git a/headless/lib/browser/headless_browser_context_impl.h b/headless/lib/browser/headless_browser_context_impl.h
index da7ab59..7f8d3bb 100644
--- a/headless/lib/browser/headless_browser_context_impl.h
+++ b/headless/lib/browser/headless_browser_context_impl.h
@@ -27,16 +27,21 @@
 class HeadlessBrowserContextImpl : public HeadlessBrowserContext,
                                    public content::BrowserContext {
  public:
-  HeadlessBrowserContextImpl(HeadlessBrowserImpl* browser,
-                             HeadlessBrowserContextOptions context_options);
   ~HeadlessBrowserContextImpl() override;
 
   static HeadlessBrowserContextImpl* From(
       HeadlessBrowserContext* browser_context);
 
+  static std::unique_ptr<HeadlessBrowserContextImpl> Create(
+      HeadlessBrowserContext::Builder* builder);
+
   // HeadlessBrowserContext implementation:
   HeadlessWebContents::Builder CreateWebContentsBuilder() override;
   std::vector<HeadlessWebContents*> GetAllWebContents() override;
+  HeadlessWebContents* GetWebContentsForDevToolsAgentHostId(
+      const std::string& devtools_agent_host_id) override;
+  void Close() override;
+  const std::string& Id() const override;
 
   // BrowserContext implementation:
   std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
@@ -64,26 +69,34 @@
       const base::FilePath& partition_path,
       bool in_memory) override;
 
-  void RegisterWebContents(HeadlessWebContentsImpl*);
-  void UnregisterWebContents(HeadlessWebContentsImpl*);
+  HeadlessWebContents* CreateWebContents(HeadlessWebContents::Builder* builder);
+  // Register web contents which were created not through Headless API
+  // (calling window.open() is a best example for this).
+  void RegisterWebContents(
+      std::unique_ptr<HeadlessWebContentsImpl> web_contents);
+  void DestroyWebContents(HeadlessWebContentsImpl* web_contents);
 
   HeadlessBrowserImpl* browser() const;
   const HeadlessBrowserContextOptions* options() const;
 
  private:
+  HeadlessBrowserContextImpl(
+      HeadlessBrowserImpl* browser,
+      std::unique_ptr<HeadlessBrowserContextOptions> context_options);
+
   // Performs initialization of the HeadlessBrowserContextImpl while IO is still
   // allowed on the current thread.
   void InitWhileIOAllowed();
 
   HeadlessBrowserImpl* browser_;  // Not owned.
-  HeadlessBrowserContextOptions context_options_;
+  std::unique_ptr<HeadlessBrowserContextOptions> context_options_;
   std::unique_ptr<HeadlessResourceContext> resource_context_;
   base::FilePath path_;
 
-  // Web contents are owned by |HeadlessBrowser|, we keep track of
-  // contents corresponding to this context to delete them when context goes
-  // away.
-  std::unordered_map<std::string, HeadlessWebContents*> web_contents_map_;
+  std::unordered_map<std::string, std::unique_ptr<HeadlessWebContents>>
+      web_contents_map_;
+
+  std::string id_;
 
   DISALLOW_COPY_AND_ASSIGN(HeadlessBrowserContextImpl);
 };
diff --git a/headless/lib/browser/headless_browser_impl.cc b/headless/lib/browser/headless_browser_impl.cc
index d464630..57f32e5 100644
--- a/headless/lib/browser/headless_browser_impl.cc
+++ b/headless/lib/browser/headless_browser_impl.cc
@@ -51,13 +51,14 @@
     HeadlessBrowser::Options options)
     : on_start_callback_(on_start_callback),
       options_(std::move(options)),
-      browser_main_parts_(nullptr) {}
+      browser_main_parts_(nullptr),
+      weak_ptr_factory_(this) {}
 
 HeadlessBrowserImpl::~HeadlessBrowserImpl() {}
 
 HeadlessBrowserContext::Builder
 HeadlessBrowserImpl::CreateBrowserContextBuilder() {
-  DCHECK(BrowserMainThread()->BelongsToCurrentThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   return HeadlessBrowserContext::Builder(this);
 }
 
@@ -74,37 +75,33 @@
 }
 
 void HeadlessBrowserImpl::Shutdown() {
-  DCHECK(BrowserMainThread()->BelongsToCurrentThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  // DevToolsManagerDelegate owns some BrowserContexts. Tell it to delete them.
-  if (devtools_manager_delegate()) {
-    devtools_manager_delegate()->Shutdown();
-  }
+  weak_ptr_factory_.InvalidateWeakPtrs();
 
-  // We need to close all WebContents here.
-  std::vector<HeadlessWebContents*> all_web_contents = GetAllWebContents();
-  for (HeadlessWebContents* web_contents : all_web_contents) {
-    web_contents->Close();
-  }
-  DCHECK(web_contents_map_.empty());
+  // Destroy all browser contexts.
+  browser_contexts_.clear();
 
   BrowserMainThread()->PostTask(FROM_HERE,
                                 base::MessageLoop::QuitWhenIdleClosure());
 }
 
-std::vector<HeadlessWebContents*> HeadlessBrowserImpl::GetAllWebContents() {
-  std::vector<HeadlessWebContents*> result;
-  result.reserve(web_contents_map_.size());
+std::vector<HeadlessBrowserContext*>
+HeadlessBrowserImpl::GetAllBrowserContexts() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  for (const auto& web_contents_pair : web_contents_map_) {
-    result.push_back(web_contents_pair.second.get());
+  std::vector<HeadlessBrowserContext*> result;
+  result.reserve(browser_contexts_.size());
+
+  for (const auto& browser_context_pair : browser_contexts_) {
+    result.push_back(browser_context_pair.second.get());
   }
 
   return result;
 }
 
 HeadlessBrowserMainParts* HeadlessBrowserImpl::browser_main_parts() const {
-  DCHECK(BrowserMainThread()->BelongsToCurrentThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   return browser_main_parts_;
 }
 
@@ -127,51 +124,57 @@
   on_start_callback_ = base::Callback<void(HeadlessBrowser*)>();
 }
 
-HeadlessWebContents* HeadlessBrowserImpl::CreateWebContents(
-    HeadlessWebContents::Builder* builder) {
-  DCHECK(BrowserMainThread()->BelongsToCurrentThread());
-  std::unique_ptr<HeadlessWebContentsImpl> headless_web_contents =
-      HeadlessWebContentsImpl::Create(builder, window_tree_host_->window());
-  if (!headless_web_contents)
+HeadlessBrowserContext* HeadlessBrowserImpl::CreateBrowserContext(
+    HeadlessBrowserContext::Builder* builder) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  std::unique_ptr<HeadlessBrowserContextImpl> browser_context =
+      HeadlessBrowserContextImpl::Create(builder);
+
+  if (!browser_context) {
     return nullptr;
-  builder->browser_context_->RegisterWebContents(headless_web_contents.get());
-  return RegisterWebContents(std::move(headless_web_contents));
+  }
+
+  HeadlessBrowserContext* result = browser_context.get();
+
+  browser_contexts_[browser_context->Id()] = std::move(browser_context);
+
+  return result;
 }
 
-HeadlessWebContentsImpl* HeadlessBrowserImpl::RegisterWebContents(
-    std::unique_ptr<HeadlessWebContentsImpl> web_contents) {
-  DCHECK(web_contents);
-  HeadlessWebContentsImpl* unowned_web_contents = web_contents.get();
-  web_contents_map_[unowned_web_contents->GetDevtoolsAgentHostId()] =
-      std::move(web_contents);
-  return unowned_web_contents;
+void HeadlessBrowserImpl::DestroyBrowserContext(
+    HeadlessBrowserContextImpl* browser_context) {
+  auto it = browser_contexts_.find(browser_context->Id());
+  DCHECK(it != browser_contexts_.end());
+  browser_contexts_.erase(it);
 }
 
-void HeadlessBrowserImpl::DestroyWebContents(
-    HeadlessWebContentsImpl* web_contents) {
-  auto it = web_contents_map_.find(web_contents->GetDevtoolsAgentHostId());
-  DCHECK(it != web_contents_map_.end());
-  web_contents_map_.erase(it);
-}
-
-HeadlessDevToolsManagerDelegate*
-HeadlessBrowserImpl::devtools_manager_delegate() const {
+base::WeakPtr<HeadlessBrowserImpl> HeadlessBrowserImpl::GetWeakPtr() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  return devtools_manager_delegate_.get();
+  return weak_ptr_factory_.GetWeakPtr();
 }
 
-void HeadlessBrowserImpl::set_devtools_manager_delegate(
-    base::WeakPtr<HeadlessDevToolsManagerDelegate> devtools_manager_delegate) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  devtools_manager_delegate_ = devtools_manager_delegate;
+aura::WindowTreeHost* HeadlessBrowserImpl::window_tree_host() const {
+  return window_tree_host_.get();
 }
 
-HeadlessWebContents* HeadlessBrowserImpl::GetWebContentsForDevtoolsAgentHostId(
+HeadlessWebContents* HeadlessBrowserImpl::GetWebContentsForDevToolsAgentHostId(
     const std::string& devtools_agent_host_id) {
-  auto it = web_contents_map_.find(devtools_agent_host_id);
-  if (it == web_contents_map_.end())
+  for (HeadlessBrowserContext* context : GetAllBrowserContexts()) {
+    HeadlessWebContents* web_contents =
+        context->GetWebContentsForDevToolsAgentHostId(devtools_agent_host_id);
+    if (web_contents)
+      return web_contents;
+  }
+  return nullptr;
+}
+
+HeadlessBrowserContext* HeadlessBrowserImpl::GetBrowserContextForId(
+    const std::string& id) {
+  auto find_it = browser_contexts_.find(id);
+  if (find_it == browser_contexts_.end())
     return nullptr;
-  return it->second.get();
+  return find_it->second.get();
 }
 
 void RunChildProcessIfNeeded(int argc, const char** argv) {
diff --git a/headless/lib/browser/headless_browser_impl.h b/headless/lib/browser/headless_browser_impl.h
index 75f9856..a97410e 100644
--- a/headless/lib/browser/headless_browser_impl.h
+++ b/headless/lib/browser/headless_browser_impl.h
@@ -26,7 +26,7 @@
 
 namespace headless {
 
-class HeadlessBrowserContext;
+class HeadlessBrowserContextImpl;
 class HeadlessBrowserMainParts;
 
 class HeadlessBrowserImpl : public HeadlessBrowser {
@@ -45,9 +45,11 @@
 
   void Shutdown() override;
 
-  std::vector<HeadlessWebContents*> GetAllWebContents() override;
-  HeadlessWebContents* GetWebContentsForDevtoolsAgentHostId(
+  std::vector<HeadlessBrowserContext*> GetAllBrowserContexts() override;
+  HeadlessWebContents* GetWebContentsForDevToolsAgentHostId(
       const std::string& devtools_agent_host_id) override;
+  HeadlessBrowserContext* GetBrowserContextForId(
+      const std::string& id) override;
 
   void set_browser_main_parts(HeadlessBrowserMainParts* browser_main_parts);
   HeadlessBrowserMainParts* browser_main_parts() const;
@@ -56,28 +58,31 @@
 
   HeadlessBrowser::Options* options() { return &options_; }
 
-  HeadlessWebContents* CreateWebContents(HeadlessWebContents::Builder* builder);
-  HeadlessWebContentsImpl* RegisterWebContents(
-      std::unique_ptr<HeadlessWebContentsImpl> web_contents);
+  HeadlessBrowserContext* CreateBrowserContext(
+      HeadlessBrowserContext::Builder* builder);
+  // Close given |browser_context| and delete it
+  // (all web contents associated with it go away too).
+  void DestroyBrowserContext(HeadlessBrowserContextImpl* browser_context);
 
-  // Close given |web_contents| and delete it.
-  void DestroyWebContents(HeadlessWebContentsImpl* web_contents);
+  base::WeakPtr<HeadlessBrowserImpl> GetWeakPtr();
 
-  HeadlessDevToolsManagerDelegate* devtools_manager_delegate() const;
-  void set_devtools_manager_delegate(
-      base::WeakPtr<HeadlessDevToolsManagerDelegate>);
+  aura::WindowTreeHost* window_tree_host() const;
 
  protected:
   base::Callback<void(HeadlessBrowser*)> on_start_callback_;
   HeadlessBrowser::Options options_;
   HeadlessBrowserMainParts* browser_main_parts_;  // Not owned.
+
+  // TODO(eseckler): Currently one window and one window_tree_host
+  // is used for all web contents. We should probably use one
+  // window per web contents, but additional investigation is needed.
   std::unique_ptr<aura::WindowTreeHost> window_tree_host_;
   std::unique_ptr<aura::client::WindowTreeClient> window_tree_client_;
 
-  std::unordered_map<std::string, std::unique_ptr<HeadlessWebContents>>
-      web_contents_map_;
+  std::unordered_map<std::string, std::unique_ptr<HeadlessBrowserContextImpl>>
+      browser_contexts_;
 
-  base::WeakPtr<HeadlessDevToolsManagerDelegate> devtools_manager_delegate_;
+  base::WeakPtrFactory<HeadlessBrowserImpl> weak_ptr_factory_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(HeadlessBrowserImpl);
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index 4a52361..1c83d75 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -30,11 +30,7 @@
 
 content::DevToolsManagerDelegate*
 HeadlessContentBrowserClient::GetDevToolsManagerDelegate() {
-  std::unique_ptr<HeadlessDevToolsManagerDelegate> devtools_manager_delegate =
-      base::WrapUnique(new HeadlessDevToolsManagerDelegate(browser_));
-  browser_->set_devtools_manager_delegate(
-      devtools_manager_delegate->GetWeakPtr());
-  return devtools_manager_delegate.release();
+  return new HeadlessDevToolsManagerDelegate(browser_->GetWeakPtr());
 }
 
 }  // namespace headless
diff --git a/headless/lib/browser/headless_devtools_manager_delegate.cc b/headless/lib/browser/headless_devtools_manager_delegate.cc
index 508fc8b..338c5cc 100644
--- a/headless/lib/browser/headless_devtools_manager_delegate.cc
+++ b/headless/lib/browser/headless_devtools_manager_delegate.cc
@@ -7,7 +7,7 @@
 #include <string>
 #include <utility>
 
-#include "base/guid.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "headless/lib/browser/headless_browser_context_impl.h"
 #include "headless/lib/browser/headless_browser_impl.h"
@@ -17,8 +17,8 @@
 namespace headless {
 
 HeadlessDevToolsManagerDelegate::HeadlessDevToolsManagerDelegate(
-    HeadlessBrowserImpl* browser)
-    : browser_(browser), weak_ptr_factory_(this) {
+    base::WeakPtr<HeadlessBrowserImpl> browser)
+    : browser_(std::move(browser)), default_browser_context_(nullptr) {
   command_map_["Browser.createTarget"] =
       &HeadlessDevToolsManagerDelegate::CreateTarget;
   command_map_["Browser.closeTarget"] =
@@ -34,6 +34,11 @@
 base::DictionaryValue* HeadlessDevToolsManagerDelegate::HandleCommand(
     content::DevToolsAgentHost* agent_host,
     base::DictionaryValue* command) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!browser_)
+    return nullptr;
+
   int id;
   std::string method;
   const base::DictionaryValue* params = nullptr;
@@ -56,16 +61,6 @@
   return result.release();
 }
 
-void HeadlessDevToolsManagerDelegate::Shutdown() {
-  default_browser_context_.reset();
-  browser_context_map_.clear();
-}
-
-base::WeakPtr<HeadlessDevToolsManagerDelegate>
-HeadlessDevToolsManagerDelegate::GetWeakPtr() {
-  return weak_ptr_factory_.GetWeakPtr();
-}
-
 std::unique_ptr<base::Value> HeadlessDevToolsManagerDelegate::CreateTarget(
     const base::DictionaryValue* params) {
   std::string url;
@@ -77,16 +72,15 @@
   params->GetInteger("width", &width);
   params->GetInteger("height", &height);
 
-  HeadlessBrowserContext* context;
-  auto find_it = browser_context_map_.find(browser_context_id);
-  if (find_it != browser_context_map_.end()) {
-    context = find_it->second.get();
-  } else {
+  // TODO(alexclarke): Should we fail when user passes incorrect id?
+  HeadlessBrowserContext* context =
+      browser_->GetBrowserContextForId(browser_context_id);
+  if (!context) {
     if (!default_browser_context_) {
       default_browser_context_ =
           browser_->CreateBrowserContextBuilder().Build();
     }
-    context = default_browser_context_.get();
+    context = default_browser_context_;
   }
 
   HeadlessWebContentsImpl* web_contents_impl =
@@ -96,7 +90,7 @@
                                         .Build());
 
   return browser::CreateTargetResult::Builder()
-      .SetTargetId(web_contents_impl->GetDevtoolsAgentHostId())
+      .SetTargetId(web_contents_impl->GetDevToolsAgentHostId())
       .Build()
       ->Serialize();
 }
@@ -108,7 +102,7 @@
     return nullptr;
   }
   HeadlessWebContents* web_contents =
-      browser_->GetWebContentsForDevtoolsAgentHostId(target_id);
+      browser_->GetWebContentsForDevToolsAgentHostId(target_id);
   bool success = false;
   if (web_contents) {
     web_contents->Close();
@@ -123,12 +117,12 @@
 std::unique_ptr<base::Value>
 HeadlessDevToolsManagerDelegate::CreateBrowserContext(
     const base::DictionaryValue* params) {
-  std::string browser_context_id = base::GenerateGUID();
-  browser_context_map_[browser_context_id] =
+  HeadlessBrowserContext* browser_context =
       browser_->CreateBrowserContextBuilder().Build();
+
   std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
   return browser::CreateBrowserContextResult::Builder()
-      .SetBrowserContextId(browser_context_id)
+      .SetBrowserContextId(browser_context->Id())
       .Build()
       ->Serialize();
 }
@@ -140,25 +134,16 @@
   if (!params->GetString("browserContextId", &browser_context_id)) {
     return nullptr;
   }
-  auto find_it = browser_context_map_.find(browser_context_id);
+  HeadlessBrowserContext* context =
+      browser_->GetBrowserContextForId(browser_context_id);
+
   bool success = false;
-  if (find_it != browser_context_map_.end()) {
+  if (context && context != default_browser_context_ &&
+      context->GetAllWebContents().empty()) {
     success = true;
-    HeadlessBrowserContextImpl* headless_browser_context =
-        HeadlessBrowserContextImpl::From(find_it->second.get());
-    // Make sure |headless_browser_context| isn't in use!
-    for (HeadlessWebContents* headless_web_contents :
-         browser_->GetAllWebContents()) {
-      content::WebContents* web_contents =
-          HeadlessWebContentsImpl::From(headless_web_contents)->web_contents();
-      if (web_contents->GetBrowserContext() == headless_browser_context) {
-        success = false;
-        break;
-      }
-    }
-    if (success)
-      browser_context_map_.erase(find_it);
+    context->Close();
   }
+
   return browser::DisposeBrowserContextResult::Builder()
       .SetSuccess(success)
       .Build()
diff --git a/headless/lib/browser/headless_devtools_manager_delegate.h b/headless/lib/browser/headless_devtools_manager_delegate.h
index e5c2697..dbc6a25 100644
--- a/headless/lib/browser/headless_devtools_manager_delegate.h
+++ b/headless/lib/browser/headless_devtools_manager_delegate.h
@@ -22,7 +22,8 @@
 class HeadlessDevToolsManagerDelegate
     : public content::DevToolsManagerDelegate {
  public:
-  explicit HeadlessDevToolsManagerDelegate(HeadlessBrowserImpl* browser);
+  explicit HeadlessDevToolsManagerDelegate(
+      base::WeakPtr<HeadlessBrowserImpl> browser);
   ~HeadlessDevToolsManagerDelegate() override;
 
   // DevToolsManagerDelegate implementation:
@@ -33,11 +34,6 @@
   base::DictionaryValue* HandleCommand(content::DevToolsAgentHost* agent_host,
                                        base::DictionaryValue* command) override;
 
-  // Delete owned browser contexts.
-  void Shutdown();
-
-  base::WeakPtr<HeadlessDevToolsManagerDelegate> GetWeakPtr();
-
  private:
   std::unique_ptr<base::Value> CreateTarget(
       const base::DictionaryValue* params);
@@ -47,18 +43,14 @@
   std::unique_ptr<base::Value> DisposeBrowserContext(
       const base::DictionaryValue* params);
 
-  HeadlessBrowserImpl* browser_;  // Not owned.
-  std::map<std::string, std::unique_ptr<HeadlessBrowserContext>>
-      browser_context_map_;
+  base::WeakPtr<HeadlessBrowserImpl> browser_;
 
   using CommandMemberFnPtr = std::unique_ptr<base::Value> (
       HeadlessDevToolsManagerDelegate::*)(const base::DictionaryValue* params);
 
   std::map<std::string, CommandMemberFnPtr> command_map_;
 
-  std::unique_ptr<HeadlessBrowserContext> default_browser_context_;
-
-  base::WeakPtrFactory<HeadlessDevToolsManagerDelegate> weak_ptr_factory_;
+  HeadlessBrowserContext* default_browser_context_;
 };
 
 }  // namespace headless
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
index 89f3ff7..75158cf 100644
--- a/headless/lib/browser/headless_web_contents_impl.cc
+++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
@@ -75,8 +76,7 @@
 
     DCHECK(new_contents->GetBrowserContext() == browser_context_);
 
-    browser_context_->RegisterWebContents(web_contents.get());
-    browser_context_->browser()->RegisterWebContents(std::move(web_contents));
+    browser_context_->RegisterWebContents(std::move(web_contents));
   }
 
  private:
@@ -175,11 +175,11 @@
 }
 
 void HeadlessWebContentsImpl::Close() {
-  browser_context()->UnregisterWebContents(this);
-  browser()->DestroyWebContents(this);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  browser_context()->DestroyWebContents(this);
 }
 
-std::string HeadlessWebContentsImpl::GetDevtoolsAgentHostId() {
+std::string HeadlessWebContentsImpl::GetDevToolsAgentHostId() {
   return agent_host_->GetId();
 }
 
@@ -250,7 +250,7 @@
 }
 
 HeadlessWebContents* HeadlessWebContents::Builder::Build() {
-  return browser_context_->browser()->CreateWebContents(this);
+  return browser_context_->CreateWebContents(this);
 }
 
 HeadlessWebContents::Builder::MojoService::MojoService() {}
diff --git a/headless/lib/browser/headless_web_contents_impl.h b/headless/lib/browser/headless_web_contents_impl.h
index 4aca28c8..4329384 100644
--- a/headless/lib/browser/headless_web_contents_impl.h
+++ b/headless/lib/browser/headless_web_contents_impl.h
@@ -67,7 +67,7 @@
 
   void Close() override;
 
-  std::string GetDevtoolsAgentHostId();
+  std::string GetDevToolsAgentHostId();
 
   HeadlessBrowserImpl* browser() const;
   HeadlessBrowserContextImpl* browser_context() const;
diff --git a/headless/lib/embedder_mojo_browsertest.cc b/headless/lib/embedder_mojo_browsertest.cc
index 799b6b0f..a8338e0 100644
--- a/headless/lib/embedder_mojo_browsertest.cc
+++ b/headless/lib/embedder_mojo_browsertest.cc
@@ -42,7 +42,8 @@
   EmbedderMojoTest() : EmbedderMojoTest(HttpPolicy::DEFAULT) {}
 
   explicit EmbedderMojoTest(HttpPolicy http_policy)
-      : web_contents_(nullptr),
+      : browser_context_(nullptr),
+        web_contents_(nullptr),
         devtools_client_(HeadlessDevToolsClient::Create()),
         http_policy_(http_policy) {}
 
@@ -114,7 +115,8 @@
     web_contents_->Close();
     web_contents_ = nullptr;
 
-    browser_context_.reset();
+    browser_context_->Close();
+    browser_context_ = nullptr;
   }
 
   void CreateTestMojoService(
@@ -122,7 +124,7 @@
     test_embedder_mojo_bindings_.AddBinding(this, std::move(request));
   }
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context_;
+  HeadlessBrowserContext* browser_context_;
   HeadlessWebContents* web_contents_;
   std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
 
diff --git a/headless/lib/headless_browser_browsertest.cc b/headless/lib/headless_browser_browsertest.cc
index a4256b2..998b112c 100644
--- a/headless/lib/headless_browser_browsertest.cc
+++ b/headless/lib/headless_browser_browsertest.cc
@@ -27,90 +27,143 @@
 
 namespace headless {
 
-IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyWebContents) {
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyBrowserContext) {
+  HeadlessBrowserContext* browser_context =
       browser()->CreateBrowserContextBuilder().Build();
+
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context));
+
+  browser_context->Close();
+
+  EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
+}
+
+IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
+                       CreateAndDoNotDestroyBrowserContext) {
+  HeadlessBrowserContext* browser_context =
+      browser()->CreateBrowserContextBuilder().Build();
+
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context));
+
+  // We check that HeadlessBrowser correctly handles non-closed BrowserContexts.
+  // We can rely on Chromium DCHECKs to capture this.
+}
+
+IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyWebContents) {
+  HeadlessBrowserContext* browser_context =
+      browser()->CreateBrowserContextBuilder().Build();
+
   HeadlessWebContents* web_contents =
       browser_context->CreateWebContentsBuilder().Build();
   EXPECT_TRUE(web_contents);
 
-  EXPECT_THAT(browser()->GetAllWebContents(),
-              UnorderedElementsAre(web_contents));
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context));
   EXPECT_THAT(browser_context->GetAllWebContents(),
               UnorderedElementsAre(web_contents));
+
   // TODO(skyostil): Verify viewport dimensions once we can.
 
   web_contents->Close();
 
-  EXPECT_TRUE(browser()->GetAllWebContents().empty());
   EXPECT_TRUE(browser_context->GetAllWebContents().empty());
+
+  browser_context->Close();
+
+  EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
 }
 
 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
                        WebContentsAreDestroyedWithContext) {
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()->CreateBrowserContextBuilder().Build();
+
   HeadlessWebContents* web_contents =
       browser_context->CreateWebContentsBuilder().Build();
   EXPECT_TRUE(web_contents);
 
-  EXPECT_THAT(browser()->GetAllWebContents(),
-              UnorderedElementsAre(web_contents));
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context));
   EXPECT_THAT(browser_context->GetAllWebContents(),
               UnorderedElementsAre(web_contents));
 
-  browser_context.reset();
+  browser_context->Close();
 
-  EXPECT_TRUE(browser()->GetAllWebContents().empty());
+  EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
+
+  // If WebContents are not destroyed, Chromium DCHECKs will capture this.
+}
+
+IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDoNotDestroyWebContents) {
+  HeadlessBrowserContext* browser_context =
+      browser()->CreateBrowserContextBuilder().Build();
+
+  HeadlessWebContents* web_contents =
+      browser_context->CreateWebContentsBuilder().Build();
+  EXPECT_TRUE(web_contents);
+
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context));
+  EXPECT_THAT(browser_context->GetAllWebContents(),
+              UnorderedElementsAre(web_contents));
+
+  // If WebContents are not destroyed, Chromium DCHECKs will capture this.
 }
 
 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, DestroyAndCreateTwoWebContents) {
-  std::unique_ptr<HeadlessBrowserContext> browser_context1 =
+  HeadlessBrowserContext* browser_context1 =
       browser()->CreateBrowserContextBuilder().Build();
+  EXPECT_TRUE(browser_context1);
   HeadlessWebContents* web_contents1 =
       browser_context1->CreateWebContentsBuilder().Build();
+  EXPECT_TRUE(web_contents1);
 
-  EXPECT_THAT(browser()->GetAllWebContents(),
-              UnorderedElementsAre(web_contents1));
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context1));
   EXPECT_THAT(browser_context1->GetAllWebContents(),
               UnorderedElementsAre(web_contents1));
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context2 =
+  HeadlessBrowserContext* browser_context2 =
       browser()->CreateBrowserContextBuilder().Build();
+  EXPECT_TRUE(browser_context2);
   HeadlessWebContents* web_contents2 =
       browser_context2->CreateWebContentsBuilder().Build();
+  EXPECT_TRUE(web_contents2);
 
-  EXPECT_THAT(browser()->GetAllWebContents(),
-              UnorderedElementsAre(web_contents1, web_contents2));
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context1, browser_context2));
   EXPECT_THAT(browser_context1->GetAllWebContents(),
               UnorderedElementsAre(web_contents1));
   EXPECT_THAT(browser_context2->GetAllWebContents(),
               UnorderedElementsAre(web_contents2));
 
-  browser_context1.reset();
+  browser_context1->Close();
 
-  EXPECT_THAT(browser()->GetAllWebContents(),
-              UnorderedElementsAre(web_contents2));
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context2));
   EXPECT_THAT(browser_context2->GetAllWebContents(),
               UnorderedElementsAre(web_contents2));
 
-  browser_context2.reset();
+  browser_context2->Close();
 
-  EXPECT_TRUE(browser()->GetAllWebContents().empty());
+  EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
 }
 
 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateWithBadURL) {
   GURL bad_url("not_valid");
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()->CreateBrowserContextBuilder().Build();
+
   HeadlessWebContents* web_contents =
       browser_context->CreateWebContentsBuilder()
           .SetInitialURL(bad_url)
           .Build();
 
   EXPECT_FALSE(web_contents);
-  EXPECT_TRUE(browser()->GetAllWebContents().empty());
+  EXPECT_TRUE(browser_context->GetAllWebContents().empty());
 }
 
 class HeadlessBrowserTestWithProxy : public HeadlessBrowserTest {
@@ -138,7 +191,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithProxy, SetProxyServer) {
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()
           ->CreateBrowserContextBuilder()
           .SetProxyServer(proxy_server()->host_port_pair())
@@ -146,18 +199,17 @@
 
   // Load a page which doesn't actually exist, but for which the our proxy
   // returns valid content anyway.
-  //
-  // TODO(altimin): Currently this construction does not serve hello.html
-  // from headless/test/data as expected. We should fix this.
   HeadlessWebContents* web_contents =
       browser_context->CreateWebContentsBuilder()
           .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html"))
           .Build();
   EXPECT_TRUE(WaitForLoad(web_contents));
-  EXPECT_THAT(browser()->GetAllWebContents(),
+  EXPECT_THAT(browser()->GetAllBrowserContexts(),
+              UnorderedElementsAre(browser_context));
+  EXPECT_THAT(browser_context->GetAllWebContents(),
               UnorderedElementsAre(web_contents));
   web_contents->Close();
-  EXPECT_TRUE(browser()->GetAllWebContents().empty());
+  EXPECT_TRUE(browser_context->GetAllWebContents().empty());
 }
 
 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, SetHostResolverRules) {
@@ -167,7 +219,7 @@
       base::StringPrintf("MAP not-an-actual-domain.tld 127.0.0.1:%d",
                          embedded_test_server()->host_port_pair().port());
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()
           ->CreateBrowserContextBuilder()
           .SetHostResolverRules(host_resolver_rules)
@@ -179,6 +231,7 @@
       browser_context->CreateWebContentsBuilder()
           .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html"))
           .Build();
+  EXPECT_TRUE(web_contents);
 
   EXPECT_TRUE(WaitForLoad(web_contents));
 }
@@ -189,7 +242,7 @@
   protocol_handlers[url::kHttpScheme] =
       base::WrapUnique(new TestProtocolHandler(kResponseBody));
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()
           ->CreateBrowserContextBuilder()
           .SetProtocolHandlers(std::move(protocol_handlers))
@@ -201,6 +254,7 @@
       browser_context->CreateWebContentsBuilder()
           .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html"))
           .Build();
+  EXPECT_TRUE(web_contents);
   EXPECT_TRUE(WaitForLoad(web_contents));
 
   std::string inner_html;
@@ -217,7 +271,7 @@
   protocol_handlers[url::kHttpsScheme] =
       base::WrapUnique(new TestProtocolHandler(kResponseBody));
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()
           ->CreateBrowserContextBuilder()
           .SetProtocolHandlers(std::move(protocol_handlers))
@@ -229,6 +283,7 @@
       browser_context->CreateWebContentsBuilder()
           .SetInitialURL(GURL("https://not-an-actual-domain.tld/hello.html"))
           .Build();
+  EXPECT_TRUE(web_contents);
   EXPECT_TRUE(WaitForLoad(web_contents));
 
   std::string inner_html;
@@ -240,7 +295,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, WebGLSupported) {
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()->CreateBrowserContextBuilder().Build();
 
   HeadlessWebContents* web_contents =
@@ -258,7 +313,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, DefaultSizes) {
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()->CreateBrowserContextBuilder().Build();
 
   HeadlessWebContents* web_contents =
@@ -398,7 +453,7 @@
   protocol_handlers[url::kHttpsScheme] =
       base::WrapUnique(new ProtocolHandlerWithCookies(&sent_cookies));
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()
           ->CreateBrowserContextBuilder()
           .SetProtocolHandlers(std::move(protocol_handlers))
diff --git a/headless/lib/headless_browser_context_browsertest.cc b/headless/lib/headless_browser_context_browsertest.cc
index 77859f9..a6ad735 100644
--- a/headless/lib/headless_browser_context_browsertest.cc
+++ b/headless/lib/headless_browser_context_browsertest.cc
@@ -48,7 +48,8 @@
     : public HeadlessAsyncDevTooledBrowserTest {
  public:
   HeadlessBrowserContextIsolationTest()
-      : web_contents2_(nullptr),
+      : browser_context_(nullptr),
+        web_contents2_(nullptr),
         devtools_client2_(HeadlessDevToolsClient::Create()) {
     EXPECT_TRUE(embedded_test_server()->Start());
   }
@@ -142,12 +143,12 @@
   void FinishTest() {
     web_contents2_->RemoveObserver(this);
     web_contents2_->Close();
-    browser_context_.reset();
+    browser_context_->Close();
     FinishAsynchronousTest();
   }
 
  private:
-  std::unique_ptr<HeadlessBrowserContext> browser_context_;
+  HeadlessBrowserContext* browser_context_;
   HeadlessWebContents* web_contents2_;
   std::unique_ptr<HeadlessDevToolsClient> devtools_client2_;
   std::unique_ptr<LoadObserver> load_observer_;
@@ -163,7 +164,7 @@
 
   // Load a page which doesn't actually exist, but which is fetched by our
   // custom protocol handler.
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()
           ->CreateBrowserContextBuilder()
           .SetProtocolHandlers(std::move(protocol_handlers))
@@ -182,7 +183,7 @@
   EXPECT_EQ(kResponseBody, inner_html);
   web_contents->Close();
 
-  std::unique_ptr<HeadlessBrowserContext> another_browser_context =
+  HeadlessBrowserContext* another_browser_context =
       browser()->CreateBrowserContextBuilder().Build();
 
   // Loading the same non-existent page using a tab with a different context
@@ -214,7 +215,7 @@
   // Newly created temp directory should be empty.
   EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.path()));
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()
           ->CreateBrowserContextBuilder()
           .SetUserDataDir(user_data_dir.path())
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index dd20b038..9eb22d1 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -18,6 +18,23 @@
 
 namespace headless {
 
+namespace {
+
+std::vector<HeadlessWebContents*> GetAllWebContents(HeadlessBrowser* browser) {
+  std::vector<HeadlessWebContents*> result;
+
+  for (HeadlessBrowserContext* browser_context :
+       browser->GetAllBrowserContexts()) {
+    std::vector<HeadlessWebContents*> web_contents =
+        browser_context->GetAllWebContents();
+    result.insert(result.end(), web_contents.begin(), web_contents.end());
+  }
+
+  return result;
+}
+
+}  // namespace
+
 class HeadlessDevToolsClientNavigationTest
     : public HeadlessAsyncDevTooledBrowserTest,
       page::ExperimentalObserver {
@@ -179,7 +196,7 @@
   void RunDevTooledTest() override {
     EXPECT_TRUE(embedded_test_server()->Start());
 
-    EXPECT_EQ(1u, browser()->GetAllWebContents().size());
+    EXPECT_EQ(1u, GetAllWebContents(browser()).size());
 
     devtools_client_->GetBrowser()->GetExperimental()->CreateTarget(
         browser::CreateTargetParams::Builder()
@@ -193,7 +210,7 @@
 
   void OnCreateTargetResult(
       std::unique_ptr<browser::CreateTargetResult> result) {
-    EXPECT_EQ(2u, browser()->GetAllWebContents().size());
+    EXPECT_EQ(2u, GetAllWebContents(browser()).size());
 
     devtools_client_->GetBrowser()->GetExperimental()->CloseTarget(
         browser::CloseTargetParams::Builder()
@@ -205,7 +222,7 @@
 
   void OnCloseTargetResult(std::unique_ptr<browser::CloseTargetResult> result) {
     EXPECT_TRUE(result->GetSuccess());
-    EXPECT_EQ(1u, browser()->GetAllWebContents().size());
+    EXPECT_EQ(1u, GetAllWebContents(browser()).size());
     FinishAsynchronousTest();
   }
 };
@@ -217,7 +234,7 @@
   void RunDevTooledTest() override {
     EXPECT_TRUE(embedded_test_server()->Start());
 
-    EXPECT_EQ(1u, browser()->GetAllWebContents().size());
+    EXPECT_EQ(1u, GetAllWebContents(browser()).size());
 
     devtools_client_->GetBrowser()->GetExperimental()->CreateBrowserContext(
         browser::CreateBrowserContextParams::Builder().Build(),
@@ -244,7 +261,7 @@
 
   void OnCreateTargetResult(
       std::unique_ptr<browser::CreateTargetResult> result) {
-    EXPECT_EQ(2u, browser()->GetAllWebContents().size());
+    EXPECT_EQ(2u, GetAllWebContents(browser()).size());
 
     devtools_client_->GetBrowser()->GetExperimental()->CloseTarget(
         browser::CloseTargetParams::Builder()
@@ -256,7 +273,7 @@
   }
 
   void OnCloseTargetResult(std::unique_ptr<browser::CloseTargetResult> result) {
-    EXPECT_EQ(1u, browser()->GetAllWebContents().size());
+    EXPECT_EQ(1u, GetAllWebContents(browser()).size());
     EXPECT_TRUE(result->GetSuccess());
 
     devtools_client_->GetBrowser()->GetExperimental()->DisposeBrowserContext(
@@ -285,7 +302,7 @@
   void RunDevTooledTest() override {
     EXPECT_TRUE(embedded_test_server()->Start());
 
-    EXPECT_EQ(1u, browser()->GetAllWebContents().size());
+    EXPECT_EQ(1u, GetAllWebContents(browser()).size());
     devtools_client_->GetBrowser()->GetExperimental()->CreateBrowserContext(
         browser::CreateBrowserContextParams::Builder().Build(),
         base::Bind(&BrowserDomainDisposeContextFailsIfInUse::OnContextCreated,
diff --git a/headless/lib/headless_web_contents_browsertest.cc b/headless/lib/headless_web_contents_browsertest.cc
index 9ef8e4c..0fd92837 100644
--- a/headless/lib/headless_web_contents_browsertest.cc
+++ b/headless/lib/headless_web_contents_browsertest.cc
@@ -12,10 +12,13 @@
 #include "headless/public/headless_devtools_client.h"
 #include "headless/public/headless_web_contents.h"
 #include "headless/test/headless_browser_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/size.h"
 #include "url/gurl.h"
 
+using testing::UnorderedElementsAre;
+
 namespace headless {
 
 class HeadlessWebContentsTest : public HeadlessBrowserTest {};
@@ -23,7 +26,7 @@
 IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, Navigation) {
   EXPECT_TRUE(embedded_test_server()->Start());
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()->CreateBrowserContextBuilder().Build();
 
   HeadlessWebContents* web_contents =
@@ -32,17 +35,14 @@
           .Build();
   EXPECT_TRUE(WaitForLoad(web_contents));
 
-  std::vector<HeadlessWebContents*> all_web_contents =
-      browser()->GetAllWebContents();
-
-  EXPECT_EQ(static_cast<size_t>(1), all_web_contents.size());
-  EXPECT_EQ(web_contents, all_web_contents[0]);
+  EXPECT_THAT(browser_context->GetAllWebContents(),
+              UnorderedElementsAre(web_contents));
 }
 
 IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, WindowOpen) {
   EXPECT_TRUE(embedded_test_server()->Start());
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context =
+  HeadlessBrowserContext* browser_context =
       browser()->CreateBrowserContextBuilder().Build();
 
   HeadlessWebContents* web_contents =
@@ -51,10 +51,8 @@
           .Build();
   EXPECT_TRUE(WaitForLoad(web_contents));
 
-  std::vector<HeadlessWebContents*> all_web_contents =
-      browser()->GetAllWebContents();
-
-  EXPECT_EQ(static_cast<size_t>(2), all_web_contents.size());
+  EXPECT_EQ(static_cast<size_t>(2),
+            browser_context->GetAllWebContents().size());
 }
 
 class HeadlessWebContentsScreenshotTest
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h
index 7813824..ccc14369 100644
--- a/headless/public/headless_browser.h
+++ b/headless/public/headless_browser.h
@@ -38,17 +38,23 @@
 
   // Create a new browser context which can be used to create tabs and isolate
   // them from one another.
-  // User owns newly created HeadlessBrowserContext and should delete them
-  // before calling HeadlessBrowser::Shutdown().
+  // Pointer to HeadlessBrowserContext becomes invalid after:
+  // a) Calling HeadlessBrowserContext::Close or
+  // b) Calling HeadlessBrowser::Shutdown
   virtual HeadlessBrowserContext::Builder CreateBrowserContextBuilder() = 0;
 
-  virtual std::vector<HeadlessWebContents*> GetAllWebContents() = 0;
+  virtual std::vector<HeadlessBrowserContext*> GetAllBrowserContexts() = 0;
 
   // Returns the HeadlessWebContents associated with the
   // |devtools_agent_host_id| if any.  Otherwise returns null.
-  virtual HeadlessWebContents* GetWebContentsForDevtoolsAgentHostId(
+  virtual HeadlessWebContents* GetWebContentsForDevToolsAgentHostId(
       const std::string& devtools_agent_host_id) = 0;
 
+  // Returns HeadlessBrowserContext associated with the given id if any.
+  // Otherwise returns null.
+  virtual HeadlessBrowserContext* GetBrowserContextForId(
+      const std::string& id) = 0;
+
   // Returns a task runner for submitting work to the browser main thread.
   virtual scoped_refptr<base::SingleThreadTaskRunner> BrowserMainThread()
       const = 0;
@@ -59,6 +65,8 @@
 
   // Requests browser to stop as soon as possible. |Run| will return as soon as
   // browser stops.
+  // IMPORTANT: All pointers to HeadlessBrowserContexts and HeadlessWebContents
+  // become invalid after calling this function.
   virtual void Shutdown() = 0;
 
  protected:
diff --git a/headless/public/headless_browser_context.h b/headless/public/headless_browser_context.h
index 2bbfba3d..702541e 100644
--- a/headless/public/headless_browser_context.h
+++ b/headless/public/headless_browser_context.h
@@ -36,10 +36,25 @@
 
   // Open a new tab. Returns a builder object which can be used to set
   // properties for the new tab.
+  // Pointer to HeadlessWebContents becomes invalid after:
+  // a) Calling HeadlessWebContents::Close, or
+  // b) Calling HeadlessBrowserContext::Close on associated browser context, or
+  // c) Calling HeadlessBrowser::Shutdown.
   virtual HeadlessWebContents::Builder CreateWebContentsBuilder() = 0;
 
+  // Returns all web contents owned by this browser context.
   virtual std::vector<HeadlessWebContents*> GetAllWebContents() = 0;
 
+  // See HeadlessBrowser::GetWebContentsForDevToolsAgentHostId.
+  virtual HeadlessWebContents* GetWebContentsForDevToolsAgentHostId(
+      const std::string& devtools_agent_host_id) = 0;
+
+  // Destroy this BrowserContext and all WebContents associated with it.
+  virtual void Close() = 0;
+
+  // GUID for this browser context.
+  virtual const std::string& Id() const = 0;
+
   // TODO(skyostil): Allow saving and restoring contexts (crbug.com/617931).
 
  protected:
@@ -87,10 +102,11 @@
   Builder& SetWindowSize(const gfx::Size& window_size);
   Builder& SetUserDataDir(const base::FilePath& user_data_dir);
 
-  std::unique_ptr<HeadlessBrowserContext> Build();
+  HeadlessBrowserContext* Build();
 
  private:
   friend class HeadlessBrowserImpl;
+  friend class HeadlessBrowserContextImpl;
 
   explicit Builder(HeadlessBrowserImpl* browser);
 
diff --git a/headless/test/headless_browser_test.cc b/headless/test/headless_browser_test.cc
index edf9bab..b56c97da 100644
--- a/headless/test/headless_browser_test.cc
+++ b/headless/test/headless_browser_test.cc
@@ -202,7 +202,8 @@
   web_contents_->RemoveObserver(this);
   web_contents_->Close();
   web_contents_ = nullptr;
-  browser_context_.reset();
+  browser_context_->Close();
+  browser_context_ = nullptr;
 }
 
 }  // namespace headless
diff --git a/headless/test/headless_browser_test.h b/headless/test/headless_browser_test.h
index 3ed1fb18..bc868dd 100644
--- a/headless/test/headless_browser_test.h
+++ b/headless/test/headless_browser_test.h
@@ -110,7 +110,7 @@
  protected:
   void RunTest();
 
-  std::unique_ptr<HeadlessBrowserContext> browser_context_;
+  HeadlessBrowserContext* browser_context_;  // Not owned.
   HeadlessWebContents* web_contents_;
   std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
 };
diff --git a/headless/testserver.log b/headless/testserver.log
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/headless/testserver.log
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index abfb446..e554428a 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -34,7 +34,7 @@
       builders { name: "android_compile_dbg" }
       builders {
         name: "android_n5x_swarming_rel"
-        experiment_percentage: 70
+        experiment_percentage: 100
       }
       builders { name: "cast_shell_android" }
       builders { name: "linux_android_rel_ng" }
diff --git a/infra/scripts/legacy/scripts/slave/xvfb.py b/infra/scripts/legacy/scripts/slave/xvfb.py
index f5f3577..051413a 100644
--- a/infra/scripts/legacy/scripts/slave/xvfb.py
+++ b/infra/scripts/legacy/scripts/slave/xvfb.py
@@ -60,6 +60,14 @@
       print 'xdisplaycheck says there is a display still running, exiting...'
       raise Exception('Display already present.')
 
+  xvfb_lock_filename = '/tmp/.X%s-lock' % _XvfbDisplayIndex(slave_build_name)
+  if os.path.exists(xvfb_lock_filename):
+    print 'Removing stale xvfb lock file %r' % xvfb_lock_filename
+    try:
+      os.unlink(xvfb_lock_filename)
+    except OSError as e:
+      print 'Removing xvfb lock file failed: %s' % e
+
   # Figure out which X server to try.
   cmd = 'Xvfb'
   if server_dir and os.path.exists(server_dir):
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 0b99b37f..9674f2c 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -341,6 +341,8 @@
     "reading_list/reading_list_model_storage.h",
     "reading_list/reading_list_model_storage_defaults.h",
     "reading_list/reading_list_model_storage_defaults.mm",
+    "reading_list/url_downloader.cc",
+    "reading_list/url_downloader.h",
     "root_coordinator.h",
     "root_coordinator.mm",
     "search/search_util.h",
diff --git a/ios/chrome/browser/autofill/personal_data_manager_factory.h b/ios/chrome/browser/autofill/personal_data_manager_factory.h
index ec988e5..75ab40a 100644
--- a/ios/chrome/browser/autofill/personal_data_manager_factory.h
+++ b/ios/chrome/browser/autofill/personal_data_manager_factory.h
@@ -46,8 +46,4 @@
 
 }  // namespace autofill
 
-// TODO(crbug.com/513344): Remove this typedef once downstream code has
-// been fixed to use the fully namespaced name.
-using PersonalDataManagerFactory = autofill::PersonalDataManagerFactory;
-
 #endif  // IOS_CHROME_BROWSER_AUTOFILL_PERSONAL_DATA_MANAGER_FACTORY_H_
diff --git a/ios/chrome/browser/net/retryable_url_fetcher.h b/ios/chrome/browser/net/retryable_url_fetcher.h
index cd153980..a26b29c7 100644
--- a/ios/chrome/browser/net/retryable_url_fetcher.h
+++ b/ios/chrome/browser/net/retryable_url_fetcher.h
@@ -20,7 +20,8 @@
 - (NSString*)urlToFetch;
 
 // Callback function after URL has been fetched. |response| is the content of
-// the HTTP response. |response| may be nil if the HTTP request failed.
+// the HTTP response. This method may be called with a nil |response| if the
+// HTTP request failed.
 - (void)processSuccessResponse:(NSString*)response;
 
 @end
diff --git a/ios/chrome/browser/net/retryable_url_fetcher.mm b/ios/chrome/browser/net/retryable_url_fetcher.mm
index 87aca533..10c7e99 100644
--- a/ios/chrome/browser/net/retryable_url_fetcher.mm
+++ b/ios/chrome/browser/net/retryable_url_fetcher.mm
@@ -63,6 +63,10 @@
                                        fetcherDelegate_.get());
     fetcher_->SetRequestContext(requestContextGetter_.get());
     fetcher_->Start();
+  } else {
+    // Invalid URLs returned from delegate method are considered a permanent
+    // failure. Delegate method is called with nil to indicate failure.
+    [delegate_ processSuccessResponse:nil];
   }
 }
 
diff --git a/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm b/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm
index 8cdaa7dc..43593dc1 100644
--- a/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm
+++ b/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm
@@ -42,6 +42,24 @@
 
 @end
 
+@interface TestFailingURLFetcherDelegate : NSObject<RetryableURLFetcherDelegate>
+@property(nonatomic, assign) BOOL responsesProcessed;
+@end
+
+@implementation TestFailingURLFetcherDelegate
+@synthesize responsesProcessed;
+
+- (NSString*)urlToFetch {
+  return nil;
+}
+
+- (void)processSuccessResponse:(NSString*)response {
+  EXPECT_FALSE(response);
+  responsesProcessed = YES;
+}
+
+@end
+
 namespace {
 
 class RetryableURLFetcherTest : public PlatformTest {
@@ -101,4 +119,27 @@
   EXPECT_EQ(0U, [test_delegate_ responsesProcessed]);
 }
 
+// Tests that response callback method is called if delegate returns an
+// invalid URL.
+TEST_F(RetryableURLFetcherTest, TestFailingURLNoRetry) {
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter =
+      new net::TestURLRequestContextGetter(message_loop_.task_runner());
+  base::scoped_nsobject<TestFailingURLFetcherDelegate> failing_delegate(
+      [[TestFailingURLFetcherDelegate alloc] init]);
+  base::scoped_nsobject<RetryableURLFetcher> retryable_fetcher(
+      [[RetryableURLFetcher alloc]
+          initWithRequestContextGetter:request_context_getter.get()
+                              delegate:failing_delegate.get()
+                         backoffPolicy:nil]);
+  [retryable_fetcher startFetch];
+
+  // |failing_delegate| does not have URL to fetch, so a fetcher should never
+  // be created.
+  net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+  EXPECT_FALSE(fetcher);
+
+  // Verify that response has been called.
+  EXPECT_TRUE([failing_delegate responsesProcessed]);
+}
+
 }  // namespace
diff --git a/ios/chrome/browser/reading_list/url_downloader.cc b/ios/chrome/browser/reading_list/url_downloader.cc
new file mode 100644
index 0000000..2a777a5
--- /dev/null
+++ b/ios/chrome/browser/reading_list/url_downloader.cc
@@ -0,0 +1,201 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/reading_list/url_downloader.h"
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/md5.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "ios/chrome/browser/chrome_paths.h"
+#include "ios/chrome/browser/dom_distiller/distiller_viewer.h"
+#include "ios/web/public/web_thread.h"
+#include "url/gurl.h"
+
+namespace {
+char const kOfflineDirectory[] = "Offline";
+
+// TODO(crbug.com/629771): Handle errors & retrying of failed saves, including
+// distillation failure.
+
+}  // namespace
+
+// URLDownloader
+
+URLDownloader::URLDownloader(
+    dom_distiller::DomDistillerService* distiller_service,
+    PrefService* prefs,
+    base::FilePath chrome_profile_path,
+    const SuccessCompletion& download_completion,
+    const SuccessCompletion& delete_completion)
+    : distiller_service_(distiller_service),
+      pref_service_(prefs),
+      download_completion_(download_completion),
+      delete_completion_(delete_completion),
+      working_(false),
+      base_directory_(chrome_profile_path),
+      task_tracker_() {}
+
+URLDownloader::~URLDownloader() {
+  task_tracker_.TryCancelAll();
+}
+
+void URLDownloader::OfflineURLExists(const GURL& url,
+                                     base::Callback<void(bool)> callback) {
+  task_tracker_.PostTaskAndReplyWithResult(
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(),
+      FROM_HERE, base::Bind(&base::PathExists, OfflineURLPagePath(url)),
+      callback);
+}
+
+void URLDownloader::RemoveOfflineURL(const GURL& url) {
+  // Remove all download tasks for this url as it would be pointless work.
+  std::remove(tasks_.begin(), tasks_.end(), std::make_pair(DOWNLOAD, url));
+  tasks_.push_back(std::make_pair(DELETE, url));
+  HandleNextTask();
+}
+
+void URLDownloader::DownloadOfflineURL(const GURL& url) {
+  if (std::find(tasks_.begin(), tasks_.end(), std::make_pair(DOWNLOAD, url)) ==
+      tasks_.end()) {
+    tasks_.push_back(std::make_pair(DOWNLOAD, url));
+    HandleNextTask();
+  }
+}
+
+void URLDownloader::DownloadCompletionHandler(const GURL& url, bool success) {
+  DCHECK(working_);
+  download_completion_.Run(url, success);
+  distiller_.reset();
+  working_ = false;
+  HandleNextTask();
+}
+
+void URLDownloader::DeleteCompletionHandler(const GURL& url, bool success) {
+  DCHECK(working_);
+  delete_completion_.Run(url, success);
+  working_ = false;
+  HandleNextTask();
+}
+
+void URLDownloader::HandleNextTask() {
+  if (working_ || tasks_.empty()) {
+    return;
+  }
+  working_ = true;
+
+  Task task = tasks_.front();
+  tasks_.pop_front();
+  GURL url = task.second;
+
+  if (task.first == DELETE) {
+    task_tracker_.PostTaskAndReplyWithResult(
+        web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(),
+        FROM_HERE,
+        base::Bind(&base::DeleteFile, OfflineURLDirectoryPath(url), true),
+        base::Bind(&URLDownloader::DeleteCompletionHandler,
+                   base::Unretained(this), url));
+  } else if (task.first == DOWNLOAD) {
+    DCHECK(!distiller_);
+    OfflineURLExists(url, base::Bind(&URLDownloader::DownloadURL,
+                                     base::Unretained(this), url));
+  }
+}
+
+void URLDownloader::DownloadURL(GURL url, bool offlineURLExists) {
+  if (offlineURLExists) {
+    DownloadCompletionHandler(url, false);
+    return;
+  }
+  distiller_.reset(new dom_distiller::DistillerViewer(
+      distiller_service_, pref_service_, url,
+      base::Bind(&URLDownloader::DistillerCallback, base::Unretained(this))));
+}
+
+void URLDownloader::DistillerCallback(
+    const GURL& pageURL,
+    const std::string& html,
+    const std::vector<dom_distiller::DistillerViewer::ImageInfo>& images) {
+  std::vector<dom_distiller::DistillerViewer::ImageInfo> imagesBlock = images;
+  std::string blockHTML = html;
+  task_tracker_.PostTaskAndReplyWithResult(
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(),
+      FROM_HERE,
+      base::Bind(&URLDownloader::SaveDistilledHTML, base::Unretained(this),
+                 pageURL, imagesBlock, blockHTML),
+      base::Bind(&URLDownloader::DownloadCompletionHandler,
+                 base::Unretained(this), pageURL));
+}
+
+bool URLDownloader::SaveDistilledHTML(
+    const GURL& url,
+    std::vector<dom_distiller::DistillerViewer::ImageInfo> images,
+    std::string html) {
+  if (CreateOfflineURLDirectory(url)) {
+    return SaveHTMLForURL(SaveAndReplaceImagesInHTML(url, html, images), url);
+  }
+  return false;
+}
+
+base::FilePath URLDownloader::OfflineDirectoryPath() {
+  return base_directory_.Append(kOfflineDirectory);
+}
+
+base::FilePath URLDownloader::OfflineURLDirectoryPath(const GURL& url) {
+  std::string hash = base::MD5String(url.spec());
+  return OfflineDirectoryPath().Append(hash);
+}
+
+base::FilePath URLDownloader::OfflineURLPagePath(const GURL& url) {
+  return OfflineURLDirectoryPath(url).Append("page.html");
+}
+
+bool URLDownloader::CreateOfflineURLDirectory(const GURL& url) {
+  base::FilePath path = OfflineURLDirectoryPath(url);
+  if (!DirectoryExists(path)) {
+    return CreateDirectoryAndGetError(path, nil);
+  }
+  return true;
+}
+
+std::string URLDownloader::SaveImage(const GURL& url,
+                                     const GURL& imageURL,
+                                     const std::string& data) {
+  base::FilePath path =
+      OfflineURLDirectoryPath(url).Append(base::MD5String(imageURL.spec()));
+  if (!base::PathExists(path)) {
+    base::WriteFile(path, data.c_str(), data.length());
+  }
+  return path.AsUTF8Unsafe();
+}
+
+// TODO(crbug.com/625621) DomDistiller doesn't correctly handle srcset
+// attributes in img tags.
+std::string URLDownloader::SaveAndReplaceImagesInHTML(
+    const GURL& url,
+    const std::string& html,
+    const std::vector<dom_distiller::DistillerViewer::ImageInfo>& images) {
+  std::string mutableHTML = html;
+  for (size_t i = 0; i < images.size(); i++) {
+    const std::string& localImagePath =
+        SaveImage(url, images[i].url, images[i].data);
+    const std::string& imageURL = images[i].url.spec();
+    size_t imageURLSize = imageURL.size();
+    size_t pos = mutableHTML.find(imageURL, 0);
+    while (pos != std::string::npos) {
+      mutableHTML.replace(pos, imageURLSize, localImagePath);
+      pos = mutableHTML.find(imageURL, pos + imageURLSize);
+    }
+  }
+  return mutableHTML;
+}
+
+bool URLDownloader::SaveHTMLForURL(std::string html, const GURL& url) {
+  base::FilePath path = OfflineURLPagePath(url);
+  return base::WriteFile(path, html.c_str(), html.length()) < 0;
+}
\ No newline at end of file
diff --git a/ios/chrome/browser/reading_list/url_downloader.h b/ios/chrome/browser/reading_list/url_downloader.h
new file mode 100644
index 0000000..cdba38ee
--- /dev/null
+++ b/ios/chrome/browser/reading_list/url_downloader.h
@@ -0,0 +1,114 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_READING_LIST_URL_DOWNLOADER_H_
+#define IOS_CHROME_BROWSER_READING_LIST_URL_DOWNLOADER_H_
+
+#include <queue>
+
+#include "base/callback.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "ios/chrome/browser/dom_distiller/distiller_viewer.h"
+
+class PrefService;
+class GURL;
+namespace base {
+class FilePath;
+}
+
+namespace dom_distiller {
+class DomDistillerService;
+}
+
+// This class downloads and deletes offline versions of URLs using DOM distiller
+// to fetch the page and simplify it. Only one item is downloaded or deleted at
+// a time using a queue of tasks that are handled sequentially. Items (page +
+// images) are saved to individual folders within an offline folder, using md5
+// hashing to create unique file names. When a deletion is requested, all
+// previous downloads for that URL are cancelled as they would be deleted.
+class URLDownloader {
+ public:
+  // A completion callback that takes a GURL and a bool indicating
+  // success and returns void.
+  using SuccessCompletion = base::Callback<void(const GURL&, bool)>;
+
+  // Create a URL downloader with completion callbacks for downloads and
+  // deletions.
+  URLDownloader(dom_distiller::DomDistillerService* distiller_service,
+                PrefService* prefs,
+                base::FilePath chrome_profile_path,
+                const SuccessCompletion& download_completion,
+                const SuccessCompletion& delete_completion);
+  virtual ~URLDownloader();
+
+  // Asynchronously download an offline version of the URL.
+  void DownloadOfflineURL(const GURL& url);
+
+  // Asynchronously remove the offline version of the URL if it exists.
+  void RemoveOfflineURL(const GURL& url);
+
+ private:
+  enum TaskType { DELETE, DOWNLOAD };
+  using Task = std::pair<TaskType, GURL>;
+
+  // Calls callback with true if an offline file exists for this URL.
+  void OfflineURLExists(const GURL& url, base::Callback<void(bool)> callback);
+  // Handles the next task in the queue, if no task is currently being handled.
+  void HandleNextTask();
+  // Callback for completed (or failed) download, handles calling
+  // downloadCompletion and starting the next task.
+  void DownloadCompletionHandler(const GURL& url, bool success);
+  // Callback for completed (or failed) deletion, handles calling
+  // deleteCompletion and starting the next task.
+  void DeleteCompletionHandler(const GURL& url, bool success);
+  // The path of the directory where offline URLs are saved.
+  base::FilePath OfflineDirectoryPath();
+  // The path of the directory where a specific URL is saved offline. Contains
+  // the page and supporting files (images).
+  base::FilePath OfflineURLDirectoryPath(const GURL& url);
+  // The path of the offline webpage for the URL. The file may not exist.
+  base::FilePath OfflineURLPagePath(const GURL& url);
+  // Creates the offline directory for |url|. Returns true if successful or if
+  // the directory already exists.
+  bool CreateOfflineURLDirectory(const GURL& url);
+  // Saves the |data| for image at |imageURL| to disk, for main URL |url|;
+  // returns path of saved file.
+  std::string SaveImage(const GURL& url,
+                        const GURL& imageURL,
+                        const std::string& data);
+  // Saves images in |images| array to disk and replaces references in |html| to
+  // local path. Returns updated html.
+  std::string SaveAndReplaceImagesInHTML(
+      const GURL& url,
+      const std::string& html,
+      const std::vector<dom_distiller::DistillerViewer::ImageInfo>& images);
+  // Saves |html| to disk in the correct location for |url|; returns success.
+  bool SaveHTMLForURL(std::string html, const GURL& url);
+  // Downloads |url|, depending on |offlineURLExists| state.
+  void DownloadURL(GURL url, bool offlineURLExists);
+  // Saves distilled html to disk, including saving images and main file.
+  bool SaveDistilledHTML(
+      const GURL& url,
+      std::vector<dom_distiller::DistillerViewer::ImageInfo> images,
+      std::string html);
+  // Callback for distillation completion.
+  void DistillerCallback(
+      const GURL& pageURL,
+      const std::string& html,
+      const std::vector<dom_distiller::DistillerViewer::ImageInfo>& images);
+
+  dom_distiller::DomDistillerService* distiller_service_;
+  PrefService* pref_service_;
+  const SuccessCompletion download_completion_;
+  const SuccessCompletion delete_completion_;
+  std::deque<Task> tasks_;
+  bool working_;
+  base::FilePath base_directory_;
+  std::unique_ptr<dom_distiller::DistillerViewer> distiller_;
+  base::CancelableTaskTracker task_tracker_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLDownloader);
+};
+
+#endif  // IOS_CHROME_BROWSER_READING_LIST_URL_DOWNLOADER_H_
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc
index b29077b..e22f414 100644
--- a/media/audio/android/audio_manager_android.cc
+++ b/media/audio/android/audio_manager_android.cc
@@ -27,6 +27,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace media {
diff --git a/media/audio/android/audio_record_input.cc b/media/audio/android/audio_record_input.cc
index 90102ffac..2f69be36 100644
--- a/media/audio/android/audio_record_input.cc
+++ b/media/audio/android/audio_record_input.cc
@@ -9,6 +9,8 @@
 #include "media/audio/android/audio_manager_android.h"
 #include "media/base/audio_bus.h"
 
+using base::android::JavaParamRef;
+
 namespace media {
 
 AudioRecordInputStream::AudioRecordInputStream(
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index 5c714596..a7e7469 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -36,6 +36,7 @@
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::JavaByteArrayToByteVector;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index b04a13d..225d103 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -20,6 +20,7 @@
 #include "media/base/timestamp_constants.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace media {
diff --git a/media/base/android/media_player_listener.cc b/media/base/android/media_player_listener.cc
index 850e02ea..95dd0c533 100644
--- a/media/base/android/media_player_listener.cc
+++ b/media/base/android/media_player_listener.cc
@@ -14,6 +14,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::CheckException;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace media {
diff --git a/media/capture/content/android/screen_capture_machine_android.cc b/media/capture/content/android/screen_capture_machine_android.cc
index 204cb55a..df57fa2 100644
--- a/media/capture/content/android/screen_capture_machine_android.cc
+++ b/media/capture/content/android/screen_capture_machine_android.cc
@@ -12,6 +12,7 @@
 #include "third_party/libyuv/include/libyuv.h"
 
 using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
 
 namespace media {
 
diff --git a/media/capture/video/android/video_capture_device_android.cc b/media/capture/video/android/video_capture_device_android.cc
index 3d0774c2..a0596b50 100644
--- a/media/capture/video/android/video_capture_device_android.cc
+++ b/media/capture/video/android/video_capture_device_android.cc
@@ -20,6 +20,7 @@
 using base::android::AttachCurrentThread;
 using base::android::CheckException;
 using base::android::GetClass;
+using base::android::JavaParamRef;
 using base::android::MethodID;
 using base::android::JavaRef;
 using base::android::ScopedJavaLocalRef;
diff --git a/media/midi/midi_device_android.cc b/media/midi/midi_device_android.cc
index 860127c..8b7963b 100644
--- a/media/midi/midi_device_android.cc
+++ b/media/midi/midi_device_android.cc
@@ -9,6 +9,8 @@
 #include "jni/MidiDeviceAndroid_jni.h"
 #include "media/midi/midi_output_port_android.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace media {
 namespace midi {
 
diff --git a/media/midi/midi_input_port_android.cc b/media/midi/midi_input_port_android.cc
index 82adffe7..3389c024 100644
--- a/media/midi/midi_input_port_android.cc
+++ b/media/midi/midi_input_port_android.cc
@@ -8,6 +8,8 @@
 #include "base/time/time.h"
 #include "jni/MidiInputPortAndroid_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace media {
 namespace midi {
 
diff --git a/media/midi/midi_manager_android.cc b/media/midi/midi_manager_android.cc
index 617daeb..d59fa77 100644
--- a/media/midi/midi_manager_android.cc
+++ b/media/midi/midi_manager_android.cc
@@ -16,6 +16,8 @@
 #include "media/midi/midi_switches.h"
 #include "media/midi/usb_midi_device_factory_android.h"
 
+using base::android::JavaParamRef;
+
 namespace media {
 namespace midi {
 
diff --git a/media/midi/midi_output_port_android.cc b/media/midi/midi_output_port_android.cc
index 7fa1cefbd..5a45ce40 100644
--- a/media/midi/midi_output_port_android.cc
+++ b/media/midi/midi_output_port_android.cc
@@ -7,6 +7,8 @@
 #include "base/android/jni_array.h"
 #include "jni/MidiOutputPortAndroid_jni.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace media {
 namespace midi {
 
diff --git a/media/midi/usb_midi_device_android.cc b/media/midi/usb_midi_device_android.cc
index bbdb6c3..b9003d3 100644
--- a/media/midi/usb_midi_device_android.cc
+++ b/media/midi/usb_midi_device_android.cc
@@ -13,6 +13,9 @@
 #include "jni/UsbMidiDeviceAndroid_jni.h"
 #include "media/midi/usb_midi_descriptor_parser.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace media {
 namespace midi {
 
diff --git a/media/midi/usb_midi_device_factory_android.cc b/media/midi/usb_midi_device_factory_android.cc
index 24c99db..80fc4276 100644
--- a/media/midi/usb_midi_device_factory_android.cc
+++ b/media/midi/usb_midi_device_factory_android.cc
@@ -16,6 +16,8 @@
 #include "jni/UsbMidiDeviceFactoryAndroid_jni.h"
 #include "media/midi/usb_midi_device_android.h"
 
+using base::android::JavaParamRef;
+
 namespace media {
 namespace midi {
 
diff --git a/mojo/android/javatests/mojo_test_case.cc b/mojo/android/javatests/mojo_test_case.cc
index 6d88985..d8c94f8 100644
--- a/mojo/android/javatests/mojo_test_case.cc
+++ b/mojo/android/javatests/mojo_test_case.cc
@@ -18,6 +18,8 @@
 #include "jni/MojoTestCase_jni.h"
 #include "mojo/message_pump/message_pump_mojo.h"
 
+using base::android::JavaParamRef;
+
 namespace {
 
 struct TestEnvironment {
diff --git a/mojo/android/javatests/validation_test_util.cc b/mojo/android/javatests/validation_test_util.cc
index fb4d140..69ad15c5 100644
--- a/mojo/android/javatests/validation_test_util.cc
+++ b/mojo/android/javatests/validation_test_util.cc
@@ -14,6 +14,9 @@
 #include "jni/ValidationTestUtil_jni.h"
 #include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace mojo {
 namespace android {
 
diff --git a/mojo/android/system/base_run_loop.cc b/mojo/android/system/base_run_loop.cc
index e48d2f0..b2276dde 100644
--- a/mojo/android/system/base_run_loop.cc
+++ b/mojo/android/system/base_run_loop.cc
@@ -14,6 +14,8 @@
 #include "jni/BaseRunLoop_jni.h"
 #include "mojo/message_pump/message_pump_mojo.h"
 
+using base::android::JavaParamRef;
+
 namespace mojo {
 namespace android {
 
diff --git a/mojo/android/system/core_impl.cc b/mojo/android/system/core_impl.cc
index 526c0503..1d884fe 100644
--- a/mojo/android/system/core_impl.cc
+++ b/mojo/android/system/core_impl.cc
@@ -22,6 +22,9 @@
 #include "mojo/message_pump/handle_watcher.h"
 #include "mojo/public/c/system/core.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace {
 
 using MojoAsyncWaitID = uintptr_t;
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index e97a4f7..3ab0bd73 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -7,6 +7,7 @@
   "//chrome/browser/media/router/mojo/typemaps.gni",
   "//components/arc/common/typemaps.gni",
   "//components/typemaps.gni",
+  "//content/common/bluetooth/typemaps.gni",
   "//device/bluetooth/public/interfaces/typemaps.gni",
   "//gpu/ipc/common/typemaps.gni",
   "//media/mojo/interfaces/typemaps.gni",
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 1cec182..423bbed3 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1202,6 +1202,8 @@
     "tools/quic/quic_process_packet_interface.h",
     "tools/quic/quic_simple_client.cc",
     "tools/quic/quic_simple_client.h",
+    "tools/quic/quic_simple_dispatcher.cc",
+    "tools/quic/quic_simple_dispatcher.h",
     "tools/quic/quic_simple_per_connection_packet_writer.cc",
     "tools/quic/quic_simple_per_connection_packet_writer.h",
     "tools/quic/quic_simple_server.cc",
diff --git a/net/android/cert_verify_result_android.cc b/net/android/cert_verify_result_android.cc
index 2b020c6..327a1e0 100644
--- a/net/android/cert_verify_result_android.cc
+++ b/net/android/cert_verify_result_android.cc
@@ -10,6 +10,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::JavaArrayOfByteArrayToStringVector;
+using base::android::ScopedJavaLocalRef;
 
 namespace net {
 namespace android {
diff --git a/net/android/dummy_spnego_authenticator.cc b/net/android/dummy_spnego_authenticator.cc
index 5614c33..934d098 100644
--- a/net/android/dummy_spnego_authenticator.cc
+++ b/net/android/dummy_spnego_authenticator.cc
@@ -8,6 +8,8 @@
 #include "net/test/jni/DummySpnegoAuthenticator_jni.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::android::JavaParamRef;
+
 namespace net {
 
 // iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2)
diff --git a/net/android/gurl_utils.cc b/net/android/gurl_utils.cc
index 5b2ff3f..826b1b8 100644
--- a/net/android/gurl_utils.cc
+++ b/net/android/gurl_utils.cc
@@ -8,6 +8,9 @@
 #include "jni/GURLUtils_jni.h"
 #include "url/gurl.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace net {
 
 ScopedJavaLocalRef<jstring> GetOrigin(JNIEnv* env,
diff --git a/net/android/http_auth_negotiate_android.cc b/net/android/http_auth_negotiate_android.cc
index 7586246..fa6f19b25 100644
--- a/net/android/http_auth_negotiate_android.cc
+++ b/net/android/http_auth_negotiate_android.cc
@@ -20,6 +20,7 @@
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace net {
diff --git a/net/android/network_change_notifier_delegate_android.cc b/net/android/network_change_notifier_delegate_android.cc
index d3da5ed0..0627d51 100644
--- a/net/android/network_change_notifier_delegate_android.cc
+++ b/net/android/network_change_notifier_delegate_android.cc
@@ -10,6 +10,9 @@
 #include "jni/NetworkChangeNotifier_jni.h"
 #include "net/android/network_change_notifier_android.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace net {
 
 namespace {
diff --git a/net/cert/cert_verify_proc_ios.cc b/net/cert/cert_verify_proc_ios.cc
index 017d84b..05276b3 100644
--- a/net/cert/cert_verify_proc_ios.cc
+++ b/net/cert/cert_verify_proc_ios.cc
@@ -278,7 +278,7 @@
       verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
       break;
     default:
-      CFArrayRef properties = SecTrustCopyProperties(trust_ref);
+      ScopedCFTypeRef<CFArrayRef> properties(SecTrustCopyProperties(trust_ref));
       verify_result->cert_status |= GetFailureFromTrustProperties(properties);
   }
 
diff --git a/net/cert/x509_util_android.cc b/net/cert/x509_util_android.cc
index ee47845f..b2219b1a 100644
--- a/net/cert/x509_util_android.cc
+++ b/net/cert/x509_util_android.cc
@@ -10,6 +10,8 @@
 #include "jni/X509Util_jni.h"
 #include "net/cert/cert_database.h"
 
+using base::android::JavaParamRef;
+
 namespace net {
 
 void NotifyKeyChainChanged(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
diff --git a/net/net.gyp b/net/net.gyp
index abede0f..e630835 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -840,6 +840,8 @@
         'tools/quic/quic_process_packet_interface.h',
         'tools/quic/quic_simple_client.cc',
         'tools/quic/quic_simple_client.h',
+        'tools/quic/quic_simple_dispatcher.cc',
+        'tools/quic/quic_simple_dispatcher.h',
         'tools/quic/quic_simple_per_connection_packet_writer.cc',
         'tools/quic/quic_simple_per_connection_packet_writer.h',
         'tools/quic/quic_simple_server.cc',
diff --git a/net/proxy/proxy_config_service_android.cc b/net/proxy/proxy_config_service_android.cc
index 990b614f..44f41fe 100644
--- a/net/proxy/proxy_config_service_android.cc
+++ b/net/proxy/proxy_config_service_android.cc
@@ -31,7 +31,9 @@
 using base::android::ConvertJavaStringToUTF8;
 using base::android::CheckException;
 using base::android::ClearException;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace net {
 
diff --git a/net/quic/chromium/crypto/proof_source_chromium.cc b/net/quic/chromium/crypto/proof_source_chromium.cc
index a1bae824..44b5e825 100644
--- a/net/quic/chromium/crypto/proof_source_chromium.cc
+++ b/net/quic/chromium/crypto/proof_source_chromium.cc
@@ -84,7 +84,6 @@
                                    const string& server_config,
                                    QuicVersion quic_version,
                                    base::StringPiece chlo_hash,
-                                   bool ecdsa_ok,
                                    scoped_refptr<ProofSource::Chain>* out_chain,
                                    string* out_signature,
                                    string* out_leaf_cert_sct) {
@@ -156,16 +155,14 @@
                                    const std::string& server_config,
                                    QuicVersion quic_version,
                                    base::StringPiece chlo_hash,
-                                   bool ecdsa_ok,
                                    std::unique_ptr<Callback> callback) {
   // As a transitional implementation, just call the synchronous version of
   // GetProof, then invoke the callback with the results and destroy it.
   scoped_refptr<ProofSource::Chain> chain;
   string signature;
   string leaf_cert_sct;
-  const bool ok =
-      GetProof(server_ip, hostname, server_config, quic_version, chlo_hash,
-               ecdsa_ok, &chain, &signature, &leaf_cert_sct);
+  const bool ok = GetProof(server_ip, hostname, server_config, quic_version,
+                           chlo_hash, &chain, &signature, &leaf_cert_sct);
   callback->Run(ok, chain, signature, leaf_cert_sct, nullptr /* details */);
 }
 
diff --git a/net/quic/chromium/crypto/proof_source_chromium.h b/net/quic/chromium/crypto/proof_source_chromium.h
index e2a989c..2610258c 100644
--- a/net/quic/chromium/crypto/proof_source_chromium.h
+++ b/net/quic/chromium/crypto/proof_source_chromium.h
@@ -38,7 +38,6 @@
                 const std::string& server_config,
                 QuicVersion quic_version,
                 base::StringPiece chlo_hash,
-                bool ecdsa_ok,
                 scoped_refptr<ProofSource::Chain>* out_chain,
                 std::string* out_signature,
                 std::string* out_leaf_cert_sct) override;
@@ -48,7 +47,6 @@
                 const std::string& server_config,
                 QuicVersion quic_version,
                 base::StringPiece chlo_hash,
-                bool ecdsa_ok,
                 std::unique_ptr<Callback> callback) override;
 
  private:
diff --git a/net/quic/core/congestion_control/pacing_sender.cc b/net/quic/core/congestion_control/pacing_sender.cc
index 242cf2c..1d63947 100644
--- a/net/quic/core/congestion_control/pacing_sender.cc
+++ b/net/quic/core/congestion_control/pacing_sender.cc
@@ -9,20 +9,32 @@
 using std::min;
 
 namespace net {
+namespace {
 
-PacingSender::PacingSender(SendAlgorithmInterface* sender,
-                           QuicTime::Delta alarm_granularity,
-                           uint32_t initial_packet_burst)
-    : sender_(sender),
-      alarm_granularity_(alarm_granularity),
-      initial_packet_burst_(initial_packet_burst),
+// The estimated system alarm granularity.
+static const QuicTime::Delta kAlarmGranularity =
+    QuicTime::Delta::FromMilliseconds(1);
+
+// Configured maximum size of the burst coming out of quiescence.  The burst
+// is never larger than the current CWND in packets.
+static const uint32_t kInitialUnpacedBurst = 10;
+
+}  // namespace
+
+PacingSender::PacingSender()
+    : sender_(nullptr),
       max_pacing_rate_(QuicBandwidth::Zero()),
-      burst_tokens_(initial_packet_burst),
+      burst_tokens_(kInitialUnpacedBurst),
       last_delayed_packet_sent_time_(QuicTime::Zero()),
       ideal_next_packet_send_time_(QuicTime::Zero()),
-      was_last_send_delayed_(false) {}
+      was_last_send_delayed_(false),
+      owns_sender_(false) {}
 
-PacingSender::~PacingSender() {}
+PacingSender::~PacingSender() {
+  if (owns_sender_) {
+    delete sender_;
+  }
+}
 
 void PacingSender::SetFromConfig(const QuicConfig& config,
                                  Perspective perspective) {
@@ -44,6 +56,14 @@
   max_pacing_rate_ = max_pacing_rate;
 }
 
+void PacingSender::SetSender(SendAlgorithmInterface* sender, bool owns_sender) {
+  if (owns_sender_) {
+    delete sender_;
+  }
+  sender_ = sender;
+  owns_sender_ = owns_sender;
+}
+
 void PacingSender::OnCongestionEvent(bool rtt_updated,
                                      QuicByteCount bytes_in_flight,
                                      const CongestionVector& acked_packets,
@@ -74,7 +94,7 @@
     // limit it to the equivalent of a single bulk write, not exceeding the
     // current CWND in packets.
     burst_tokens_ = min(
-        initial_packet_burst_,
+        kInitialUnpacedBurst,
         static_cast<uint32_t>(sender_->GetCongestionWindow() / kDefaultTCPMSS));
   }
   if (burst_tokens_ > 0) {
@@ -140,7 +160,7 @@
   }
 
   // If the next send time is within the alarm granularity, send immediately.
-  if (ideal_next_packet_send_time_ > now + alarm_granularity_) {
+  if (ideal_next_packet_send_time_ > now + kAlarmGranularity) {
     DVLOG(1) << "Delaying packet: "
              << (ideal_next_packet_send_time_ - now).ToMicroseconds();
     was_last_send_delayed_ = true;
diff --git a/net/quic/core/congestion_control/pacing_sender.h b/net/quic/core/congestion_control/pacing_sender.h
index c53f2973..6b44967 100644
--- a/net/quic/core/congestion_control/pacing_sender.h
+++ b/net/quic/core/congestion_control/pacing_sender.h
@@ -27,16 +27,13 @@
 
 class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface {
  public:
-  // Create a PacingSender to wrap the specified sender.  |alarm_granularity|
-  // indicates to the pacer to send that far into the future, since it should
-  // not expect a callback before that time delta.  |initial_packet_burst| is
-  // the number of packets sent without pacing after quiescence.
-  PacingSender(SendAlgorithmInterface* sender,
-               QuicTime::Delta alarm_granularity,
-               uint32_t initial_packet_burst);
+  PacingSender();
   ~PacingSender() override;
 
   void SetMaxPacingRate(QuicBandwidth max_pacing_rate);
+  // Sets the underlying sender. Takes ownership of |sender| if |owns_sender| is
+  // true.
+  void SetSender(SendAlgorithmInterface* sender, bool owns_sender);
 
   // SendAlgorithmInterface methods.
   void SetFromConfig(const QuicConfig& config,
@@ -69,12 +66,8 @@
   // End implementation of SendAlgorithmInterface.
 
  private:
-  std::unique_ptr<SendAlgorithmInterface> sender_;  // Underlying sender.
-  // The estimated system alarm granularity.
-  const QuicTime::Delta alarm_granularity_;
-  // Configured maximum size of the burst coming out of quiescence.  The burst
-  // is never larger than the current CWND in packets.
-  const uint32_t initial_packet_burst_;
+  // Underlying sender. Owned if |owns_sender_| is true.
+  SendAlgorithmInterface* sender_;
   // If not QuicBandidth::Zero, the maximum rate the PacingSender will use.
   QuicBandwidth max_pacing_rate_;
 
@@ -84,6 +77,7 @@
   QuicTime last_delayed_packet_sent_time_;
   QuicTime ideal_next_packet_send_time_;  // When can the next packet be sent.
   mutable bool was_last_send_delayed_;  // True when the last send was delayed.
+  bool owns_sender_;                    // True if PacingSender owns |sender_|.
 
   DISALLOW_COPY_AND_ASSIGN(PacingSender);
 };
diff --git a/net/quic/core/congestion_control/pacing_sender_test.cc b/net/quic/core/congestion_control/pacing_sender_test.cc
index 046c157..cefcdae 100644
--- a/net/quic/core/congestion_control/pacing_sender_test.cc
+++ b/net/quic/core/congestion_control/pacing_sender_test.cc
@@ -29,9 +29,8 @@
         infinite_time_(QuicTime::Delta::Infinite()),
         packet_number_(1),
         mock_sender_(new StrictMock<MockSendAlgorithm>()),
-        pacing_sender_(new PacingSender(mock_sender_,
-                                        QuicTime::Delta::FromMilliseconds(1),
-                                        0)) {
+        pacing_sender_(new PacingSender) {
+    pacing_sender_->SetSender(mock_sender_, true);
     // Pick arbitrary time.
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(9));
   }
@@ -39,11 +38,19 @@
   ~PacingSenderTest() override {}
 
   void InitPacingRate(QuicPacketCount burst_size, QuicBandwidth bandwidth) {
-    pacing_sender_.reset();
     mock_sender_ = new StrictMock<MockSendAlgorithm>();
-    pacing_sender_.reset(new PacingSender(
-        mock_sender_, QuicTime::Delta::FromMilliseconds(1), burst_size));
+    pacing_sender_.reset(new PacingSender);
+    pacing_sender_->SetSender(mock_sender_, true);
     EXPECT_CALL(*mock_sender_, PacingRate(_)).WillRepeatedly(Return(bandwidth));
+    if (burst_size == 0) {
+      EXPECT_CALL(*mock_sender_, OnCongestionEvent(_, _, _, _));
+      SendAlgorithmInterface::CongestionVector lost_packets;
+      lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
+      SendAlgorithmInterface::CongestionVector empty;
+      pacing_sender_->OnCongestionEvent(true, 1234, empty, lost_packets);
+    } else if (burst_size != kInitialBurstPackets) {
+      LOG(FATAL) << "Unsupported burst_size specificied.";
+    }
   }
 
   void CheckPacketIsSentImmediately(HasRetransmittableData retransmittable_data,
@@ -337,6 +344,9 @@
 }
 
 TEST_F(PacingSenderTest, VerifyInnerSenderCalled) {
+  // Configure pacing rate of 1 packet per 1 ms with no burst tokens.
+  InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta(
+                        kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
   QuicBandwidth kBandwidth = QuicBandwidth::FromBitsPerSecond(1000);
   QuicTime kTime = QuicTime::Infinite();
   QuicTime::Delta kTimeDelta = QuicTime::Delta::Infinite();
diff --git a/net/quic/core/crypto/proof_source.h b/net/quic/core/crypto/proof_source.h
index ed0b88c..0160f22 100644
--- a/net/quic/core/crypto/proof_source.h
+++ b/net/quic/core/crypto/proof_source.h
@@ -86,9 +86,7 @@
   // key is RSA.
   //
   // The signature uses SHA-256 as the hash function when the key is ECDSA.
-  //
-  // If |ecdsa_ok| is true, the signature may use an ECDSA key. Otherwise, the
-  // signature must use an RSA key.
+  // The signature may use an ECDSA key.
   //
   // |out_chain| is reference counted to avoid the (assumed) expense of copying
   // out the certificates.
@@ -118,7 +116,6 @@
                         const std::string& server_config,
                         QuicVersion quic_version,
                         base::StringPiece chlo_hash,
-                        bool ecdsa_ok,
                         scoped_refptr<Chain>* out_chain,
                         std::string* out_signature,
                         std::string* out_leaf_cert_sct) = 0;
@@ -132,7 +129,6 @@
                         const std::string& server_config,
                         QuicVersion quic_version,
                         base::StringPiece chlo_hash,
-                        bool ecdsa_ok,
                         std::unique_ptr<Callback> callback) = 0;
 };
 
diff --git a/net/quic/core/crypto/proof_test.cc b/net/quic/core/crypto/proof_test.cc
index fed5c80..2a1123b 100644
--- a/net/quic/core/crypto/proof_test.cc
+++ b/net/quic/core/crypto/proof_test.cc
@@ -162,12 +162,12 @@
   string error_details, signature, first_signature, first_cert_sct, cert_sct;
   IPAddress server_ip;
 
-  ASSERT_TRUE(source->GetProof(
-      server_ip, hostname, server_config, quic_version, first_chlo_hash,
-      false /* no ECDSA */, &first_chain, &first_signature, &first_cert_sct));
   ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, quic_version,
-                               second_chlo_hash, false /* no ECDSA */, &chain,
-                               &signature, &cert_sct));
+                               first_chlo_hash, &first_chain, &first_signature,
+                               &first_cert_sct));
+  ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, quic_version,
+                               second_chlo_hash, &chain, &signature,
+                               &cert_sct));
 
   // Check that the proof source is caching correctly:
   ASSERT_EQ(first_chain->certs, chain->certs);
@@ -217,9 +217,8 @@
   string expected_signature;
   string expected_leaf_cert_sct;
   ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, quic_version,
-                               first_chlo_hash, false /* no ECDSA */,
-                               &expected_chain, &expected_signature,
-                               &expected_leaf_cert_sct));
+                               first_chlo_hash, &expected_chain,
+                               &expected_signature, &expected_leaf_cert_sct));
 
   // Call asynchronous version and compare results
   bool called = false;
@@ -230,7 +229,7 @@
   std::unique_ptr<ProofSource::Callback> cb(
       new TestCallback(&called, &ok, &chain, &signature, &leaf_cert_sct));
   source->GetProof(server_ip, hostname, server_config, quic_version,
-                   first_chlo_hash, false /* no ECDSA */, std::move(cb));
+                   first_chlo_hash, std::move(cb));
   // TODO(gredner): whan GetProof really invokes the callback asynchronously,
   // figure out what to do here.
   ASSERT_TRUE(called);
@@ -250,8 +249,7 @@
   IPAddress server_ip;
 
   ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, GetParam(),
-                               chlo_hash, false /* no ECDSA */, &chain,
-                               &signature, &cert_sct));
+                               chlo_hash, &chain, &signature, &cert_sct));
 
   // Make sure we can safely access results after deleting where they came from.
   EXPECT_FALSE(chain->HasOneRef());
diff --git a/net/quic/core/crypto/quic_crypto_client_config.cc b/net/quic/core/crypto/quic_crypto_client_config.cc
index fd6f43ab6..bf67be53 100644
--- a/net/quic/core/crypto/quic_crypto_client_config.cc
+++ b/net/quic/core/crypto/quic_crypto_client_config.cc
@@ -56,7 +56,7 @@
 
 QuicCryptoClientConfig::QuicCryptoClientConfig(
     std::unique_ptr<ProofVerifier> proof_verifier)
-    : proof_verifier_(std::move(proof_verifier)), disable_ecdsa_(false) {
+    : proof_verifier_(std::move(proof_verifier)) {
   DCHECK(proof_verifier_.get());
   SetDefaults();
 }
@@ -382,8 +382,6 @@
 
   // Authenticated encryption algorithms. Prefer RFC 7539 ChaCha20 by default.
   aead = {kCC20, kAESG};
-
-  disable_ecdsa_ = false;
 }
 
 QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate(
@@ -453,11 +451,7 @@
   rand->RandBytes(proof_nonce, arraysize(proof_nonce));
   out->SetStringPiece(kNONP, StringPiece(proof_nonce, arraysize(proof_nonce)));
 
-  if (disable_ecdsa_) {
-    out->SetVector(kPDMD, QuicTagVector{kX59R});
-  } else {
-    out->SetVector(kPDMD, QuicTagVector{kX509});
-  }
+  out->SetVector(kPDMD, QuicTagVector{kX509});
 
   if (common_cert_sets) {
     out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
@@ -946,10 +940,6 @@
   }
 }
 
-void QuicCryptoClientConfig::DisableEcdsa() {
-  disable_ecdsa_ = true;
-}
-
 bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
     const QuicServerId& server_id,
     CachedState* server_state) {
diff --git a/net/quic/core/crypto/quic_crypto_client_config.h b/net/quic/core/crypto/quic_crypto_client_config.h
index fde1f83..56f996f 100644
--- a/net/quic/core/crypto/quic_crypto_client_config.h
+++ b/net/quic/core/crypto/quic_crypto_client_config.h
@@ -321,11 +321,6 @@
   // called after SetDefaults().
   void PreferAesGcm();
 
-  // Disables the use of ECDSA for proof verification.
-  // Call this method on platforms that do not support ECDSA.
-  // TODO(rch): remove this method when we drop support for Windows XP.
-  void DisableEcdsa();
-
   // Saves the |user_agent_id| that will be passed in QUIC's CHLO message.
   void set_user_agent_id(const std::string& user_agent_id) {
     user_agent_id_ = user_agent_id;
@@ -374,9 +369,6 @@
   std::unique_ptr<ProofVerifier> proof_verifier_;
   std::unique_ptr<ChannelIDSource> channel_id_source_;
 
-  // True if ECDSA should be disabled.
-  bool disable_ecdsa_;
-
   // The |user_agent_id_| passed in QUIC's CHLO message.
   std::string user_agent_id_;
 
diff --git a/net/quic/core/crypto/quic_crypto_client_config_test.cc b/net/quic/core/crypto/quic_crypto_client_config_test.cc
index f3a58e7..c4656972 100644
--- a/net/quic/core/crypto/quic_crypto_client_config_test.cc
+++ b/net/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -217,22 +217,6 @@
   EXPECT_EQ("12345678", scid);
 }
 
-TEST(QuicCryptoClientConfigTest, InchoateChloSecureNoEcdsa) {
-  QuicCryptoClientConfig::CachedState state;
-  QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
-  config.DisableEcdsa();
-  QuicCryptoNegotiatedParameters params;
-  CryptoHandshakeMessage msg;
-  QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
-  MockRandom rand;
-  config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
-                                 /* demand_x509_proof= */ true, &params, &msg);
-
-  QuicTag pdmd;
-  EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kPDMD, &pdmd));
-  EXPECT_EQ(kX59R, pdmd);
-}
-
 TEST(QuicCryptoClientConfigTest, FillClientHello) {
   QuicCryptoClientConfig::CachedState state;
   QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
diff --git a/net/quic/core/crypto/quic_crypto_server_config.cc b/net/quic/core/crypto/quic_crypto_server_config.cc
index f2148cf..bb1b809 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.cc
+++ b/net/quic/core/crypto/quic_crypto_server_config.cc
@@ -538,7 +538,7 @@
   }
 
   if (result->error_code == QUIC_NO_ERROR) {
-    if (FLAGS_quic_refresh_proof && version > QUIC_VERSION_30) {
+    if (version > QUIC_VERSION_30) {
       // QUIC v31 and above require a new proof for each CHLO so clear the
       // existing proof, if any.
       crypto_proof->chain = nullptr;
@@ -615,10 +615,7 @@
 
   out->Clear();
 
-  bool x509_supported = false;
-  bool x509_ecdsa_supported = false;
-  ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported);
-  if (!x509_supported && FLAGS_quic_require_x509) {
+  if (!ClientDemandsX509Proof(client_hello) && FLAGS_quic_require_x509) {
     *error_details = "Missing or invalid PDMD";
     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
   }
@@ -627,10 +624,10 @@
   CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash);
   // No need to get a new proof if one was already generated.
   if (!crypto_proof->chain &&
-      !proof_source_->GetProof(
-          server_ip, info.sni.as_string(), primary_config->serialized, version,
-          chlo_hash, x509_ecdsa_supported, &crypto_proof->chain,
-          &crypto_proof->signature, &crypto_proof->cert_sct)) {
+      !proof_source_->GetProof(server_ip, info.sni.as_string(),
+                               primary_config->serialized, version, chlo_hash,
+                               &crypto_proof->chain, &crypto_proof->signature,
+                               &crypto_proof->cert_sct)) {
     return QUIC_HANDSHAKE_FAILED;
   }
 
@@ -1118,16 +1115,11 @@
   }
 
   bool get_proof_failed = false;
-  bool x509_supported = false;
-  bool x509_ecdsa_supported = false;
-  ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported);
   string serialized_config = primary_config->serialized;
   string chlo_hash;
   CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash);
   bool need_proof = true;
-  if (FLAGS_quic_refresh_proof) {
-    need_proof = !crypto_proof->chain;
-  }
+  need_proof = !crypto_proof->chain;
   if (FLAGS_enable_async_get_proof) {
     if (need_proof) {
       // Make an async call to GetProof and setup the callback to trampoline
@@ -1139,7 +1131,7 @@
               client_hello_state, done_cb));
       proof_source_->GetProof(server_ip, info->sni.as_string(),
                               serialized_config, version, chlo_hash,
-                              x509_ecdsa_supported, std::move(cb));
+                              std::move(cb));
       helper.DetachCallback();
       return;
     }
@@ -1147,10 +1139,10 @@
 
   // No need to get a new proof if one was already generated.
   if (need_proof &&
-      !proof_source_->GetProof(
-          server_ip, info->sni.as_string(), serialized_config, version,
-          chlo_hash, x509_ecdsa_supported, &crypto_proof->chain,
-          &crypto_proof->signature, &crypto_proof->cert_sct)) {
+      !proof_source_->GetProof(server_ip, info->sni.as_string(),
+                               serialized_config, version, chlo_hash,
+                               &crypto_proof->chain, &crypto_proof->signature,
+                               &crypto_proof->cert_sct)) {
     get_proof_failed = true;
   }
 
@@ -1308,8 +1300,7 @@
   string signature;
   string cert_sct;
   if (!proof_source_->GetProof(server_ip, params.sni, serialized, version,
-                               chlo_hash, params.x509_ecdsa_supported, &chain,
-                               &signature, &cert_sct)) {
+                               chlo_hash, &chain, &signature, &cert_sct)) {
     DVLOG(1) << "Server: failed to get proof.";
     return false;
   }
@@ -1365,7 +1356,6 @@
           std::move(message), std::move(cb)));
 
   proof_source_->GetProof(server_ip, params.sni, serialized, version, chlo_hash,
-                          params.x509_ecdsa_supported,
                           std::move(proof_source_cb));
 }
 
@@ -1476,10 +1466,7 @@
   out->SetVector(kRREJ, info.reject_reasons);
 
   // The client may have requested a certificate chain.
-  bool x509_supported = false;
-  ParseProofDemand(client_hello, &x509_supported,
-                   &params->x509_ecdsa_supported);
-  if (!x509_supported && FLAGS_quic_require_x509) {
+  if (!ClientDemandsX509Proof(client_hello) && FLAGS_quic_require_x509) {
     QUIC_BUG << "x509 certificates not supported in proof demand";
     return;
   }
@@ -2024,30 +2011,23 @@
          hash_from_client;
 }
 
-void QuicCryptoServerConfig::ParseProofDemand(
-    const CryptoHandshakeMessage& client_hello,
-    bool* x509_supported,
-    bool* x509_ecdsa_supported) const {
+bool QuicCryptoServerConfig::ClientDemandsX509Proof(
+    const CryptoHandshakeMessage& client_hello) const {
   const QuicTag* their_proof_demands;
   size_t num_their_proof_demands;
 
   if (client_hello.GetTaglist(kPDMD, &their_proof_demands,
                               &num_their_proof_demands) != QUIC_NO_ERROR) {
-    return;
+    return false;
   }
 
-  *x509_supported = false;
   for (size_t i = 0; i < num_their_proof_demands; i++) {
     switch (their_proof_demands[i]) {
       case kX509:
-        *x509_supported = true;
-        *x509_ecdsa_supported = true;
-        break;
-      case kX59R:
-        *x509_supported = true;
-        break;
+        return true;
     }
   }
+  return false;
 }
 
 QuicCryptoServerConfig::Config::Config()
diff --git a/net/quic/core/crypto/quic_crypto_server_config.h b/net/quic/core/crypto/quic_crypto_server_config.h
index 694daac..7203fa5 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.h
+++ b/net/quic/core/crypto/quic_crypto_server_config.h
@@ -637,11 +637,9 @@
       const CryptoHandshakeMessage& client_hello,
       const QuicCryptoProof& crypto_proof) const;
 
-  // ParseProofDemand reads the PDMD field from the client hello and sets the
-  // |x509_ecdsa_supported| and |x509_supported| output parameters.
-  void ParseProofDemand(const CryptoHandshakeMessage& client_hello,
-                        bool* x509_supported,
-                        bool* x509_ecdsa_supported) const;
+  // Returns true if the PDMD field from the client hello demands an X509
+  // certificate.
+  bool ClientDemandsX509Proof(const CryptoHandshakeMessage& client_hello) const;
 
   // Callback to receive the results of ProofSource::GetProof.  Note: this
   // callback has no cancellation support, since the lifetime of the ProofSource
diff --git a/net/quic/core/quic_bandwidth.cc b/net/quic/core/quic_bandwidth.cc
index 0895fb37..9ba96f3 100644
--- a/net/quic/core/quic_bandwidth.cc
+++ b/net/quic/core/quic_bandwidth.cc
@@ -6,11 +6,17 @@
 
 #include <stdint.h>
 
+#include <limits>
+
+#include "base/format_macros.h"
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_time.h"
 #include "net/quic/core/quic_types.h"
 
+using base::StringPrintf;
+
 namespace net {
 
 // Highest number that QuicBandwidth can hold.
@@ -22,6 +28,11 @@
 }
 
 // static
+QuicBandwidth QuicBandwidth::Infinite() {
+  return QuicBandwidth(std::numeric_limits<int64_t>::max());
+}
+
+// static
 QuicBandwidth QuicBandwidth::FromBitsPerSecond(int64_t bits_per_second) {
   return QuicBandwidth(bits_per_second);
 }
@@ -103,4 +114,30 @@
                                            bits_per_second_);
 }
 
+std::string QuicBandwidth::ToDebugValue() const {
+  if (bits_per_second_ < 80000) {
+    return StringPrintf("%" PRId64 " bits/s (%" PRId64 " bytes/s)",
+                        bits_per_second_, bits_per_second_ / 8);
+  }
+
+  double divisor;
+  char unit;
+  if (bits_per_second_ < 8 * 1000 * 1000) {
+    divisor = 1e3;
+    unit = 'k';
+  } else if (bits_per_second_ < INT64_C(8) * 1000 * 1000 * 1000) {
+    divisor = 1e6;
+    unit = 'M';
+  } else {
+    divisor = 1e9;
+    unit = 'G';
+  }
+
+  double bits_per_second_with_unit = bits_per_second_ / divisor;
+  double bytes_per_second_with_unit = bits_per_second_with_unit / 8;
+  return StringPrintf("%.2f %cbits/s (%.2f %cbytes/s)",
+                      bits_per_second_with_unit, unit,
+                      bytes_per_second_with_unit, unit);
+}
+
 }  // namespace net
diff --git a/net/quic/core/quic_bandwidth.h b/net/quic/core/quic_bandwidth.h
index 7b524aca..7a8b55d 100644
--- a/net/quic/core/quic_bandwidth.h
+++ b/net/quic/core/quic_bandwidth.h
@@ -9,6 +9,8 @@
 
 #include <stdint.h>
 
+#include <ostream>
+
 #include "base/compiler_specific.h"
 #include "net/quic/core/quic_time.h"
 
@@ -22,6 +24,9 @@
   // Creates a new QuicBandwidth with an internal value of 0.
   static QuicBandwidth Zero();
 
+  // Creates a new QuicBandwidth with an internal value of INT64_MAX.
+  static QuicBandwidth Infinite();
+
   // Create a new QuicBandwidth holding the bits per second.
   static QuicBandwidth FromBitsPerSecond(int64_t bits_per_second);
 
@@ -54,6 +59,8 @@
 
   QuicTime::Delta TransferTime(QuicByteCount bytes) const;
 
+  std::string ToDebugValue() const;
+
  private:
   explicit QuicBandwidth(int64_t bits_per_second);
   int64_t bits_per_second_;
@@ -97,5 +104,12 @@
   return rhs * lhs;
 }
 
+// Override stream output operator for gtest.
+inline std::ostream& operator<<(std::ostream& output,
+                                const QuicBandwidth bandwidth) {
+  output << bandwidth.ToDebugValue();
+  return output;
+}
+
 }  // namespace net
 #endif  // NET_QUIC_QUIC_BANDWIDTH_H_
diff --git a/net/quic/core/quic_bandwidth_test.cc b/net/quic/core/quic_bandwidth_test.cc
index 8af5572b0..78fac50 100644
--- a/net/quic/core/quic_bandwidth_test.cc
+++ b/net/quic/core/quic_bandwidth_test.cc
@@ -95,5 +95,21 @@
   EXPECT_GE(b2, b1);
 }
 
+TEST_F(QuicBandwidthTest, DebugValue) {
+  EXPECT_EQ("128 bits/s (16 bytes/s)",
+            QuicBandwidth::FromBytesPerSecond(16).ToDebugValue());
+  EXPECT_EQ("4096 bits/s (512 bytes/s)",
+            QuicBandwidth::FromBytesPerSecond(512).ToDebugValue());
+
+  QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(1000 * 50);
+  EXPECT_EQ("400.00 kbits/s (50.00 kbytes/s)", bandwidth.ToDebugValue());
+
+  bandwidth = bandwidth * 1000;
+  EXPECT_EQ("400.00 Mbits/s (50.00 Mbytes/s)", bandwidth.ToDebugValue());
+
+  bandwidth = bandwidth * 1000;
+  EXPECT_EQ("400.00 Gbits/s (50.00 Gbytes/s)", bandwidth.ToDebugValue());
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/core/quic_client_promised_info_test.cc b/net/quic/core/quic_client_promised_info_test.cc
index 0eff4b2..a6e92ffe 100644
--- a/net/quic/core/quic_client_promised_info_test.cc
+++ b/net/quic/core/quic_client_promised_info_test.cc
@@ -78,8 +78,6 @@
         session_(connection_, &push_promise_index_),
         body_("hello world"),
         promise_id_(gfe_quic::test::kServerDataStreamId1) {
-    FLAGS_quic_supports_push_promise = true;
-
     session_.Initialize();
 
     headers_.SetResponseFirstline("HTTP/1.1", 200, "Ok");
diff --git a/net/quic/core/quic_client_push_promise_index_test.cc b/net/quic/core/quic_client_push_promise_index_test.cc
index f9eb569..73407c5 100644
--- a/net/quic/core/quic_client_push_promise_index_test.cc
+++ b/net/quic/core/quic_client_push_promise_index_test.cc
@@ -50,7 +50,6 @@
                                                        Perspective::IS_CLIENT)),
         session_(connection_, &index_),
         promised_(&session_, kServerDataStreamId1, url_) {
-    FLAGS_quic_supports_push_promise = true;
     request_[":path"] = "/bar";
     request_[":authority"] = "www.google.com";
     request_[":version"] = "HTTP/1.1";
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index 3858611..7d23d90 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -311,7 +311,8 @@
       largest_received_packet_size_(0),
       goaway_sent_(false),
       goaway_received_(false),
-      multipath_enabled_(false) {
+      multipath_enabled_(false),
+      write_error_occured_(false) {
   DVLOG(1) << ENDPOINT
            << "Created connection with connection_id: " << connection_id;
   framer_.set_visitor(this);
@@ -663,7 +664,7 @@
 
   // Once the server receives a forward secure packet, the handshake is
   // confirmed.
-  if (FLAGS_quic_no_shlo_listener && level == ENCRYPTION_FORWARD_SECURE &&
+  if (level == ENCRYPTION_FORWARD_SECURE &&
       perspective_ == Perspective::IS_SERVER) {
     sent_packet_manager_->SetHandshakeConfirmed();
   }
@@ -1557,8 +1558,6 @@
   }
 
   // Allow acks to be sent immediately.
-  // TODO(ianswett): Remove retransmittable from
-  // SendAlgorithmInterface::TimeUntilSend.
   if (retransmittable == NO_RETRANSMITTABLE_DATA) {
     return true;
   }
@@ -1571,8 +1570,7 @@
   // sent on path_id.
   QuicPathId path_id = kInvalidPathId;
   QuicTime now = clock_->Now();
-  QuicTime::Delta delay =
-      sent_packet_manager_->TimeUntilSend(now, retransmittable, &path_id);
+  QuicTime::Delta delay = sent_packet_manager_->TimeUntilSend(now, &path_id);
   if (delay.IsInfinite()) {
     DCHECK_EQ(kInvalidPathId, path_id);
     send_alarm_->Cancel();
@@ -1689,9 +1687,17 @@
     // TODO(ianswett): Change the packet number length and other packet creator
     // options by a more explicit API than setting a struct value directly,
     // perhaps via the NetworkChangeVisitor.
-    packet_generator_.UpdateSequenceNumberLength(
-        sent_packet_manager_->GetLeastPacketAwaitedByPeer(packet->path_id),
-        sent_packet_manager_->EstimateMaxPacketsInFlight(max_packet_length()));
+    if (FLAGS_quic_least_unacked_packet_number_length) {
+      packet_generator_.UpdateSequenceNumberLength(
+          sent_packet_manager_->GetLeastUnacked(packet->path_id),
+          sent_packet_manager_->EstimateMaxPacketsInFlight(
+              max_packet_length()));
+    } else {
+      packet_generator_.UpdateSequenceNumberLength(
+          sent_packet_manager_->GetLeastPacketAwaitedByPeer(packet->path_id),
+          sent_packet_manager_->EstimateMaxPacketsInFlight(
+              max_packet_length()));
+    }
   }
 
   bool reset_retransmission_alarm = sent_packet_manager_->OnPacketSent(
@@ -1751,13 +1757,29 @@
 }
 
 void QuicConnection::OnWriteError(int error_code) {
+  if (FLAGS_quic_close_connection_on_packet_too_large && write_error_occured_) {
+    // A write error already occurred. The connection is being closed.
+    return;
+  }
+  write_error_occured_ = true;
+
   const string error_details = "Write failed with error: " +
                                base::IntToString(error_code) + " (" +
                                ErrorToString(error_code) + ")";
   DVLOG(1) << ENDPOINT << error_details;
   // We can't send an error as the socket is presumably borked.
-  TearDownLocalConnectionState(QUIC_PACKET_WRITE_ERROR, error_details,
-                               ConnectionCloseSource::FROM_SELF);
+  switch (error_code) {
+    case ERR_MSG_TOO_BIG:
+      if (FLAGS_quic_close_connection_on_packet_too_large) {  // NOLINT
+        CloseConnection(QUIC_PACKET_WRITE_ERROR, error_details,
+                        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+        break;
+      }
+    default:
+      // We can't send an error as the socket is presumably borked.
+      TearDownLocalConnectionState(QUIC_PACKET_WRITE_ERROR, error_details,
+                                   ConnectionCloseSource::FROM_SELF);
+  }
 }
 
 void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) {
@@ -1843,7 +1865,8 @@
   // If a forward-secure encrypter is available but is not being used and the
   // next packet number is the first packet which requires
   // forward security, start using the forward-secure encrypter.
-  if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
+  if (!FLAGS_quic_remove_obsolete_forward_secure &&
+      encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
       has_forward_secure_encrypter_ &&
       packet->packet_number >= first_required_forward_secure_packet_ - 1) {
     SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
@@ -1913,7 +1936,8 @@
 void QuicConnection::SetEncrypter(EncryptionLevel level,
                                   QuicEncrypter* encrypter) {
   packet_generator_.SetEncrypter(level, encrypter);
-  if (level == ENCRYPTION_FORWARD_SECURE) {
+  if (!FLAGS_quic_remove_obsolete_forward_secure &&
+      level == ENCRYPTION_FORWARD_SECURE) {
     has_forward_secure_encrypter_ = true;
     first_required_forward_secure_packet_ =
         packet_number_of_last_sent_packet_ +
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h
index 639370d..a18b87a 100644
--- a/net/quic/core/quic_connection.h
+++ b/net/quic/core/quic_connection.h
@@ -1072,6 +1072,10 @@
   // If true, multipath is enabled for this connection.
   bool multipath_enabled_;
 
+  // Indicates whether a write error is encountered currently. This is used to
+  // avoid infinite write errors.
+  bool write_error_occured_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicConnection);
 };
 
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc
index 94e167c..fbeae11 100644
--- a/net/quic/core/quic_connection_test.cc
+++ b/net/quic/core/quic_connection_test.cc
@@ -279,6 +279,8 @@
         write_blocked_(false),
         write_should_fail_(false),
         block_on_next_write_(false),
+        next_packet_too_large_(false),
+        always_get_packet_too_large_(false),
         is_write_blocked_data_buffered_(false),
         final_bytes_of_last_packet_(0),
         final_bytes_of_previous_packet_(0),
@@ -311,6 +313,14 @@
       write_blocked_ = true;
       block_on_next_write_ = false;
     }
+    if (next_packet_too_large_) {
+      next_packet_too_large_ = false;
+      return WriteResult(WRITE_STATUS_ERROR, ERR_MSG_TOO_BIG);
+    }
+    if (always_get_packet_too_large_) {
+      LOG(ERROR) << "RETURNING TOO BIG";
+      return WriteResult(WRITE_STATUS_ERROR, ERR_MSG_TOO_BIG);
+    }
     if (IsWriteBlocked()) {
       return WriteResult(WRITE_STATUS_BLOCKED, -1);
     }
@@ -346,6 +356,10 @@
 
   void BlockOnNextWrite() { block_on_next_write_ = true; }
 
+  void SimulateNextPacketTooLarge() { next_packet_too_large_ = true; }
+
+  void AlwaysGetPacketTooLarge() { always_get_packet_too_large_ = true; }
+
   // Sets the amount of time that the writer should before the actual write.
   void SetWritePauseTimeDelta(QuicTime::Delta delta) {
     write_pause_time_delta_ = delta;
@@ -428,6 +442,8 @@
   bool write_blocked_;
   bool write_should_fail_;
   bool block_on_next_write_;
+  bool next_packet_too_large_;
+  bool always_get_packet_too_large_;
   bool is_write_blocked_data_buffered_;
   uint32_t final_bytes_of_last_packet_;
   uint32_t final_bytes_of_previous_packet_;
@@ -1022,6 +1038,10 @@
     EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
   }
 
+  void SimulateNextPacketTooLarge() { writer_->SimulateNextPacketTooLarge(); }
+
+  void AlwaysGetPacketTooLarge() { writer_->AlwaysGetPacketTooLarge(); }
+
   void SetWritePauseTimeDelta(QuicTime::Delta delta) {
     writer_->SetWritePauseTimeDelta(delta);
   }
@@ -2575,6 +2595,7 @@
 }
 
 TEST_P(QuicConnectionTest, DelayForwardSecureEncryptionUntilClientIsReady) {
+  FLAGS_quic_remove_obsolete_forward_secure = false;
   // A TaggingEncrypter puts kTagSize copies of the given byte (0x02 here) at
   // the end of the packet. We can test this to check which encrypter was used.
   use_tagging_decrypter();
@@ -2598,6 +2619,7 @@
 }
 
 TEST_P(QuicConnectionTest, DelayForwardSecureEncryptionUntilManyPacketSent) {
+  FLAGS_quic_remove_obsolete_forward_secure = false;
   // Set a congestion window of 10 packets.
   QuicPacketCount congestion_window = 10;
   EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
@@ -4944,6 +4966,30 @@
   ProcessFramePacket(QuicFrame(&frame1_));
 }
 
+TEST_P(QuicConnectionTest, CloseConnectionOnPacketTooLarge) {
+  FLAGS_quic_close_connection_on_packet_too_large = true;
+  SimulateNextPacketTooLarge();
+  // Although the data packet cannot be written, the send packet manager is
+  // informed. Also a connection close packet is sent.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PACKET_WRITE_ERROR, _,
+                                           ConnectionCloseSource::FROM_SELF))
+      .Times(1);
+  connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+}
+
+TEST_P(QuicConnectionTest, AlwaysGetPacketTooLarge) {
+  // Test even we always get packet too large, we do not infinitely try to send
+  // close packet.
+  FLAGS_quic_close_connection_on_packet_too_large = true;
+  AlwaysGetPacketTooLarge();
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+  EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PACKET_WRITE_ERROR, _,
+                                           ConnectionCloseSource::FROM_SELF))
+      .Times(1);
+  connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/core/quic_crypto_server_stream.cc b/net/quic/core/quic_crypto_server_stream.cc
index 6709b04..37d68ad 100644
--- a/net/quic/core/quic_crypto_server_stream.cc
+++ b/net/quic/core/quic_crypto_server_stream.cc
@@ -41,15 +41,6 @@
 }
 }  // namespace
 
-void ServerHelloNotifier::OnPacketAcked(int acked_bytes,
-                                        QuicTime::Delta ack_delay_time) {
-  DCHECK(!FLAGS_quic_no_shlo_listener);
-  // The SHLO is sent in one packet.
-  server_stream_->OnServerHelloAcked();
-}
-
-void ServerHelloNotifier::OnPacketRetransmitted(int /*retransmitted_bytes*/) {}
-
 QuicCryptoServerStreamBase::QuicCryptoServerStreamBase(
     QuicServerSessionBase* session)
     : QuicCryptoStream(session) {}
@@ -237,13 +228,7 @@
     session()->connection()->SetDiversificationNonce(diversification_nonce);
   }
 
-  // We want to be notified when the SHLO is ACKed so that we can disable
-  // HANDSHAKE_MODE in the sent packet manager.
-  scoped_refptr<ServerHelloNotifier> server_hello_notifier(
-      new ServerHelloNotifier(this));
-  SendHandshakeMessage(reply, FLAGS_quic_no_shlo_listener
-                                  ? nullptr
-                                  : server_hello_notifier.get());
+  SendHandshakeMessage(reply);
 
   session()->connection()->SetEncrypter(
       ENCRYPTION_FORWARD_SECURE,
diff --git a/net/quic/core/quic_crypto_server_stream.h b/net/quic/core/quic_crypto_server_stream.h
index dcf18be..92cf176 100644
--- a/net/quic/core/quic_crypto_server_stream.h
+++ b/net/quic/core/quic_crypto_server_stream.h
@@ -30,25 +30,6 @@
 class QuicCryptoServerStreamPeer;
 }  // namespace test
 
-// Receives a notification when the server hello (SHLO) has been ACKed by the
-// peer. At this point we disable HANDSHAKE_MODE in the sent packet manager.
-class NET_EXPORT_PRIVATE ServerHelloNotifier : public QuicAckListenerInterface {
- public:
-  explicit ServerHelloNotifier(QuicCryptoServerStreamBase* stream)
-      : server_stream_(stream) {}
-
-  void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override;
-
-  void OnPacketRetransmitted(int retransmitted_bytes) override;
-
- private:
-  ~ServerHelloNotifier() override {}
-
-  QuicCryptoServerStreamBase* server_stream_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServerHelloNotifier);
-};
-
 // TODO(alyssar) see what can be moved out of QuicCryptoServerStream with
 // various code and test refactoring.
 class NET_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream {
diff --git a/net/quic/core/quic_crypto_stream.cc b/net/quic/core/quic_crypto_stream.cc
index 831b57fc..cffd838 100644
--- a/net/quic/core/quic_crypto_stream.cc
+++ b/net/quic/core/quic_crypto_stream.cc
@@ -63,20 +63,13 @@
 
 void QuicCryptoStream::SendHandshakeMessage(
     const CryptoHandshakeMessage& message) {
-  SendHandshakeMessage(message, nullptr);
-}
-
-void QuicCryptoStream::SendHandshakeMessage(
-    const CryptoHandshakeMessage& message,
-    QuicAckListenerInterface* listener) {
   DVLOG(1) << ENDPOINT << "Sending " << message.DebugString();
   if (FLAGS_quic_neuter_unencrypted_when_sending) {
     session()->connection()->NeuterUnencryptedPackets();
   }
   session()->OnCryptoHandshakeMessageSent(message);
   const QuicData& data = message.GetSerialized();
-  // TODO(wtc): check the return value.
-  WriteOrBufferData(StringPiece(data.data(), data.length()), false, listener);
+  WriteOrBufferData(StringPiece(data.data(), data.length()), false, nullptr);
 }
 
 bool QuicCryptoStream::ExportKeyingMaterial(StringPiece label,
diff --git a/net/quic/core/quic_crypto_stream.h b/net/quic/core/quic_crypto_stream.h
index 0d46eb9..e048cb0 100644
--- a/net/quic/core/quic_crypto_stream.h
+++ b/net/quic/core/quic_crypto_stream.h
@@ -45,10 +45,6 @@
   // Sends |message| to the peer.
   // TODO(wtc): return a success/failure status.
   void SendHandshakeMessage(const CryptoHandshakeMessage& message);
-  // As above, but registers |delegate| for notification when |message| has been
-  // ACKed by the peer.
-  void SendHandshakeMessage(const CryptoHandshakeMessage& message,
-                            QuicAckListenerInterface* listener);
 
   // Performs key extraction to derive a new secret of |result_len| bytes
   // dependent on |label|, |context|, and the stream's negotiated subkey secret.
diff --git a/net/quic/core/quic_flags.cc b/net/quic/core/quic_flags.cc
index a78ca599..5b7e208 100644
--- a/net/quic/core/quic_flags.cc
+++ b/net/quic/core/quic_flags.cc
@@ -33,10 +33,6 @@
 // This flag is not in use, just to keep consistency for shared code.
 bool FLAGS_quic_always_log_bugs_for_tests = true;
 
-// If true, a QUIC connection option with tag DHDT can be used to disable
-// HPACK\'s dynamic table.
-bool FLAGS_quic_disable_hpack_dynamic_table = true;
-
 // If true, multipath is enabled for the connection.
 bool FLAGS_quic_enable_multipath = false;
 
@@ -60,9 +56,6 @@
 // If true, Close the connection instead of writing unencrypted stream data.
 bool FLAGS_quic_never_write_unencrypted_data = true;
 
-// If true, headers stream will support receiving PUSH_PROMISE frames.
-bool FLAGS_quic_supports_push_promise = true;
-
 // If true, QUIC connections can do bandwidth resumption with an initial window
 // of < 10 packets.
 bool FLAGS_quic_no_lower_bw_resumption_limit = true;
@@ -79,13 +72,6 @@
 // flags.
 bool FLAGS_quic_use_old_public_reset_packets = true;
 
-// If true, ignore QUIC data frames of length 0 for flow control.
-bool FLAGS_quic_ignore_zero_length_frames = true;
-
-// If true, replace ServerHelloNotifier with a check to see if a decrypted
-// packet is forward secure.
-bool FLAGS_quic_no_shlo_listener = true;
-
 // Adds a RATE connection option to do rate based sending.
 bool FLAGS_quic_rate_based_sending = true;
 
@@ -120,10 +106,6 @@
 // If true, deprecate safeguards for b/26023400.
 bool FLAGS_quic_deprecate_kfixd = false;
 
-// If true, QUIC will refresh the proof for versions 31 and beyond on subsequent
-// CHLOs.
-bool FLAGS_quic_refresh_proof = true;
-
 // If true, a connection does not migrate on an old packet even the peer address
 // changes.
 bool FLAGS_quic_do_not_migrate_on_old_packet = true;
@@ -148,3 +130,27 @@
 bool FLAGS_quic_use_packet_number_queue_intervals = false;
 
 bool FLAGS_quic_sequencer_buffer_retire_block_in_time = true;
+
+// Remove obsolete code to force QUIC to go forward secure, now that the server
+// immediately goes forward secure.
+bool FLAGS_quic_remove_obsolete_forward_secure = false;
+
+// If true, close QUIC connection explicitly on write error due to packet being
+// too large.
+bool FLAGS_quic_close_connection_on_packet_too_large = true;
+
+// Use GetLeastUnacked when updating the packet number length, instead of
+// GetLeastPacketAwaitedByPeer.
+bool FLAGS_quic_least_unacked_packet_number_length = true;
+
+// If true, close the write side of a QUIC spdy stream when all queued bytes
+// have been written and a FIN has been sent.
+bool FLAGS_quic_close_stream_after_writing_queued_data = false;
+
+// If true, close connection with QUIC_TOO_MANY_FRAME_GAPS error when number of
+// gaps in QuicStreamSequenceBuffer exceeds allowed limit.
+bool FLAGS_quic_limit_frame_gaps_in_buffer = false;
+
+// If true, QuicSentPacketManager will use inline pacing functionality instead
+// of wrapping the SendAlgorithm with a PacingSender.
+bool FLAGS_quic_use_inline_pacing = false;
diff --git a/net/quic/core/quic_flags.h b/net/quic/core/quic_flags.h
index f5aaaf9..6cd8c3e 100644
--- a/net/quic/core/quic_flags.h
+++ b/net/quic/core/quic_flags.h
@@ -15,21 +15,16 @@
 NET_EXPORT_PRIVATE extern int64_t FLAGS_quic_time_wait_list_max_connections;
 NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stateless_reject_support;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_always_log_bugs_for_tests;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_disable_hpack_dynamic_table;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_multipath;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_handshake_confirmation;
 NET_EXPORT_PRIVATE extern bool FLAGS_shift_quic_cubic_epoch_when_app_limited;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_measure_headers_hol_blocking_time;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_disable_pacing_for_perf_tests;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_never_write_unencrypted_data;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_supports_push_promise;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_supports_push_promise;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_no_lower_bw_resumption_limit;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_loss_recovery_use_largest_acked;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_only_one_sending_alarm;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_old_public_reset_packets;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_ignore_zero_length_frames;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_no_shlo_listener;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_rate_based_sending;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_cheap_stateless_rejects;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_socket_walltimestamps;
@@ -40,7 +35,6 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_version_36;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_x509;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_deprecate_kfixd;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_refresh_proof;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_do_not_migrate_on_old_packet;
 NET_EXPORT_PRIVATE extern bool FLAGS_enable_async_get_proof;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_neuter_unencrypted_when_sending;
@@ -48,5 +42,12 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_handshake_confirmation_pre33;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_packet_number_queue_intervals;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_sequencer_buffer_retire_block_in_time;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_remove_obsolete_forward_secure;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_close_connection_on_packet_too_large;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_least_unacked_packet_number_length;
+NET_EXPORT_PRIVATE extern bool
+    FLAGS_quic_close_stream_after_writing_queued_data;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_limit_frame_gaps_in_buffer;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_inline_pacing;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/core/quic_headers_stream.cc b/net/quic/core/quic_headers_stream.cc
index 52446ca43..579db23 100644
--- a/net/quic/core/quic_headers_stream.cc
+++ b/net/quic/core/quic_headers_stream.cc
@@ -320,10 +320,7 @@
       fin_(false),
       frame_len_(0),
       uncompressed_frame_len_(0),
-      measure_headers_hol_blocking_time_(
-          FLAGS_quic_measure_headers_hol_blocking_time),
-      supports_push_promise_(session->perspective() == Perspective::IS_CLIENT &&
-                             FLAGS_quic_supports_push_promise),
+      supports_push_promise_(session->perspective() == Perspective::IS_CLIENT),
       cur_max_timestamp_(QuicTime::Zero()),
       prev_max_timestamp_(QuicTime::Zero()),
       spdy_framer_(HTTP2),
@@ -440,19 +437,12 @@
   while (true) {
     iov.iov_base = buffer;
     iov.iov_len = arraysize(buffer);
-    if (measure_headers_hol_blocking_time_) {
-      if (!sequencer()->GetReadableRegion(&iov, &timestamp)) {
-        // No more data to read.
-        break;
-      }
-      DCHECK(timestamp.IsInitialized());
-      cur_max_timestamp_ = std::max(timestamp, cur_max_timestamp_);
-    } else {
-      if (sequencer()->GetReadableRegions(&iov, 1) != 1) {
-        // No more data to read.
-        break;
-      }
+    if (!sequencer()->GetReadableRegion(&iov, &timestamp)) {
+      // No more data to read.
+      break;
     }
+    DCHECK(timestamp.IsInitialized());
+    cur_max_timestamp_ = std::max(timestamp, cur_max_timestamp_);
     if (spdy_framer_.ProcessInput(static_cast<char*>(iov.iov_base),
                                   iov.iov_len) != iov.iov_len) {
       // Error processing data.
@@ -502,21 +492,19 @@
   if (len == 0) {
     DCHECK_NE(0u, stream_id_);
     DCHECK_NE(0u, frame_len_);
-    if (measure_headers_hol_blocking_time_) {
-      if (prev_max_timestamp_ > cur_max_timestamp_) {
-        // prev_max_timestamp_ > cur_max_timestamp_ implies that
-        // headers from lower numbered streams actually came off the
-        // wire after headers for the current stream, hence there was
-        // HOL blocking.
-        QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_;
-        DVLOG(1) << "stream " << stream_id
-                 << ": Net.QuicSession.HeadersHOLBlockedTime "
-                 << delta.ToMilliseconds();
-        spdy_session_->OnHeadersHeadOfLineBlocking(delta);
-      }
-      prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_);
-      cur_max_timestamp_ = QuicTime::Zero();
+    if (prev_max_timestamp_ > cur_max_timestamp_) {
+      // prev_max_timestamp_ > cur_max_timestamp_ implies that
+      // headers from lower numbered streams actually came off the
+      // wire after headers for the current stream, hence there was
+      // HOL blocking.
+      QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_;
+      DVLOG(1) << "stream " << stream_id
+               << ": Net.QuicSession.HeadersHOLBlockedTime "
+               << delta.ToMilliseconds();
+      spdy_session_->OnHeadersHeadOfLineBlocking(delta);
     }
+    prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_);
+    cur_max_timestamp_ = QuicTime::Zero();
     if (promised_stream_id_ == kInvalidStreamId) {
       spdy_session_->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
     } else {
@@ -549,21 +537,20 @@
 void QuicHeadersStream::OnHeaderList(const QuicHeaderList& header_list) {
   DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
            << header_list.DebugString();
-  if (measure_headers_hol_blocking_time_) {
-    if (prev_max_timestamp_ > cur_max_timestamp_) {
-      // prev_max_timestamp_ > cur_max_timestamp_ implies that
-      // headers from lower numbered streams actually came off the
-      // wire after headers for the current stream, hence there was
-      // HOL blocking.
-      QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_;
-      DVLOG(1) << "stream " << stream_id_
-               << ": Net.QuicSession.HeadersHOLBlockedTime "
-               << delta.ToMilliseconds();
-      spdy_session_->OnHeadersHeadOfLineBlocking(delta);
-    }
-    prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_);
-    cur_max_timestamp_ = QuicTime::Zero();
+  if (prev_max_timestamp_ > cur_max_timestamp_) {
+    // prev_max_timestamp_ > cur_max_timestamp_ implies that
+    // headers from lower numbered streams actually came off the
+    // wire after headers for the current stream, hence there was
+    // HOL blocking.
+    QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_;
+    DVLOG(1) << "stream " << stream_id_
+             << ": Net.QuicSession.HeadersHOLBlockedTime "
+             << delta.ToMilliseconds();
+    spdy_session_->OnHeadersHeadOfLineBlocking(delta);
   }
+
+  prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_);
+  cur_max_timestamp_ = QuicTime::Zero();
   if (promised_stream_id_ == kInvalidStreamId) {
     spdy_session_->OnStreamHeaderList(stream_id_, fin_, frame_len_,
                                       header_list);
diff --git a/net/quic/core/quic_headers_stream.h b/net/quic/core/quic_headers_stream.h
index cd8288d9..872bf74 100644
--- a/net/quic/core/quic_headers_stream.h
+++ b/net/quic/core/quic_headers_stream.h
@@ -150,8 +150,6 @@
   size_t frame_len_;
   size_t uncompressed_frame_len_;
 
-  // Helper variables that cache the corresponding feature flag.
-  bool measure_headers_hol_blocking_time_;
   bool supports_push_promise_;
 
   // Timestamps used to measure HOL blocking, these are recorded by
diff --git a/net/quic/core/quic_headers_stream_test.cc b/net/quic/core/quic_headers_stream_test.cc
index 49e09fde..00fd09d9 100644
--- a/net/quic/core/quic_headers_stream_test.cc
+++ b/net/quic/core/quic_headers_stream_test.cc
@@ -208,7 +208,6 @@
         FLAGS_spdy_framer_use_new_methods2 = true;
         break;
     }
-    FLAGS_quic_supports_push_promise = true;
     FLAGS_quic_always_log_bugs_for_tests = true;
     VLOG(1) << "TestParams: version: " << QuicVersionToString(version)
             << ", perspective: " << perspective
@@ -533,9 +532,6 @@
 }
 
 TEST_P(QuicHeadersStreamTest, EmptyHeaderHOLBlockedTime) {
-  if (!FLAGS_quic_measure_headers_hol_blocking_time) {
-    return;
-  }
   EXPECT_CALL(session_, OnHeadersHeadOfLineBlocking(_)).Times(0);
   testing::InSequence seq;
   bool fin = true;
diff --git a/net/quic/core/quic_multipath_sent_packet_manager.cc b/net/quic/core/quic_multipath_sent_packet_manager.cc
index a11d959e..a3f9320 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager.cc
+++ b/net/quic/core/quic_multipath_sent_packet_manager.cc
@@ -202,7 +202,6 @@
 
 QuicTime::Delta QuicMultipathSentPacketManager::TimeUntilSend(
     QuicTime now,
-    HasRetransmittableData retransmittable,
     QuicPathId* path_id) {
   QuicTime::Delta delay = QuicTime::Delta::Infinite();
   *path_id = kInvalidPathId;
@@ -212,8 +211,8 @@
       continue;
     }
 
-    QuicTime::Delta path_delay = path_managers_info_[i].manager->TimeUntilSend(
-        now, retransmittable, path_id);
+    QuicTime::Delta path_delay =
+        path_managers_info_[i].manager->TimeUntilSend(now, path_id);
     if (!path_delay.IsInfinite() && path_delay < delay) {
       delay = path_delay;
       *path_id = i;
diff --git a/net/quic/core/quic_multipath_sent_packet_manager.h b/net/quic/core/quic_multipath_sent_packet_manager.h
index 0607e3f..46fe740 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager.h
+++ b/net/quic/core/quic_multipath_sent_packet_manager.h
@@ -98,9 +98,7 @@
 
   // Returns the earliest time the next packet can be sent. Sets |path_id| to be
   // the path on which the next packet should be sent.
-  QuicTime::Delta TimeUntilSend(QuicTime now,
-                                HasRetransmittableData retransmittable,
-                                QuicPathId* path_id) override;
+  QuicTime::Delta TimeUntilSend(QuicTime now, QuicPathId* path_id) override;
 
   // Returns the earliest retransmission time of all paths.
   const QuicTime GetRetransmissionTime() const override;
diff --git a/net/quic/core/quic_multipath_sent_packet_manager_test.cc b/net/quic/core/quic_multipath_sent_packet_manager_test.cc
index fa574c9..f7bd7187 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager_test.cc
+++ b/net/quic/core/quic_multipath_sent_packet_manager_test.cc
@@ -4,6 +4,7 @@
 
 #include "net/quic/core/quic_multipath_sent_packet_manager.h"
 
+#include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/test_tools/quic_multipath_sent_packet_manager_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "net/test/gtest_util.h"
@@ -35,6 +36,7 @@
         &multipath_manager_, manager_1_);
     QuicMultipathSentPacketManagerPeer::AddPathWithCloseState(
         &multipath_manager_, manager_2_);
+    FLAGS_quic_always_log_bugs_for_tests = true;
   }
 
   ~QuicMultipathSentPacketManagerTest() override {}
@@ -202,15 +204,12 @@
 
 TEST_F(QuicMultipathSentPacketManagerTest, TimeUntilSend) {
   QuicPathId path_id = kInvalidPathId;
-  EXPECT_CALL(*manager_0_,
-              TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id))
+  EXPECT_CALL(*manager_0_, TimeUntilSend(clock_.Now(), &path_id))
       .WillOnce(Return(QuicTime::Delta::FromMilliseconds(200)));
-  EXPECT_CALL(*manager_1_,
-              TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id))
+  EXPECT_CALL(*manager_1_, TimeUntilSend(clock_.Now(), &path_id))
       .WillOnce(Return(QuicTime::Delta::FromMilliseconds(100)));
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100),
-            multipath_manager_.TimeUntilSend(
-                clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+            multipath_manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_EQ(kTestPathId1, path_id);
 }
 
diff --git a/net/quic/core/quic_packet_creator.cc b/net/quic/core/quic_packet_creator.cc
index 90e16c4..285ad708 100644
--- a/net/quic/core/quic_packet_creator.cc
+++ b/net/quic/core/quic_packet_creator.cc
@@ -422,6 +422,7 @@
   CopyToBuffer(iov, iov_offset, bytes_consumed, stream_buffer.get());
   std::unique_ptr<QuicStreamFrame> frame(new QuicStreamFrame(
       id, set_fin, stream_offset, bytes_consumed, std::move(stream_buffer)));
+  DVLOG(1) << "Adding frame: " << *frame;
 
   // TODO(ianswett): AppendTypeByte and AppendStreamFrame could be optimized
   // into one method that takes a QuicStreamFrame, if warranted.
diff --git a/net/quic/core/quic_protocol.cc b/net/quic/core/quic_protocol.cc
index 78d0607..6b879458 100644
--- a/net/quic/core/quic_protocol.cc
+++ b/net/quic/core/quic_protocol.cc
@@ -819,6 +819,26 @@
                      length() - start_of_encrypted_data);
 }
 
+QuicVersionManager::QuicVersionManager(QuicVersionVector supported_versions) {
+  enable_quic_version_35_ = FLAGS_quic_enable_version_35;
+  enable_quic_version_36_ = FLAGS_quic_enable_version_36;
+  allowed_supported_versions_ = supported_versions;
+  filtered_supported_versions_ = FilterSupportedVersions(supported_versions);
+}
+
+const QuicVersionVector& QuicVersionManager::GetSupportedVersions() {
+  if (enable_quic_version_35_ != FLAGS_quic_enable_version_35 ||
+      enable_quic_version_36_ != FLAGS_quic_enable_version_36) {
+    enable_quic_version_35_ = FLAGS_quic_enable_version_35;
+    enable_quic_version_36_ = FLAGS_quic_enable_version_36;
+    filtered_supported_versions_ =
+        FilterSupportedVersions(allowed_supported_versions_);
+  }
+  return filtered_supported_versions_;
+}
+
+QuicVersionManager::~QuicVersionManager() {}
+
 AckListenerWrapper::AckListenerWrapper(QuicAckListenerInterface* listener,
                                        QuicPacketLength data_length)
     : ack_listener(listener), length(data_length) {
diff --git a/net/quic/core/quic_protocol.h b/net/quic/core/quic_protocol.h
index 7db6586..0ac0b33 100644
--- a/net/quic/core/quic_protocol.h
+++ b/net/quic/core/quic_protocol.h
@@ -212,6 +212,10 @@
 // duplicated.
 const size_t kDiversificationNonceSize = 32;
 
+// The largest gap in packets we'll accept without closing the connection.
+// This will likely have to be tuned.
+const QuicPacketNumber kMaxPacketGap = 5000;
+
 enum TransmissionType : int8_t {
   NOT_RETRANSMISSION,
   FIRST_TRANSMISSION_TYPE = NOT_RETRANSMISSION,
@@ -697,8 +701,12 @@
   // Network changed, but connection had one or more non-migratable streams.
   QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM = 84,
 
+  // Stream frames arrived too discontiguously so that stream sequencer buffer
+  // maintains too many gaps.
+  QUIC_TOO_MANY_FRAME_GAPS = 93,
+
   // No error. Used as bound while iterating.
-  QUIC_LAST_ERROR = 93,
+  QUIC_LAST_ERROR = 94,
 };
 
 typedef char DiversificationNonce[32];
@@ -1382,6 +1390,27 @@
                                     ConnectionCloseSource source) = 0;
 };
 
+// Used to generate filtered supported versions based on flags.
+class NET_EXPORT_PRIVATE QuicVersionManager {
+ public:
+  explicit QuicVersionManager(QuicVersionVector supported_versions);
+  ~QuicVersionManager();
+
+  // Returns supported versions based on flags.
+  const QuicVersionVector& GetSupportedVersions();
+
+ private:
+  // FLAGS_quic_enable_version_35
+  bool enable_quic_version_35_;
+  // FLAGS_quic_enable_version_36
+  bool enable_quic_version_36_;
+  // The list of versions that may be supported.
+  QuicVersionVector allowed_supported_versions_;
+  // This vector contains QUIC versions which are currently supported based
+  // on flags.
+  QuicVersionVector filtered_supported_versions_;
+};
+
 struct NET_EXPORT_PRIVATE AckListenerWrapper {
   AckListenerWrapper(QuicAckListenerInterface* listener,
                      QuicPacketLength data_length);
diff --git a/net/quic/core/quic_protocol_test.cc b/net/quic/core/quic_protocol_test.cc
index 31d652e..0626bfd0 100644
--- a/net/quic/core/quic_protocol_test.cc
+++ b/net/quic/core/quic_protocol_test.cc
@@ -300,6 +300,20 @@
   EXPECT_EQ(QUIC_VERSION_34, filtered_versions[4]);
 }
 
+TEST(QuicProtocolTest, QuicVersionManager) {
+  FLAGS_quic_enable_version_35 = false;
+  FLAGS_quic_enable_version_36 = false;
+  QuicVersionManager manager(QuicSupportedVersions());
+  EXPECT_EQ(FilterSupportedVersions(QuicSupportedVersions()),
+            manager.GetSupportedVersions());
+  FLAGS_quic_enable_version_35 = true;
+  FLAGS_quic_enable_version_36 = true;
+  EXPECT_EQ(FilterSupportedVersions(QuicSupportedVersions()),
+            manager.GetSupportedVersions());
+  EXPECT_EQ(QUIC_VERSION_36, manager.GetSupportedVersions()[0]);
+  EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[1]);
+}
+
 // Tests that a queue contains the expected data after calls to Add().
 TEST(PacketNumberQueueTest, AddRange) {
   PacketNumberQueue queue;
diff --git a/net/quic/core/quic_sent_packet_manager.cc b/net/quic/core/quic_sent_packet_manager.cc
index f122a1a6..6c618841 100644
--- a/net/quic/core/quic_sent_packet_manager.cc
+++ b/net/quic/core/quic_sent_packet_manager.cc
@@ -41,9 +41,6 @@
 // per draft RFC draft-dukkipati-tcpm-tcp-loss-probe.
 static const size_t kDefaultMaxTailLossProbes = 2;
 
-// Number of unpaced packets to send after quiescence.
-static const size_t kInitialUnpacedBurst = 10;
-
 bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
   DCHECK(!transmission_info.has_crypto_handshake ||
          !transmission_info.retransmittable_frames.empty());
@@ -90,6 +87,7 @@
       max_tail_loss_probes_(kDefaultMaxTailLossProbes),
       enable_half_rtt_tail_loss_probe_(false),
       using_pacing_(false),
+      using_inline_pacing_(false),
       use_new_rto_(false),
       undo_pending_retransmits_(false),
       largest_newly_acked_(0),
@@ -193,7 +191,9 @@
 }
 
 void QuicSentPacketManager::SetMaxPacingRate(QuicBandwidth max_pacing_rate) {
-  if (using_pacing_) {
+  if (using_inline_pacing_) {
+    pacing_sender_.SetMaxPacingRate(max_pacing_rate);
+  } else if (using_pacing_) {
     static_cast<PacingSender*>(send_algorithm_.get())
         ->SetMaxPacingRate(max_pacing_rate);
   }
@@ -281,8 +281,13 @@
   if (!rtt_updated && packets_acked_.empty() && packets_lost_.empty()) {
     return;
   }
-  send_algorithm_->OnCongestionEvent(rtt_updated, bytes_in_flight,
+  if (using_inline_pacing_) {
+    pacing_sender_.OnCongestionEvent(rtt_updated, bytes_in_flight,
                                      packets_acked_, packets_lost_);
+  } else {
+    send_algorithm_->OnCongestionEvent(rtt_updated, bytes_in_flight,
+                                       packets_acked_, packets_lost_);
+  }
   packets_acked_.clear();
   packets_lost_.clear();
   if (network_change_visitor_ != nullptr) {
@@ -558,10 +563,16 @@
     --pending_timer_transmission_count_;
   }
 
-  // TODO(ianswett): Remove sent_time, because it's unused.
-  const bool in_flight = send_algorithm_->OnPacketSent(
-      sent_time, unacked_packets_.bytes_in_flight(), packet_number,
-      serialized_packet->encrypted_length, has_retransmittable_data);
+  bool in_flight;
+  if (using_inline_pacing_) {
+    in_flight = pacing_sender_.OnPacketSent(
+        sent_time, unacked_packets_.bytes_in_flight(), packet_number,
+        serialized_packet->encrypted_length, has_retransmittable_data);
+  } else {
+    in_flight = send_algorithm_->OnPacketSent(
+        sent_time, unacked_packets_.bytes_in_flight(), packet_number,
+        serialized_packet->encrypted_length, has_retransmittable_data);
+  }
 
   unacked_packets_.AddSentPacket(serialized_packet, original_packet_number,
                                  transmission_type, sent_time, in_flight);
@@ -766,18 +777,21 @@
   return true;
 }
 
-QuicTime::Delta QuicSentPacketManager::TimeUntilSend(
-    QuicTime now,
-    HasRetransmittableData retransmittable,
-    QuicPathId* path_id) {
+QuicTime::Delta QuicSentPacketManager::TimeUntilSend(QuicTime now,
+                                                     QuicPathId* path_id) {
   QuicTime::Delta delay = QuicTime::Delta::Infinite();
   // The TLP logic is entirely contained within QuicSentPacketManager, so the
   // send algorithm does not need to be consulted.
   if (pending_timer_transmission_count_ > 0) {
     delay = QuicTime::Delta::Zero();
   } else {
-    delay =
-        send_algorithm_->TimeUntilSend(now, unacked_packets_.bytes_in_flight());
+    if (using_inline_pacing_) {
+      delay =
+          pacing_sender_.TimeUntilSend(now, unacked_packets_.bytes_in_flight());
+    } else {
+      delay = send_algorithm_->TimeUntilSend(
+          now, unacked_packets_.bytes_in_flight());
+    }
   }
   if (!delay.IsInfinite()) {
     *path_id = path_id_;
@@ -924,18 +938,23 @@
 }
 
 void QuicSentPacketManager::EnablePacing() {
-  // TODO(ianswett): Replace with a method which wraps the send algorithm in a
-  // pacer every time a new algorithm is set.
-  if (using_pacing_) {
-    return;
-  }
+  if (FLAGS_quic_use_inline_pacing) {
+    using_inline_pacing_ = true;
+    pacing_sender_.SetSender(send_algorithm_.get(), false);
+  } else {
+    // TODO(ianswett): Replace with a method which wraps the send algorithm in a
+    // pacer every time a new algorithm is set.
+    if (using_pacing_) {
+      return;
+    }
 
-  // Set up a pacing sender with a 1 millisecond alarm granularity, the same as
-  // the default granularity of the Linux kernel's FQ qdisc.
-  using_pacing_ = true;
-  send_algorithm_.reset(new PacingSender(send_algorithm_.release(),
-                                         QuicTime::Delta::FromMilliseconds(1),
-                                         kInitialUnpacedBurst));
+    // Set up a pacing sender with a 1 millisecond alarm granularity, the same
+    // as the default granularity of the Linux kernel's FQ qdisc.
+    using_pacing_ = true;
+    PacingSender* pacing_sender = new PacingSender;
+    pacing_sender->SetSender(send_algorithm_.release(), true);
+    send_algorithm_.reset(pacing_sender);
+  }
 }
 
 void QuicSentPacketManager::OnConnectionMigration(QuicPathId,
@@ -967,6 +986,7 @@
   return unacked_packets_.largest_sent_packet();
 }
 
+// Remove this method when deprecating QUIC_VERSION_33.
 QuicPacketNumber QuicSentPacketManager::GetLeastPacketAwaitedByPeer(
     QuicPathId) const {
   return least_packet_awaited_by_peer_;
diff --git a/net/quic/core/quic_sent_packet_manager.h b/net/quic/core/quic_sent_packet_manager.h
index 0cdd733e..a875bc9 100644
--- a/net/quic/core/quic_sent_packet_manager.h
+++ b/net/quic/core/quic_sent_packet_manager.h
@@ -16,6 +16,7 @@
 #include "base/macros.h"
 #include "net/base/linked_hash_map.h"
 #include "net/quic/core/congestion_control/loss_detection_interface.h"
+#include "net/quic/core/congestion_control/pacing_sender.h"
 #include "net/quic/core/congestion_control/rtt_stats.h"
 #include "net/quic/core/congestion_control/send_algorithm_interface.h"
 #include "net/quic/core/quic_protocol.h"
@@ -143,9 +144,7 @@
   // TimeUntilSend again until we receive an OnIncomingAckFrame event.
   // Note 2: Send algorithms may or may not use |retransmit| in their
   // calculations.
-  QuicTime::Delta TimeUntilSend(QuicTime now,
-                                HasRetransmittableData retransmittable,
-                                QuicPathId* path_id) override;
+  QuicTime::Delta TimeUntilSend(QuicTime now, QuicPathId* path_id) override;
 
   // Returns the current delay for the retransmission timer, which may send
   // either a tail loss probe or do a full RTO.  Returns QuicTime::Zero() if
@@ -369,6 +368,10 @@
   // If true, send the TLP at 0.5 RTT.
   bool enable_half_rtt_tail_loss_probe_;
   bool using_pacing_;
+  // TODO(jdorfman): Remove |using_pacing_| and rename |using_inline_pacing_| to
+  // |using_pacing| when deprecating
+  // gfe2_reloadable_flag_quic_use_inline_pacing.
+  bool using_inline_pacing_;
   // If true, use the new RTO with loss based CWND reduction instead of the send
   // algorithms's OnRetransmissionTimeout to reduce the congestion window.
   bool use_new_rto_;
@@ -384,6 +387,8 @@
   // Largest packet in bytes ever acknowledged.
   QuicPacketLength largest_mtu_acked_;
 
+  PacingSender pacing_sender_;
+
   // Set to true after the crypto handshake has successfully completed. After
   // this is true we no longer use HANDSHAKE_MODE, and further frames sent on
   // the crypto stream (i.e. SCUP messages) are treated like normal
diff --git a/net/quic/core/quic_sent_packet_manager_interface.h b/net/quic/core/quic_sent_packet_manager_interface.h
index 30a48d3..e1f9d48 100644
--- a/net/quic/core/quic_sent_packet_manager_interface.h
+++ b/net/quic/core/quic_sent_packet_manager_interface.h
@@ -116,9 +116,7 @@
 
   // Returns the earliest time we can send the next packet. Sets |path_id| to be
   // the path on which the next packet will be sent.
-  virtual QuicTime::Delta TimeUntilSend(QuicTime now,
-                                        HasRetransmittableData retransmittable,
-                                        QuicPathId* path_id) = 0;
+  virtual QuicTime::Delta TimeUntilSend(QuicTime now, QuicPathId* path_id) = 0;
 
   // Returns the earliest retransmission time of all paths.
   // TODO(fayang): This method should not be const becasue the return value
diff --git a/net/quic/core/quic_sent_packet_manager_test.cc b/net/quic/core/quic_sent_packet_manager_test.cc
index 2b6f595..3e7c4502 100644
--- a/net/quic/core/quic_sent_packet_manager_test.cc
+++ b/net/quic/core/quic_sent_packet_manager_test.cc
@@ -708,9 +708,8 @@
   QuicPathId path_id = kInvalidPathId;
   // The first tail loss probe retransmits 1 packet.
   manager_.OnRetransmissionTimeout();
-  EXPECT_EQ(
-      QuicTime::Delta::Zero(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Zero(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
   manager_.MaybeRetransmitTailLossProbe();
   EXPECT_TRUE(manager_.HasPendingRetransmissions());
@@ -719,18 +718,16 @@
 
   // The second tail loss probe retransmits 1 packet.
   manager_.OnRetransmissionTimeout();
-  EXPECT_EQ(
-      QuicTime::Delta::Zero(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Zero(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
   manager_.MaybeRetransmitTailLossProbe();
   EXPECT_TRUE(manager_.HasPendingRetransmissions());
   RetransmitNextPacket(3);
   EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
       .WillOnce(Return(QuicTime::Delta::Infinite()));
-  EXPECT_EQ(
-      QuicTime::Delta::Infinite(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Infinite(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
 
   // Ack the third and ensure the first two are still pending.
@@ -773,35 +770,31 @@
   // The first tail loss probe retransmits 1 packet.
   manager_.OnRetransmissionTimeout();
   QuicPathId path_id = kInvalidPathId;
-  EXPECT_EQ(
-      QuicTime::Delta::Zero(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Zero(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
   manager_.MaybeRetransmitTailLossProbe();
   EXPECT_TRUE(manager_.HasPendingRetransmissions());
   RetransmitNextPacket(101);
   EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
       .WillOnce(Return(QuicTime::Delta::Infinite()));
-  EXPECT_EQ(
-      QuicTime::Delta::Infinite(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Infinite(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
   clock_.AdvanceTime(manager_.GetRetransmissionTime() - clock_.Now());
 
   // The second tail loss probe retransmits 1 packet.
   manager_.OnRetransmissionTimeout();
-  EXPECT_EQ(
-      QuicTime::Delta::Zero(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Zero(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
   EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe());
   EXPECT_TRUE(manager_.HasPendingRetransmissions());
   RetransmitNextPacket(102);
   EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
       .WillOnce(Return(QuicTime::Delta::Infinite()));
-  EXPECT_EQ(
-      QuicTime::Delta::Infinite(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Infinite(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
 
   // Ensure the RTO is set based on the correct packet.
   rto_packet_time = clock_.Now();
@@ -849,9 +842,8 @@
   // The first retransmits 2 packets.
   QuicPathId path_id = kInvalidPathId;
   manager_.OnRetransmissionTimeout();
-  EXPECT_EQ(
-      QuicTime::Delta::Zero(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Zero(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   RetransmitNextPacket(6);
   RetransmitNextPacket(7);
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -859,9 +851,8 @@
 
   // The second retransmits 2 packets.
   manager_.OnRetransmissionTimeout();
-  EXPECT_EQ(
-      QuicTime::Delta::Zero(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Zero(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   RetransmitNextPacket(8);
   RetransmitNextPacket(9);
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -1241,18 +1232,16 @@
   clock_.AdvanceTime(expected_tlp_delay);
   manager_.OnRetransmissionTimeout();
   QuicPathId path_id = kInvalidPathId;
-  EXPECT_EQ(
-      QuicTime::Delta::Zero(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Zero(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
   EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe());
   EXPECT_TRUE(manager_.HasPendingRetransmissions());
   RetransmitNextPacket(3);
   EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
       .WillOnce(Return(QuicTime::Delta::Infinite()));
-  EXPECT_EQ(
-      QuicTime::Delta::Infinite(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
+  EXPECT_EQ(QuicTime::Delta::Infinite(),
+            manager_.TimeUntilSend(clock_.Now(), &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
 
   expected_time = clock_.Now() + expected_tlp_delay;
diff --git a/net/quic/core/quic_session_test.cc b/net/quic/core/quic_session_test.cc
index 0645c474d..64de93e 100644
--- a/net/quic/core/quic_session_test.cc
+++ b/net/quic/core/quic_session_test.cc
@@ -1186,8 +1186,6 @@
 }
 
 TEST_P(QuicSessionTestClient, EnableDHDTThroughConnectionOption) {
-  FLAGS_quic_disable_hpack_dynamic_table = true;
-
   QuicTagVector copt;
   copt.push_back(kDHDT);
   QuicConfigPeer::SetConnectionOptionsToSend(session_.config(), copt);
diff --git a/net/quic/core/quic_spdy_session.cc b/net/quic/core/quic_spdy_session.cc
index e8b85c9..65bfadeb 100644
--- a/net/quic/core/quic_spdy_session.cc
+++ b/net/quic/core/quic_spdy_session.cc
@@ -149,8 +149,7 @@
 
 void QuicSpdySession::OnConfigNegotiated() {
   QuicSession::OnConfigNegotiated();
-  if (FLAGS_quic_disable_hpack_dynamic_table &&
-      config()->HasClientSentConnectionOption(kDHDT, perspective())) {
+  if (config()->HasClientSentConnectionOption(kDHDT, perspective())) {
     headers_stream_->DisableHpackDynamicTable();
   }
   const QuicVersion version = connection()->version();
diff --git a/net/quic/core/quic_spdy_stream.cc b/net/quic/core/quic_spdy_stream.cc
index 196d6532..a6323cb 100644
--- a/net/quic/core/quic_spdy_stream.cc
+++ b/net/quic/core/quic_spdy_stream.cc
@@ -355,6 +355,16 @@
   }
 }
 
+void QuicSpdyStream::OnCanWrite() {
+  ReliableQuicStream::OnCanWrite();
+
+  // Trailers (and hence a FIN) may have been sent ahead of queued body bytes.
+  if (FLAGS_quic_close_stream_after_writing_queued_data && !HasBufferedData() &&
+      fin_sent()) {
+    CloseWriteSide();
+  }
+}
+
 bool QuicSpdyStream::FinishedReadingHeaders() const {
   return headers_decompressed_ && decompressed_headers_.empty() &&
          header_list_.empty();
diff --git a/net/quic/core/quic_spdy_stream.h b/net/quic/core/quic_spdy_stream.h
index 279b6dd..acbf8c0 100644
--- a/net/quic/core/quic_spdy_stream.h
+++ b/net/quic/core/quic_spdy_stream.h
@@ -75,6 +75,9 @@
   // ReliableQuicStream implementation
   void OnClose() override;
 
+  // Override to maybe close the write side after writing.
+  void OnCanWrite() override;
+
   // Called by the session when decompressed headers data is received
   // for this stream.
   // May be called multiple times, with each call providing additional headers
diff --git a/net/quic/core/quic_spdy_stream_test.cc b/net/quic/core/quic_spdy_stream_test.cc
index 6e433e5..ced5e17 100644
--- a/net/quic/core/quic_spdy_stream_test.cc
+++ b/net/quic/core/quic_spdy_stream_test.cc
@@ -971,6 +971,15 @@
   if (!session_->force_hol_blocking()) {
     EXPECT_FALSE(stream_->write_side_closed());
   }
+
+  if (!FLAGS_quic_close_stream_after_writing_queued_data) {
+    return;
+  }
+  // Writing the queued bytes will close the write side of the stream.
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+      .WillOnce(Return(QuicConsumedData(1, false)));
+  stream_->OnCanWrite();
+  EXPECT_TRUE(stream_->write_side_closed());
 }
 
 TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) {
diff --git a/net/quic/core/quic_stream_sequencer_buffer.cc b/net/quic/core/quic_stream_sequencer_buffer.cc
index 99cf594..011a016d 100644
--- a/net/quic/core/quic_stream_sequencer_buffer.cc
+++ b/net/quic/core/quic_stream_sequencer_buffer.cc
@@ -13,11 +13,19 @@
 using std::string;
 
 namespace net {
+namespace {
+
+// Upper limit of how many gaps allowed in buffer, which ensures a reasonable
+// number of iterations needed to find the right gap to fill when a frame
+// arrives.
+const size_t kMaxNumGapsAllowed = 2 * kMaxPacketGap;
+
+}  // namespace
 
 namespace {
 
 string RangeDebugString(QuicStreamOffset start, QuicStreamOffset end) {
-  return string("[") + base::Uint64ToString(start) + ", " +
+  return std::string("[") + base::Uint64ToString(start) + ", " +
          base::Uint64ToString(end) + ") ";
 }
 
@@ -131,6 +139,16 @@
     return QUIC_INTERNAL_ERROR;
   }
 
+  if (FLAGS_quic_limit_frame_gaps_in_buffer &&
+      current_gap->begin_offset != starting_offset &&
+      current_gap->end_offset != starting_offset + data.length() &&
+      gaps_.size() >= kMaxNumGapsAllowed) {
+    // This frame is going to create one more gap which exceeds max number of
+    // gaps allowed. Stop processing.
+    *error_details = "Too many gaps created for this stream.";
+    return QUIC_TOO_MANY_FRAME_GAPS;
+  }
+
   size_t total_written = 0;
   size_t source_remaining = size;
   const char* source = data.data();
diff --git a/net/quic/core/quic_stream_sequencer_buffer_test.cc b/net/quic/core/quic_stream_sequencer_buffer_test.cc
index 655b13a..7c22bfe2 100644
--- a/net/quic/core/quic_stream_sequencer_buffer_test.cc
+++ b/net/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -47,6 +47,8 @@
   return '\0';
 }
 
+const size_t kMaxNumGapsAllowed = 2 * kMaxPacketGap;
+
 static const size_t kBlockSizeBytes =
     QuicStreamSequencerBuffer::kBlockSizeBytes;
 typedef QuicStreamSequencerBuffer::BufferBlock BufferBlock;
@@ -831,6 +833,26 @@
   EXPECT_TRUE(helper_->CheckBufferInvariants());
 }
 
+TEST_F(QuicStreamSequencerBufferTest, TooManyGaps) {
+  FLAGS_quic_limit_frame_gaps_in_buffer = true;
+  // Make sure max capacity is large enough that it is possible to have more
+  // than |kMaxNumGapsAllowed| number of gaps.
+  max_capacity_bytes_ = 3 * kBlockSizeBytes;
+  // Feed buffer with 1-byte discontiguous frames. e.g. [1,2), [3,4), [5,6)...
+  for (QuicStreamOffset begin = 1; begin <= max_capacity_bytes_; begin += 2) {
+    size_t written;
+    QuicErrorCode rs = buffer_->OnStreamData(
+        begin, "a", clock_.ApproximateNow(), &written, &error_details_);
+
+    QuicStreamOffset last_straw = 2 * kMaxNumGapsAllowed - 1;
+    if (begin == last_straw) {
+      EXPECT_EQ(QUIC_TOO_MANY_FRAME_GAPS, rs);
+      EXPECT_EQ("Too many gaps created for this stream.", error_details_);
+      break;
+    }
+  }
+}
+
 class QuicStreamSequencerBufferRandomIOTest
     : public QuicStreamSequencerBufferTest {
  public:
diff --git a/net/quic/core/quic_time.cc b/net/quic/core/quic_time.cc
index 8c9239f..c9e72ce 100644
--- a/net/quic/core/quic_time.cc
+++ b/net/quic/core/quic_time.cc
@@ -4,12 +4,34 @@
 
 #include "net/quic/core/quic_time.h"
 
+#include <cinttypes>
+#include <cstdlib>
 #include <limits>
 
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
+
+using base::StringPrintf;
 
 namespace net {
 
+std::string QuicTime::Delta::ToDebugValue() const {
+  const int64_t one_ms = 1000;
+  const int64_t one_s = 1000 * one_ms;
+
+  int64_t absolute_value = std::abs(time_offset_);
+
+  // For debugging purposes, always display the value with the highest precision
+  // available.
+  if (absolute_value > one_s && absolute_value % one_s == 0) {
+    return StringPrintf("%" PRId64 "s", time_offset_ / one_s);
+  }
+  if (absolute_value > one_ms && absolute_value % one_ms == 0) {
+    return StringPrintf("%" PRId64 "ms", time_offset_ / one_ms);
+  }
+  return StringPrintf("%" PRId64 "us", time_offset_);
+}
+
 uint64_t QuicWallTime::ToUNIXSeconds() const {
   return microseconds_ / 1000000;
 }
diff --git a/net/quic/core/quic_time.h b/net/quic/core/quic_time.h
index ffdbb80..9e1e238 100644
--- a/net/quic/core/quic_time.h
+++ b/net/quic/core/quic_time.h
@@ -13,6 +13,8 @@
 
 #include <stdint.h>
 
+#include <ostream>
+
 #include "base/compiler_specific.h"
 #include "base/time/time.h"
 #include "net/base/net_export.h"
@@ -76,6 +78,8 @@
       return time_offset_ == kQuicInfiniteTimeUs;
     }
 
+    std::string ToDebugValue() const;
+
    private:
     base::TimeDelta delta_;
     friend inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs);
@@ -263,6 +267,12 @@
   return QuicTime::Delta(lhs.time_ - rhs.time_);
 }
 
+// Override stream output operator for gtest.
+inline std::ostream& operator<<(std::ostream& output,
+                                const QuicTime::Delta delta) {
+  output << delta.ToDebugValue();
+  return output;
+}
 }  // namespace net
 
 #endif  // NET_QUIC_QUIC_TIME_H_
diff --git a/net/quic/core/quic_time_test.cc b/net/quic/core/quic_time_test.cc
index 42ab0e0..49dcc174 100644
--- a/net/quic/core/quic_time_test.cc
+++ b/net/quic/core/quic_time_test.cc
@@ -74,6 +74,20 @@
                QuicTime::Delta::FromSeconds(0));
 }
 
+TEST(QuicTimeDeltaTest, DebugValue) {
+  const QuicTime::Delta one_us = QuicTime::Delta::FromMicroseconds(1);
+  const QuicTime::Delta one_ms = QuicTime::Delta::FromMilliseconds(1);
+  const QuicTime::Delta one_s = QuicTime::Delta::FromSeconds(1);
+
+  EXPECT_EQ("3s", (3 * one_s).ToDebugValue());
+  EXPECT_EQ("3ms", (3 * one_ms).ToDebugValue());
+  EXPECT_EQ("3us", (3 * one_us).ToDebugValue());
+
+  EXPECT_EQ("3001us", (3 * one_ms + one_us).ToDebugValue());
+  EXPECT_EQ("3001ms", (3 * one_s + one_ms).ToDebugValue());
+  EXPECT_EQ("3000001us", (3 * one_s + one_us).ToDebugValue());
+}
+
 class QuicTimeTest : public ::testing::Test {
  protected:
   MockClock clock_;
diff --git a/net/quic/core/quic_utils.cc b/net/quic/core/quic_utils.cc
index 130a91c3..25cb2d4 100644
--- a/net/quic/core/quic_utils.cc
+++ b/net/quic/core/quic_utils.cc
@@ -301,6 +301,7 @@
     RETURN_STRING_LITERAL(QUIC_CRYPTO_CHLO_TOO_LARGE);
     RETURN_STRING_LITERAL(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST);
     RETURN_STRING_LITERAL(QUIC_MULTIPATH_PATH_NOT_ACTIVE);
+    RETURN_STRING_LITERAL(QUIC_TOO_MANY_FRAME_GAPS);
     RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
     // Intentionally have no default case, so we'll break the build
     // if we add errors and don't put them here.
diff --git a/net/quic/core/reliable_quic_stream.cc b/net/quic/core/reliable_quic_stream.cc
index b594bad..7ea3c01 100644
--- a/net/quic/core/reliable_quic_stream.cc
+++ b/net/quic/core/reliable_quic_stream.cc
@@ -106,7 +106,7 @@
 
   // Flow control is interested in tracking highest received offset.
   // Only interested in received frames that carry data.
-  if ((!FLAGS_quic_ignore_zero_length_frames || frame_payload_size > 0) &&
+  if (frame_payload_size > 0 &&
       MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) {
     // As the highest received offset has changed, check to see if this is a
     // violation of flow control.
diff --git a/net/quic/core/reliable_quic_stream_test.cc b/net/quic/core/reliable_quic_stream_test.cc
index 0e38d2a..18b9e16 100644
--- a/net/quic/core/reliable_quic_stream_test.cc
+++ b/net/quic/core/reliable_quic_stream_test.cc
@@ -620,25 +620,17 @@
       StringPiece());
   EXPECT_EQ(0, zero_length_stream_frame_with_fin.data_length);
 
-  if (FLAGS_quic_ignore_zero_length_frames) {
-    EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
-  } else {
-    EXPECT_CALL(*connection_,
-                CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _))
-        .Times(1);
-  }
+  EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
   stream_->OnStreamFrame(zero_length_stream_frame_with_fin);
   EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
 
-  if (FLAGS_quic_ignore_zero_length_frames) {
-    // The flow control receive offset values should not have changed.
-    EXPECT_EQ(current_stream_flow_control_offset,
-              QuicFlowControllerPeer::ReceiveWindowOffset(
-                  stream_->flow_controller()));
-    EXPECT_EQ(current_connection_flow_control_offset,
-              QuicFlowControllerPeer::ReceiveWindowOffset(
-                  session_->flow_controller()));
-  }
+  // The flow control receive offset values should not have changed.
+  EXPECT_EQ(
+      current_stream_flow_control_offset,
+      QuicFlowControllerPeer::ReceiveWindowOffset(stream_->flow_controller()));
+  EXPECT_EQ(
+      current_connection_flow_control_offset,
+      QuicFlowControllerPeer::ReceiveWindowOffset(session_->flow_controller()));
 }
 
 TEST_F(ReliableQuicStreamTest, SetDrainingIncomingOutgoing) {
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index cbbe354..f285e254 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -524,8 +524,8 @@
   std::unique_ptr<ProofSource> proof_source(
       CryptoTestUtils::ProofSourceForTesting());
   if (!proof_source->GetProof(server_ip, "", "",
-                              QuicSupportedVersions().front(), "", false,
-                              &chain, &sig, &cert_sct) ||
+                              QuicSupportedVersions().front(), "", &chain, &sig,
+                              &cert_sct) ||
       chain->certs.empty()) {
     DCHECK(false) << "Proof generation failed";
     return 0;
diff --git a/net/quic/test_tools/mock_quic_dispatcher.cc b/net/quic/test_tools/mock_quic_dispatcher.cc
index 7e051ea..8cb38ef 100644
--- a/net/quic/test_tools/mock_quic_dispatcher.cc
+++ b/net/quic/test_tools/mock_quic_dispatcher.cc
@@ -12,15 +12,16 @@
 MockQuicDispatcher::MockQuicDispatcher(
     const QuicConfig& config,
     const QuicCryptoServerConfig* crypto_config,
+    QuicVersionManager* version_manager,
     std::unique_ptr<QuicConnectionHelperInterface> helper,
     std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
     std::unique_ptr<QuicAlarmFactory> alarm_factory)
-    : QuicDispatcher(config,
-                     crypto_config,
-                     QuicSupportedVersions(),
-                     std::move(helper),
-                     std::move(session_helper),
-                     std::move(alarm_factory)) {}
+    : QuicSimpleDispatcher(config,
+                           crypto_config,
+                           version_manager,
+                           std::move(helper),
+                           std::move(session_helper),
+                           std::move(alarm_factory)) {}
 
 MockQuicDispatcher::~MockQuicDispatcher() {}
 
diff --git a/net/quic/test_tools/mock_quic_dispatcher.h b/net/quic/test_tools/mock_quic_dispatcher.h
index 2391f58..4084b4de 100644
--- a/net/quic/test_tools/mock_quic_dispatcher.h
+++ b/net/quic/test_tools/mock_quic_dispatcher.h
@@ -10,17 +10,18 @@
 #include "net/quic/core/crypto/quic_crypto_server_config.h"
 #include "net/quic/core/quic_config.h"
 #include "net/quic/core/quic_protocol.h"
-#include "net/tools/quic/quic_dispatcher.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace net {
 namespace test {
 
-class MockQuicDispatcher : public QuicDispatcher {
+class MockQuicDispatcher : public QuicSimpleDispatcher {
  public:
   MockQuicDispatcher(
       const QuicConfig& config,
       const QuicCryptoServerConfig* crypto_config,
+      QuicVersionManager* version_manager,
       std::unique_ptr<QuicConnectionHelperInterface> helper,
       std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
       std::unique_ptr<QuicAlarmFactory> alarm_factory);
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index 916f5f0..fd2a3afe 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -28,6 +28,7 @@
     SendAlgorithmInterface* send_algorithm) {
   GetSentPacketManager(connection, path_id)
       ->send_algorithm_.reset(send_algorithm);
+  GetSentPacketManager(connection, path_id)->using_inline_pacing_ = false;
 }
 
 // static
diff --git a/net/quic/test_tools/quic_sent_packet_manager_peer.cc b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
index 00402ae..b3ad0b5 100644
--- a/net/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -69,6 +69,7 @@
     QuicSentPacketManager* sent_packet_manager,
     SendAlgorithmInterface* send_algorithm) {
   sent_packet_manager->send_algorithm_.reset(send_algorithm);
+  sent_packet_manager->using_inline_pacing_ = false;
 }
 
 // static
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 44db134..edf176ee 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -927,8 +927,7 @@
                     TransmissionType,
                     HasRetransmittableData));
   MOCK_METHOD0(OnRetransmissionTimeout, void(void));
-  MOCK_METHOD3(TimeUntilSend,
-               QuicTime::Delta(QuicTime, HasRetransmittableData, QuicPathId*));
+  MOCK_METHOD2(TimeUntilSend, QuicTime::Delta(QuicTime, QuicPathId*));
   MOCK_CONST_METHOD0(GetRetransmissionTime, const QuicTime(void));
   MOCK_CONST_METHOD0(GetRttStats, const RttStats*(void));
   MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void));
diff --git a/net/test/embedded_test_server/android/embedded_test_server_android.cc b/net/test/embedded_test_server/android/embedded_test_server_android.cc
index 3a43e497..0d2ce061 100644
--- a/net/test/embedded_test_server/android/embedded_test_server_android.cc
+++ b/net/test/embedded_test_server/android/embedded_test_server_android.cc
@@ -12,6 +12,8 @@
 #include "base/trace_event/trace_event.h"
 #include "net/test/jni/EmbeddedTestServerImpl_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace net {
 namespace test_server {
 
diff --git a/net/tools/balsa/balsa_headers.cc b/net/tools/balsa/balsa_headers.cc
index 0ad88c52..abac006b 100644
--- a/net/tools/balsa/balsa_headers.cc
+++ b/net/tools/balsa/balsa_headers.cc
@@ -770,6 +770,12 @@
   DumpHeadersToString(str);
 }
 
+std::string BalsaHeaders::DebugString() const {
+  std::string s;
+  DumpToString(&s);
+  return s;
+}
+
 void BalsaHeaders::DumpHeadersToString(std::string* str) const {
   const base::StringPiece firstline = first_line();
   // If the header is complete, then just dump them with the logical key value
diff --git a/net/tools/balsa/balsa_headers.h b/net/tools/balsa/balsa_headers.h
index a67e743..d796e9a 100644
--- a/net/tools/balsa/balsa_headers.h
+++ b/net/tools/balsa/balsa_headers.h
@@ -828,6 +828,7 @@
   // object is not completely parsed, e.g., when there was an error in the
   // middle of parsing.
   void DumpToString(std::string* str) const;
+  std::string DebugString() const;
 
   const base::StringPiece first_line() const {
     DCHECK_GE(whitespace_4_idx_, non_whitespace_1_idx_);
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 9a53dadf..c6156a6 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -2429,7 +2429,6 @@
   const size_t kNumMaxStreams = 10;
 
   EndToEndTestServerPush() : EndToEndTest() {
-    FLAGS_quic_supports_push_promise = true;
     client_config_.SetMaxStreamsPerConnection(kNumMaxStreams, kNumMaxStreams);
     client_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams);
     server_config_.SetMaxStreamsPerConnection(kNumMaxStreams, kNumMaxStreams);
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 4ef4670..6100b59 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -187,7 +187,7 @@
 QuicDispatcher::QuicDispatcher(
     const QuicConfig& config,
     const QuicCryptoServerConfig* crypto_config,
-    const QuicVersionVector& supported_versions,
+    QuicVersionManager* version_manager,
     std::unique_ptr<QuicConnectionHelperInterface> helper,
     std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
     std::unique_ptr<QuicAlarmFactory> alarm_factory)
@@ -201,10 +201,9 @@
       delete_sessions_alarm_(
           alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))),
       buffered_packets_(this, helper_->GetClock(), alarm_factory_.get()),
-      supported_versions_(supported_versions),
-      allowed_supported_versions_(supported_versions),
       current_packet_(nullptr),
-      framer_(supported_versions,
+      version_manager_(version_manager),
+      framer_(GetSupportedVersions(),
               /*unused*/ QuicTime::Zero(),
               Perspective::IS_SERVER),
       last_error_(QUIC_NO_ERROR) {
@@ -609,22 +608,6 @@
     QuicConnectionId connection_id,
     QuicBufferedPacketStore::BufferedPacketList early_arrived_packets) {}
 
-QuicServerSessionBase* QuicDispatcher::CreateQuicSession(
-    QuicConnectionId connection_id,
-    const IPEndPoint& client_address) {
-  // The QuicServerSessionBase takes ownership of |connection| below.
-  QuicConnection* connection = new QuicConnection(
-      connection_id, client_address, helper_.get(), alarm_factory_.get(),
-      CreatePerConnectionWriter(),
-      /* owns_writer= */ true, Perspective::IS_SERVER, GetSupportedVersions());
-
-  QuicServerSessionBase* session = new QuicSimpleServerSession(
-      config_, connection, this, session_helper_.get(), crypto_config_,
-      &compressed_certs_cache_);
-  session->Initialize();
-  return session;
-}
-
 void QuicDispatcher::OnConnectionRejectedStatelessly() {}
 
 void QuicDispatcher::OnConnectionClosedStatelessly(QuicErrorCode error) {}
@@ -680,13 +663,13 @@
   }
 
   StatelessRejector rejector(header.public_header.versions.front(),
-                             supported_versions_, crypto_config_,
+                             GetSupportedVersions(), crypto_config_,
                              &compressed_certs_cache_, helper()->GetClock(),
                              helper()->GetRandomGenerator(),
                              current_client_address_, current_server_address_);
   ChloValidator validator(session_helper_.get(), current_server_address_,
                           &rejector);
-  if (!ChloExtractor::Extract(*current_packet_, supported_versions_,
+  if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
                               &validator)) {
     DVLOG(1) << "Buffering undecryptable packet.";
     buffered_packets_.EnqueuePacket(connection_id, *current_packet_,
@@ -739,13 +722,7 @@
 }
 
 const QuicVersionVector& QuicDispatcher::GetSupportedVersions() {
-  // Filter (or un-filter) the list of supported versions based on the flag.
-  if (false) {
-    DCHECK_EQ(supported_versions_.capacity(),
-              allowed_supported_versions_.capacity());
-    supported_versions_ = FilterSupportedVersions(allowed_supported_versions_);
-  }
-  return supported_versions_;
+  return version_manager_->GetSupportedVersions();
 }
 
 }  // namespace net
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 4b2a19c..8c1cfca 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -49,7 +49,7 @@
 
   QuicDispatcher(const QuicConfig& config,
                  const QuicCryptoServerConfig* crypto_config,
-                 const QuicVersionVector& supported_versions,
+                 QuicVersionManager* version_manager,
                  std::unique_ptr<QuicConnectionHelperInterface> helper,
                  std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
                  std::unique_ptr<QuicAlarmFactory> alarm_factory);
@@ -149,7 +149,7 @@
  protected:
   virtual QuicServerSessionBase* CreateQuicSession(
       QuicConnectionId connection_id,
-      const IPEndPoint& client_address);
+      const IPEndPoint& client_address) = 0;
 
   // Called when a connection is rejected statelessly.
   virtual void OnConnectionRejectedStatelessly();
@@ -189,6 +189,7 @@
 
   const QuicVersionVector& GetSupportedVersions();
 
+  QuicConnectionId current_connection_id() { return current_connection_id_; }
   const IPEndPoint& current_server_address() { return current_server_address_; }
   const IPEndPoint& current_client_address() { return current_client_address_; }
   const QuicReceivedPacket& current_packet() { return *current_packet_; }
@@ -286,23 +287,15 @@
   // created to handle them.
   QuicBufferedPacketStore buffered_packets_;
 
-  // This vector contains QUIC versions which we currently support.
-  // This should be ordered such that the highest supported version is the first
-  // element, with subsequent elements in descending order (versions can be
-  // skipped as necessary).
-  QuicVersionVector supported_versions_;
-
-  // The std::list of versions that may be supported by this dispatcher.
-  // |supported_versions| is derived from this std::list and
-  // |disable_quic_pre_30_|.
-  const QuicVersionVector allowed_supported_versions_;
-
   // Information about the packet currently being handled.
   IPEndPoint current_client_address_;
   IPEndPoint current_server_address_;
   const QuicReceivedPacket* current_packet_;
   QuicConnectionId current_connection_id_;
 
+  // Used to get the supported versions based on flag. Does not own.
+  QuicVersionManager* version_manager_;
+
   QuicFramer framer_;
 
   // The last error set by SetLastError(), which is called by
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 2b5b9a7b..967474df 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -97,11 +97,12 @@
  public:
   TestDispatcher(const QuicConfig& config,
                  const QuicCryptoServerConfig* crypto_config,
+                 QuicVersionManager* version_manager,
                  EpollServer* eps)
       : QuicDispatcher(
             config,
             crypto_config,
-            QuicSupportedVersions(),
+            version_manager,
             std::unique_ptr<QuicEpollConnectionHelper>(
                 new QuicEpollConnectionHelper(eps, QuicAllocator::BUFFER_POOL)),
             std::unique_ptr<QuicServerSessionBase::Helper>(
@@ -172,10 +173,14 @@
   QuicDispatcherTest()
       : helper_(&eps_, QuicAllocator::BUFFER_POOL),
         alarm_factory_(&eps_),
+        version_manager_(QuicSupportedVersions()),
         crypto_config_(QuicCryptoServerConfig::TESTING,
                        QuicRandom::GetInstance(),
                        CryptoTestUtils::ProofSourceForTesting()),
-        dispatcher_(new TestDispatcher(config_, &crypto_config_, &eps_)),
+        dispatcher_(new TestDispatcher(config_,
+                                       &crypto_config_,
+                                       &version_manager_,
+                                       &eps_)),
         time_wait_list_manager_(nullptr),
         session1_(nullptr),
         session2_(nullptr) {
@@ -281,6 +286,7 @@
   QuicEpollAlarmFactory alarm_factory_;
   MockAlarmFactory mock_alarm_factory_;
   QuicConfig config_;
+  QuicVersionManager version_manager_;
   QuicCryptoServerConfig crypto_config_;
   IPEndPoint server_address_;
   std::unique_ptr<TestDispatcher> dispatcher_;
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index 080fe963..9f3235d 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -27,6 +27,7 @@
 #include "net/tools/quic/quic_epoll_connection_helper.h"
 #include "net/tools/quic/quic_in_memory_cache.h"
 #include "net/tools/quic/quic_packet_reader.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
 #include "net/tools/quic/quic_simple_server_session_helper.h"
 #include "net/tools/quic/quic_socket_utils.h"
 
@@ -67,7 +68,7 @@
                      QuicRandom::GetInstance(),
                      std::move(proof_source)),
       crypto_config_options_(crypto_config_options),
-      supported_versions_(supported_versions),
+      version_manager_(supported_versions),
       packet_reader_(new QuicPacketReader()) {
   Initialize();
 }
@@ -147,8 +148,8 @@
 
 QuicDispatcher* QuicServer::CreateQuicDispatcher() {
   QuicEpollAlarmFactory alarm_factory(&epoll_server_);
-  return new QuicDispatcher(
-      config_, &crypto_config_, supported_versions_,
+  return new QuicSimpleDispatcher(
+      config_, &crypto_config_, &version_manager_,
       std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper(
           &epoll_server_, QuicAllocator::BUFFER_POOL)),
       std::unique_ptr<QuicServerSessionBase::Helper>(
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h
index d5f40f8..0a5b903 100644
--- a/net/tools/quic/quic_server.h
+++ b/net/tools/quic/quic_server.h
@@ -81,13 +81,12 @@
 
   const QuicConfig& config() const { return config_; }
   const QuicCryptoServerConfig& crypto_config() const { return crypto_config_; }
-  const QuicVersionVector& supported_versions() const {
-    return supported_versions_;
-  }
   EpollServer* epoll_server() { return &epoll_server_; }
 
   QuicDispatcher* dispatcher() { return dispatcher_.get(); }
 
+  QuicVersionManager* version_manager() { return &version_manager_; }
+
  private:
   friend class net::test::QuicServerPeer;
 
@@ -122,11 +121,8 @@
   // crypto_config_options_ contains crypto parameters for the handshake.
   QuicCryptoServerConfig::ConfigOptions crypto_config_options_;
 
-  // This vector contains QUIC versions which we currently support.
-  // This should be ordered such that the highest supported version is the first
-  // element, with subsequent elements in descending order (versions can be
-  // skipped as necessary).
-  QuicVersionVector supported_versions_;
+  // Used to generate current supported versions.
+  QuicVersionManager version_manager_;
 
   // Point to a QuicPacketReader object on the heap. The reader allocates more
   // space than allowed on the stack.
diff --git a/net/tools/quic/quic_server_test.cc b/net/tools/quic/quic_server_test.cc
index bd6f35f..92a89dd1 100644
--- a/net/tools/quic/quic_server_test.cc
+++ b/net/tools/quic/quic_server_test.cc
@@ -28,9 +28,11 @@
       : crypto_config_("blah",
                        QuicRandom::GetInstance(),
                        CryptoTestUtils::ProofSourceForTesting()),
+        version_manager_(QuicSupportedVersions()),
         dispatcher_(
             config_,
             &crypto_config_,
+            &version_manager_,
             std::unique_ptr<QuicEpollConnectionHelper>(
                 new QuicEpollConnectionHelper(&eps_,
                                               QuicAllocator::BUFFER_POOL)),
@@ -49,6 +51,7 @@
  protected:
   QuicConfig config_;
   QuicCryptoServerConfig crypto_config_;
+  QuicVersionManager version_manager_;
   EpollServer eps_;
   MockQuicDispatcher dispatcher_;
 };
diff --git a/net/tools/quic/quic_simple_dispatcher.cc b/net/tools/quic/quic_simple_dispatcher.cc
new file mode 100644
index 0000000..f0df075
--- /dev/null
+++ b/net/tools/quic/quic_simple_dispatcher.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/quic/quic_simple_dispatcher.h"
+
+#include "net/tools/quic/quic_simple_server_session.h"
+
+namespace net {
+
+QuicSimpleDispatcher::QuicSimpleDispatcher(
+    const QuicConfig& config,
+    const QuicCryptoServerConfig* crypto_config,
+    QuicVersionManager* version_manager,
+    std::unique_ptr<QuicConnectionHelperInterface> helper,
+    std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+    std::unique_ptr<QuicAlarmFactory> alarm_factory)
+    : QuicDispatcher(config,
+                     crypto_config,
+                     version_manager,
+                     std::move(helper),
+                     std::move(session_helper),
+                     std::move(alarm_factory)) {}
+
+QuicSimpleDispatcher::~QuicSimpleDispatcher() {}
+
+QuicServerSessionBase* QuicSimpleDispatcher::CreateQuicSession(
+    QuicConnectionId connection_id,
+    const IPEndPoint& client_address) {
+  // The QuicServerSessionBase takes ownership of |connection| below.
+  QuicConnection* connection = new QuicConnection(
+      connection_id, client_address, helper(), alarm_factory(),
+      CreatePerConnectionWriter(),
+      /* owns_writer= */ true, Perspective::IS_SERVER, GetSupportedVersions());
+
+  QuicServerSessionBase* session =
+      new QuicSimpleServerSession(config(), connection, this, session_helper(),
+                                  crypto_config(), compressed_certs_cache());
+  session->Initialize();
+  return session;
+}
+
+}  // namespace net
diff --git a/net/tools/quic/quic_simple_dispatcher.h b/net/tools/quic/quic_simple_dispatcher.h
new file mode 100644
index 0000000..29c87ab
--- /dev/null
+++ b/net/tools/quic/quic_simple_dispatcher.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
+#define NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
+
+#include "net/tools/quic/quic_dispatcher.h"
+
+namespace net {
+
+class QuicSimpleDispatcher : public QuicDispatcher {
+ public:
+  QuicSimpleDispatcher(
+      const QuicConfig& config,
+      const QuicCryptoServerConfig* crypto_config,
+      QuicVersionManager* version_manager,
+      std::unique_ptr<QuicConnectionHelperInterface> helper,
+      std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+      std::unique_ptr<QuicAlarmFactory> alarm_factory);
+
+  ~QuicSimpleDispatcher() override;
+
+ protected:
+  QuicServerSessionBase* CreateQuicSession(
+      QuicConnectionId connection_id,
+      const IPEndPoint& client_address) override;
+};
+
+}  // namespace net
+
+#endif  // NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
diff --git a/net/tools/quic/quic_simple_server.cc b/net/tools/quic/quic_simple_server.cc
index e4301bb..5a9b73f 100644
--- a/net/tools/quic/quic_simple_server.cc
+++ b/net/tools/quic/quic_simple_server.cc
@@ -16,7 +16,7 @@
 #include "net/quic/core/quic_crypto_stream.h"
 #include "net/quic/core/quic_data_reader.h"
 #include "net/quic/core/quic_protocol.h"
-#include "net/tools/quic/quic_dispatcher.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
 #include "net/tools/quic/quic_simple_per_connection_packet_writer.h"
 #include "net/tools/quic/quic_simple_server_packet_writer.h"
 #include "net/tools/quic/quic_simple_server_session_helper.h"
@@ -32,46 +32,13 @@
 // the limit.
 const int kReadBufferSize = 2 * kMaxPacketSize;
 
-class SimpleQuicDispatcher : public QuicDispatcher {
- public:
-  SimpleQuicDispatcher(const QuicConfig& config,
-                       const QuicCryptoServerConfig* crypto_config,
-                       const QuicVersionVector& supported_versions,
-                       QuicConnectionHelperInterface* helper,
-                       QuicAlarmFactory* alarm_factory)
-      : QuicDispatcher(
-            config,
-            crypto_config,
-            supported_versions,
-            std::unique_ptr<QuicConnectionHelperInterface>(helper),
-            std::unique_ptr<QuicServerSessionBase::Helper>(
-                new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
-            std::unique_ptr<QuicAlarmFactory>(alarm_factory)) {}
-
- protected:
-  QuicServerSessionBase* CreateQuicSession(
-      QuicConnectionId connection_id,
-      const IPEndPoint& client_address) override {
-    QuicServerSessionBase* session =
-        QuicDispatcher::CreateQuicSession(connection_id, client_address);
-    static_cast<QuicSimplePerConnectionPacketWriter*>(
-        session->connection()->writer())
-        ->set_connection(session->connection());
-    return session;
-  }
-
-  QuicPacketWriter* CreatePerConnectionWriter() override {
-    return new QuicSimplePerConnectionPacketWriter(
-        static_cast<QuicSimpleServerPacketWriter*>(writer()));
-  }
-};
-
 }  // namespace
 
 QuicSimpleServer::QuicSimpleServer(std::unique_ptr<ProofSource> proof_source,
                                    const QuicConfig& config,
                                    const QuicVersionVector& supported_versions)
-    : helper_(
+    : version_manager_(supported_versions),
+      helper_(
           new QuicChromiumConnectionHelper(&clock_, QuicRandom::GetInstance())),
       alarm_factory_(new QuicChromiumAlarmFactory(
           base::ThreadTaskRunnerHandle::Get().get(),
@@ -80,7 +47,6 @@
       crypto_config_(kSourceAddressTokenSecret,
                      QuicRandom::GetInstance(),
                      std::move(proof_source)),
-      supported_versions_(supported_versions),
       read_pending_(false),
       synchronous_read_count_(0),
       read_buffer_(new IOBufferWithSize(kReadBufferSize)),
@@ -153,8 +119,12 @@
 
   socket_.swap(socket);
 
-  dispatcher_.reset(new SimpleQuicDispatcher(
-      config_, &crypto_config_, supported_versions_, helper_, alarm_factory_));
+  dispatcher_.reset(new QuicSimpleDispatcher(
+      config_, &crypto_config_, &version_manager_,
+      std::unique_ptr<QuicConnectionHelperInterface>(helper_),
+      std::unique_ptr<QuicServerSessionBase::Helper>(
+          new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+      std::unique_ptr<QuicAlarmFactory>(alarm_factory_)));
   QuicSimpleServerPacketWriter* writer =
       new QuicSimpleServerPacketWriter(socket_.get(), dispatcher_.get());
   dispatcher_->InitializeWithWriter(writer);
diff --git a/net/tools/quic/quic_simple_server.h b/net/tools/quic/quic_simple_server.h
index e64eda7..5449628 100644
--- a/net/tools/quic/quic_simple_server.h
+++ b/net/tools/quic/quic_simple_server.h
@@ -65,6 +65,8 @@
   // Initialize the internal state of the server.
   void Initialize();
 
+  QuicVersionManager version_manager_;
+
   // Accepts data from the framer and demuxes clients to sessions.
   std::unique_ptr<QuicDispatcher> dispatcher_;
 
@@ -86,12 +88,6 @@
   // crypto_config_ contains crypto parameters for the handshake.
   QuicCryptoServerConfig crypto_config_;
 
-  // This vector contains QUIC versions which we currently support.
-  // This should be ordered such that the highest supported version is the first
-  // element, with subsequent elements in descending order (versions can be
-  // skipped as necessary).
-  QuicVersionVector supported_versions_;
-
   // The address that the server listens on.
   IPEndPoint server_address_;
 
diff --git a/net/tools/quic/quic_simple_server_test.cc b/net/tools/quic/quic_simple_server_test.cc
index c1cd8ae..b4fad39 100644
--- a/net/tools/quic/quic_simple_server_test.cc
+++ b/net/tools/quic/quic_simple_server_test.cc
@@ -25,9 +25,11 @@
       : crypto_config_("blah",
                        QuicRandom::GetInstance(),
                        CryptoTestUtils::ProofSourceForTesting()),
+        version_manager_(QuicSupportedVersions()),
         dispatcher_(
             config_,
             &crypto_config_,
+            &version_manager_,
             std::unique_ptr<MockQuicConnectionHelper>(
                 new net::test::MockQuicConnectionHelper),
             std::unique_ptr<QuicServerSessionBase::Helper>(
@@ -45,6 +47,7 @@
  protected:
   QuicConfig config_;
   QuicCryptoServerConfig crypto_config_;
+  QuicVersionManager version_manager_;
   net::test::MockQuicDispatcher dispatcher_;
 };
 
diff --git a/net/tools/quic/quic_spdy_client_stream.cc b/net/tools/quic/quic_spdy_client_stream.cc
index 98f5a94..8ef5025 100644
--- a/net/tools/quic/quic_spdy_client_stream.cc
+++ b/net/tools/quic/quic_spdy_client_stream.cc
@@ -149,12 +149,10 @@
 }
 
 void QuicSpdyClientStream::OnDataAvailable() {
-  if (FLAGS_quic_supports_push_promise) {
-    // For push streams, visitor will not be set until the rendezvous
-    // between server promise and client request is complete.
-    if (visitor() == nullptr)
-      return;
-  }
+  // For push streams, visitor will not be set until the rendezvous
+  // between server promise and client request is complete.
+  if (visitor() == nullptr)
+    return;
 
   while (HasBytesToRead()) {
     struct iovec iov;
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 3de46fa..a401223 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -228,6 +228,7 @@
                                      config,
                                      supported_versions,
                                      &epoll_server_)),
+      response_complete_(false),
       allow_bidirectional_data_(false) {
   Initialize();
 }
@@ -245,11 +246,13 @@
                                      supported_versions,
                                      &epoll_server_,
                                      std::move(proof_verifier))),
+      response_complete_(false),
       allow_bidirectional_data_(false) {
   Initialize();
 }
 
-QuicTestClient::QuicTestClient() : allow_bidirectional_data_(false) {}
+QuicTestClient::QuicTestClient()
+    : response_complete_(false), allow_bidirectional_data_(false) {}
 
 QuicTestClient::~QuicTestClient() {
   if (stream_) {
@@ -358,6 +361,10 @@
 
 ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
   stream_ = nullptr;  // Always force creation of a stream for SendMessage.
+  // Any response we might have received for a previous request would no longer
+  // be valid.  TODO(jeffpiazza): There's probably additional client state that
+  // should be reset here, too, if we were being more careful.
+  response_complete_ = false;
 
   // If we're not connected, try to find an sni hostname.
   if (!connected()) {
@@ -444,6 +451,14 @@
   return SendCustomSynchronousRequest(message);
 }
 
+void QuicTestClient::SetStream(QuicSpdyClientStream* stream) {
+  stream_ = stream;
+  if (stream_ != nullptr) {
+    response_complete_ = false;
+    stream_->set_visitor(this);
+  }
+}
+
 QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
   if (!connect_attempted_ || auto_reconnect_) {
     if (!connected()) {
@@ -454,14 +469,11 @@
     }
   }
   if (!stream_) {
-    stream_ = client_->CreateReliableClientStream();
-    if (stream_ == nullptr) {
-      return nullptr;
+    SetStream(client_->CreateReliableClientStream());
+    if (stream_) {
+      stream_->SetPriority(priority_);
+      stream_->set_allow_bidirectional_data(allow_bidirectional_data_);
     }
-    stream_->set_visitor(this);
-    QuicSpdyClientStream* cs = reinterpret_cast<QuicSpdyClientStream*>(stream_);
-    cs->SetPriority(priority_);
-    cs->set_allow_bidirectional_data(allow_bidirectional_data_);
   }
 
   return stream_;
@@ -543,7 +555,7 @@
           !client_->session()->IsClosedStream(stream_->id()));
 }
 
-void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
+void QuicTestClient::WaitUntil(int timeout_ms, std::function<bool()> trigger) {
   int64_t timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
   int64_t old_timeout_us = epoll_server()->timeout_in_us();
   if (timeout_us > 0) {
@@ -554,34 +566,15 @@
           ->GetClock();
   QuicTime end_waiting_time =
       clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
-  while (HaveActiveStream() &&
+  while (HaveActiveStream() && !(trigger && trigger()) &&
          (timeout_us < 0 || clock->Now() < end_waiting_time)) {
     client_->WaitForEvents();
   }
   if (timeout_us > 0) {
     epoll_server()->set_timeout_in_us(old_timeout_us);
   }
-}
-
-void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
-  int64_t timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
-  int64_t old_timeout_us = epoll_server()->timeout_in_us();
-  if (timeout_us > 0) {
-    epoll_server()->set_timeout_in_us(timeout_us);
-  }
-  const QuicClock* clock =
-      QuicConnectionPeer::GetHelper(client()->session()->connection())
-          ->GetClock();
-  QuicTime end_waiting_time =
-      clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
-  while (stream_ != nullptr &&
-         !client_->session()->IsClosedStream(stream_->id()) &&
-         stream_->stream_bytes_read() == 0 &&
-         (timeout_us < 0 || clock->Now() < end_waiting_time)) {
-    client_->WaitForEvents();
-  }
-  if (timeout_us > 0) {
-    epoll_server()->set_timeout_in_us(old_timeout_us);
+  if (trigger && !trigger()) {
+    VLOG(1) << "Client WaitUntil returning with trigger returning false.";
   }
 }
 
@@ -611,15 +604,27 @@
 }
 
 int64_t QuicTestClient::response_size() const {
-  return bytes_read_;
+  return bytes_read();
 }
 
 size_t QuicTestClient::bytes_read() const {
-  return bytes_read_;
+  // While stream_ is available, its member functions provide more accurate
+  // information.  bytes_read_ is updated only when stream_ becomes null.
+  if (stream_) {
+    return stream_->stream_bytes_read() + stream_->header_bytes_read();
+  } else {
+    return bytes_read_;
+  }
 }
 
 size_t QuicTestClient::bytes_written() const {
-  return bytes_written_;
+  // While stream_ is available, its member functions provide more accurate
+  // information.  bytes_written_ is updated only when stream_ becomes null.
+  if (stream_) {
+    return stream_->stream_bytes_written() + stream_->header_bytes_written();
+  } else {
+    return bytes_written_;
+  }
 }
 
 void QuicTestClient::OnClose(QuicSpdyStream* stream) {
@@ -659,9 +664,8 @@
 void QuicTestClient::OnRendezvousResult(QuicSpdyStream* stream) {
   std::unique_ptr<TestClientDataToResend> data_to_resend =
       std::move(push_promise_data_to_resend_);
-  stream_ = static_cast<QuicSpdyClientStream*>(stream);
+  SetStream(static_cast<QuicSpdyClientStream*>(stream));
   if (stream) {
-    stream->set_visitor(this);
     stream->OnDataAvailable();
   } else if (data_to_resend.get()) {
     data_to_resend->Resend();
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index d5fbea4..3ebeb2d9 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -124,8 +124,7 @@
   void Disconnect() override;
   IPEndPoint local_address() const override;
   void ClearPerRequestState() override;
-  void WaitForResponseForMs(int timeout_ms) override;
-  void WaitForInitialResponseForMs(int timeout_ms) override;
+  void WaitUntil(int timeout_ms, std::function<bool()> trigger) override;
   ssize_t Send(const void* buffer, size_t size) override;
   bool response_complete() const override;
   bool response_headers_complete() const override;
@@ -170,6 +169,8 @@
   // ConnectionId instead of a random one.
   void UseConnectionId(QuicConnectionId connection_id);
 
+  // Update internal stream_ pointer and perform accompanying housekeeping.
+  void SetStream(QuicSpdyClientStream* stream);
   // Returns nullptr if the maximum number of streams have already been created.
   QuicSpdyClientStream* GetOrCreateStream();
 
@@ -274,6 +275,8 @@
 
   SpdyPriority priority_;
   std::string response_;
+  // bytes_read_ and bytes_written_ are updated only when stream_ is released;
+  // prefer bytes_read() and bytes_written() member functions.
   uint64_t bytes_read_;
   uint64_t bytes_written_;
   // The number of uncompressed HTTP header bytes received.
diff --git a/net/tools/quic/test_tools/quic_test_server.cc b/net/tools/quic/test_tools/quic_test_server.cc
index ea1efb4..b96d356 100644
--- a/net/tools/quic/test_tools/quic_test_server.cc
+++ b/net/tools/quic/test_tools/quic_test_server.cc
@@ -18,9 +18,9 @@
 #include "net/quic/core/quic_connection.h"
 #include "net/quic/core/quic_packet_writer.h"
 #include "net/quic/core/quic_protocol.h"
-#include "net/tools/quic/quic_dispatcher.h"
 #include "net/tools/quic/quic_epoll_alarm_factory.h"
 #include "net/tools/quic/quic_epoll_connection_helper.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
 #include "net/tools/quic/quic_simple_server_session.h"
 #include "net/tools/quic/quic_simple_server_session_helper.h"
 #include "net/tools/quic/quic_simple_server_stream.h"
@@ -75,21 +75,21 @@
   QuicTestServer::CryptoStreamFactory* crypto_stream_factory_;  // Not owned.
 };
 
-class QuicTestDispatcher : public QuicDispatcher {
+class QuicTestDispatcher : public QuicSimpleDispatcher {
  public:
   QuicTestDispatcher(
       const QuicConfig& config,
       const QuicCryptoServerConfig* crypto_config,
-      const QuicVersionVector& versions,
+      QuicVersionManager* version_manager,
       std::unique_ptr<QuicConnectionHelperInterface> helper,
       std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
       std::unique_ptr<QuicAlarmFactory> alarm_factory)
-      : QuicDispatcher(config,
-                       crypto_config,
-                       versions,
-                       std::move(helper),
-                       std::move(session_helper),
-                       std::move(alarm_factory)),
+      : QuicSimpleDispatcher(config,
+                             crypto_config,
+                             version_manager,
+                             std::move(helper),
+                             std::move(session_helper),
+                             std::move(alarm_factory)),
         session_factory_(nullptr),
         stream_factory_(nullptr),
         crypto_stream_factory_(nullptr) {}
@@ -99,7 +99,7 @@
     base::AutoLock lock(factory_lock_);
     if (session_factory_ == nullptr && stream_factory_ == nullptr &&
         crypto_stream_factory_ == nullptr) {
-      return QuicDispatcher::CreateQuicSession(id, client);
+      return QuicSimpleDispatcher::CreateQuicSession(id, client);
     }
     QuicConnection* connection = new QuicConnection(
         id, client, helper(), alarm_factory(), CreatePerConnectionWriter(),
@@ -162,7 +162,7 @@
 
 QuicDispatcher* QuicTestServer::CreateQuicDispatcher() {
   return new QuicTestDispatcher(
-      config(), &crypto_config(), supported_versions(),
+      config(), &crypto_config(), version_manager(),
       std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper(
           epoll_server(), QuicAllocator::BUFFER_POOL)),
       std::unique_ptr<QuicServerSessionBase::Helper>(
diff --git a/net/tools/quic/test_tools/simple_client.cc b/net/tools/quic/test_tools/simple_client.cc
index 3559da13..f6ac39f 100644
--- a/net/tools/quic/test_tools/simple_client.cc
+++ b/net/tools/quic/test_tools/simple_client.cc
@@ -4,6 +4,8 @@
 
 #include "net/tools/quic/test_tools/simple_client.h"
 
+#include "net/tools/balsa/balsa_headers.h"
+
 namespace net {
 namespace test {
 
@@ -16,6 +18,18 @@
   WaitForInitialResponseForMs(-1);
 }
 
+void SimpleClient::WaitForResponseForMs(int timeout_ms) {
+  WaitUntil(timeout_ms, [this]() { return response_complete(); });
+  if (response_complete()) {
+    VLOG(1) << "Client received response:" << response_headers()->DebugString()
+            << response_body();
+  }
+}
+
+void SimpleClient::WaitForInitialResponseForMs(int timeout_ms) {
+  WaitUntil(timeout_ms, [this]() { return response_size() != 0; });
+}
+
 int SimpleClient::ResetSocket() {
   LOG(FATAL) << "SimpleClient::ResetSocket is not implemented";
   return 0;
diff --git a/net/tools/quic/test_tools/simple_client.h b/net/tools/quic/test_tools/simple_client.h
index 3c5d02c..68b5c89 100644
--- a/net/tools/quic/test_tools/simple_client.h
+++ b/net/tools/quic/test_tools/simple_client.h
@@ -55,11 +55,13 @@
 
   // Returns once a complete response or a connection close has been received
   // from the server, or once the timeout expires. -1 for no timeout.
-  virtual void WaitForResponseForMs(int timeout_ms) = 0;
+  virtual void WaitForResponseForMs(int timeout_ms);
 
   // Waits for some data or response from the server, or once the timeout
   // expires. -1 for no timeout.
-  virtual void WaitForInitialResponseForMs(int timeout_ms) = 0;
+  virtual void WaitForInitialResponseForMs(int timeout_ms);
+
+  virtual void WaitUntil(int timeout_ms, std::function<bool()> trigger) = 0;
 
   // Clears any outstanding state from the last request.
   virtual void ClearPerRequestState() = 0;
diff --git a/printing/printing_context_android.cc b/printing/printing_context_android.cc
index 88d76571..113329a 100644
--- a/printing/printing_context_android.cc
+++ b/printing/printing_context_android.cc
@@ -21,6 +21,9 @@
 #include "printing/units.h"
 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace {
 
 // 1 inch in mils.
diff --git a/services/ui/input_devices/BUILD.gn b/services/ui/input_devices/BUILD.gn
index cb5ab9d4..bd9e5a2a 100644
--- a/services/ui/input_devices/BUILD.gn
+++ b/services/ui/input_devices/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//testing/test.gni")
+
 source_set("input_devices") {
   sources = [
     "input_device_server.cc",
@@ -10,8 +12,7 @@
 
   deps = [
     "//base",
-    "//services/shell/public/cpp:sources",
-    "//skia",
+    "//services/shell/public/cpp",
     "//ui/events/devices",
   ]
 
@@ -19,3 +20,24 @@
     "//services/ui/public/interfaces/input_devices",
   ]
 }
+
+test("input_device_unittests") {
+  testonly = true
+
+  sources = [
+    "input_device_unittests.cc",
+  ]
+
+  deps = [
+    ":input_devices",
+    "//base",
+    "//base/test:test_support",
+    "//mojo/edk/test:run_all_unittests",
+    "//services/shell/public/cpp",
+    "//services/shell/public/cpp:service_test_support",
+    "//services/ui/public/cpp/input_devices",
+    "//services/ui/public/interfaces/input_devices",
+    "//testing/gtest",
+    "//ui/events/devices",
+  ]
+}
diff --git a/services/ui/input_devices/OWNERS b/services/ui/input_devices/OWNERS
new file mode 100644
index 0000000..4a1df28
--- /dev/null
+++ b/services/ui/input_devices/OWNERS
@@ -0,0 +1,2 @@
+kylechar@chromium.org
+
diff --git a/services/ui/input_devices/input_device_server.cc b/services/ui/input_devices/input_device_server.cc
index 7f21f56..c6bf1e94 100644
--- a/services/ui/input_devices/input_device_server.cc
+++ b/services/ui/input_devices/input_device_server.cc
@@ -34,7 +34,7 @@
 }
 
 void InputDeviceServer::AddInterface(shell::Connection* connection) {
-  DCHECK(manager_);
+  DCHECK(IsRegisteredAsObserver());
   connection->AddInterface<mojom::InputDeviceServer>(this);
 }
 
diff --git a/services/ui/input_devices/input_device_unittests.cc b/services/ui/input_devices/input_device_unittests.cc
new file mode 100644
index 0000000..c11c2337
--- /dev/null
+++ b/services/ui/input_devices/input_device_unittests.cc
@@ -0,0 +1,198 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "services/ui/input_devices/input_device_server.h"
+#include "services/ui/public/cpp/input_devices/input_device_client.h"
+#include "services/ui/public/interfaces/input_devices/input_device_server.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/devices/device_data_manager.h"
+#include "ui/events/devices/device_hotplug_event_observer.h"
+
+namespace ui {
+
+namespace {
+
+// Helper to place items into a std::vector<T> to provide as input.
+template <class T>
+std::vector<T> AsVector(std::initializer_list<T> input) {
+  return std::vector<T>(input);
+}
+
+// Test client that doesn't register itself as the InputDeviceManager.
+class TestInputDeviceClient : public InputDeviceClient {
+ public:
+  TestInputDeviceClient() : InputDeviceClient(false) {}
+  ~TestInputDeviceClient() override {}
+
+  using InputDeviceClient::GetIntefacePtr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestInputDeviceClient);
+};
+
+class InputDeviceTest : public testing::Test {
+ public:
+  InputDeviceTest() {}
+  ~InputDeviceTest() override {}
+
+  void RunUntilIdle() { task_runner_->RunUntilIdle(); }
+
+  void AddClientAsObserver(TestInputDeviceClient* client) {
+    server_.AddObserver(client->GetIntefacePtr());
+  }
+
+  DeviceHotplugEventObserver* GetHotplugObserver() {
+    return DeviceDataManager::GetInstance();
+  }
+
+  // testing::Test:
+  void SetUp() override {
+    task_runner_ = make_scoped_refptr(new base::TestMockTimeTaskRunner(
+        base::Time::Now(), base::TimeTicks::Now()));
+    message_loop_.SetTaskRunner(task_runner_);
+
+    DeviceDataManager::CreateInstance();
+    server_.RegisterAsObserver();
+  }
+
+  void TearDown() override { DeviceDataManager::DeleteInstance(); }
+
+ private:
+  base::MessageLoop message_loop_;
+  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+  InputDeviceServer server_;
+
+  DISALLOW_COPY_AND_ASSIGN(InputDeviceTest);
+};
+
+}  // namespace
+
+TEST_F(InputDeviceTest, DeviceListsComplete) {
+  TestInputDeviceClient client;
+  AddClientAsObserver(&client);
+
+  RunUntilIdle();
+  EXPECT_FALSE(client.AreDeviceListsComplete());
+
+  GetHotplugObserver()->OnDeviceListsComplete();
+
+  // Observer should get notification for device lists complete now.
+  RunUntilIdle();
+  EXPECT_TRUE(client.AreDeviceListsComplete());
+}
+
+TEST_F(InputDeviceTest, DeviceListsCompleteTwoClients) {
+  TestInputDeviceClient client1;
+  AddClientAsObserver(&client1);
+
+  TestInputDeviceClient client2;
+  AddClientAsObserver(&client2);
+
+  RunUntilIdle();
+  EXPECT_FALSE(client1.AreDeviceListsComplete());
+  EXPECT_FALSE(client2.AreDeviceListsComplete());
+
+  GetHotplugObserver()->OnDeviceListsComplete();
+
+  // Both observers should get notifications for device lists complete now.
+  RunUntilIdle();
+  EXPECT_TRUE(client1.AreDeviceListsComplete());
+  EXPECT_TRUE(client2.AreDeviceListsComplete());
+}
+
+TEST_F(InputDeviceTest, AddDevices) {
+  const TouchscreenDevice touchscreen(100, INPUT_DEVICE_INTERNAL, "Touchscreen",
+                                      gfx::Size(2600, 1700), 3);
+
+  TestInputDeviceClient client;
+  AddClientAsObserver(&client);
+
+  // Add keyboard and mark device lists complete.
+  GetHotplugObserver()->OnTouchscreenDevicesUpdated(AsVector({touchscreen}));
+  GetHotplugObserver()->OnDeviceListsComplete();
+
+  RunUntilIdle();
+  EXPECT_TRUE(client.AreDeviceListsComplete());
+  EXPECT_EQ(1u, client.GetTouchscreenDevices().size());
+  EXPECT_EQ(0u, client.GetKeyboardDevices().size());
+  EXPECT_EQ(0u, client.GetMouseDevices().size());
+  EXPECT_EQ(0u, client.GetTouchpadDevices().size());
+}
+
+TEST_F(InputDeviceTest, AddDeviceAfterComplete) {
+  const InputDevice keyboard1(100, INPUT_DEVICE_INTERNAL, "Keyboard1");
+  const InputDevice keyboard2(200, INPUT_DEVICE_EXTERNAL, "Keyboard2");
+  const InputDevice mouse(300, INPUT_DEVICE_EXTERNAL, "Mouse");
+
+  TestInputDeviceClient client;
+  AddClientAsObserver(&client);
+
+  // Add mouse and mark device lists complete.
+  GetHotplugObserver()->OnKeyboardDevicesUpdated(AsVector({keyboard1}));
+  GetHotplugObserver()->OnDeviceListsComplete();
+
+  RunUntilIdle();
+  EXPECT_TRUE(client.AreDeviceListsComplete());
+  EXPECT_EQ(1lu, client.GetKeyboardDevices().size());
+
+  // Add a second keyboard and a mouse.
+  GetHotplugObserver()->OnMouseDevicesUpdated(AsVector({mouse}));
+  GetHotplugObserver()->OnKeyboardDevicesUpdated(
+      AsVector({keyboard1, keyboard2}));
+
+  RunUntilIdle();
+  EXPECT_EQ(0u, client.GetTouchscreenDevices().size());
+  EXPECT_EQ(2u, client.GetKeyboardDevices().size());
+  EXPECT_EQ(1u, client.GetMouseDevices().size());
+  EXPECT_EQ(0u, client.GetTouchpadDevices().size());
+}
+
+TEST_F(InputDeviceTest, AddThenRemoveDevice) {
+  const InputDevice mouse(100, INPUT_DEVICE_INTERNAL, "Mouse");
+
+  TestInputDeviceClient client;
+  AddClientAsObserver(&client);
+
+  // Add mouse and mark device lists complete.
+  GetHotplugObserver()->OnMouseDevicesUpdated(AsVector({mouse}));
+  GetHotplugObserver()->OnDeviceListsComplete();
+
+  RunUntilIdle();
+  EXPECT_TRUE(client.AreDeviceListsComplete());
+  EXPECT_EQ(1u, client.GetMouseDevices().size());
+
+  // Remove mouse device.
+  GetHotplugObserver()->OnMouseDevicesUpdated(AsVector<InputDevice>({}));
+
+  RunUntilIdle();
+  EXPECT_EQ(0u, client.GetMouseDevices().size());
+}
+
+TEST_F(InputDeviceTest, CheckClientDeviceFields) {
+  const InputDevice touchpad(100, INPUT_DEVICE_INTERNAL, "Touchpad");
+
+  TestInputDeviceClient client;
+  AddClientAsObserver(&client);
+
+  // Add touchpad and mark device lists complete.
+  GetHotplugObserver()->OnTouchpadDevicesUpdated(AsVector({touchpad}));
+  GetHotplugObserver()->OnDeviceListsComplete();
+
+  RunUntilIdle();
+  EXPECT_TRUE(client.AreDeviceListsComplete());
+  EXPECT_EQ(1u, client.GetTouchpadDevices().size());
+
+  // Check the touchpad fields match.
+  const InputDevice& output = client.GetTouchpadDevices()[0];
+  EXPECT_EQ(touchpad.id, output.id);
+  EXPECT_EQ(touchpad.type, output.type);
+  EXPECT_EQ(touchpad.name, output.name);
+}
+
+}  // namespace ui
diff --git a/services/ui/public/cpp/input_devices/BUILD.gn b/services/ui/public/cpp/input_devices/BUILD.gn
index 1b91813..da90c47 100644
--- a/services/ui/public/cpp/input_devices/BUILD.gn
+++ b/services/ui/public/cpp/input_devices/BUILD.gn
@@ -10,8 +10,7 @@
 
   deps = [
     "//base",
-    "//services/shell/public/cpp:sources",
-    "//skia",
+    "//services/shell/public/cpp",
     "//ui/events/devices",
   ]
 
diff --git a/services/ui/public/cpp/input_devices/OWNERS b/services/ui/public/cpp/input_devices/OWNERS
new file mode 100644
index 0000000..4a1df28
--- /dev/null
+++ b/services/ui/public/cpp/input_devices/OWNERS
@@ -0,0 +1,2 @@
+kylechar@chromium.org
+
diff --git a/services/ui/public/cpp/input_devices/input_device_client.cc b/services/ui/public/cpp/input_devices/input_device_client.cc
index 4137e2b..ad52b7a 100644
--- a/services/ui/public/cpp/input_devices/input_device_client.cc
+++ b/services/ui/public/cpp/input_devices/input_device_client.cc
@@ -8,18 +8,63 @@
 
 namespace ui {
 
-InputDeviceClient::InputDeviceClient() : binding_(this) {
-  InputDeviceManager::SetInstance(this);
-}
+InputDeviceClient::InputDeviceClient() : InputDeviceClient(true) {}
 
 InputDeviceClient::~InputDeviceClient() {
-  InputDeviceManager::ClearInstance();
+  if (is_input_device_manager_)
+    InputDeviceManager::ClearInstance();
 }
 
 void InputDeviceClient::Connect(mojom::InputDeviceServerPtr server) {
   DCHECK(server.is_bound());
+  server->AddObserver(GetIntefacePtr());
+}
 
-  server->AddObserver(binding_.CreateInterfacePtrAndBind());
+const std::vector<ui::InputDevice>& InputDeviceClient::GetKeyboardDevices()
+    const {
+  return keyboard_devices_;
+}
+
+const std::vector<ui::TouchscreenDevice>&
+InputDeviceClient::GetTouchscreenDevices() const {
+  return touchscreen_devices_;
+}
+
+const std::vector<ui::InputDevice>& InputDeviceClient::GetMouseDevices() const {
+  return mouse_devices_;
+}
+
+const std::vector<ui::InputDevice>& InputDeviceClient::GetTouchpadDevices()
+    const {
+  return touchpad_devices_;
+}
+
+bool InputDeviceClient::AreDeviceListsComplete() const {
+  return device_lists_complete_;
+}
+
+bool InputDeviceClient::AreTouchscreensEnabled() const {
+  // TODO(kylechar): This obviously isn't right. We either need to pass this
+  // state around or modify the interface.
+  return true;
+}
+
+void InputDeviceClient::AddObserver(ui::InputDeviceEventObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void InputDeviceClient::RemoveObserver(ui::InputDeviceEventObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+InputDeviceClient::InputDeviceClient(bool is_input_device_manager)
+    : binding_(this), is_input_device_manager_(is_input_device_manager) {
+  if (is_input_device_manager_)
+    InputDeviceManager::SetInstance(this);
+}
+
+mojom::InputDeviceObserverMojoPtr InputDeviceClient::GetIntefacePtr() {
+  return binding_.CreateInterfacePtrAndBind();
 }
 
 void InputDeviceClient::OnKeyboardDeviceConfigurationChanged(
@@ -72,41 +117,4 @@
   }
 }
 
-void InputDeviceClient::AddObserver(ui::InputDeviceEventObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void InputDeviceClient::RemoveObserver(ui::InputDeviceEventObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetKeyboardDevices()
-    const {
-  return keyboard_devices_;
-}
-
-const std::vector<ui::TouchscreenDevice>&
-InputDeviceClient::GetTouchscreenDevices() const {
-  return touchscreen_devices_;
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetMouseDevices() const {
-  return mouse_devices_;
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetTouchpadDevices()
-    const {
-  return touchpad_devices_;
-}
-
-bool InputDeviceClient::AreDeviceListsComplete() const {
-  return device_lists_complete_;
-}
-
-bool InputDeviceClient::AreTouchscreensEnabled() const {
-  // TODO(kylechar): This obviously isn't right. We either need to pass this
-  // state around or modify the interface.
-  return true;
-}
-
 }  // namespace ui
diff --git a/services/ui/public/cpp/input_devices/input_device_client.h b/services/ui/public/cpp/input_devices/input_device_client.h
index 54e578d..50a9fa1 100644
--- a/services/ui/public/cpp/input_devices/input_device_client.h
+++ b/services/ui/public/cpp/input_devices/input_device_client.h
@@ -47,7 +47,12 @@
   void AddObserver(ui::InputDeviceEventObserver* observer) override;
   void RemoveObserver(ui::InputDeviceEventObserver* observer) override;
 
- private:
+ protected:
+  // Default constructor registers as InputDeviceManager. Can be subclassed in
+  // tests to avoid this.
+  explicit InputDeviceClient(bool is_input_device_manager);
+  mojom::InputDeviceObserverMojoPtr GetIntefacePtr();
+
   // mojom::InputDeviceObserverMojo:
   void OnKeyboardDeviceConfigurationChanged(
       const std::vector<ui::InputDevice>& devices) override;
@@ -63,8 +68,11 @@
       const std::vector<ui::InputDevice>& mouse_devices,
       const std::vector<ui::InputDevice>& touchpad_devices) override;
 
+ private:
   mojo::Binding<mojom::InputDeviceObserverMojo> binding_;
 
+  bool is_input_device_manager_;
+
   // Holds the list of input devices and signal that we have received the lists
   // after initialization.
   std::vector<ui::InputDevice> keyboard_devices_;
diff --git a/services/ui/surfaces/display_compositor.cc b/services/ui/surfaces/display_compositor.cc
index 5cb51a1..1f38c4f8 100644
--- a/services/ui/surfaces/display_compositor.cc
+++ b/services/ui/surfaces/display_compositor.cc
@@ -121,16 +121,4 @@
 void DisplayCompositor::DisplaySetMemoryPolicy(
     const cc::ManagedMemoryPolicy& policy) {}
 
-void DisplayCompositor::DisplayWillDrawAndSwap(
-    bool will_draw_and_swap,
-    const cc::RenderPassList& render_passes) {
-  // This notification is not relevant to our client outside of tests.
-}
-
-void DisplayCompositor::DisplayDidDrawAndSwap() {
-  // This notification is not relevant to our client outside of tests. We
-  // unblock the client from the DrawCallback when the surface is going to
-  // be drawn.
-}
-
 }  // namespace ui
diff --git a/services/ui/surfaces/display_compositor.h b/services/ui/surfaces/display_compositor.h
index dfeed0d..13019cb1 100644
--- a/services/ui/surfaces/display_compositor.h
+++ b/services/ui/surfaces/display_compositor.h
@@ -60,9 +60,6 @@
   // DisplayClient implementation.
   void DisplayOutputSurfaceLost() override;
   void DisplaySetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override;
-  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
-                              const cc::RenderPassList& render_passes) override;
-  void DisplayDidDrawAndSwap() override;
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   scoped_refptr<SurfacesState> surfaces_state_;
diff --git a/testing/android/native_test/native_test_launcher.cc b/testing/android/native_test/native_test_launcher.cc
index aadf06a..32b47f5 100644
--- a/testing/android/native_test/native_test_launcher.cc
+++ b/testing/android/native_test/native_test_launcher.cc
@@ -29,6 +29,8 @@
 #include "jni/NativeTest_jni.h"
 #include "testing/android/native_test/native_test_util.h"
 
+using base::android::JavaParamRef;
+
 // The main function of the program to be wrapped as a test apk.
 extern int main(int argc, char** argv);
 
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 264d8729..d41b2de 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -25,6 +25,9 @@
         "args": [
           "--override-use-gl-with-osmesa-for-tests"
         ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "mash_unittests"
       }
     ]
@@ -50,6 +53,9 @@
         "args": [
           "--override-use-gl-with-osmesa-for-tests"
         ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "mash_unittests"
       }
     ]
@@ -117,6 +123,9 @@
         "test": "chromeos_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "chromevox_tests"
       },
       {
@@ -145,9 +154,6 @@
         "test": "crypto_unittests"
       },
       {
-        "test": "dbus_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -215,6 +221,12 @@
       },
       {
         "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "input_device_unittests"
+      },
+      {
+        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 3
         },
@@ -257,6 +269,9 @@
         "test": "midi_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "nacl_helper_nonsfi_unittests"
       },
       {
@@ -272,6 +287,9 @@
         "test": "net_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ozone_unittests"
       },
       {
@@ -320,6 +338,9 @@
         "test": "sync_unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_arc_unittests"
       },
       {
@@ -329,6 +350,9 @@
         "test": "ui_base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_chromeos_unittests"
       },
       {
@@ -421,6 +445,9 @@
           "--use-test-config"
         ],
         "name": "mash_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
         "test": "browser_tests"
       },
       {
@@ -455,6 +482,9 @@
         "test": "chromeos_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "chromevox_tests"
       },
       {
@@ -488,9 +518,6 @@
         "test": "crypto_unittests"
       },
       {
-        "test": "dbus_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -560,6 +587,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "input_device_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "interactive_ui_tests"
       },
       {
@@ -608,6 +641,9 @@
         "test": "midi_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "nacl_helper_nonsfi_unittests"
       },
       {
@@ -668,6 +704,9 @@
         "test": "sync_unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_arc_unittests"
       },
       {
@@ -677,6 +716,9 @@
         "test": "ui_base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_chromeos_unittests"
       },
       {
@@ -824,9 +866,6 @@
         "test": "crypto_unittests"
       },
       {
-        "test": "dbus_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -930,6 +969,9 @@
         "test": "midi_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "nacl_helper_nonsfi_unittests"
       },
       {
@@ -990,6 +1032,9 @@
         "test": "sync_unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_arc_unittests"
       },
       {
@@ -999,6 +1044,9 @@
         "test": "ui_base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_chromeos_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.full.json b/testing/buildbot/chromium.full.json
index 6e5ea18..29f26fd 100644
--- a/testing/buildbot/chromium.full.json
+++ b/testing/buildbot/chromium.full.json
@@ -191,6 +191,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
@@ -482,6 +485,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
@@ -771,6 +777,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 4fff6ed2..bba53a4 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -639,6 +639,9 @@
       },
       {
         "test": "webapk_client_junit_tests"
+      },
+      {
+        "test": "webapk_shell_apk_junit_tests"
       }
     ],
     "scripts": [
@@ -840,15 +843,27 @@
         "test": "capture_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "cast_alsa_cma_backend_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "cast_base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "cast_crash_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "cast_media_unittests"
       },
       {
@@ -859,9 +874,15 @@
           "--no-sandbox",
           "--test-launcher-jobs=1"
         ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "cast_shell_browser_test"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "cast_shell_unittests"
       },
       {
@@ -1119,6 +1140,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
@@ -1203,6 +1227,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "input_device_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "interactive_ui_tests"
       },
       {
@@ -1314,6 +1344,9 @@
         "test": "mus_clipboard_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "mus_gpu_unittests"
       },
       {
@@ -1623,6 +1656,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
@@ -1656,6 +1692,9 @@
         "test": "extensions_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "filesystem_service_unittests"
       },
       {
@@ -1768,6 +1807,9 @@
         "test": "mus_clipboard_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "mus_gpu_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.full.json b/testing/buildbot/chromium.memory.full.json
index 6e5ea18..29f26fd 100644
--- a/testing/buildbot/chromium.memory.full.json
+++ b/testing/buildbot/chromium.memory.full.json
@@ -191,6 +191,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
@@ -482,6 +485,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
@@ -771,6 +777,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json
index 6e5ea18..29f26fd 100644
--- a/testing/buildbot/chromium.memory.fyi.json
+++ b/testing/buildbot/chromium.memory.fyi.json
@@ -191,6 +191,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
@@ -482,6 +485,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
@@ -771,6 +777,9 @@
         "test": "crypto_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "dbus_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 72540d8..6917cf03 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -516,6 +516,9 @@
         "test": "sync_unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_arc_unittests"
       },
       {
@@ -525,6 +528,9 @@
         "test": "ui_base_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_chromeos_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 3d4f81e..40dc302 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -238,6 +238,9 @@
         "test": "jingle_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "keyboard_unittests"
       },
       {
@@ -316,6 +319,9 @@
         "test": "mojo_system_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "mus_gpu_unittests"
       },
       {
@@ -325,6 +331,9 @@
         "test": "mus_public_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "mus_ws_unittests"
       },
       {
@@ -737,6 +746,9 @@
         "test": "jingle_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "keyboard_unittests"
       },
       {
@@ -1195,6 +1207,9 @@
         "test": "jingle_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "keyboard_unittests"
       },
       {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 27d6124b..23a140d 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -173,19 +173,19 @@
   },
   "cast_alsa_cma_backend_unittests": {
     "label": "//chromecast/media/cma/backend/alsa:cast_alsa_cma_backend_unittests",
-    "type": "unknown",
+    "type": "console_test_launcher",
   },
   "cast_base_unittests": {
     "label": "//cast:cast_base_unittests",
-    "type": "unknown",
+    "type": "console_test_launcher",
   },
   "cast_crash_unittests": {
     "label": "//chromecast/crash:cast_crash_unittests",
-    "type": "unknown",
+    "type": "console_test_launcher",
   },
   "cast_shell_unittests": {
     "label": "//chromecast/app:cast_shell_unittests",
-    "type": "unknown",
+    "type": "console_test_launcher",
   },
   "cast_unittests": {
     "label": "//media/cast:cast_unittests",
@@ -219,6 +219,10 @@
     "label": "//chromeos:chromeos_unittests",
     "type": "console_test_launcher",
   },
+  "chromevox_tests": {
+    "label": "//chrome/browser/resources/chromeos/chromevox:chromevox_tests",
+    "type": "windowed_test_launcher",
+  },
   "components_browsertests": {
     "label": "//components:components_browsertests",
     "type": "windowed_test_launcher",
@@ -260,7 +264,7 @@
   },
   "dbus_unittests": {
     "label": "//dbus:dbus_unittests",
-    "type": "unknown",
+    "type": "windowed_test_launcher",
   },
   "device_unittests": {
     "label": "//device:device_unittests",
@@ -342,6 +346,10 @@
     "label": "//headless:headless_unittests",
     "type": "console_test_launcher",
   },
+  "input_device_unittests": {
+    "label": "//services/ui/input_devices:input_device_unittests",
+    "type": "console_test_launcher",
+  },
   "installer_util_unittests": {
     "label": "//chrome/installer/util:installer_util_unittests",
     "type": "console_test_launcher",
@@ -364,7 +372,7 @@
   },
   "keyboard_unittests": {
     "label": "//ui/keyboard:keyboard_unittests",
-    "type": "unknown",
+    "type": "console_test_launcher",
   },
   "leveldb_service_unittests": {
     "label": "//components/leveldb:leveldb_service_unittests",
@@ -460,6 +468,11 @@
     "label": "//services/ui/ws:mus_ws_unittests",
     "type": "windowed_test_launcher",
   },
+  "nacl_helper_nonsfi_unittests": {
+    "label": "//components/nacl/loader:nacl_helper_nonsfi_unittests",
+    "type": "raw",
+    "args": [],
+  },
   "nacl_loader_unittests": {
     "label": "//components/nacl/loader:nacl_loader_unittests",
     "type": "raw",
@@ -475,7 +488,7 @@
   },
   "ozone_unittests": {
     "label": "//ui/ozone:ozone_unittests",
-    "type": "unknown",
+    "type": "console_test_launcher",
   },
   "ppapi_unittests": {
     "label": "//ppapi:ppapi_unittests",
@@ -595,7 +608,7 @@
   },
   "ui_chromeos_unittests": {
     "label": "//ui/chromeos:ui_chromeos_unittests",
-    "type": "unknown",
+    "type": "windowed_test_launcher",
   },
   "ui_arc_unittests": {
     "label": "//ui/arc:ui_arc_unittests",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/isolate-extensions b/third_party/WebKit/LayoutTests/FlagExpectations/isolate-extensions
index 51df470..c4ee30e6 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/isolate-extensions
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/isolate-extensions
@@ -1,4 +1 @@
-# These tests currently fail when they run with --isolate-sites-for-testing=*.is
-
-# https://crbug.com/585194 - back/forward lists look different with --site-per-process
-http/tests/navigation/back-to-dynamic-iframe.html [ Failure Timeout ]
+# Any tests below fail when they run with --isolate-sites-for-testing=*.is
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index 775cbf9..5f9177e6 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -41,9 +41,6 @@
 http/tests/security/mixedContent/insecure-iframe-in-iframe.html [ Failure ]
 http/tests/security/mixedContent/insecure-iframe-in-main-frame-allowed.html [ Failure ]
 
-# https://crbug.com/585194 - back/forward lists look different with --site-per-process
-http/tests/navigation/back-to-dynamic-iframe.html [ Failure Timeout ]
-
 # https://crbug.com/585188 - testRunner.addOriginAccessWhitelistEntry is not replicated to OOPIFs.
 http/tests/xmlhttprequest/origin-whitelisting-all.html [ Failure ]
 http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 24e0a1b..19fdc070 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1236,7 +1236,9 @@
 
 crbug.com/577380 [ Linux Debug ] http/tests/serviceworker/chromium/registration-stress.html [ Failure ]
 
-crbug.com/587136 [ Linux Debug ] http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Timeout Pass ]
+crbug.com/634199 http/tests/serviceworker/fetch-event-network-error.html [ Crash Pass ]
+
+crbug.com/634264 http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Crash ]
 
 crbug.com/587593 [ Android ] fast/js/pic/cached-single-entry-transition.html [ Pass Failure ]
 
@@ -1370,7 +1372,7 @@
 
 crbug.com/627782 [ Win ] svg/filters/filter-source-position.svg [ Pass Failure ]
 
-# crbug.com/627798 editing/spelling/inline-spelling-markers-hidpi-composited.html [ Pass Failure ]
+crbug.com/627798 editing/spelling/inline-spelling-markers-hidpi-composited.html [ Pass Failure ]
 crbug.com/627798 fast/repaint/line-flow-with-floats-9.html [ Pass Failure ]
 crbug.com/627798 fast/repaint/nested-fixed-iframe-scrolled.html [ Pass Failure ]
 crbug.com/627798 fast/repaint/repaint-during-scroll-with-zoom.html [ Pass Failure ]
@@ -1401,14 +1403,10 @@
 crbug.com/631039 [ Win7 ] virtual/threaded/fast/scroll-behavior/main-frame-scroll.html [ Pass Failure ]
 crbug.com/631039 [ Win7 ] virtual/threaded/fast/scroll-behavior/overflow-scroll-scroll.html [ Pass Failure ]
 
-crbug.com/619452 editing/spelling/inline-spelling-markers-hidpi-composited.html [ NeedsManualRebaseline ]
-
 crbug.com/630870 svg/animations/use-animate-width-and-height.html [ Skip ]
 # Flaky on Win7 dbg and Mac10.11 (retina)
 crbug.com/634019 [ Win7 Debug Mac10.11 Retina ] virtual/asyncawait/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html [ Pass Timeout ]
 
-crbug.com/634073 [ Win7 ] transforms/2d/hindi-rotated.html [ Pass Failure ]
-
 # This test breaks when the feature introduced in the bug is enabled. We keep
 # this tested without the feature by using the virtual test. See
 # virtual/stable/http/tests/navigation/beacon-cross-origin-redirect-blob-expected.txt
diff --git a/third_party/WebKit/LayoutTests/accessibility/show-context-menu-crash.html b/third_party/WebKit/LayoutTests/accessibility/show-context-menu-crash.html
new file mode 100644
index 0000000..8f06ccd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/accessibility/show-context-menu-crash.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<script>
+test(function(t)
+{
+    accessibilityController.focusedElement.showMenu();
+}, "showing the context menu on the document element should not crash");
+</script>
+
+
+<script>
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/compositing/change-compositing-settings.html b/third_party/WebKit/LayoutTests/compositing/change-compositing-settings.html
deleted file mode 100644
index 48c0a63d..0000000
--- a/third_party/WebKit/LayoutTests/compositing/change-compositing-settings.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE HTML>
-<script src="../resources/js-test.js"></script>
-<style>
-#scroller {
-    overflow: scroll;
-    height: 300px;
-    width: 300px;
-    background-color: red;
-}
-
-#scrolled {
-    height: 1000px;
-    width: 250px;
-    background-color: green;
-}
-</style>
-
-<script>
-jsTestIsAsync = true;
-
-description('This test checks that changes to the compositor\'s settings are applied correctly.');
-
-function isUsingCompositedScrolling(layer) {
-    layer = layer || JSON.parse(window.internals.layerTreeAsText(document));
-    if (layer.bounds[1] == 1000)
-        return true;
-    if (layer.children) {
-        for (var i = 0; i < layer.children.length; i++) {
-            if (isUsingCompositedScrolling(layer.children[i]))
-                return true;
-        }
-    }
-    return false;
-}
-
-window.onload = function() {
-    if (!window.internals) {
-        testFailed('This test requires window.internals');
-        return;
-    }
-    window.internals.settings.setPreferCompositingToLCDTextEnabled(false);
-    var stateBefore = isUsingCompositedScrolling();
-    window.internals.settings.setPreferCompositingToLCDTextEnabled(true);
-    var stateAfter = isUsingCompositedScrolling();
-
-    if (!stateBefore && stateAfter) {
-        testPassed('Composited scrolling became enabled.');
-    } else {
-        testFailed('Composited scrolling did not become enabled: ' + stateBefore + ", " + stateAfter);
-    }
-    finishJSTest();
-};
-</script>
-
-<div id="scroller">
-    <div id="scrolled"></div>
-</div>
diff --git a/third_party/WebKit/LayoutTests/compositing/change-preferCompositingToLCDText-setting.html b/third_party/WebKit/LayoutTests/compositing/change-preferCompositingToLCDText-setting.html
new file mode 100644
index 0000000..8165651
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/change-preferCompositingToLCDText-setting.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<style>
+#scroller {
+    overflow: scroll;
+    height: 300px;
+    width: 300px;
+    background-color: rgba(255,0,0,0.5); /* Force non-promotion due to background opacity */;
+}
+
+#scrolled {
+    height: 1000px;
+    width: 250px;
+    background-color: rgba(0,128,0,0.5); /* Force non-promotion due to background opacity */;
+}
+</style>
+
+<script>
+
+var t = async_test("Check that the preferCompositingToLCDText flag results in compositing");
+
+function isUsingCompositedScrolling(layer) {
+    layer = layer || JSON.parse(window.internals.layerTreeAsText(document));
+    if (layer.bounds[1] == 1000)
+        return true;
+    if (layer.children) {
+        for (var i = 0; i < layer.children.length; i++) {
+            if (isUsingCompositedScrolling(layer.children[i]))
+                return true;
+        }
+    }
+    return false;
+}
+
+window.onload = function() {
+  t.step(function() {
+    assert_not_equals(window.internals, null, 'This test requires window.internals');
+
+    window.internals.settings.setPreferCompositingToLCDTextEnabled(false);
+    var stateBefore = isUsingCompositedScrolling();
+    window.internals.settings.setPreferCompositingToLCDTextEnabled(true);
+    var stateAfter = isUsingCompositedScrolling();
+
+    assert_false(stateBefore, 'Composited scrolling began disabled');
+    assert_true(stateAfter, 'Composited scrolling became enabled');
+    t.done();
+  });
+};
+</script>
+
+<div id="scroller">
+    <div id="scrolled"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers.html b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers.html
index cf61ae31..225fbf6 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers.html
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers.html
@@ -67,7 +67,7 @@
   <pre id="layertree"></pre>
 
   <div class="scrollable bigBox">
-    <div style="height: 800px;"></div>
+    <div style="height: 800px; background-image: linear-gradient(to bottom,red,orange,yellow, green, blue,indigo,violet);"></div>
     <div class="fixed lime box"></div>
   </div>
 </body>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent.html b/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent.html
index 262affad..ccd0946 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent.html
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent.html
@@ -8,6 +8,7 @@
         border: 4px solid black;
         overflow-y: scroll;
         resize: both;
+        background-color: rgba(0,255,0,0.5);
     }
 
     .box {
@@ -16,7 +17,7 @@
         height: 100px;
         width: 100px;
         margin: 10px;
-        background-color: blue;
+        background-color: rgba(0,0,255,0.5);
     }
 
 
@@ -31,7 +32,7 @@
     }
 
     .red {
-        background-color: red;
+        background-color: rgba(255,0,0,0.5);
     }
 
     .clip {
@@ -54,7 +55,7 @@
         if (!window.internals) {
             var description = "This test ensures that amongst the graphics "
                 + "layers corresponding to a single Layer, only one may "
-                + "have a scroll parent."; 
+                + "have a scroll parent.";
             pre.innerHTML = description;
         } else {
             document.body.offsetTop;
diff --git a/third_party/WebKit/LayoutTests/custom-elements/spec/adopt-node.html b/third_party/WebKit/LayoutTests/custom-elements/spec/adopt-node.html
new file mode 100644
index 0000000..4ef1a13
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/custom-elements/spec/adopt-node.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Custom Elements: adopt node</title>
+<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-adopt">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/custom-elements-helpers.js"></script>
+<body>
+<script>
+'use strict'
+
+// 3.2 For each inclusiveDescendant in node’s shadow-including inclusive descendants that is a custom 
+// element, enqueue a custom element callback reaction with inclusiveDescendant,
+// callback name "adoptedCallback", and an empty argument list.
+promise_test((t) => {
+  return Promise.all([
+    create_window_in_test(t),
+    create_window_in_test(t)])
+    .then(([w1, w2]) => {
+      let invocations = [];
+      class X extends w1.HTMLElement {
+        adoptedCallback() { invocations.push(['adopted', this, []]); }
+      }
+      w1.customElements.define('a-a', X);
+      let a = w1.document.createElement('a-a');
+      w2.document.adoptNode(a);
+      assert_array_equals_callback_invocations(invocations, [ ['adopted', a, []] ]);
+    });
+}, 'adopting a custom element to the different document should enqueue an adoptedCallback reaction');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js b/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
index d5030f0..7a1c7196 100644
--- a/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
+++ b/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
@@ -32,4 +32,14 @@
     }
   }, description);
   assert_true(exception instanceof global_context.DOMException, 'DOMException on the appropriate window');
-}
\ No newline at end of file
+}
+
+function assert_array_equals_callback_invocations(actual, expected, description) {
+  assert_equals(actual.length, expected.length);
+  for (let len=actual.length, i=0; i<len; ++i) {
+    let callback = expected[i][0];
+    assert_equals(actual[i][0], expected[i][0], callback + ' callback should be invoked');
+    assert_equals(actual[i][1], expected[i][1], callback + ' should be invoked on the element ' + expected[i][1]);
+    assert_array_equals(actual[i][2], expected[i][2], callback + ' should be invoked with the arguments ' + expected[i][2]);
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-edit-word-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/grammar-edit-word-expected.txt
new file mode 100644
index 0000000..2b8c72c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-edit-word-expected.txt
@@ -0,0 +1,13 @@
+Test if WebKit removes grammar markers when we edit a grammatically-incorrect word. To test manually, type a grammatically-incorrect sentence "You has the right." and type a backspace key to delete the last character of "has". This test succeeds when "ha" does not have grammar markers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 4, 2) became false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+You ha
+
+
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-edit-word.html b/third_party/WebKit/LayoutTests/editing/spelling/grammar-edit-word.html
new file mode 100644
index 0000000..957862c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-edit-word.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<title>Editing a grammatically-incorrect word</title> 
+</head> 
+<body>
+<div id="src" contenteditable="true" spellcheck="true"></div><br/>
+<script language="javascript">
+description('Test if WebKit removes grammar markers when we edit a grammatically-incorrect word. '
+    + 'To test manually, type a grammatically-incorrect sentence "You has the right." and type '
+    + 'a backspace key to delete the last character of "has". '
+    + 'This test succeeds when "ha" does not have grammar markers.');
+
+jsTestIsAsync = true;
+
+if (window.internals)
+    internals.settings.setUnifiedTextCheckerEnabled(true);
+
+function editAndCheckSentence()
+{
+    // Delete the end of this sentence until it becomes "You ha".
+    for (var i = 0; i < 12; ++i)
+        testRunner.execCommand("DeleteBackward");
+
+    shouldBecomeEqual('internals.hasGrammarMarker(document, 4, 2)', 'false', finishJSTest);
+}
+
+var target = document.getElementById('src');
+target.focus();
+document.execCommand("InsertText", false, "You has the right.");
+
+if (window.internals)
+    shouldBecomeEqual('internals.hasGrammarMarker(document, 4, 3)', 'true', editAndCheckSentence);
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/grammar-expected.txt
new file mode 100644
index 0000000..61e6023
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-expected.txt
@@ -0,0 +1,10 @@
+This tests whether the grammatically-incorrect phrase 'I have a issue' has grammar marker on 'a'.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.hasGrammarMarker(document, 7, 1) became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-expected.txt
new file mode 100644
index 0000000..2cb8b16
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-expected.txt
@@ -0,0 +1,12 @@
+This tests whether WebKit can render grammar markers when pasting text if it has a grammar-checker. To test manually, copy the text in the first div element and paste it to the second div element. This test succeeds when WebKit renders a grammar marker under a word "has".
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS ungrammatical phrase 'has' on 'You has the right.'
+PASS verifyGrammarMarker(target, "has") became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+You has the right.
+You has the right.
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-hidpi-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-hidpi-expected.txt
new file mode 100644
index 0000000..2cb8b16
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-hidpi-expected.txt
@@ -0,0 +1,12 @@
+This tests whether WebKit can render grammar markers when pasting text if it has a grammar-checker. To test manually, copy the text in the first div element and paste it to the second div element. This test succeeds when WebKit renders a grammar marker under a word "has".
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS ungrammatical phrase 'has' on 'You has the right.'
+PASS verifyGrammarMarker(target, "has") became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+You has the right.
+You has the right.
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-hidpi.html b/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-hidpi.html
new file mode 100644
index 0000000..05a9fc62
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers-hidpi.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+</head>
+<body>
+<div id="source" contenteditable="true" spellcheck="false">You has the right.</div>
+<div id="target" contenteditable="true" spellcheck="true"></div>
+
+<script>
+description('This tests whether WebKit can render grammar markers when pasting text if it has a grammar-checker. To test manually, copy the text in the first div element and paste it to the second div element. This test succeeds when WebKit renders a grammar marker under a word "has".');
+
+jsTestIsAsync = true;
+
+function verifyGrammarMarker(destination, ungrammaticalPhrase)
+{
+    if (internals.hasGrammarMarker(document, destination.innerHTML.indexOf(ungrammaticalPhrase), ungrammaticalPhrase.length)) {
+        testPassed("ungrammatical phrase '" + ungrammaticalPhrase + "' on '" + destination.innerHTML + "'");
+        return true;
+    } else
+        return false;
+}
+
+if (window.testRunner) {
+    testRunner.dumpAsTextWithPixelResults();
+    testRunner.setBackingScaleFactor(2, function () {
+        shouldBecomeEqual('verifyGrammarMarker(target, "has")', 'true', finishJSTest);
+    });
+}
+
+var source = document.getElementById('source');
+window.getSelection().selectAllChildren(source);
+document.execCommand('Copy');
+var target = document.getElementById('target');
+window.getSelection().selectAllChildren(target);
+document.execCommand('Paste');
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers.html b/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers.html
new file mode 100644
index 0000000..84d190d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-markers.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+</head>
+<body>
+<div id="source" contenteditable="true" spellcheck="false">You has the right.</div>
+<div id="target" contenteditable="true" spellcheck="true"></div>
+
+<script>
+description('This tests whether WebKit can render grammar markers when pasting text if it has a grammar-checker. To test manually, copy the text in the first div element and paste it to the second div element. This test succeeds when WebKit renders a grammar marker under a word "has".');
+
+jsTestIsAsync = true;
+
+if (window.testRunner)
+    testRunner.dumpAsTextWithPixelResults();
+
+function verifyGrammarMarker(destination, ungrammaticalPhrase)
+{
+    if (window.internals && internals.hasGrammarMarker(document, destination.innerHTML.indexOf(ungrammaticalPhrase), ungrammaticalPhrase.length)) {
+        testPassed("ungrammatical phrase '" + ungrammaticalPhrase + "' on '" + destination.innerHTML + "'");
+        return true;
+    } else
+        return false;
+}
+
+var source = document.getElementById('source');
+window.getSelection().selectAllChildren(source);
+document.execCommand('Copy');
+var target = document.getElementById('target');
+window.getSelection().selectAllChildren(target);
+document.execCommand('Paste');
+
+shouldBecomeEqual('verifyGrammarMarker(target, "has")', 'true', finishJSTest);
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-paste-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/grammar-paste-expected.txt
new file mode 100644
index 0000000..f5d1a94d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-paste-expected.txt
@@ -0,0 +1,27 @@
+Grammar checking for pasted text.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS DIV ungrammatical phrase 'has' on 'You has the right.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS DIV ungrammatical phrase 'a' on 'I have a<b>n ki</b>wi. I have no idea.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS DIV ungrammatical phrase 'an,an' on 'I have an grape. I have an muscat. I don't know.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS INPUT ungrammatical phrase 'has' on 'You has the right.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS INPUT ungrammatical phrase 'an' on 'I have an kiwi. I have no idea.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS INPUT ungrammatical phrase 'an,an' on 'I have an grape. I have an muscat. I don't know.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS TEXTAREA ungrammatical phrase 'has' on 'You has the right.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS TEXTAREA ungrammatical phrase 'an' on 'I have an kiwi. I have no idea.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS TEXTAREA ungrammatical phrase 'an,an' on 'I have an grape. I have an muscat. I don't know.'
+PASS verifyMarker(destination, ungrammaticalPhrase) became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar-paste.html b/third_party/WebKit/LayoutTests/editing/spelling/grammar-paste.html
new file mode 100644
index 0000000..73f2f1a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar-paste.html
@@ -0,0 +1,139 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+description('Grammar checking for pasted text.');
+
+jsTestIsAsync = true;
+
+var testRoot = document.createElement("div");
+document.body.insertBefore(testRoot, document.body.firstChild);
+
+var testTextArea = document.createElement("textarea");
+testRoot.appendChild(testTextArea);
+
+var testInput = document.createElement("input");
+testInput.setAttribute("type", "text");
+testRoot.appendChild(testInput);
+
+var testEditable = document.createElement("div");
+testEditable.setAttribute("contentEditable", "true");
+testRoot.appendChild(testEditable);
+
+var testSourcePlain = document.createElement("div");
+testSourcePlain.innerHTML = "You has the right.";
+testRoot.appendChild(testSourcePlain);
+
+var testSourceDecorated = document.createElement("div");
+testSourceDecorated.innerHTML = "I have a<b>n ki</b>wi. I have no idea.";
+testRoot.appendChild(testSourceDecorated);
+
+var testSourceMulti = document.createElement("div");
+testSourceMulti.innerHTML = "I have an grape. I have an muscat. I don't know.";
+testRoot.appendChild(testSourceMulti);
+
+var sel = window.getSelection();
+
+var tests = [];
+
+function done()
+{
+    var next = tests.shift();
+    if (next)
+        return window.setTimeout(next, 0);
+    testRoot.style.display = "none";
+    finishJSTest();
+}
+
+function findFirstTextNode(node)
+{
+    function iterToFindFirstTextNode(node)
+    {
+        if (node instanceof Text)
+            return node;
+
+        var childNodes = node.childNodes;
+        for (var i = 0; i < childNodes.length; ++i) {
+            var n = iterToFindFirstTextNode(childNodes[i]);
+            if (n)
+                return n;
+        }
+
+        return null;
+    }
+
+
+    if (node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement)
+        return iterToFindFirstTextNode(internals.shadowRoot(node));
+    else
+        return iterToFindFirstTextNode(node);
+}
+
+function verifyMarker(node, expectedMarked)
+{
+    if (node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement)
+        node.focus();
+    else
+        sel.selectAllChildren(node);
+
+    var textNode = findFirstTextNode(node);
+    var num = internals.markerCountForNode(textNode, "grammar");
+    if (num != expectedMarked.length)
+        return false;
+    for (var i = 0; i < num; ++i) {
+        var range = internals.markerRangeForNode(textNode, "grammar", i);
+        if (range.toString() != expectedMarked[i])
+            return false;
+    }
+
+    var nodeContent = node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement ? node.value : node.innerHTML;
+    testPassed(node.tagName + " ungrammatical phrase '" + expectedMarked + "' on '" + nodeContent + "'");
+
+    return true;
+}
+
+var destination = null;
+var expectedMarked = null;
+function pasteAndVerify(source, dest, expectedMarked)
+{
+    sel.selectAllChildren(source);
+    document.execCommand("Copy");
+    if (dest instanceof HTMLInputElement || dest instanceof HTMLTextAreaElement) {
+        dest.value = "";
+        dest.focus();
+    } else {
+        dest.innerHTML = "";
+        sel.selectAllChildren(dest);
+    }
+    document.execCommand("Paste");
+
+    if (window.internals) {
+        destination = dest;
+        ungrammaticalPhrase = expectedMarked;
+        shouldBecomeEqual('verifyMarker(destination, ungrammaticalPhrase)', 'true', done);
+    }
+};
+
+tests.push(function() { pasteAndVerify(testSourcePlain, testEditable, ["has"]); });
+tests.push(function() { pasteAndVerify(testSourceDecorated, testEditable, ["a"]); }); // Checks only 'a'.
+tests.push(function() { pasteAndVerify(testSourceMulti, testEditable, ["an", "an"]); });
+
+tests.push(function() { pasteAndVerify(testSourcePlain, testInput, ["has"]); });
+tests.push(function() { pasteAndVerify(testSourceDecorated, testInput, ["an"]); });
+tests.push(function() { pasteAndVerify(testSourceMulti, testInput, ["an", "an"]); });
+
+tests.push(function() { pasteAndVerify(testSourcePlain, testTextArea, ["has"]); });
+tests.push(function() { pasteAndVerify(testSourceDecorated, testTextArea, ["an"]); });
+tests.push(function() { pasteAndVerify(testSourceMulti, testTextArea, ["an", "an"]); });
+
+done();
+
+var successfullyParsed = true;
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/grammar.html b/third_party/WebKit/LayoutTests/editing/spelling/grammar.html
new file mode 100644
index 0000000..408c4e2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/spelling/grammar.html
@@ -0,0 +1,48 @@
+<html> 
+<head>
+<script src="../../resources/js-test.js"></script>
+
+<style>
+.editing { 
+    border: 2px solid red; 
+    padding: 12px; 
+    font-size: 24px; 
+}
+</style>
+<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
+
+<script>
+function editingTest() {
+    if (window.testRunner)
+        testRunner.dumpAsText();
+
+    document.getElementById("root").focus();
+    document.execCommand("InsertText", false, "I have a issue.");
+
+    if (window.internals) {
+        shouldBecomeEqual('internals.hasGrammarMarker(document, 7, 1)', 'true', function() {
+            document.getElementById("root").style.display = "none";
+            finishJSTest();
+        });
+    }
+}
+
+</script>
+
+<title>Editing Test</title> 
+</head> 
+<body>
+<div contenteditable id="root" class="editing"></div>
+<script>
+description("This tests whether the grammatically-incorrect phrase "
+    + "'I have a issue' has grammar marker on 'a'.");
+
+jsTestIsAsync = true;
+
+if (window.internals)
+    internals.settings.setUnifiedTextCheckerEnabled(true);
+
+editingTest();
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-composited-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-composited-expected.txt
index bf321e2..9c32b79 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-composited-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-composited-expected.txt
@@ -1,4 +1,4 @@
-This tests the correct placement of inline spelling markers in text. Spelling markers should line up exactly under misspelled words in all cases.
+This tests the correct placement of inline spelling and grammar markers in text. Spelling markers should line up exactly under misspelled words in all cases.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
@@ -7,18 +7,26 @@
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testRTL:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testLTREllipses:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testRTLEllipses:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-composited.html b/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-composited.html
index 1613519..02b2255 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-composited.html
+++ b/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-composited.html
@@ -26,7 +26,7 @@
 <body>
 
 <script>
-description("This tests the correct placement of inline spelling "
+description("This tests the correct placement of inline spelling and grammar "
     + "markers in text. Spelling markers should line up exactly under misspelled "
     + "words in all cases.");
 
@@ -67,15 +67,22 @@
     if (!window.internals)
         return done();
 
+    // Take care of spelling markers first.
     shouldBecomeEqual('internals.hasSpellingMarker(document, 8, 4)', 'true', function() { // Verifies 'adlj'.
         shouldBecomeEqual('internals.hasSpellingMarker(document, 13, 6)', 'true', function() { // Verifies 'adaasj'.
-            shouldBecomeEqual('internals.hasSpellingMarker(document, 20, 5)', 'true', function() { // Verifies 'sdklj'.
+            shouldBecomeEqual('internals.hasSpellingMarker(document, 20, 5)', 'true', verifyGrammarMarkers) // Verifies 'sdklj'.
+        })
+    });
+
+    function verifyGrammarMarkers() {
+        shouldBecomeEqual('internals.hasGrammarMarker(document, 4, 3)', 'true', function() { // Verifies second 'the'.
+            shouldBecomeEqual('internals.hasGrammarMarker(document, 33, 5)', 'true', function() { // Verifies second 'there'.
                 // Markers of next element can not be found after modification selection without blur event.
                 div.blur();
                 done();
             })
-        })
-    });
+        });
+    }
 }
 
 var tests = [ function() { moveCursorOverAllWords('testLTR'); },
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-expected.txt
index bf321e2..9c32b79 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi-expected.txt
@@ -1,4 +1,4 @@
-This tests the correct placement of inline spelling markers in text. Spelling markers should line up exactly under misspelled words in all cases.
+This tests the correct placement of inline spelling and grammar markers in text. Spelling markers should line up exactly under misspelled words in all cases.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
@@ -7,18 +7,26 @@
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testRTL:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testLTREllipses:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testRTLEllipses:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi.html b/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi.html
index 1cf623c..bac826a 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi.html
+++ b/third_party/WebKit/LayoutTests/editing/spelling/inline-spelling-markers-hidpi.html
@@ -27,7 +27,7 @@
 <body>
 
 <script>
-description("This tests the correct placement of inline spelling "
+description("This tests the correct placement of inline spelling and grammar "
     + "markers in text. Spelling markers should line up exactly under misspelled "
     + "words in all cases.");
 
@@ -68,15 +68,22 @@
     if (!window.internals)
         return done();
 
+    // Take care of spelling markers first.
     shouldBecomeEqual('internals.hasSpellingMarker(document, 8, 4)', 'true', function() { // Verifies 'adlj'.
         shouldBecomeEqual('internals.hasSpellingMarker(document, 13, 6)', 'true', function() { // Verifies 'adaasj'.
-            shouldBecomeEqual('internals.hasSpellingMarker(document, 20, 5)', 'true', function() { // Verifies 'sdklj'.
+            shouldBecomeEqual('internals.hasSpellingMarker(document, 20, 5)', 'true', verifyGrammarMarkers) // Verifies 'sdklj'.
+        })
+    });
+
+    function verifyGrammarMarkers() {
+        shouldBecomeEqual('internals.hasGrammarMarker(document, 4, 3)', 'true', function() { // Verifies second 'the'.
+            shouldBecomeEqual('internals.hasGrammarMarker(document, 33, 5)', 'true', function() { // Verifies second 'there'.
                 // Markers of next element can not be found after modification selection without blur event.
                 div.blur();
                 done();
             })
-        })
-    });
+        });
+    }
 }
 
 var tests = [ function() { moveCursorOverAllWords('testLTR'); },
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/inline_spelling_markers-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/inline_spelling_markers-expected.txt
index 91554993..b176b68 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/inline_spelling_markers-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/spelling/inline_spelling_markers-expected.txt
@@ -1,4 +1,4 @@
-This tests the correct placement of inline spelling markers in text. Spelling markers should line up exactly under misspelled words in all cases.
+This tests the correct placement of inline spelling and grammar markers in text. Spelling markers should line up exactly under misspelled words in all cases.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
@@ -7,18 +7,26 @@
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testRTL:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testLTREllipses:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 testRTLEllipses:
 PASS internals.hasSpellingMarker(document, 8, 4) became true
 PASS internals.hasSpellingMarker(document, 13, 6) became true
 PASS internals.hasSpellingMarker(document, 20, 5) became true
+PASS internals.hasGrammarMarker(document, 4, 3) became true
+PASS internals.hasGrammarMarker(document, 33, 5) became true
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/inline_spelling_markers.html b/third_party/WebKit/LayoutTests/editing/spelling/inline_spelling_markers.html
index 54dbf29..da206462 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/inline_spelling_markers.html
+++ b/third_party/WebKit/LayoutTests/editing/spelling/inline_spelling_markers.html
@@ -27,7 +27,7 @@
 </head>
 <body>
 <script>
-description("This tests the correct placement of inline spelling "
+description("This tests the correct placement of inline spelling and grammar "
     + "markers in text. Spelling markers should line up exactly under misspelled "
     + "words in all cases.");
 
@@ -72,15 +72,22 @@
     if (!window.internals)
         return done();
 
+    // Take care of spelling markers first.
     shouldBecomeEqual('internals.hasSpellingMarker(document, 8, 4)', 'true', function() { // Verifies 'adlj'.
         shouldBecomeEqual('internals.hasSpellingMarker(document, 13, 6)', 'true', function() { // Verifies 'adaasj'.
-            shouldBecomeEqual('internals.hasSpellingMarker(document, 20, 5)', 'true', function() { // Verifies 'sdklj'.
+            shouldBecomeEqual('internals.hasSpellingMarker(document, 20, 5)', 'true', verifyGrammarMarkers) // Verifies 'sdklj'.
+        })
+    });
+
+    function verifyGrammarMarkers() {
+        shouldBecomeEqual('internals.hasGrammarMarker(document, 4, 3)', 'true', function() { // Verifies second 'the'.
+            shouldBecomeEqual('internals.hasGrammarMarker(document, 33, 5)', 'true', function() { // Verifies second 'there'.
                 // Markers of next element can not be found after modification selection without blur event.
                 div.blur();
                 done();
             })
-        })
-    });
+        });
+    }
 }
 
 var tests = [ function() { moveCursorOverAllWords('testLTR'); },
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/markers-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/markers-expected.txt
index 01c55ff..42f00f3 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/markers-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/spelling/markers-expected.txt
@@ -1,4 +1,4 @@
-Tests spelling markers for misspellings.
+Tests spelling and grammar markers for misspellings.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
@@ -7,8 +7,13 @@
 PASS range.toString() is next.issue
 PASS internals.markerCountForNode(element.firstChild, next.marker) became 1
 PASS range.toString() is next.issue
+PASS internals.markerCountForNode(element.firstChild, next.marker) became 1
+PASS range.toString() is next.issue
+PASS internals.markerCountForNode(element.firstChild, next.marker) became 1
+PASS range.toString() is next.issue
 PASS successfullyParsed is true
 
 TEST COMPLETE
+I have a issue.
 zz.
 orange,zz,apple.
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/markers.html b/third_party/WebKit/LayoutTests/editing/spelling/markers.html
index fe97fd8..bb0b7f45 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/markers.html
+++ b/third_party/WebKit/LayoutTests/editing/spelling/markers.html
@@ -14,7 +14,7 @@
 <body>
 <div id="container"></div>
 <script>
-description("Tests spelling markers for misspellings.");
+description("Tests spelling and grammar markers for misspellings.");
 
 jsTestIsAsync = true;
 
@@ -38,11 +38,14 @@
 
 var container = document.getElementById('container');
 
+var elementWithGrammarIssue = createEditableElement(container);
+typeText(elementWithGrammarIssue, 'I have a issue.');
+
 var elementWithSpellingIssue  = createEditableElement(container);
 typeText(elementWithSpellingIssue, 'zz.');
 
-var elementAlsoWithSpellingIssue = createEditableElement(container);
-typeText(elementAlsoWithSpellingIssue, 'orange,zz,apple.');
+var elementWithGrammarAndSpellingIssue = createEditableElement(container);
+typeText(elementWithGrammarAndSpellingIssue, 'orange,zz,apple.');
 
 var element;
 var next;
@@ -65,12 +68,15 @@
 }
 
 var misspellings = [
+    { marker:'grammar', issue:'a' },
     { marker:'spelling', issue:'zz' },
+    { marker:'grammar', issue:'orange,zz,apple.' }
 ];
 
 var tests = [
-    function() { verifyMarkers(elementWithSpellingIssue, misspellings.slice(0, 1)) },
-    function() { verifyMarkers(elementAlsoWithSpellingIssue, misspellings.slice(0, 1)) },
+    function() { verifyMarkers(elementWithGrammarIssue, misspellings.slice(0, 1)) },
+    function() { verifyMarkers(elementWithSpellingIssue, misspellings.slice(1, 2)) },
+    function() { verifyMarkers(elementWithGrammarAndSpellingIssue, misspellings.slice(1, 3)) },
 ];
 
 function done()
diff --git a/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store-expected.txt b/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store-expected.txt
index 5c963f3..ea256ee 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store-expected.txt
@@ -25,7 +25,8 @@
                   "children": [
                     {
                       "name": "LayoutBlockFlow DIV id='content'",
-                      "bounds": [285, 1000]
+                      "bounds": [285, 1000],
+                      "drawsContent": true
                     }
                   ]
                 }
diff --git a/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store.html b/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store.html
index 70fe5239..8ee2297 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store.html
+++ b/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store.html
@@ -18,12 +18,12 @@
     width: 300px;
     height: 300px;
     overflow: auto;
-    background-color: lime;
 }
 
 #content {
     height: 1000px;
     transform: translatez(0);
+    background-image: linear-gradient(to bottom,red,orange,yellow, green, blue,indigo,violet);
 }
 
 </style>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/create-element-after-stack-overflow-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/create-element-after-stack-overflow-expected.txt
index dccf03a5..509484a 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/create-element-after-stack-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/create-element-after-stack-overflow-expected.txt
@@ -1,3 +1,2 @@
 CONSOLE ERROR: line 10: Uncaught RangeError: Maximum call stack size exceeded.
-CONSOLE ERROR: line 11: Uncaught RangeError: Failed to execute 'createdCallback' on 'HTMLMarqueeElement': Maximum call stack size exceeded.
 Pass when no crash observed.
diff --git a/third_party/WebKit/LayoutTests/fast/dom/create-element-after-stack-overflow.html b/third_party/WebKit/LayoutTests/fast/dom/create-element-after-stack-overflow.html
index aa1ae4f..3e0304c 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/create-element-after-stack-overflow.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/create-element-after-stack-overflow.html
@@ -8,7 +8,7 @@
   var target = document.getElementById("target");
   e.initEvent("beforecut", new Boolean(false), new Boolean(true));
   target.dispatchEvent(e);
-  document.createElement("marquee");
+  document.createElement("div");
 }
 </script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/http/tests/push_messaging/subscribe-failure-permission-denied-in-document.html b/third_party/WebKit/LayoutTests/http/tests/push_messaging/subscribe-failure-permission-denied-in-document.html
index 1feb6c6..5c2b29d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/push_messaging/subscribe-failure-permission-denied-in-document.html
+++ b/third_party/WebKit/LayoutTests/http/tests/push_messaging/subscribe-failure-permission-denied-in-document.html
@@ -27,7 +27,7 @@
         .then(function(pushSubscription) {
             assert_unreached('Subscription must not succeed after permission is denied.');
         }, function(e) {
-            assert_equals(e.name, 'PermissionDeniedError');
+            assert_equals(e.name, 'NotAllowedError');
             assert_regexp_match(e.message, /permission denied/);
             return service_worker_unregister_and_done(test, workerScope);
         })
diff --git a/third_party/WebKit/LayoutTests/media/media-play-promise.html b/third_party/WebKit/LayoutTests/media/media-play-promise.html
index 317a4c02..80ba9ad 100644
--- a/third_party/WebKit/LayoutTests/media/media-play-promise.html
+++ b/third_party/WebKit/LayoutTests/media/media-play-promise.html
@@ -220,7 +220,98 @@
         audio.oncanplaythrough = t.step_func(function() {
             audio.play();
         });
-    }
+    },
+
+    // Test that running the load algorithm will not drop all the promises about
+    // to be resolved.
+    function loadAlgorithmDoesNotCancelTasks(t, audio) {
+        audio.src = findMediaFile('audio', 'content/test');
+        audio.addEventListener('canplaythrough', t.step_func(function() {
+            // The play() promise will be queued to be resolved.
+            playExpectingResolvedPromise(t, audio);
+            audio.src = findMediaFile('audio', 'content/test');
+            assert_true(audio.paused);
+        }));
+    },
+
+    // Test that when the load algorithm is run, if it does not pause the
+    // playback, it will leave the promise pending, allowing it to be resolved.
+    function loadAlgorithmKeepPromisesPendingWhenNotPausing(t, audio) {
+        playExpectingResolvedPromise(t, audio);
+        setTimeout(t.step_func(function() {
+            audio.src = findMediaFile('audio', 'content/test');
+            assert_false(audio.paused);
+        }), 0);
+    },
+
+    // Test that when the load algorithm is run, if it resolves multiple
+    // promises, they are resolved in the order in which they were added.
+    function loadAlgorithmResolveOrdering(t, audio) {
+        audio.src = findMediaFile('audio', 'content/test');
+        audio.addEventListener('canplaythrough', t.step_func(function() {
+            var firstPromiseResolved = false;
+            audio.play().then(t.step_func(_ => firstPromiseResolved = true),
+                              t.unreached_func());
+
+            audio.play().then(t.step_func_done(function() {
+                assert_true(firstPromiseResolved);
+            }), t.unreached_func());
+
+            audio.src = findMediaFile('audio', 'content/test');
+        }));
+    },
+
+    // Test that when the load algorithm is run, if it does not pause the
+    // playback, it will leave the promise pending, allowing it to be resolved
+    // (version with preload='none').
+    // TODO(mlamouri): there is a bug in Blink where the media element ends up
+    // in a broken state, see https://crbug.com/633591
+    // function loadAlgorithmKeepPromisesPendingWhenNotPausingAndPreloadNone(t, audio) {
+    //     audio.preload = 'none';
+    //     playExpectingRejectedPromise(t, audio, 'AbortError');
+    //     setTimeout(_ => audio.src = findMediaFile('audio', 'content/test'), 0);
+    // },
+
+    // Test that when the load algorithm is run, if it does pause the playback,
+    // it will reject the pending promises.
+    function loadAlgorithmRejectPromisesWhenPausing(t, audio) {
+        playExpectingRejectedPromise(t, audio, 'AbortError');
+        audio.src = findMediaFile('audio', 'content/test');
+        assert_true(audio.paused);
+    },
+
+    // Test that when the load algorithm is run, if it does pause the playback,
+    // it will reject the pending promises (version with preload='none').
+    function loadAlgorithmRejectPromisesWhenPausingAndPreloadNone(t, audio) {
+        audio.preload = 'none';
+        playExpectingRejectedPromise(t, audio, 'AbortError');
+        audio.src = findMediaFile('audio', 'content/test');
+        assert_true(audio.paused);
+    },
+
+    // Test that when the load algorithm is run, if it rejects multiple
+    // promises, they are rejected in the order in which they were added.
+    function loadAlgorithmResolveOrdering(t, audio) {
+        var firstPromiseRejected = false;
+        audio.play().then(t.unreached_func(), t.step_func(function(e) {
+            assert_equals(e.name, 'AbortError');
+            assert_equals(e.message,
+                'The play() request was interrupted by a call to pause().');
+            firstPromiseRejected = true;
+        }));
+
+        audio.play().then(t.unreached_func(), t.step_func_done(function(e) {
+            assert_equals(e.name, 'AbortError');
+            assert_equals(e.message,
+                'The play() request was interrupted by a call to pause().');
+            assert_true(firstPromiseRejected);
+        }));
+
+        setTimeout(t.step_func(function() {
+            audio.pause();
+            audio.src = findMediaFile('audio', 'content/test');
+        }), 0);
+    },
 ];
 
 tests.forEach(function(test) {
@@ -278,4 +369,4 @@
     eventSender.mouseDown();
     eventSender.mouseUp();
 }
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/grammar-markers-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/grammar-markers-expected.png
new file mode 100644
index 0000000..1417a34
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/grammar-markers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/grammar-markers-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/grammar-markers-hidpi-expected.png
new file mode 100644
index 0000000..955aa26
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/grammar-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/inline-spelling-markers-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/inline-spelling-markers-hidpi-expected.png
index 332906c..d951a70 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/inline-spelling-markers-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/inline-spelling-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/inline_spelling_markers-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/inline_spelling_markers-expected.png
index d1f686d..588dba49 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/inline_spelling_markers-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/editing/spelling/inline_spelling_markers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/grammar-markers-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/grammar-markers-expected.png
new file mode 100644
index 0000000..24e86467
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/grammar-markers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/grammar-markers-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/grammar-markers-hidpi-expected.png
new file mode 100644
index 0000000..b2b767b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/grammar-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/inline-spelling-markers-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/inline-spelling-markers-hidpi-expected.png
index f3f2f17b..a1846a84 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/inline-spelling-markers-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/inline-spelling-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/inline_spelling_markers-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/inline_spelling_markers-expected.png
index 30005fd6..679fd86 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/inline_spelling_markers-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/editing/spelling/inline_spelling_markers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/grammar-markers-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/grammar-markers-expected.png
new file mode 100644
index 0000000..ae4c48e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/grammar-markers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/grammar-markers-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/grammar-markers-hidpi-expected.png
new file mode 100644
index 0000000..2ce6ca5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/grammar-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/inline-spelling-markers-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/inline-spelling-markers-hidpi-expected.png
index 5945afe..23a2292 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/inline-spelling-markers-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/inline-spelling-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/inline_spelling_markers-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/inline_spelling_markers-expected.png
index 3141ef55..1affc0c2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/inline_spelling_markers-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/spelling/inline_spelling_markers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/spelling/grammar-markers-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/spelling/grammar-markers-expected.png
new file mode 100644
index 0000000..05158da7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/spelling/grammar-markers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/spelling/grammar-markers-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/spelling/grammar-markers-hidpi-expected.png
new file mode 100644
index 0000000..7add1851
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/spelling/grammar-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/spelling/inline-spelling-markers-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/spelling/inline-spelling-markers-hidpi-expected.png
index 499c000a..4c89f6c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/editing/spelling/inline-spelling-markers-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/spelling/inline-spelling-markers-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/spelling/inline_spelling_markers-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/spelling/inline_spelling_markers-expected.png
index 2bfc73d..93e2bfb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/editing/spelling/inline_spelling_markers-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/spelling/inline_spelling_markers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/transforms/2d/hindi-rotated-expected.png b/third_party/WebKit/LayoutTests/platform/win7/transforms/2d/hindi-rotated-expected.png
index bcd512d..c3463739 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/transforms/2d/hindi-rotated-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/transforms/2d/hindi-rotated-expected.png
Binary files differ
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
index aa3b22d6..f315c193 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
@@ -106,6 +106,7 @@
     const v8::Local<v8::Object>& prototype,
     const v8::Local<v8::Function>& connectedCallback,
     const v8::Local<v8::Function>& disconnectedCallback,
+    const v8::Local<v8::Function>& adoptedCallback,
     const v8::Local<v8::Function>& attributeChangedCallback,
     const HashSet<AtomicString>& observedAttributes)
 {
@@ -117,6 +118,7 @@
             prototype,
             connectedCallback,
             disconnectedCallback,
+            adoptedCallback,
             attributeChangedCallback,
             observedAttributes);
 
@@ -130,11 +132,12 @@
 
     // We add the prototype and callbacks here to keep them alive. We use the
     // name as the key because it is unique per-registry.
-    v8::Local<v8::Array> array = v8::Array::New(scriptState->isolate(), 4);
+    v8::Local<v8::Array> array = v8::Array::New(scriptState->isolate(), 5);
     keepAlive(array, 0, prototype, definition->m_prototype, scriptState);
     keepAlive(array, 1, connectedCallback, definition->m_connectedCallback, scriptState);
     keepAlive(array, 2, disconnectedCallback, definition->m_disconnectedCallback, scriptState);
-    keepAlive(array, 3, attributeChangedCallback, definition->m_attributeChangedCallback, scriptState);
+    keepAlive(array, 3, adoptedCallback, definition->m_adoptedCallback, scriptState);
+    keepAlive(array, 4, attributeChangedCallback, definition->m_attributeChangedCallback, scriptState);
     map->Set(scriptState->context(), nameValue, array).ToLocalChecked();
 
     return definition;
@@ -147,6 +150,7 @@
     const v8::Local<v8::Object>& prototype,
     const v8::Local<v8::Function>& connectedCallback,
     const v8::Local<v8::Function>& disconnectedCallback,
+    const v8::Local<v8::Function>& adoptedCallback,
     const v8::Local<v8::Function>& attributeChangedCallback,
     const HashSet<AtomicString>& observedAttributes)
     : CustomElementDefinition(descriptor, observedAttributes)
@@ -230,11 +234,10 @@
     if (tryCatch.HasCaught())
         return false;
 
-    // To report InvalidStateError Exception, when the constructor returns some differnt object
+    // To report InvalidStateError Exception, when the constructor returns some different object
     if (result != element) {
         const String& message = "custom element constructors must call super() first and must "
             "not return a different object";
-
         std::unique_ptr<SourceLocation> location = SourceLocation::fromFunction(constructor().As<v8::Function>());
         v8::Local<v8::Value> exception =  V8ThrowException::createDOMException(
             m_scriptState->isolate(),
@@ -302,6 +305,11 @@
     return !m_disconnectedCallback.isEmpty();
 }
 
+bool ScriptCustomElementDefinition::hasAdoptedCallback() const
+{
+    return !m_adoptedCallback.isEmpty();
+}
+
 void ScriptCustomElementDefinition::runCallback(
     v8::Local<v8::Function> callback,
     Element* element, int argc, v8::Local<v8::Value> argv[])
@@ -343,6 +351,15 @@
     runCallback(m_disconnectedCallback.newLocal(isolate), element);
 }
 
+void ScriptCustomElementDefinition::runAdoptedCallback(Element* element)
+{
+    if (!m_scriptState->contextIsValid())
+        return;
+    ScriptState::Scope scope(m_scriptState.get());
+    v8::Isolate* isolate = m_scriptState->isolate();
+    runCallback(m_adoptedCallback.newLocal(isolate), element);
+}
+
 void ScriptCustomElementDefinition::runAttributeChangedCallback(
     Element* element, const QualifiedName& name,
     const AtomicString& oldValue, const AtomicString& newValue)
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.h b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.h
index b6621d5..5b76fc0f 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.h
@@ -35,6 +35,7 @@
         const v8::Local<v8::Object>& prototype,
         const v8::Local<v8::Function>& connectedCallback,
         const v8::Local<v8::Function>& disconnectedCallback,
+        const v8::Local<v8::Function>& adoptedCallback,
         const v8::Local<v8::Function>& attributeChangedCallback,
         const HashSet<AtomicString>& observedAttributes);
 
@@ -54,9 +55,11 @@
 
     bool hasConnectedCallback() const override;
     bool hasDisconnectedCallback() const override;
+    bool hasAdoptedCallback() const override;
 
     void runConnectedCallback(Element*) override;
     void runDisconnectedCallback(Element*) override;
+    void runAdoptedCallback(Element*) override;
     void runAttributeChangedCallback(Element*, const QualifiedName&,
         const AtomicString& oldValue, const AtomicString& newValue) override;
 
@@ -68,6 +71,7 @@
         const v8::Local<v8::Object>& prototype,
         const v8::Local<v8::Function>& connectedCallback,
         const v8::Local<v8::Function>& disconnectedCallback,
+        const v8::Local<v8::Function>& adoptedCallback,
         const v8::Local<v8::Function>& attributeChangedCallback,
         const HashSet<AtomicString>& observedAttributes);
 
@@ -84,6 +88,7 @@
     ScopedPersistent<v8::Object> m_prototype;
     ScopedPersistent<v8::Function> m_connectedCallback;
     ScopedPersistent<v8::Function> m_disconnectedCallback;
+    ScopedPersistent<v8::Function> m_adoptedCallback;
     ScopedPersistent<v8::Function> m_attributeChangedCallback;
 };
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.cpp
index 616d518..0c3bb65 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.cpp
@@ -156,9 +156,11 @@
     // CustomElementDefinition is built, even if JS changes them afterwards.
     const String kConnectedCallback = "connectedCallback";
     const String kDisconnectedCallback = "disconnectedCallback";
+    const String kAdoptedCallback = "adoptedCallback";
     const String kAttributeChangedCallback = "attributeChangedCallback";
     return callableForName(kConnectedCallback, m_connectedCallback)
         && callableForName(kDisconnectedCallback, m_disconnectedCallback)
+        && callableForName(kAdoptedCallback, m_adoptedCallback)
         && callableForName(kAttributeChangedCallback, m_attributeChangedCallback)
         && (m_attributeChangedCallback.IsEmpty() || retrieveObservedAttributes());
 }
@@ -174,6 +176,7 @@
         m_prototype,
         m_connectedCallback,
         m_disconnectedCallback,
+        m_adoptedCallback,
         m_attributeChangedCallback,
         m_observedAttributes);
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.h b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.h
index 4293471..695adca 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.h
@@ -52,6 +52,7 @@
     v8::Local<v8::Object> m_prototype;
     v8::Local<v8::Function> m_connectedCallback;
     v8::Local<v8::Function> m_disconnectedCallback;
+    v8::Local<v8::Function> m_adoptedCallback;
     v8::Local<v8::Function> m_attributeChangedCallback;
     HashSet<AtomicString> m_observedAttributes;
     ExceptionState& m_exceptionState;
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.cpp
index fe38dab..67b1369 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappable.cpp
@@ -24,9 +24,7 @@
     ASSERT(!DOMDataStore::containsWrapper(this, isolate));
 
     v8::Local<v8::Object> wrapper = V8DOMWrapper::createWrapper(isolate, creationContext, wrapperTypeInfo);
-    if (UNLIKELY(wrapper.IsEmpty()))
-        return wrapper;
-
+    DCHECK(!wrapper.IsEmpty());
     wrapperTypeInfo->installConditionallyEnabledProperties(wrapper, isolate);
     return associateWithWrapper(isolate, wrapperTypeInfo, wrapper);
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8DOMWrapper.cpp b/third_party/WebKit/Source/bindings/core/v8/V8DOMWrapper.cpp
index 2c1739f..92ba2f3 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8DOMWrapper.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8DOMWrapper.cpp
@@ -62,11 +62,8 @@
         // V8PerContextData::createWrapperFromCache, though there is no need to
         // cache resulting objects or their constructors.
         const DOMWrapperWorld& world = DOMWrapperWorld::world(scope.context());
-        if (!type->domTemplate(isolate, world)->InstanceTemplate()->NewInstance(scope.context()).ToLocal(&wrapper)) {
-            // Nothing to do.
-        }
+        wrapper = type->domTemplate(isolate, world)->InstanceTemplate()->NewInstance(scope.context()).ToLocalChecked();
     }
-
     return wrapper;
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8HTMLElementCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8HTMLElementCustom.cpp
index 1c6d41a..4924584 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8HTMLElementCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8HTMLElementCustom.cpp
@@ -12,6 +12,7 @@
 #include "bindings/core/v8/V8DOMWrapper.h"
 #include "bindings/core/v8/V8ThrowException.h"
 #include "core/dom/Document.h"
+#include "core/dom/Element.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/custom/CustomElementsRegistry.h"
 #include "core/frame/LocalDOMWindow.h"
@@ -63,7 +64,7 @@
             *window->document());
         // TODO(davaajav): write this as one call to setCustomElementState instead of two
         element->setCustomElementState(CustomElementState::Undefined);
-        element->setCustomElementState(CustomElementState::Custom);
+        element->setCustomElementDefinition(definition);
     } else {
         element = definition->constructionStack().last();
         if (element) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/generated.gni b/third_party/WebKit/Source/bindings/core/v8/generated.gni
index bbf23b0..440d3a3f 100644
--- a/third_party/WebKit/Source/bindings/core/v8/generated.gni
+++ b/third_party/WebKit/Source/bindings/core/v8/generated.gni
@@ -12,6 +12,7 @@
       [ "$bindings_core_v8_output_dir/V8GeneratedCoreBindings.cpp" ]
 } else {
   bindings_core_generated_aggregate_files = [
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings00.cpp",
     "$bindings_core_v8_output_dir/V8GeneratedCoreBindings01.cpp",
     "$bindings_core_v8_output_dir/V8GeneratedCoreBindings02.cpp",
     "$bindings_core_v8_output_dir/V8GeneratedCoreBindings03.cpp",
@@ -31,6 +32,66 @@
     "$bindings_core_v8_output_dir/V8GeneratedCoreBindings17.cpp",
     "$bindings_core_v8_output_dir/V8GeneratedCoreBindings18.cpp",
     "$bindings_core_v8_output_dir/V8GeneratedCoreBindings19.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings20.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings21.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings22.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings23.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings24.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings25.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings26.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings27.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings28.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings29.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings30.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings31.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings32.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings33.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings34.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings35.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings36.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings37.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings38.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings39.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings40.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings41.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings42.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings43.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings44.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings45.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings46.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings47.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings48.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings49.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings50.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings51.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings52.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings53.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings54.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings55.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings56.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings57.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings58.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings59.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings60.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings61.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings62.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings63.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings64.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings65.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings66.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings67.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings68.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings69.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings70.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings71.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings72.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings73.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings74.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings75.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings76.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings77.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings78.cpp",
+    "$bindings_core_v8_output_dir/V8GeneratedCoreBindings79.cpp",
   ]
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/generated.gypi b/third_party/WebKit/Source/bindings/core/v8/generated.gypi
index baa23e7..4371776 100644
--- a/third_party/WebKit/Source/bindings/core/v8/generated.gypi
+++ b/third_party/WebKit/Source/bindings/core/v8/generated.gypi
@@ -75,6 +75,7 @@
         ],
       }, {
         'bindings_core_v8_generated_aggregate_files': [
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings00.cpp',
           '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings01.cpp',
           '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings02.cpp',
           '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings03.cpp',
@@ -94,6 +95,66 @@
           '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings17.cpp',
           '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings18.cpp',
           '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings19.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings20.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings21.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings22.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings23.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings24.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings25.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings26.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings27.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings28.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings29.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings30.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings31.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings32.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings33.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings34.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings35.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings36.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings37.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings38.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings39.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings40.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings41.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings42.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings43.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings44.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings45.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings46.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings47.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings48.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings49.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings50.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings51.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings52.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings53.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings54.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings55.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings56.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings57.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings58.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings59.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings60.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings61.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings62.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings63.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings64.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings65.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings66.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings67.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings68.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings69.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings70.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings71.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings72.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings73.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings74.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings75.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings76.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings77.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings78.cpp',
+          '<(bindings_core_v8_output_dir)/V8GeneratedCoreBindings79.cpp',
         ],
       }],
     ],
diff --git a/third_party/WebKit/Source/bindings/modules/v8/generated.gni b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
index 514f228..e4f7a52 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/generated.gni
+++ b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
@@ -12,6 +12,7 @@
       [ "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings.cpp" ]
 } else {
   bindings_modules_generated_aggregate_files = [
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings00.cpp",
     "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings01.cpp",
     "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings02.cpp",
     "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings03.cpp",
@@ -31,6 +32,66 @@
     "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings17.cpp",
     "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings18.cpp",
     "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings19.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings20.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings21.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings22.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings23.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings24.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings25.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings26.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings27.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings28.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings29.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings30.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings31.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings32.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings33.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings34.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings35.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings36.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings37.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings38.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings39.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings40.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings41.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings42.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings43.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings44.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings45.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings46.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings47.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings48.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings49.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings50.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings51.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings52.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings53.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings54.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings55.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings56.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings57.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings58.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings59.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings60.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings61.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings62.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings63.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings64.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings65.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings66.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings67.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings68.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings69.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings70.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings71.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings72.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings73.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings74.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings75.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings76.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings77.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings78.cpp",
+    "$bindings_modules_v8_output_dir/V8GeneratedModulesBindings79.cpp",
   ]
 }
 
diff --git a/third_party/WebKit/Source/bindings/modules/v8/generated.gypi b/third_party/WebKit/Source/bindings/modules/v8/generated.gypi
index 00ea1ae2..360698ad 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/generated.gypi
+++ b/third_party/WebKit/Source/bindings/modules/v8/generated.gypi
@@ -63,6 +63,7 @@
         ],
       }, {
         'bindings_modules_v8_generated_aggregate_files': [
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings00.cpp',
           '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings01.cpp',
           '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings02.cpp',
           '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings03.cpp',
@@ -82,6 +83,66 @@
           '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings17.cpp',
           '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings18.cpp',
           '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings19.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings20.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings21.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings22.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings23.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings24.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings25.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings26.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings27.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings28.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings29.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings30.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings31.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings32.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings33.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings34.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings35.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings36.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings37.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings38.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings39.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings40.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings41.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings42.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings43.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings44.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings45.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings46.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings47.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings48.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings49.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings50.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings51.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings52.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings53.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings54.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings55.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings56.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings57.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings58.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings59.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings60.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings61.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings62.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings63.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings64.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings65.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings66.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings67.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings68.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings69.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings70.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings71.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings72.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings73.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings74.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings75.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings76.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings77.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings78.cpp',
+          '<(bindings_modules_v8_output_dir)/V8GeneratedModulesBindings79.cpp',
         ],
       }],
     ],
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_interface.py b/third_party/WebKit/Source/bindings/scripts/v8_interface.py
index 6f690139..269ea81 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_interface.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_interface.py
@@ -177,6 +177,7 @@
     is_check_security = 'CheckSecurity' in extended_attributes
     if is_check_security:
         includes.add('bindings/core/v8/BindingSecurity.h')
+        includes.add('core/frame/LocalDOMWindow.h')
 
     # [DependentLifetime]
     is_dependent_lifetime = 'DependentLifetime' in extended_attributes
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp
index c4eff8b..71883ba 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceCheckSecurity.cpp
@@ -11,6 +11,7 @@
 #include "bindings/core/v8/V8DOMConfiguration.h"
 #include "bindings/core/v8/V8ObjectConstructor.h"
 #include "core/dom/Document.h"
+#include "core/frame/LocalDOMWindow.h"
 #include "wtf/GetPtr.h"
 #include "wtf/RefPtr.h"
 
diff --git a/third_party/WebKit/Source/build/scripts/make_event_factory.py b/third_party/WebKit/Source/build/scripts/make_event_factory.py
index 34d1479..48b9586 100755
--- a/third_party/WebKit/Source/build/scripts/make_event_factory.py
+++ b/third_party/WebKit/Source/build/scripts/make_event_factory.py
@@ -50,14 +50,9 @@
 # All events on the following whitelist are matched case-insensitively
 # in createEvent.
 #
-# All events not on the list are being measured (except for already
-# deprecated ones). The plan is to limit createEvent to just a few
-# selected events necessary for legacy content in accordance with the
-# specification:
-#
 # https://dom.spec.whatwg.org/#dom-document-createevent
 def create_event_whitelist(name):
-    return (name == ('HTMLEvents')
+    return (name == 'HTMLEvents'
             or name == 'Event'
             or name == 'Events'
             or name.startswith('UIEvent')
@@ -68,6 +63,85 @@
             or name == 'TouchEvent')
 
 
+# All events on the following whitelist are matched case-sensitively
+# in createEvent and are measured using UseCounter.
+#
+# TODO(foolip): All events on this list should either be added to the spec and
+# moved to the above whitelist (causing them to be matched case-insensitively)
+# or be deprecated/removed. https://crbug.com/569690
+def create_event_legacy_whitelist(name):
+    return (name == 'AnimationEvent'
+            or name == 'AnimationPlayerEvent'
+            or name == 'ApplicationCacheErrorEvent'
+            or name == 'AudioProcessingEvent'
+            or name == 'BeforeInstallPromptEvent'
+            or name == 'BeforeUnloadEvent'
+            or name == 'BlobEvent'
+            or name == 'ClipboardEvent'
+            or name == 'CloseEvent'
+            or name == 'CompositionEvent'
+            or name == 'DeviceLightEvent'
+            or name == 'DeviceMotionEvent'
+            or name == 'DeviceOrientationEvent'
+            or name == 'DragEvent'
+            or name == 'ErrorEvent'
+            or name == 'ExtendableEvent'
+            or name == 'ExtendableMessageEvent'
+            or name == 'FetchEvent'
+            or name == 'FocusEvent'
+            or name == 'FontFaceSetLoadEvent'
+            or name == 'ForeignFetchEvent'
+            or name == 'GamepadEvent'
+            or name == 'HashChangeEvent'
+            or name == 'IDBVersionChangeEvent'
+            or name == 'InputEvent'
+            or name == 'InstallEvent'
+            or name == 'KeyboardEvents'
+            or name == 'MediaEncryptedEvent'
+            or name == 'MediaKeyMessageEvent'
+            or name == 'MediaQueryListEvent'
+            or name == 'MediaStreamEvent'
+            or name == 'MediaStreamTrackEvent'
+            or name == 'MIDIConnectionEvent'
+            or name == 'MIDIMessageEvent'
+            or name == 'MutationEvent'
+            or name == 'MutationEvents'
+            or name == 'NotificationEvent'
+            or name == 'OfflineAudioCompletionEvent'
+            or name == 'OrientationEvent'
+            or name == 'PageTransitionEvent'
+            or name == 'PaymentRequestUpdateEvent'
+            or name == 'PointerEvent'
+            or name == 'PopStateEvent'
+            or name == 'PresentationConnectionAvailableEvent'
+            or name == 'PresentationConnectionCloseEvent'
+            or name == 'ProgressEvent'
+            or name == 'PromiseRejectionEvent'
+            or name == 'PushEvent'
+            or name == 'RelatedEvent'
+            or name == 'ResourceProgressEvent'
+            or name == 'RTCDataChannelEvent'
+            or name == 'RTCDTMFToneChangeEvent'
+            or name == 'RTCIceCandidateEvent'
+            or name == 'SecurityPolicyViolationEvent'
+            or name == 'SensorErrorEvent'
+            or name == 'SensorReadingEvent'
+            or name == 'ServiceWorkerMessageEvent'
+            or name == 'SpeechRecognitionError'
+            or name == 'SpeechRecognitionEvent'
+            or name == 'SpeechSynthesisEvent'
+            or name == 'StorageEvent'
+            or name == 'SVGEvents'
+            or name == 'SyncEvent'
+            or name == 'TextEvent'
+            or name == 'TrackEvent'
+            or name == 'TransitionEvent'
+            or name == 'WebGLContextEvent'
+            or name == 'WebKitAnimationEvent'
+            or name == 'WebKitTransitionEvent'
+            or name == 'WheelEvent')
+
+
 def measure_name(name):
     return 'DocumentCreateEvent' + name
 
@@ -87,6 +161,7 @@
         'lower_first': name_utilities.lower_first,
         'script_name': name_utilities.script_name,
         'create_event_whitelist': create_event_whitelist,
+        'create_event_legacy_whitelist': create_event_legacy_whitelist,
         'measure_name': measure_name,
     }
 
diff --git a/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
index fa0067d0..c40f0c6 100644
--- a/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
@@ -15,7 +15,7 @@
 
 {{namespace}}* {{namespace}}{{suffix}}Factory::create(ExecutionContext* executionContext, const String& type)
 {
-    {% for event in events %}
+    {% for event in events if event|script_name|create_event_whitelist or event|script_name|create_event_legacy_whitelist %}
     {% if event|script_name|create_event_whitelist %}
     if (equalIgnoringCase(type, "{{event|script_name}}"){% if event.RuntimeEnabled %} && RuntimeEnabledFeatures::{{event.RuntimeEnabled|lower_first}}(){% endif %}) {
     {% else %}
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index b689e35..7d98dc0 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -2662,6 +2662,8 @@
             'dom/custom/CEReactionsScope.h',
             'dom/custom/CustomElement.cpp',
             'dom/custom/CustomElement.h',
+            'dom/custom/CustomElementAdoptedCallbackReaction.cpp',
+            'dom/custom/CustomElementAdoptedCallbackReaction.h',
             'dom/custom/CustomElementAttributeChangedCallbackReaction.cpp',
             'dom/custom/CustomElementAttributeChangedCallbackReaction.h',
             'dom/custom/CustomElementConnectedCallbackReaction.cpp',
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 44900c5..8c1c043 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5850,9 +5850,7 @@
     }
 
     v8::Local<v8::Object> wrapper = V8DOMWrapper::createWrapper(isolate, creationContext, wrapperType);
-    if (UNLIKELY(wrapper.IsEmpty()))
-        return wrapper;
-
+    DCHECK(!wrapper.IsEmpty());
     wrapperType->installConditionallyEnabledProperties(wrapper, isolate);
     return associateWithWrapper(isolate, wrapperType, wrapper);
 }
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 9cce24f..8fb4a4d 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -1941,15 +1941,30 @@
     layoutObject->layer()->updateSelfPaintingLayer();
 }
 
-void Element::setCustomElementDefinition(V0CustomElementDefinition* definition)
+void Element::v0SetCustomElementDefinition(V0CustomElementDefinition* definition)
 {
     if (!hasRareData() && !definition)
         return;
-    DCHECK(!customElementDefinition());
-    ensureElementRareData().setCustomElementDefinition(definition);
+    DCHECK(!v0CustomElementDefinition());
+    ensureElementRareData().v0SetCustomElementDefinition(definition);
 }
 
-V0CustomElementDefinition* Element::customElementDefinition() const
+V0CustomElementDefinition* Element::v0CustomElementDefinition() const
+{
+    if (hasRareData())
+        return elementRareData()->v0CustomElementDefinition();
+    return nullptr;
+}
+
+void Element::setCustomElementDefinition(CustomElementDefinition* definition)
+{
+    DCHECK(definition);
+    DCHECK(!customElementDefinition());
+    ensureElementRareData().setCustomElementDefinition(definition);
+    this->setCustomElementState(CustomElementState::Custom);
+}
+
+CustomElementDefinition* Element::customElementDefinition() const
 {
     if (hasRareData())
         return elementRareData()->customElementDefinition();
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index ed11b83..2ee3878 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -49,7 +49,7 @@
 class ClientRect;
 class ClientRectList;
 class CompositorMutation;
-class V0CustomElementDefinition;
+class CustomElementDefinition;
 class DOMStringMap;
 class DOMTokenList;
 class Dictionary;
@@ -72,6 +72,7 @@
 class ShadowRootInit;
 class StylePropertySet;
 class StylePropertyMap;
+class V0CustomElementDefinition;
 
 enum SpellcheckAttributeState {
     SpellcheckAttributeTrue,
@@ -517,8 +518,11 @@
     void clearHasPendingResources() { clearElementFlag(HasPendingResources); }
     virtual void buildPendingResource() { }
 
-    void setCustomElementDefinition(V0CustomElementDefinition*);
-    V0CustomElementDefinition* customElementDefinition() const;
+    void v0SetCustomElementDefinition(V0CustomElementDefinition*);
+    V0CustomElementDefinition* v0CustomElementDefinition() const;
+
+    void setCustomElementDefinition(CustomElementDefinition*);
+    CustomElementDefinition* customElementDefinition() const;
 
     bool containsFullScreenElement() const { return hasElementFlag(ContainsFullScreenElement); }
     void setContainsFullScreenElement(bool);
diff --git a/third_party/WebKit/Source/core/dom/ElementRareData.cpp b/third_party/WebKit/Source/core/dom/ElementRareData.cpp
index a3f7910f..dc7f0ff 100644
--- a/third_party/WebKit/Source/core/dom/ElementRareData.cpp
+++ b/third_party/WebKit/Source/core/dom/ElementRareData.cpp
@@ -43,7 +43,7 @@
     LayoutSize sizeForResizing;
     IntSize scrollOffset;
     void* pointers[10];
-    Member<void*> persistentMember[4];
+    Member<void*> persistentMember[5];
 };
 
 CSSStyleDeclaration& ElementRareData::ensureInlineCSSStyleDeclaration(Element* ownerElement)
@@ -86,6 +86,7 @@
     visitor->trace(m_cssomWrapper);
     visitor->trace(m_cssomMapWrapper);
     visitor->trace(m_pseudoElementData);
+    visitor->trace(m_v0CustomElementDefinition);
     visitor->trace(m_customElementDefinition);
     visitor->trace(m_intersectionObserverData);
     visitor->trace(m_resizeObserverData);
diff --git a/third_party/WebKit/Source/core/dom/ElementRareData.h b/third_party/WebKit/Source/core/dom/ElementRareData.h
index 283dc135..fe196fb 100644
--- a/third_party/WebKit/Source/core/dom/ElementRareData.h
+++ b/third_party/WebKit/Source/core/dom/ElementRareData.h
@@ -32,6 +32,7 @@
 #include "core/dom/NodeRareData.h"
 #include "core/dom/PseudoElement.h"
 #include "core/dom/PseudoElementData.h"
+#include "core/dom/custom/CustomElementDefinition.h"
 #include "core/dom/custom/V0CustomElementDefinition.h"
 #include "core/dom/shadow/ElementShadow.h"
 #include "core/html/ClassList.h"
@@ -125,8 +126,12 @@
     void decrementCompositorProxiedProperties(uint32_t properties);
     CompositorProxiedPropertySet* proxiedPropertyCounts() const { return m_proxiedProperties.get(); }
 
-    void setCustomElementDefinition(V0CustomElementDefinition* definition) { m_customElementDefinition = definition; }
-    V0CustomElementDefinition* customElementDefinition() const { return m_customElementDefinition.get(); }
+    void v0SetCustomElementDefinition(V0CustomElementDefinition* definition) { m_v0CustomElementDefinition = definition; }
+    V0CustomElementDefinition* v0CustomElementDefinition() const { return m_v0CustomElementDefinition.get(); }
+
+    void setCustomElementDefinition(CustomElementDefinition* definition) { m_customElementDefinition = definition; }
+    CustomElementDefinition* customElementDefinition() const { return m_customElementDefinition.get(); }
+
 
     AttrNodeList& ensureAttrNodeList();
     AttrNodeList* attrNodeList() { return m_attrNodeList.get(); }
@@ -172,7 +177,9 @@
     Member<ResizeObserverDataMap> m_resizeObserverData;
 
     RefPtr<ComputedStyle> m_computedStyle;
-    Member<V0CustomElementDefinition> m_customElementDefinition;
+    // TODO(davaajav):remove this field when v0 custom elements are deprecated
+    Member<V0CustomElementDefinition> m_v0CustomElementDefinition;
+    Member<CustomElementDefinition> m_customElementDefinition;
 
     Member<PseudoElementData> m_pseudoElementData;
 
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 8e4023e8..49dbf9b 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -2364,9 +2364,7 @@
     const WrapperTypeInfo* wrapperType = wrapperTypeInfo();
 
     v8::Local<v8::Object> wrapper = V8DOMWrapper::createWrapper(isolate, creationContext, wrapperType);
-    if (UNLIKELY(wrapper.IsEmpty()))
-        return wrapper;
-
+    DCHECK(!wrapper.IsEmpty());
     wrapperType->installConditionallyEnabledProperties(wrapper, isolate);
     return associateWithWrapper(isolate, wrapperType, wrapper);
 }
diff --git a/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp b/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp
index 6ea5268b..38bb6405 100644
--- a/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp
+++ b/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp
@@ -25,8 +25,10 @@
 #include "core/dom/TreeScopeAdopter.h"
 
 #include "core/dom/Attr.h"
+#include "core/dom/Node.h"
 #include "core/dom/NodeRareData.h"
 #include "core/dom/NodeTraversal.h"
+#include "core/dom/custom/CustomElement.h"
 #include "core/dom/shadow/ElementShadow.h"
 #include "core/dom/shadow/ShadowRoot.h"
 
@@ -128,6 +130,11 @@
 
     oldDocument.moveNodeIteratorsToNewDocument(node, newDocument);
 
+    if (node.getCustomElementState() == CustomElementState::Custom) {
+        Element& element = toElement(node);
+        CustomElement::enqueueAdoptedCallback(&element);
+    }
+
     if (node.isShadowRoot())
         toShadowRoot(node).setDocument(newDocument);
 
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElement.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElement.cpp
index 6e2242b3a..267fc32 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElement.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElement.cpp
@@ -25,7 +25,6 @@
 {
     return registry(element.document());
 }
-
 CustomElementsRegistry* CustomElement::registry(const Document& document)
 {
     if (LocalDOMWindow* window = document.domWindow())
@@ -36,9 +35,7 @@
 static CustomElementDefinition* definitionForElementWithoutCheck(const Element& element)
 {
     DCHECK_EQ(element.getCustomElementState(), CustomElementState::Custom);
-    if (CustomElementsRegistry* registry = CustomElement::registry(element))
-        return registry->definitionForName(element.localName());
-    return nullptr;
+    return element.customElementDefinition();
 }
 
 CustomElementDefinition* CustomElement::definitionForElement(const Element* element)
@@ -218,6 +215,13 @@
         definition->enqueueDisconnectedCallback(element);
 }
 
+void CustomElement::enqueueAdoptedCallback(Element* element)
+{
+    DCHECK_EQ(element->getCustomElementState(), CustomElementState::Custom);
+    CustomElementDefinition* definition = definitionForElementWithoutCheck(*element);
+    if (definition->hasAdoptedCallback())
+        definition->enqueueAdoptedCallback(element);
+}
 
 void CustomElement::enqueueAttributeChangedCallback(Element* element,
     const QualifiedName& name,
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElement.h b/third_party/WebKit/Source/core/dom/custom/CustomElement.h
index 68034ae..3d8353b 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElement.h
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElement.h
@@ -47,6 +47,7 @@
     static void enqueue(Element*, CustomElementReaction*);
     static void enqueueConnectedCallback(Element*);
     static void enqueueDisconnectedCallback(Element*);
+    static void enqueueAdoptedCallback(Element*);
     static void enqueueAttributeChangedCallback(Element*, const QualifiedName&,
         const AtomicString& oldValue, const AtomicString& newValue);
 
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementAdoptedCallbackReaction.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementAdoptedCallbackReaction.cpp
new file mode 100644
index 0000000..da9dae9b
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementAdoptedCallbackReaction.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/dom/custom/CustomElementAdoptedCallbackReaction.h"
+
+#include "core/dom/custom/CustomElementDefinition.h"
+
+namespace blink {
+
+CustomElementAdoptedCallbackReaction::CustomElementAdoptedCallbackReaction(
+    CustomElementDefinition* definition)
+    : CustomElementReaction(definition)
+{
+    DCHECK(definition->hasAdoptedCallback());
+}
+
+void CustomElementAdoptedCallbackReaction::invoke(Element* element)
+{
+    m_definition->runAdoptedCallback(element);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementAdoptedCallbackReaction.h b/third_party/WebKit/Source/core/dom/custom/CustomElementAdoptedCallbackReaction.h
new file mode 100644
index 0000000..717c67b5
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementAdoptedCallbackReaction.h
@@ -0,0 +1,27 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CustomElementAdoptedCallbackReaction_h
+#define CustomElementAdoptedCallbackReaction_h
+
+#include "core/CoreExport.h"
+#include "core/dom/custom/CustomElementReaction.h"
+#include "platform/heap/Handle.h"
+#include "wtf/Noncopyable.h"
+
+namespace blink {
+
+class CORE_EXPORT CustomElementAdoptedCallbackReaction final
+    : public CustomElementReaction {
+    WTF_MAKE_NONCOPYABLE(CustomElementAdoptedCallbackReaction);
+public:
+    CustomElementAdoptedCallbackReaction(CustomElementDefinition*);
+
+private:
+    void invoke(Element*) override;
+};
+
+} // namespace blink
+
+#endif // CustomElementAdoptedCallbackReaction_h
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.cpp
index 0b9b6f65..a9e7d5cd 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.cpp
@@ -7,6 +7,7 @@
 #include "core/dom/Attr.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/custom/CustomElement.h"
+#include "core/dom/custom/CustomElementAdoptedCallbackReaction.h"
 #include "core/dom/custom/CustomElementAttributeChangedCallbackReaction.h"
 #include "core/dom/custom/CustomElementConnectedCallbackReaction.h"
 #include "core/dom/custom/CustomElementDisconnectedCallbackReaction.h"
@@ -127,7 +128,7 @@
         return;
     }
 
-    element->setCustomElementState(CustomElementState::Custom);
+    element->setCustomElementDefinition(this);
 }
 
 bool CustomElementDefinition::hasAttributeChangedCallback(
@@ -159,6 +160,12 @@
         new CustomElementDisconnectedCallbackReaction(this));
 }
 
+void CustomElementDefinition::enqueueAdoptedCallback(Element* element)
+{
+    CustomElement::enqueue(element,
+        new CustomElementAdoptedCallbackReaction(this));
+}
+
 void CustomElementDefinition::enqueueAttributeChangedCallback(Element* element,
     const QualifiedName& name,
     const AtomicString& oldValue, const AtomicString& newValue)
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.h b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.h
index eead3c5..0bf974f5 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.h
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.h
@@ -56,17 +56,20 @@
 
     virtual bool hasConnectedCallback() const = 0;
     virtual bool hasDisconnectedCallback() const = 0;
+    virtual bool hasAdoptedCallback() const = 0;
     bool hasAttributeChangedCallback(const QualifiedName&) const;
     bool hasStyleAttributeChangedCallback() const;
 
     virtual void runConnectedCallback(Element*) = 0;
     virtual void runDisconnectedCallback(Element*) = 0;
+    virtual void runAdoptedCallback(Element*) = 0;
     virtual void runAttributeChangedCallback(Element*, const QualifiedName&,
         const AtomicString& oldValue, const AtomicString& newValue) = 0;
 
     void enqueueUpgradeReaction(Element*);
     void enqueueConnectedCallback(Element*);
     void enqueueDisconnectedCallback(Element*);
+    void enqueueAdoptedCallback(Element*);
     void enqueueAttributeChangedCallback(Element*, const QualifiedName&,
         const AtomicString& oldValue, const AtomicString& newValue);
 
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
index c22db95..96321e1 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
@@ -290,6 +290,7 @@
         Constructor,
         ConnectedCallback,
         DisconnectedCallback,
+        AdoptedCallback,
         AttributeChangedCallback,
     };
     Vector<MethodType> m_logs;
@@ -316,6 +317,7 @@
 
     bool hasConnectedCallback() const override { return true; }
     bool hasDisconnectedCallback() const override { return true; }
+    bool hasAdoptedCallback() const override {return true;}
 
     void runConnectedCallback(Element* element) override
     {
@@ -329,6 +331,12 @@
         EXPECT_EQ(element, m_element);
     }
 
+    void runAdoptedCallback(Element* element) override
+    {
+        m_logs.append(AdoptedCallback);
+        EXPECT_EQ(element, m_element);
+    }
+
     void runAttributeChangedCallback(Element* element, const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue) override
     {
         m_logs.append(AttributeChangedCallback);
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp b/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp
index be36cefc..41c3e586 100644
--- a/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp
@@ -111,7 +111,7 @@
         break;
 
     case Element::V0WaitingForUpgrade:
-        element->setCustomElementDefinition(definition);
+        element->v0SetCustomElementDefinition(definition);
         V0CustomElementScheduler::scheduleCallback(definition->callbacks(), element, V0CustomElementLifecycleCallbacks::CreatedCallback);
         break;
     }
@@ -120,7 +120,7 @@
 void V0CustomElement::attributeDidChange(Element* element, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue)
 {
     DCHECK_EQ(element->getV0CustomElementState(), Element::V0Upgraded);
-    V0CustomElementScheduler::scheduleAttributeChangedCallback(element->customElementDefinition()->callbacks(), element, name, oldValue, newValue);
+    V0CustomElementScheduler::scheduleAttributeChangedCallback(element->v0CustomElementDefinition()->callbacks(), element, name, oldValue, newValue);
 }
 
 void V0CustomElement::didAttach(Element* element, const Document& document)
@@ -128,7 +128,7 @@
     DCHECK_EQ(element->getV0CustomElementState(), Element::V0Upgraded);
     if (!document.domWindow())
         return;
-    V0CustomElementScheduler::scheduleCallback(element->customElementDefinition()->callbacks(), element, V0CustomElementLifecycleCallbacks::AttachedCallback);
+    V0CustomElementScheduler::scheduleCallback(element->v0CustomElementDefinition()->callbacks(), element, V0CustomElementLifecycleCallbacks::AttachedCallback);
 }
 
 void V0CustomElement::didDetach(Element* element, const Document& document)
@@ -136,7 +136,7 @@
     DCHECK_EQ(element->getV0CustomElementState(), Element::V0Upgraded);
     if (!document.domWindow())
         return;
-    V0CustomElementScheduler::scheduleCallback(element->customElementDefinition()->callbacks(), element, V0CustomElementLifecycleCallbacks::DetachedCallback);
+    V0CustomElementScheduler::scheduleCallback(element->v0CustomElementDefinition()->callbacks(), element, V0CustomElementLifecycleCallbacks::DetachedCallback);
 }
 
 void V0CustomElement::wasDestroyed(Element* element)
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index 5efc5bc..82c5ec5 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -714,7 +714,7 @@
     const EphemeralRange& insertedRange = toReplaceSelectionCommand(cmd)->insertedRange();
     if (insertedRange.isNull())
         return;
-    spellChecker().chunkAndMarkAllMisspellings(cmd->endingSelection().rootEditableElement(), insertedRange);
+    spellChecker().chunkAndMarkAllMisspellingsAndBadGrammar(cmd->endingSelection().rootEditableElement(), insertedRange);
 }
 
 void Editor::appliedEditing(CompositeEditCommand* cmd)
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index cbc0247..046bf4ed 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -1336,7 +1336,7 @@
     // FIXME (5098931): We should add a new insert action "WebViewInsertActionMoved" and call shouldInsertFragment here.
 
     setEndingSelection(VisibleSelection(start, end));
-    document().frame()->spellChecker().clearMisspellings(endingSelection());
+    document().frame()->spellChecker().clearMisspellingsAndBadGrammar(endingSelection());
     deleteSelection(editingState, false, false, false);
     if (editingState->isAborted())
         return;
@@ -1381,7 +1381,7 @@
     if (editingState->isAborted())
         return;
 
-    document().frame()->spellChecker().markMisspellings(endingSelection());
+    document().frame()->spellChecker().markMisspellingsAndBadGrammar(endingSelection());
 
     // If the selection is in an empty paragraph, restore styles from the old empty paragraph to the new empty paragraph.
     bool selectionIsEmptyParagraph = endingSelection().isCaret() && isStartOfParagraph(endingSelection().visibleStart()) && isEndOfParagraph(endingSelection().visibleStart());
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
index b73d2fc0..0c89d47 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -144,7 +144,7 @@
                 return;
             // We always recheck textfields because markers are removed from them on blur.
             VisibleSelection selection = VisibleSelection::selectionFromContentsOfNode(element);
-            markMisspellings(selection);
+            markMisspellingsAndBadGrammar(selection);
             if (!isTextField)
                 parent->setAlreadySpellChecked(true);
         }
@@ -226,20 +226,90 @@
     int searchEndOffsetAfterWrap = spellingSearchEnd.offsetInContainerNode();
 
     int misspellingOffset = 0;
-    String misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false);
+    GrammarDetail grammarDetail;
+    int grammarPhraseOffset = 0;
+    Position grammarSearchStart, grammarSearchEnd;
+    String badGrammarPhrase;
+    String misspelledWord;
 
-    // If we did not find a misspelled word, wrap and try again (but don't bother if we started at the beginning of the
+    bool isSpelling = true;
+    int foundOffset = 0;
+    String foundItem;
+    if (unifiedTextCheckerEnabled()) {
+        grammarSearchStart = spellingSearchStart;
+        grammarSearchEnd = spellingSearchEnd;
+        foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isSpelling, foundOffset, grammarDetail);
+        if (isSpelling) {
+            misspelledWord = foundItem;
+            misspellingOffset = foundOffset;
+        } else {
+            badGrammarPhrase = foundItem;
+            grammarPhraseOffset = foundOffset;
+        }
+    } else {
+        misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false);
+        grammarSearchStart = spellingSearchStart;
+        grammarSearchEnd = spellingSearchEnd;
+        if (!misspelledWord.isEmpty()) {
+            // Stop looking at start of next misspelled word
+            CharacterIterator chars(grammarSearchStart, grammarSearchEnd);
+            chars.advance(misspellingOffset);
+            grammarSearchEnd = chars.startPosition();
+        }
+
+        badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarSearchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
+    }
+
+    // If we found neither bad grammar nor a misspelled word, wrap and try again (but don't bother if we started at the beginning of the
     // block rather than at a selection).
-    if (startedWithSelection && !misspelledWord) {
+    if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
         spellingSearchStart = Position::editingPositionOf(topNode, 0);
         // going until the end of the very first chunk we tested is far enough
         spellingSearchEnd = Position::editingPositionOf(searchEndNodeAfterWrap, searchEndOffsetAfterWrap);
-        misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false);
+
+        if (unifiedTextCheckerEnabled()) {
+            grammarSearchStart = spellingSearchStart;
+            grammarSearchEnd = spellingSearchEnd;
+            foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isSpelling, foundOffset, grammarDetail);
+            if (isSpelling) {
+                misspelledWord = foundItem;
+                misspellingOffset = foundOffset;
+            } else {
+                badGrammarPhrase = foundItem;
+                grammarPhraseOffset = foundOffset;
+            }
+        } else {
+            misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false);
+            grammarSearchStart = spellingSearchStart;
+            grammarSearchEnd = spellingSearchEnd;
+            if (!misspelledWord.isEmpty()) {
+                // Stop looking at start of next misspelled word
+                CharacterIterator chars(grammarSearchStart, grammarSearchEnd);
+                chars.advance(misspellingOffset);
+                grammarSearchEnd = chars.startPosition();
+            }
+
+            badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarSearchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
+        }
     }
 
-    if (!misspelledWord.isEmpty()) {
-        // We found a misspelling. Select the misspelling, update the spelling
-        // panel, and store a marker so we draw the red squiggle later.
+    if (!badGrammarPhrase.isEmpty()) {
+        // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
+        // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
+        // panel, and store a marker so we draw the green squiggle later.
+
+        DCHECK_GT(badGrammarPhrase.length(), 0u);
+        DCHECK_NE(grammarDetail.location, -1);
+        DCHECK_GT(grammarDetail.length, 0);
+
+        // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
+        const EphemeralRange badGrammarRange = calculateCharacterSubrange(EphemeralRange(grammarSearchStart, grammarSearchEnd), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
+        frame().selection().setSelection(VisibleSelection(badGrammarRange));
+        frame().selection().revealSelection();
+        frame().document()->markers().addMarker(badGrammarRange.startPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, grammarDetail.userDescription);
+    } else if (!misspelledWord.isEmpty()) {
+        // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
+        // a marker so we draw the red squiggle later.
 
         const EphemeralRange misspellingRange = calculateCharacterSubrange(EphemeralRange(spellingSearchStart, spellingSearchEnd), misspellingOffset, misspelledWord.length());
         frame().selection().setSelection(VisibleSelection(misspellingRange));
@@ -260,24 +330,14 @@
     spellCheckerClient().showSpellingUI(true);
 }
 
-void SpellChecker::clearMisspellings(const VisibleSelection &movingSelection)
+void SpellChecker::clearMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
 {
     removeMarkers(movingSelection, DocumentMarker::MisspellingMarkers());
 }
 
-void SpellChecker::markMisspellings(const VisibleSelection &movingSelection)
+void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
 {
-    if (unifiedTextCheckerEnabled()) {
-        if (!isContinuousSpellCheckingEnabled())
-            return;
-
-        // markMisspellings() is triggered by selection change, in which
-        // case we check spelling, but don't autocorrect misspellings.
-        markAllMisspellingsInRange(movingSelection.toNormalizedEphemeralRange());
-        return;
-    }
-
-    markMisspellingsWithTextCheckingHelper(movingSelection);
+    markMisspellingsAndBadGrammar(movingSelection, isContinuousSpellCheckingEnabled(), movingSelection);
 }
 
 void SpellChecker::markMisspellingsAfterLineBreak(const VisibleSelection& wordSelection)
@@ -285,12 +345,22 @@
     TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterLineBreak");
 
     if (!unifiedTextCheckerEnabled()) {
-        markMisspellingsWithTextCheckingHelper(wordSelection);
+        markMisspellings(wordSelection);
         return;
     }
 
+    TextCheckingTypeMask textCheckingOptions = TextCheckingTypeGrammar;
+
     if (isContinuousSpellCheckingEnabled())
-        markAllMisspellingsInRange(wordSelection.toNormalizedEphemeralRange());
+        textCheckingOptions |= TextCheckingTypeSpelling;
+
+    VisibleSelection wholeParagraph(
+        startOfParagraph(wordSelection.visibleStart()),
+        endOfParagraph(wordSelection.visibleEnd()));
+
+    markAllMisspellingsAndBadGrammarInRanges(
+        textCheckingOptions, wordSelection.toNormalizedEphemeralRange(),
+        wholeParagraph.toNormalizedEphemeralRange());
 }
 
 void SpellChecker::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping)
@@ -306,8 +376,15 @@
         if (!(textCheckingOptions & TextCheckingTypeSpelling))
             return;
 
+        textCheckingOptions |= TextCheckingTypeGrammar;
+
         VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary));
-        markAllMisspellingsInRange(adjacentWords.toNormalizedEphemeralRange());
+        if (textCheckingOptions & TextCheckingTypeGrammar) {
+            VisibleSelection selectedSentence = VisibleSelection(startOfSentence(wordStart), endOfSentence(wordStart));
+            markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedEphemeralRange(), selectedSentence.toNormalizedEphemeralRange());
+        } else {
+            markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedEphemeralRange(), adjacentWords.toNormalizedEphemeralRange());
+        }
         return;
     }
 
@@ -315,7 +392,45 @@
         return;
 
     // Check spelling of one word
-    markMisspellingsWithTextCheckingHelper(VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)));
+    bool result = markMisspellings(VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)));
+
+    if (!result)
+        return;
+
+    // Check grammar of entire sentence
+    markBadGrammar(VisibleSelection(startOfSentence(wordStart), endOfSentence(wordStart)));
+}
+
+bool SpellChecker::markMisspellingsOrBadGrammar(const VisibleSelection& selection, bool checkSpelling)
+{
+    // This function is called with a selection already expanded to word boundaries.
+    // Might be nice to assert that here.
+
+    // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
+    // grammar checking can only be on if spell checking is also on.
+    if (!isContinuousSpellCheckingEnabled())
+        return false;
+
+    TRACE_EVENT0("blink", "SpellChecker::markMisspellingsOrBadGrammar");
+
+    const EphemeralRange range = selection.toNormalizedEphemeralRange();
+    if (range.isNull())
+        return false;
+
+    // If we're not in an editable node, bail.
+    Node* editableNode = range.startPosition().computeContainerNode();
+    if (!editableNode || !hasEditableStyle(*editableNode))
+        return false;
+
+    if (!isSpellCheckingEnabledFor(editableNode))
+        return false;
+
+    TextCheckingHelper checker(spellCheckerClient(), range.startPosition(), range.endPosition());
+    if (checkSpelling)
+        return checker.markAllMisspellings();
+
+    checker.markAllBadGrammar();
+    return false;
 }
 
 bool SpellChecker::isSpellCheckingEnabledFor(Node* node) const
@@ -350,39 +465,24 @@
     return false;
 }
 
-void SpellChecker::markMisspellingsWithTextCheckingHelper(const VisibleSelection& selection)
+bool SpellChecker::markMisspellings(const VisibleSelection& selection)
 {
-    // This function is called with a selection already expanded to word boundaries.
-    // TODO(xiaochengh): Might be nice to assert that here.
-
-    // This function is used only for as-you-type checking, so if that's off we do nothing.
-    if (!isContinuousSpellCheckingEnabled())
-        return;
-
-    TRACE_EVENT0("blink", "SpellChecker::markMisspellings");
-
-    const EphemeralRange& range = selection.toNormalizedEphemeralRange();
-    if (range.isNull())
-        return;
-
-    // If we're not in an editable node, bail.
-    Node* editableNode = range.startPosition().computeContainerNode();
-    if (!editableNode || !hasEditableStyle(*editableNode))
-        return;
-
-    if (!isSpellCheckingEnabledFor(editableNode))
-        return;
-
-    TextCheckingHelper checker(spellCheckerClient(), range.startPosition(), range.endPosition());
-    checker.markAllMisspellings();
+    return markMisspellingsOrBadGrammar(selection, true);
 }
 
-void SpellChecker::markAllMisspellingsInRange(const EphemeralRange& spellingRange)
+void SpellChecker::markBadGrammar(const VisibleSelection& selection)
+{
+    markMisspellingsOrBadGrammar(selection, false);
+}
+
+void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask textCheckingOptions, const EphemeralRange& spellingRange, const EphemeralRange& grammarRange)
 {
     DCHECK(unifiedTextCheckerEnabled());
 
+    bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar;
+
     // This function is called with selections already expanded to word boundaries.
-    if (spellingRange.isNull())
+    if (spellingRange.isNull() || (shouldMarkGrammar && grammarRange.isNull()))
         return;
 
     // If we're not in an editable node, bail.
@@ -393,8 +493,8 @@
     if (!isSpellCheckingEnabledFor(editableNode))
         return;
 
-    TextCheckingParagraph fullParagraphToCheck(spellingRange);
-    chunkAndMarkAllMisspellings(fullParagraphToCheck);
+    TextCheckingParagraph fullParagraphToCheck(shouldMarkGrammar ? grammarRange : spellingRange);
+    chunkAndMarkAllMisspellingsAndBadGrammar(textCheckingOptions, fullParagraphToCheck);
 }
 
 static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range)
@@ -415,17 +515,17 @@
     return expandEndToSentenceBoundary(EphemeralRange(sentenceStart.isNull() ? range.startPosition() : sentenceStart, range.endPosition()));
 }
 
-void SpellChecker::chunkAndMarkAllMisspellings(Node* node, const EphemeralRange& insertedRange)
+void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node, const EphemeralRange& insertedRange)
 {
-    TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellings");
+    TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar");
     if (!node)
         return;
     EphemeralRange paragraphRange(Position::firstPositionInNode(node), Position::lastPositionInNode(node));
     TextCheckingParagraph textToCheck(insertedRange, paragraphRange);
-    chunkAndMarkAllMisspellings(textToCheck);
+    chunkAndMarkAllMisspellingsAndBadGrammar(resolveTextCheckingTypeMask(TextCheckingTypeSpelling | TextCheckingTypeGrammar), textToCheck);
 }
 
-void SpellChecker::chunkAndMarkAllMisspellings(const TextCheckingParagraph& fullParagraphToCheck)
+void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(TextCheckingTypeMask textCheckingOptions, const TextCheckingParagraph& fullParagraphToCheck)
 {
     if (fullParagraphToCheck.isEmpty())
         return;
@@ -437,7 +537,7 @@
     // Check the full paragraph instead if the paragraph is short, which saves
     // the cost on sentence boundary finding.
     if (fullParagraphToCheck.rangeLength() <= kChunkSize) {
-        SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingTypeSpelling, TextCheckingProcessBatch, paragraphRange, paragraphRange, 0);
+        SpellCheckRequest* request = SpellCheckRequest::create(resolveTextCheckingTypeMask(textCheckingOptions), TextCheckingProcessBatch, paragraphRange, paragraphRange, 0);
         if (request)
             m_spellCheckRequester->requestCheckingFor(request);
         return;
@@ -448,7 +548,7 @@
         EphemeralRange chunkRange = checkRangeIterator.calculateCharacterSubrange(0, kChunkSize);
         EphemeralRange checkRange = requestNum ? expandEndToSentenceBoundary(chunkRange) : expandRangeToSentenceBoundary(chunkRange);
 
-        SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingTypeSpelling, TextCheckingProcessBatch, checkRange, paragraphRange, requestNum);
+        SpellCheckRequest* request = SpellCheckRequest::create(resolveTextCheckingTypeMask(textCheckingOptions), TextCheckingProcessBatch, checkRange, paragraphRange, requestNum);
         if (request)
             m_spellCheckRequester->requestCheckingFor(request);
 
@@ -482,6 +582,7 @@
     TextCheckingParagraph paragraph(request->checkingRange(), request->paragraphRange());
 
     bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling;
+    bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar;
 
     // Expand the range to encompass entire paragraphs, since text checking needs that much context.
     int selectionOffset = 0;
@@ -527,6 +628,18 @@
                 DCHECK_GE(resultLocation, 0);
                 const EphemeralRange misspellingRange = calculateCharacterSubrange(paragraph.paragraphRange(), resultLocation, resultLength);
                 frame().document()->markers().addMarker(misspellingRange.startPosition(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->replacement, result->hash);
+            } else if (shouldMarkGrammar && result->decoration == TextDecorationTypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) {
+                DCHECK_GT(resultLength, 0);
+                DCHECK_GE(resultLocation, 0);
+                for (unsigned j = 0; j < result->details.size(); j++) {
+                    const GrammarDetail* detail = &result->details[j];
+                    DCHECK_GT(detail->length, 0);
+                    DCHECK_GE(detail->location, 0);
+                    if (paragraph.checkingRangeCovers(resultLocation + detail->location, detail->length)) {
+                        const EphemeralRange badGrammarRange = calculateCharacterSubrange(paragraph.paragraphRange(), resultLocation + detail->location, detail->length);
+                        frame().document()->markers().addMarker(badGrammarRange.startPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->userDescription, result->hash);
+                    }
+                }
             } else if (result->decoration == TextDecorationTypeInvisibleSpellcheck && resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset) {
                 DCHECK_GT(resultLength, 0);
                 DCHECK_GE(resultLocation, 0);
@@ -553,6 +666,25 @@
     }
 }
 
+void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection)
+{
+    if (unifiedTextCheckerEnabled()) {
+        if (!isContinuousSpellCheckingEnabled())
+            return;
+
+        // markMisspellingsAndBadGrammar() is triggered by selection change, in which case we check spelling and grammar, but don't autocorrect misspellings.
+        TextCheckingTypeMask textCheckingOptions = TextCheckingTypeSpelling;
+        if (markGrammar)
+            textCheckingOptions |= TextCheckingTypeGrammar;
+        markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSelection.toNormalizedEphemeralRange(), grammarSelection.toNormalizedEphemeralRange());
+        return;
+    }
+
+    markMisspellings(spellingSelection);
+    if (markGrammar)
+        markBadGrammar(grammarSelection);
+}
+
 void SpellChecker::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionAtWordBoundary)
 {
     DCHECK(frame().selection().isAvailable());
@@ -645,6 +777,8 @@
     HTMLTextFormControlElement* textFormControlElement = toHTMLTextFormControlElement(e);
     HTMLElement* innerEditor = textFormControlElement->innerEditorElement();
     DocumentMarker::MarkerTypes markerTypes(DocumentMarker::Spelling);
+    if (unifiedTextCheckerEnabled())
+        markerTypes.add(DocumentMarker::Grammar);
     for (Node& node : NodeTraversal::inclusiveDescendantsOf(*innerEditor))
         frame().document()->markers().removeMarkers(&node, markerTypes);
 }
@@ -685,6 +819,7 @@
     // When continuous spell checking is off, existing markers disappear after the selection changes.
     if (!isContinuousSpellCheckingEnabled()) {
         frame().document()->markers().removeMarkers(DocumentMarker::Spelling);
+        frame().document()->markers().removeMarkers(DocumentMarker::Grammar);
         return;
     }
 
@@ -751,7 +886,12 @@
     VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
     if (oldAdjacentWords == newAdjacentWords)
         return;
-    markMisspellings(oldAdjacentWords);
+    if (isContinuousSpellCheckingEnabled()) {
+        VisibleSelection selectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart));
+        markMisspellingsAndBadGrammar(oldAdjacentWords, true, selectedSentence);
+        return;
+    }
+    markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords);
 }
 
 static Node* findFirstMarkable(Node* node)
@@ -795,6 +935,20 @@
     return selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
 }
 
+TextCheckingTypeMask SpellChecker::resolveTextCheckingTypeMask(TextCheckingTypeMask textCheckingOptions)
+{
+    bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling;
+    bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar;
+
+    TextCheckingTypeMask checkingTypes = 0;
+    if (shouldMarkSpelling)
+        checkingTypes |= TextCheckingTypeSpelling;
+    if (shouldMarkGrammar)
+        checkingTypes |= TextCheckingTypeGrammar;
+
+    return checkingTypes;
+}
+
 void SpellChecker::removeMarkers(const VisibleSelection& selection, DocumentMarker::MarkerTypes markerTypes)
 {
     const EphemeralRange range = selection.toNormalizedEphemeralRange();
@@ -816,7 +970,7 @@
 void SpellChecker::requestTextChecking(const Element& element)
 {
     const EphemeralRange rangeToCheck = EphemeralRange::rangeOfContents(element);
-    m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextCheckingTypeSpelling, TextCheckingProcessBatch, rangeToCheck, rangeToCheck));
+    m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextCheckingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, rangeToCheck, rangeToCheck));
 }
 
 DEFINE_TRACE(SpellChecker)
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h
index 173530b7..a02d78c 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h
@@ -61,24 +61,29 @@
     static bool isSpellCheckingEnabledFor(const VisibleSelection&);
     void markMisspellingsAfterLineBreak(const VisibleSelection& wordSelection);
     void markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping);
+    bool markMisspellings(const VisibleSelection&);
+    void markBadGrammar(const VisibleSelection&);
+    void markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection);
     void markAndReplaceFor(SpellCheckRequest*, const Vector<TextCheckingResult>&);
+    void markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask, const EphemeralRange& spellingRange, const EphemeralRange& grammarRange);
     void advanceToNextMisspelling(bool startBeforeSelection = false);
     void showSpellingGuessPanel();
     void didBeginEditing(Element*);
-    void clearMisspellings(const VisibleSelection&);
-    void markMisspellings(const VisibleSelection&);
+    void clearMisspellingsAndBadGrammar(const VisibleSelection&);
+    void markMisspellingsAndBadGrammar(const VisibleSelection&);
     void respondToChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions);
     void replaceMisspelledRange(const String&);
     void removeSpellingMarkers();
     void removeSpellingMarkersUnderWords(const Vector<String>& words);
     void spellCheckAfterBlur();
+    void spellCheckOldSelection(const VisibleSelection& oldSelection, const VisibleSelection& newAdjacentWords);
 
     void didEndEditingOnTextField(Element*);
     bool selectionStartHasMarkerFor(DocumentMarker::MarkerType, int from, int length) const;
     bool selectionStartHasSpellingMarkerFor(int from, int length) const;
     void updateMarkersForWordsAffectedByEditing(bool onlyHandleWordsContainingSelection);
     void cancelCheck();
-    void chunkAndMarkAllMisspellings(Node*, const EphemeralRange&);
+    void chunkAndMarkAllMisspellingsAndBadGrammar(Node*, const EphemeralRange&);
     void requestTextChecking(const Element&);
 
     // Exposed for testing only
@@ -101,14 +106,13 @@
         return *m_frame;
     }
 
-    void markMisspellingsWithTextCheckingHelper(const VisibleSelection&);
-    void markAllMisspellingsInRange(const EphemeralRange& spellingRange);
-    void spellCheckOldSelection(const VisibleSelection& oldSelection, const VisibleSelection& newAdjacentWords);
+    bool markMisspellingsOrBadGrammar(const VisibleSelection&, bool checkSpelling);
+    TextCheckingTypeMask resolveTextCheckingTypeMask(TextCheckingTypeMask);
 
     void removeMarkers(const VisibleSelection&, DocumentMarker::MarkerTypes);
     bool unifiedTextCheckerEnabled() const;
 
-    void chunkAndMarkAllMisspellings(const TextCheckingParagraph& fullParagraphToCheck);
+    void chunkAndMarkAllMisspellingsAndBadGrammar(TextCheckingTypeMask textCheckingOptions, const TextCheckingParagraph& fullParagraphToCheck);
 
     Member<LocalFrame> m_frame;
     const Member<SpellCheckRequester> m_spellCheckRequester;
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
index b0e55b7..7ba54bf 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
@@ -41,6 +41,34 @@
 
 namespace blink {
 
+static void findBadGrammars(TextCheckerClient& client, const UChar* text, int start, int length, Vector<TextCheckingResult>& results)
+{
+    int checkLocation = start;
+    int checkLength = length;
+
+    while (0 < checkLength) {
+        int badGrammarLocation = -1;
+        int badGrammarLength = 0;
+        Vector<GrammarDetail> badGrammarDetails;
+        client.checkGrammarOfString(String(text + checkLocation, checkLength), badGrammarDetails, &badGrammarLocation, &badGrammarLength);
+        if (!badGrammarLength)
+            break;
+        DCHECK_LE(0, badGrammarLocation);
+        DCHECK_LE(badGrammarLocation, checkLength);
+        DCHECK_LT(0, badGrammarLength);
+        DCHECK_LE(badGrammarLocation + badGrammarLength, checkLength);
+        TextCheckingResult badGrammar;
+        badGrammar.decoration = TextDecorationTypeGrammar;
+        badGrammar.location = checkLocation + badGrammarLocation;
+        badGrammar.length = badGrammarLength;
+        badGrammar.details.swap(badGrammarDetails);
+        results.append(badGrammar);
+
+        checkLocation += (badGrammarLocation + badGrammarLength);
+        checkLength -= (badGrammarLocation + badGrammarLength);
+    }
+}
+
 static void findMisspellings(TextCheckerClient& client, const UChar* text, int start, int length, Vector<TextCheckingResult>& results)
 {
     TextBreakIterator* iterator = wordBreakIterator(text + start, length);
@@ -286,6 +314,222 @@
     return firstMisspelling;
 }
 
+String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
+{
+    if (!unifiedTextCheckerEnabled())
+        return "";
+
+    String firstFoundItem;
+    String misspelledWord;
+    String badGrammarPhrase;
+
+    // Initialize out parameters; these will be updated if we find something to return.
+    outIsSpelling = true;
+    outFirstFoundOffset = 0;
+    outGrammarDetail.location = -1;
+    outGrammarDetail.length = 0;
+    outGrammarDetail.guesses.clear();
+    outGrammarDetail.userDescription = "";
+
+    // Expand the search range to encompass entire paragraphs, since text checking needs that much context.
+    // Determine the character offset from the start of the paragraph to the start of the original search range,
+    // since we will want to ignore results in this area.
+    Position paragraphStart = startOfParagraph(createVisiblePosition(m_start)).toParentAnchoredPosition();
+    Position paragraphEnd = m_end;
+    int totalRangeLength = TextIterator::rangeLength(paragraphStart, paragraphEnd);
+    paragraphEnd = endOfParagraph(createVisiblePosition(m_start)).toParentAnchoredPosition();
+
+    int rangeStartOffset = TextIterator::rangeLength(paragraphStart, m_start);
+    int totalLengthProcessed = 0;
+
+    bool firstIteration = true;
+    bool lastIteration = false;
+    while (totalLengthProcessed < totalRangeLength) {
+        // Iterate through the search range by paragraphs, checking each one for spelling and grammar.
+        int currentLength = TextIterator::rangeLength(paragraphStart, paragraphEnd);
+        int currentStartOffset = firstIteration ? rangeStartOffset : 0;
+        int currentEndOffset = currentLength;
+        if (inSameParagraph(createVisiblePosition(paragraphStart), createVisiblePosition(m_end))) {
+            // Determine the character offset from the end of the original search range to the end of the paragraph,
+            // since we will want to ignore results in this area.
+            currentEndOffset = TextIterator::rangeLength(paragraphStart, m_end);
+            lastIteration = true;
+        }
+        if (currentStartOffset < currentEndOffset) {
+            String paragraphString = plainText(EphemeralRange(paragraphStart, paragraphEnd));
+            if (paragraphString.length() > 0) {
+                bool foundGrammar = false;
+                int spellingLocation = 0;
+                int grammarPhraseLocation = 0;
+                int grammarDetailLocation = 0;
+                unsigned grammarDetailIndex = 0;
+
+                Vector<TextCheckingResult> results;
+                TextCheckingTypeMask checkingTypes = TextCheckingTypeSpelling | TextCheckingTypeGrammar;
+                checkTextOfParagraph(m_client->textChecker(), paragraphString, checkingTypes, results);
+
+                for (unsigned i = 0; i < results.size(); i++) {
+                    const TextCheckingResult* result = &results[i];
+                    if (result->decoration == TextDecorationTypeSpelling && result->location >= currentStartOffset && result->location + result->length <= currentEndOffset) {
+                        DCHECK_GT(result->length, 0);
+                        DCHECK_GE(result->location, 0);
+                        spellingLocation = result->location;
+                        misspelledWord = paragraphString.substring(result->location, result->length);
+                        DCHECK(misspelledWord.length());
+                        break;
+                    }
+                    if (result->decoration == TextDecorationTypeGrammar && result->location < currentEndOffset && result->location + result->length > currentStartOffset) {
+                        DCHECK_GT(result->length, 0);
+                        DCHECK_GE(result->location, 0);
+                        // We can't stop after the first grammar result, since there might still be a spelling result after
+                        // it begins but before the first detail in it, but we can stop if we find a second grammar result.
+                        if (foundGrammar)
+                            break;
+                        for (unsigned j = 0; j < result->details.size(); j++) {
+                            const GrammarDetail* detail = &result->details[j];
+                            DCHECK_GT(detail->length, 0);
+                            DCHECK_GE(detail->location, 0);
+                            if (result->location + detail->location >= currentStartOffset && result->location + detail->location + detail->length <= currentEndOffset && (!foundGrammar || result->location + detail->location < grammarDetailLocation)) {
+                                grammarDetailIndex = j;
+                                grammarDetailLocation = result->location + detail->location;
+                                foundGrammar = true;
+                            }
+                        }
+                        if (foundGrammar) {
+                            grammarPhraseLocation = result->location;
+                            outGrammarDetail = result->details[grammarDetailIndex];
+                            badGrammarPhrase = paragraphString.substring(result->location, result->length);
+                            DCHECK(badGrammarPhrase.length());
+                        }
+                    }
+                }
+
+                if (!misspelledWord.isEmpty() && (badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
+                    int spellingOffset = spellingLocation - currentStartOffset;
+                    if (!firstIteration)
+                        spellingOffset += TextIterator::rangeLength(m_start, paragraphStart);
+                    outIsSpelling = true;
+                    outFirstFoundOffset = spellingOffset;
+                    firstFoundItem = misspelledWord;
+                    break;
+                }
+                if (!badGrammarPhrase.isEmpty()) {
+                    int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset;
+                    if (!firstIteration)
+                        grammarPhraseOffset += TextIterator::rangeLength(m_start, paragraphStart);
+                    outIsSpelling = false;
+                    outFirstFoundOffset = grammarPhraseOffset;
+                    firstFoundItem = badGrammarPhrase;
+                    break;
+                }
+            }
+        }
+        if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength)
+            break;
+        VisiblePosition newParagraphStart = startOfNextParagraph(createVisiblePosition(paragraphEnd));
+        paragraphStart = newParagraphStart.toParentAnchoredPosition();
+        paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPosition();
+        firstIteration = false;
+        totalLengthProcessed += currentLength;
+    }
+    return firstFoundItem;
+}
+
+int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int startOffset, int endOffset, bool markAll) const
+{
+    // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
+    // Optionally add a DocumentMarker for each detail in the range.
+    int earliestDetailLocationSoFar = -1;
+    int earliestDetailIndex = -1;
+    for (unsigned i = 0; i < grammarDetails.size(); i++) {
+        const GrammarDetail* detail = &grammarDetails[i];
+        DCHECK_GT(detail->length, 0);
+        DCHECK_GE(detail->location, 0);
+
+        int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
+
+        // Skip this detail if it starts before the original search range
+        if (detailStartOffsetInParagraph < startOffset)
+            continue;
+
+        // Skip this detail if it starts after the original search range
+        if (detailStartOffsetInParagraph >= endOffset)
+            continue;
+
+        if (markAll) {
+            const EphemeralRange badGrammarRange = calculateCharacterSubrange(EphemeralRange(m_start, m_end), badGrammarPhraseLocation - startOffset + detail->location, detail->length);
+            badGrammarRange.document().markers().addMarker(badGrammarRange.startPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->userDescription);
+        }
+
+        // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
+        if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
+            earliestDetailIndex = i;
+            earliestDetailLocationSoFar = detail->location;
+        }
+    }
+
+    return earliestDetailIndex;
+}
+
+String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
+{
+    // Initialize out parameters; these will be updated if we find something to return.
+    outGrammarDetail.location = -1;
+    outGrammarDetail.length = 0;
+    outGrammarDetail.guesses.clear();
+    outGrammarDetail.userDescription = "";
+    outGrammarPhraseOffset = 0;
+
+    String firstBadGrammarPhrase;
+
+    // Expand the search range to encompass entire paragraphs, since grammar checking needs that much context.
+    // Determine the character offset from the start of the paragraph to the start of the original search range,
+    // since we will want to ignore results in this area.
+    TextCheckingParagraph paragraph(EphemeralRange(m_start, m_end));
+
+    // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range.
+    int startOffset = 0;
+    while (startOffset < paragraph.checkingEnd()) {
+        Vector<GrammarDetail> grammarDetails;
+        int badGrammarPhraseLocation = -1;
+        int badGrammarPhraseLength = 0;
+        m_client->textChecker().checkGrammarOfString(paragraph.textSubstring(startOffset), grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
+
+        if (!badGrammarPhraseLength) {
+            DCHECK_EQ(badGrammarPhraseLocation, -1);
+            return String();
+        }
+
+        DCHECK_GE(badGrammarPhraseLocation, 0);
+        badGrammarPhraseLocation += startOffset;
+
+
+        // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
+        int badGrammarIndex = findFirstGrammarDetail(grammarDetails, badGrammarPhraseLocation, paragraph.checkingStart(), paragraph.checkingEnd(), markAll);
+        if (badGrammarIndex >= 0) {
+            DCHECK_LT(static_cast<unsigned>(badGrammarIndex), grammarDetails.size());
+            outGrammarDetail = grammarDetails[badGrammarIndex];
+        }
+
+        // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but
+        // kept going so we could mark all instances).
+        if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
+            outGrammarPhraseOffset = badGrammarPhraseLocation - paragraph.checkingStart();
+            firstBadGrammarPhrase = paragraph.textSubstring(badGrammarPhraseLocation, badGrammarPhraseLength);
+
+            // Found one. We're done now, unless we're marking each instance.
+            if (!markAll)
+                break;
+        }
+
+        // These results were all between the start of the paragraph and the start of the search range; look
+        // beyond this phrase.
+        startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
+    }
+
+    return firstBadGrammarPhrase;
+}
+
 bool TextCheckingHelper::markAllMisspellings()
 {
     // Use the "markAll" feature of findFirstMisspelling. Ignore the return value and the "out parameter";
@@ -294,6 +538,15 @@
     return findFirstMisspelling(ignoredOffset, true).isEmpty();
 }
 
+void TextCheckingHelper::markAllBadGrammar()
+{
+    // Use the "markAll" feature of findFirstBadGrammar. Ignore the return value and "out parameters"; all we need to
+    // do is mark every instance.
+    GrammarDetail ignoredGrammarDetail;
+    int ignoredOffset;
+    findFirstBadGrammar(ignoredGrammarDetail, ignoredOffset, true);
+}
+
 bool TextCheckingHelper::unifiedTextCheckerEnabled() const
 {
     DCHECK(m_start.isNotNull());
@@ -311,8 +564,27 @@
     if (checkingTypes & TextCheckingTypeSpelling)
         findMisspellings(client, characters.data(), 0, length, spellingResult);
 
-    if (spellingResult.size())
-        results.swap(spellingResult);
+    Vector<TextCheckingResult> grammarResult;
+    if (checkingTypes & TextCheckingTypeGrammar) {
+        // Only checks grammartical error before the first misspellings
+        int grammarCheckLength = length;
+        for (const auto& spelling : spellingResult) {
+            if (spelling.location < grammarCheckLength)
+                grammarCheckLength = spelling.location;
+        }
+
+        findBadGrammars(client, characters.data(), 0, grammarCheckLength, grammarResult);
+    }
+
+    if (grammarResult.size())
+        results.swap(grammarResult);
+
+    if (spellingResult.size()) {
+        if (results.isEmpty())
+            results.swap(spellingResult);
+        else
+            results.appendVector(spellingResult);
+    }
 }
 
 bool unifiedTextCheckerEnabled(const LocalFrame* frame)
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h
index 0d85d37..a7c9a204 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h
+++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h
@@ -89,13 +89,17 @@
     ~TextCheckingHelper();
 
     String findFirstMisspelling(int& firstMisspellingOffset, bool markAll);
+    String findFirstMisspellingOrBadGrammar(bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail);
+    String findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll);
     bool markAllMisspellings();
+    void markAllBadGrammar();
 
 private:
     SpellCheckerClient* m_client;
     Position m_start;
     Position m_end;
 
+    int findFirstGrammarDetail(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int startOffset, int endOffset, bool markAll) const;
     bool unifiedTextCheckerEnabled() const;
 };
 
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index be04cc78..c1a17a1 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -397,7 +397,6 @@
         RequestFileSystem = 508,
         RequestFileSystemWorker = 509,
         RequestFileSystemSyncWorker = 510,
-        DevToolsConsoleProfile = 518,
         SVGStyleElementTitle = 519,
         PictureSourceSrc = 520,
         // The above items are available in M38 branch.
@@ -502,7 +501,6 @@
         AudioContextCreateMediaStreamDestination = 641,
         AudioContextCreateMediaStreamSource = 642,
         AudioContextCreateOscillator = 643,
-        AudioContextCreatePanner = 644,
         AudioContextCreatePeriodicWave = 645,
         AudioContextCreateScriptProcessor = 646,
         AudioContextCreateStereoPanner = 647,
@@ -552,7 +550,6 @@
         V8Animation_Onfinish_AttributeGetter = 700,
         V8Animation_Onfinish_AttributeSetter = 701,
         V8Window_WebKitAnimationEvent_ConstructorGetter = 707,
-        V8Window_WebKitAnimationEvent_AttributeSetter = 708,
         CryptoGetRandomValues = 710,
         SubtleCryptoEncrypt = 711,
         SubtleCryptoDecrypt = 712,
@@ -630,7 +627,6 @@
         InputTypeFileSecureOrigin = 801,
         InputTypeFileInsecureOrigin = 802,
         ElementAttachShadow = 804,
-        V8KeyboardEvent_KeyIdentifier_AttributeGetter = 805,
         V8SecurityPolicyViolationEvent_DocumentURI_AttributeGetter = 806,
         V8SecurityPolicyViolationEvent_BlockedURI_AttributeGetter = 807,
         V8SecurityPolicyViolationEvent_StatusCode_AttributeGetter = 808,
@@ -642,7 +638,6 @@
         V8DOMError_Constructor = 816,
         V8DOMError_Name_AttributeGetter = 817,
         V8DOMError_Message_AttributeGetter = 818,
-        V8FileReader_Error_AttributeGetter = 819,
         V8Location_AncestorOrigins_AttributeGetter = 823,
         V8IDBDatabase_ObjectStoreNames_AttributeGetter = 824,
         V8IDBObjectStore_IndexNames_AttributeGetter = 825,
@@ -692,8 +687,6 @@
         V8UIEvent_InitUIEvent_Method = 873,
         V8Document_CreateTouch_Method = 874,
         RequestFileSystemNonWebbyOrigin = 876,
-        V8Console_Memory_AttributeGetter = 877,
-        V8Console_Memory_AttributeSetter = 878,
         V8MemoryInfo_TotalJSHeapSize_AttributeGetter = 879,
         V8MemoryInfo_UsedJSHeapSize_AttributeGetter = 880,
         V8MemoryInfo_JSHeapSizeLimit_AttributeGetter = 881,
@@ -775,7 +768,6 @@
         CredentialManagerRequireUserMediation = 964,
         // The above items are available in M47 branch.
 
-        RequestAutocomplete = 965,
         BlockableMixedContentInSubframeBlocked = 966,
         AddEventListenerThirdArgumentIsObject = 967,
         RemoveEventListenerThirdArgumentIsObject = 968,
@@ -831,7 +823,6 @@
         CSSFilterBlur = 1023,
         CSSFilterDropShadow = 1024,
         BackgroundSyncRegister = 1025,
-        BorderImageWithBorderStyleNone = 1026,
         ExecCommandOnInputOrTextarea = 1027,
         V8History_ScrollRestoration_AttributeGetter = 1028,
         V8History_ScrollRestoration_AttributeSetter = 1029,
@@ -864,7 +855,6 @@
         RTCPeerConnectionGetStatsLegacyNonCompliant = 1058,
         NodeFilterIsFunction = 1059,
         NodeFilterIsObject = 1060,
-        TextEncoderUTF16 = 1061,
         CSSSelectorInternalPseudoListBox = 1062,
         CSSSelectorInternalMediaControlsCastButton = 1063,
         CSSSelectorInternalMediaControlsOverlayCastButton = 1064,
@@ -966,7 +956,6 @@
         DocumentCreateEventAnimationEvent = 1162,
         DocumentCreateEventAnimationPlayerEvent = 1163,
         DocumentCreateEventApplicationCacheErrorEvent = 1164,
-        DocumentCreateEventAutocompleteErrorEvent = 1165,
         DocumentCreateEventBeforeUnloadEvent = 1166,
         DocumentCreateEventClipboardEvent = 1167,
         DocumentCreateEventCompositionEvent = 1168,
@@ -1070,7 +1059,6 @@
         V8IDBFactory_WebkitGetDatabaseNames_Method = 1273,
         ImageDocument = 1274,
         ScriptPassesCSPDynamic = 1275,
-        ScriptPassesCSPNonce = 1276,
         CSPWithStrictDynamic = 1277,
         ScrollAnchored = 1278,
         AddEventListenerFourArguments = 1279,
@@ -1133,8 +1121,6 @@
         During_Microtask_Print = 1336,
         During_Microtask_Prompt = 1337,
         During_Microtask_SyncXHR = 1338,
-        URLMethodCreateObjectURLServiceWorker = 1339,
-        URLMethodRevokeObjectURLServiceWorker = 1340,
         DocumentCreateEventPaymentRequestUpdateEvent = 1341,
         CredentialManagerGetReturnedCredential = 1342,
         GeolocationInsecureOriginDeprecatedNotRemoved = 1343,
@@ -1167,9 +1153,6 @@
         DurableStoragePersisted = 1370,
         DurableStorageEstimate = 1371,
         UntrustedEventDefaultHandled = 1372,
-        // The following two items (FixedRasterScale*) are unused.
-        FixedRasterScaleBlurryContent = 1373,
-        FixedRasterScalePotentialPerformanceRegression = 1374,
         CSSDeepCombinatorAndShadow = 1375,
         OpacityWithPreserve3DQuirk = 1376,
         CSSSelectorPseudoReadOnly = 1377,
@@ -1249,16 +1232,14 @@
         V8BroadcastChannel_Constructor = 1447,
         V8BroadcastChannel_PostMessage_Method = 1448,
         V8BroadcastChannel_Close_Method = 1449,
-
         TouchStartFired = 1450,
         MouseDownFired = 1451,
-        PointerDownFired= 1452,
+        PointerDownFired = 1452,
         PointerDownFiredForTouch = 1453,
         PointerEventDispatchPointerDown = 1454,
         SVGSMILBeginOrEndEventValue = 1455,
         SVGSMILBeginOrEndSyncbaseValue = 1456,
         SVGSMILElementInsertedAfterLoad = 1457,
-
         V8VisualViewport_ScrollLeft_AttributeGetter = 1458,
         V8VisualViewport_ScrollTop_AttributeGetter = 1459,
         V8VisualViewport_PageX_AttributeGetter = 1460,
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameSetElement.h b/third_party/WebKit/Source/core/html/HTMLFrameSetElement.h
index 726ae76e..9940f92c 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameSetElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLFrameSetElement.h
@@ -25,6 +25,7 @@
 #define HTMLFrameSetElement_h
 
 #include "core/dom/Document.h"
+#include "core/frame/LocalDOMWindow.h"
 #include "core/html/HTMLDimension.h"
 #include "core/html/HTMLElement.h"
 
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 7122c3e1..6fd1abf3 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -761,20 +761,37 @@
     m_loadState = WaitingForSource;
     m_currentSourceNode = nullptr;
 
-    // 2 - If there are any tasks from the media element's media element event task source in
-    // one of the task queues, then remove those tasks.
+    // 2 - Let pending tasks be a list of tasks from the media element's media
+    // element task source in one of the task queues.
+    //
+    // 3 - For each task in the pending tasks that would run resolve pending
+    // play promises or project pending play prmoises algorithms, immediately
+    // resolve or reject those promises in the order the corresponding tasks
+    // were queued.
+    //
+    // TODO(mlamouri): the promises are first resolved then rejected but the
+    // order between resolved/rejected promises isn't respected. This could be
+    // improved when the same task is used for both cases.
+    if (m_playPromiseResolveTask->isPending()) {
+        m_playPromiseResolveTask->cancel();
+        resolveScheduledPlayPromises();
+    }
+    if (m_playPromiseRejectTask->isPending()) {
+        m_playPromiseRejectTask->cancel();
+        rejectScheduledPlayPromises();
+    }
+
+    // 4 - Remove each task in pending tasks from its task queue.
     cancelPendingEventsAndCallbacks();
 
-    rejectPlayPromises(AbortError, "The play() request was interrupted by a new load request.");
-
-    // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
+    // 5 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
     // a task to fire a simple event named abort at the media element.
     if (m_networkState == kNetworkLoading || m_networkState == kNetworkIdle)
         scheduleEvent(EventTypeNames::abort);
 
     resetMediaPlayerAndMediaSource();
 
-    // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
+    // 6 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
     if (m_networkState != kNetworkEmpty) {
         // 4.1 - Queue a task to fire a simple event named emptied at the media element.
         scheduleEvent(EventTypeNames::emptied);
@@ -782,30 +799,38 @@
         // 4.2 - If a fetching process is in progress for the media element, the user agent should stop it.
         setNetworkState(kNetworkEmpty);
 
-        // 4.3 - Forget the media element's media-resource-specific tracks.
+        // 4.4 - Forget the media element's media-resource-specific tracks.
         forgetResourceSpecificTracks();
 
-        // 4.4 - If readyState is not set to HAVE_NOTHING, then set it to that state.
+        // 4.5 - If readyState is not set to kHaveNothing, then set it to that state.
         m_readyState = kHaveNothing;
         m_readyStateMaximum = kHaveNothing;
 
-        // 4.5 - If the paused attribute is false, then set it to true.
-        m_paused = true;
+        DCHECK(!m_paused || m_playPromiseResolvers.isEmpty());
 
-        // 4.6 - If seeking is true, set it to false.
+        // 4.6 - If the paused attribute is false, then run these substeps
+        if (!m_paused) {
+            // 4.6.1 - Set the paused attribute to true.
+            m_paused = true;
+
+            // 4.6.2 - Take pending play promises and reject pending play promises with the result and an "AbortError" DOMException.
+            rejectPlayPromises(AbortError, "The play() request was interrupted by a new load request.");
+        }
+
+        // 4.7 - If seeking is true, set it to false.
         m_seeking = false;
 
-        // 4.7 - Set the current playback position to 0.
+        // 4.8 - Set the current playback position to 0.
         //       Set the official playback position to 0.
         //       If this changed the official playback position, then queue a task to fire a simple event named timeupdate at the media element.
         // FIXME: Add support for firing this event.
 
-        // 4.8 - Set the initial playback position to 0.
-        // FIXME: Make this less subtle. The position only becomes 0 because the ready state is kHaveNothing.
+        // 4.9 - Set the initial playback position to 0.
+        // FIXME: Make this less subtle. The position only becomes 0 because the ready state is HAVE_NOTHING.
         invalidateCachedTime();
 
-        // 4.9 - Set the timeline offset to Not-a-Number (NaN).
-        // 4.10 - Update the duration attribute to Not-a-Number (NaN).
+        // 4.10 - Set the timeline offset to Not-a-Number (NaN).
+        // 4.11 - Update the duration attribute to Not-a-Number (NaN).
 
         cueTimeline().updateActiveCues(0);
     } else if (!m_paused) {
@@ -817,17 +842,17 @@
         UseCounter::count(document(), UseCounter::HTMLMediaElementLoadNetworkEmptyNotPaused);
     }
 
-    // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
+    // 7 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
     setPlaybackRate(defaultPlaybackRate());
 
-    // 6 - Set the error attribute to null and the autoplaying flag to true.
+    // 8 - Set the error attribute to null and the autoplaying flag to true.
     m_error = nullptr;
     m_autoplaying = true;
 
-    // 7 - Invoke the media element's resource selection algorithm.
+    // 9 - Invoke the media element's resource selection algorithm.
     invokeResourceSelectionAlgorithm();
 
-    // 8 - Note: Playback of any previously playing media resource for this element stops.
+    // 10 - Note: Playback of any previously playing media resource for this element stops.
 }
 
 void HTMLMediaElement::invokeResourceSelectionAlgorithm()
@@ -1400,11 +1425,6 @@
 
     for (HTMLSourceElement* source = Traversal<HTMLSourceElement>::firstChild(*this); source; source = Traversal<HTMLSourceElement>::nextSibling(*source))
         source->cancelPendingErrorEvent();
-
-    m_playPromiseResolveTask->cancel();
-    m_playPromiseResolveList.clear();
-    m_playPromiseRejectTask->cancel();
-    m_playPromiseRejectList.clear();
 }
 
 void HTMLMediaElement::networkStateChanged()
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
index 07f74736..ed5d359 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
@@ -129,10 +129,15 @@
     , m_triedLoadingLinkHeaders(false)
 {
     ASSERT(shouldUseThreading() || (m_token && m_tokenizer));
+    ThreadState::current()->registerPreFinalizer(this);
 }
 
 HTMLDocumentParser::~HTMLDocumentParser()
 {
+}
+
+void HTMLDocumentParser::dispose()
+{
     // In Oilpan, HTMLDocumentParser can die together with Document, and
     // detach() is not called in this case.
     if (m_haveBackgroundParser)
@@ -721,6 +726,7 @@
     ASSERT(document());
     m_haveBackgroundParser = true;
 
+    // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground when background parser goes away.
     if (document()->frame() && document()->frame()->frameScheduler())
         document()->frame()->frameScheduler()->setDocumentParsingInBackground(true);
 
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h
index 2a54062..e83f3bb 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h
@@ -69,6 +69,7 @@
 
 class HTMLDocumentParser :  public ScriptableDocumentParser, private HTMLScriptRunnerHost {
     USING_GARBAGE_COLLECTED_MIXIN(HTMLDocumentParser);
+    USING_PRE_FINALIZER(HTMLDocumentParser, dispose);
 public:
     static HTMLDocumentParser* create(HTMLDocument& document, ParserSynchronizationPolicy backgroundParsingPolicy)
     {
@@ -77,6 +78,9 @@
     ~HTMLDocumentParser() override;
     DECLARE_VIRTUAL_TRACE();
 
+    // TODO(alexclarke): Remove when background parser goes away.
+    void dispose();
+
     // Exposed for HTMLParserScheduler
     void resumeParsingAfterYield();
 
diff --git a/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.cpp b/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.cpp
index 0904a4de..3146c5c 100644
--- a/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.cpp
+++ b/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.cpp
@@ -6,13 +6,13 @@
 
 namespace blink {
 
-NGConstraintSpace::NGConstraintSpace(LayoutUnit inlineSize,
-    LayoutUnit blockSize)
+NGConstraintSpace::NGConstraintSpace(LayoutUnit inlineContainerSize,
+    LayoutUnit blockContainerSize)
 {
-    m_inlineSize = inlineSize;
-    m_blockSize = blockSize;
-    m_inlineOverflowSize = LayoutUnit(-1);
-    m_blockOverflowSize = LayoutUnit(-1);
+    m_inlineContainerSize = inlineContainerSize;
+    m_blockContainerSize = blockContainerSize;
+    m_inlineTriggersScrollbar = 0;
+    m_blockTriggersScrollbar = 0;
     m_fixedInlineSize = 0;
     m_fixedBlockSize = 0;
     m_blockFragmentationType = FragmentNone;
@@ -24,11 +24,11 @@
 
 }
 
-void NGConstraintSpace::setOverflowSize(LayoutUnit inlineSize,
-    LayoutUnit blockSize)
+void NGConstraintSpace::setOverflowTriggersScrollbar(bool inlineTriggers,
+    bool blockTriggers)
 {
-    m_inlineOverflowSize = inlineSize;
-    m_blockOverflowSize = blockSize;
+    m_inlineTriggersScrollbar = inlineTriggers;
+    m_blockTriggersScrollbar = blockTriggers;
 }
 
 void NGConstraintSpace::setFixedSize(bool inlineFixed, bool blockFixed)
diff --git a/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.h b/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.h
index 88a401e..e6d8536 100644
--- a/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.h
+++ b/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.h
@@ -46,24 +46,44 @@
 
 class CORE_EXPORT NGConstraintSpace {
 public:
-    NGConstraintSpace(LayoutUnit inlineSize, LayoutUnit blockSize);
+    NGConstraintSpace(LayoutUnit inlineContainerSize,
+        LayoutUnit blockContainerSize);
     ~NGConstraintSpace() { }
 
     void addExclusion(const NGExclusion, unsigned options = 0);
-    void setOverflowSize(LayoutUnit inlineSize, LayoutUnit blockSize);
+    void setOverflowTriggersScrollbar(bool inlineTriggers,
+        bool blockTriggers);
     void setFixedSize(bool inlineFixed, bool blockFixed);
-    void setFragmentationType(NGFragmentationType blockFragmentationType);
+    void setFragmentationType(NGFragmentationType);
 
-    // Available space in each direction, -1 indicates infinite space.
-    LayoutUnit inlineSize() const { return m_inlineSize; }
-    LayoutUnit blockSize() const { return m_blockSize; }
+    // Size of the container in each direction. Used for the following
+    // three cases:
+    // 1) Percentage resolution.
+    // 2) Resolving absolute positions of children.
+    // 3) Defining the threashold that triggers the presence of a
+    //    scrollbar. Only applies if the corresponding scrollbarTrigger
+    //    flag has been set for the direction.
+    LayoutUnit inlineContainerSize() const
+    {
+        return m_inlineContainerSize;
+    }
+    LayoutUnit blockContainerSize() const
+    {
+        return m_blockContainerSize;
+    }
 
-    // The size threashold in the inline and block directions respectively that
-    // triggers the presence of a scrollbar. If exceeded the current layout
-    // should be aborted and invoked again with a constraint space modified to
-    // reserve space for a scrollbar. -1 indicates no limit.
-    LayoutUnit inlineOverflowSize() const { return m_inlineOverflowSize; }
-    LayoutUnit blockOverflowSize() const { return m_blockOverflowSize; }
+    // Whether exceeding the containerSize triggers the presence of a
+    // scrollbar for the indicated direction.
+    // If exceeded the current layout should be aborted and invoked again
+    // with a constraint space modified to reserve space for a scrollbar.
+    bool inlineTriggersScrollbar() const
+    {
+        return m_inlineTriggersScrollbar;
+    }
+    bool blockTriggersScrollbar() const
+    {
+        return m_blockTriggersScrollbar;
+    }
 
     // Some layout modes “stretch” their children to a fixed size (e.g. flex,
     // grid). These flags represented whether a layout needs to produce a
@@ -91,13 +111,13 @@
     void subtract(const NGFragment);
 
 private:
-    LayoutUnit m_inlineSize;
-    LayoutUnit m_blockSize;
-    LayoutUnit m_inlineOverflowSize;
-    LayoutUnit m_blockOverflowSize;
+    LayoutUnit m_inlineContainerSize;
+    LayoutUnit m_blockContainerSize;
 
     unsigned m_fixedInlineSize : 1;
     unsigned m_fixedBlockSize : 1;
+    unsigned m_inlineTriggersScrollbar : 1;
+    unsigned m_blockTriggersScrollbar : 1;
     unsigned m_blockFragmentationType : 2;
 
     DoublyLinkedList<const NGExclusion> m_exclusions;
@@ -128,20 +148,16 @@
 
     LayoutUnit inlineOffset() const;
     LayoutUnit blockOffset() const;
-
-    // When creating a derived NGConstraintSpace for the next inline level
-    // layout opportunity, inlineSize and blockSize of the NGConstraintSpace
-    // may be different from its parent. These properties hold the inline and
-    // block size of the original NGConstraintSpaces, allowing percentage
-    // resolution to work correctly.
-    LayoutUnit inlineSizeForPercentageResolution() const;
-    LayoutUnit blockSizeForPercentageResolution() const;
+    LayoutUnit inlineSize() const;
+    LayoutUnit blockSize() const;
 
 private:
     NGDerivedConstraintSpace();
 
     LayoutUnit m_inlineOffset;
     LayoutUnit m_blockOffset;
+    LayoutUnit m_inlineSize;
+    LayoutUnit m_blockSize;
     NGConstraintSpace* m_original;
 };
 
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index 95706e3..722438a8 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -283,6 +283,7 @@
     ~EmptyTextCheckerClient() { }
 
     void checkSpellingOfString(const String&, int*, int*) override {}
+    void checkGrammarOfString(const String&, Vector<GrammarDetail>&, int*, int*) override {}
     void requestCheckingOfString(TextCheckingRequest*) override;
 };
 
diff --git a/third_party/WebKit/Source/modules/filesystem/ErrorCallback.h b/third_party/WebKit/Source/modules/filesystem/ErrorCallback.h
index 3c05cec..ee25802d 100644
--- a/third_party/WebKit/Source/modules/filesystem/ErrorCallback.h
+++ b/third_party/WebKit/Source/modules/filesystem/ErrorCallback.h
@@ -35,6 +35,8 @@
 
 namespace blink {
 
+class DOMException;
+
 class ErrorCallback : public GarbageCollectedFinalized<ErrorCallback> {
 public:
     virtual ~ErrorCallback() { }
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushError.cpp b/third_party/WebKit/Source/modules/push_messaging/PushError.cpp
index 6b8d611..9effbe4c 100644
--- a/third_party/WebKit/Source/modules/push_messaging/PushError.cpp
+++ b/third_party/WebKit/Source/modules/push_messaging/PushError.cpp
@@ -17,12 +17,12 @@
         return DOMException::create(AbortError, webError.message);
     case WebPushError::ErrorTypeNetwork:
         return DOMException::create(NetworkError, webError.message);
+    case WebPushError::ErrorTypeNotAllowed:
+        return DOMException::create(NotAllowedError, webError.message);
     case WebPushError::ErrorTypeNotFound:
         return DOMException::create(NotFoundError, webError.message);
     case WebPushError::ErrorTypeNotSupported:
         return DOMException::create(NotSupportedError, webError.message);
-    case WebPushError::ErrorTypePermissionDenied:
-        return DOMException::create(PermissionDeniedError, webError.message);
     case WebPushError::ErrorTypeUnknown:
         return DOMException::create(UnknownError, webError.message);
     }
diff --git a/third_party/WebKit/Source/platform/text/TextCheckerClient.h b/third_party/WebKit/Source/platform/text/TextCheckerClient.h
index d70828e..bb9761a 100644
--- a/third_party/WebKit/Source/platform/text/TextCheckerClient.h
+++ b/third_party/WebKit/Source/platform/text/TextCheckerClient.h
@@ -42,6 +42,7 @@
     virtual ~TextCheckerClient() { }
 
     virtual void checkSpellingOfString(const String&, int* misspellingLocation, int* misspellingLength) = 0;
+    virtual void checkGrammarOfString(const String&, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) = 0;
     virtual void requestCheckingOfString(TextCheckingRequest*) = 0;
 };
 
diff --git a/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp b/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp
index 9bc31d2..3dbc908 100644
--- a/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp
+++ b/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp
@@ -147,6 +147,41 @@
     m_webView->spellCheckClient()->requestCheckingOfText(text, markers, markerOffsets, new WebTextCheckingCompletionImpl(request));
 }
 
+void SpellCheckerClientImpl::checkGrammarOfString(const String& text, WTF::Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength)
+{
+    if (badGrammarLocation)
+        *badGrammarLocation = -1;
+    if (badGrammarLength)
+        *badGrammarLength = 0;
+
+    if (!m_webView->spellCheckClient())
+        return;
+    WebVector<WebTextCheckingResult> webResults;
+    m_webView->spellCheckClient()->checkTextOfParagraph(text, WebTextCheckingTypeGrammar, &webResults);
+    if (!webResults.size())
+        return;
+
+    // Convert a list of WebTextCheckingResults to a list of GrammarDetails. If
+    // the converted vector of GrammarDetails has grammar errors, we set
+    // badGrammarLocation and badGrammarLength to tell WebKit that the input
+    // text has grammar errors.
+    for (size_t i = 0; i < webResults.size(); ++i) {
+        if (webResults[i].decoration == WebTextDecorationTypeGrammar) {
+            GrammarDetail detail;
+            detail.location = webResults[i].location;
+            detail.length = webResults[i].length;
+            detail.userDescription = webResults[i].replacement;
+            details.append(detail);
+        }
+    }
+    if (!details.size())
+        return;
+    if (badGrammarLocation)
+        *badGrammarLocation = 0;
+    if (badGrammarLength)
+        *badGrammarLength = text.length();
+}
+
 void SpellCheckerClientImpl::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
 {
     if (m_webView->spellCheckClient())
diff --git a/third_party/WebKit/Source/web/SpellCheckerClientImpl.h b/third_party/WebKit/Source/web/SpellCheckerClientImpl.h
index 9eb87dc..307635e 100644
--- a/third_party/WebKit/Source/web/SpellCheckerClientImpl.h
+++ b/third_party/WebKit/Source/web/SpellCheckerClientImpl.h
@@ -48,6 +48,8 @@
     bool isContinuousSpellCheckingEnabled() override;
     void toggleContinuousSpellChecking() override;
     void checkSpellingOfString(const String&, int* misspellingLocation, int* misspellingLength) override;
+    void checkGrammarOfString(const String&, Vector<GrammarDetail>&,
+        int* badGrammarLocation, int* badGrammarLength) override;
     void updateSpellingUIWithMisspelledWord(const String&) override;
     void showSpellingUI(bool show) override;
     bool spellingUIIsShowing() override;
diff --git a/third_party/WebKit/Source/web/WebAXObject.cpp b/third_party/WebKit/Source/web/WebAXObject.cpp
index 05c7c8b..c80ceb5a 100644
--- a/third_party/WebKit/Source/web/WebAXObject.cpp
+++ b/third_party/WebKit/Source/web/WebAXObject.cpp
@@ -972,9 +972,13 @@
     Element* element = nullptr;
     if (node->isElementNode()) {
         element = toElement(node);
+    } else if (node->isDocumentNode()) {
+        element = node->document().documentElement();
     } else {
         node->updateDistribution();
         ContainerNode* parent = FlatTreeTraversal::parent(*node);
+        if (!parent)
+            return;
         ASSERT_WITH_SECURITY_IMPLICATION(parent->isElementNode());
         element = toElement(parent);
     }
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index cd14d6e..2b9c3e87 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -5289,6 +5289,11 @@
         kick(1, 8, WebTextDecorationTypeSpelling);
     }
 
+    void kickGrammar()
+    {
+        kick(1, 8, WebTextDecorationTypeGrammar);
+    }
+
     void kickInvisibleSpellcheck()
     {
         kick(1, 8, WebTextDecorationTypeInvisibleSpellcheck);
@@ -5385,8 +5390,9 @@
     EXPECT_FALSE(exceptionState.hadException());
     auto range = EphemeralRange::rangeOfContents(*element);
     document->markers().addMarker(range.startPosition(), range.endPosition(), DocumentMarker::Spelling);
+    document->markers().addMarker(range.startPosition(), range.endPosition(), DocumentMarker::Grammar);
     document->markers().addMarker(range.startPosition(), range.endPosition(), DocumentMarker::InvisibleSpellcheck);
-    EXPECT_EQ(2U, document->markers().markers().size());
+    EXPECT_EQ(3U, document->markers().markers().size());
 
     spellcheck.kickNoResults();
     EXPECT_EQ(0U, document->markers().markers().size());
@@ -5421,6 +5427,14 @@
     document->execCommand("InsertText", false, "wellcome ", exceptionState);
     EXPECT_FALSE(exceptionState.hadException());
 
+    spellcheck.kickGrammar();
+    ASSERT_EQ(1U, document->markers().markers().size());
+    ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
+    EXPECT_EQ(DocumentMarker::Grammar, document->markers().markers()[0]->type());
+
+    document->execCommand("InsertText", false, "wellcome ", exceptionState);
+    EXPECT_FALSE(exceptionState.hadException());
+
     spellcheck.kickInvisibleSpellcheck();
     ASSERT_EQ(1U, document->markers().markers().size());
     ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
diff --git a/third_party/WebKit/Source/web/tests/data/composited_selection_bounds_editable.html b/third_party/WebKit/Source/web/tests/data/composited_selection_bounds_editable.html
index ed54882..f8cad50f 100644
--- a/third_party/WebKit/Source/web/tests/data/composited_selection_bounds_editable.html
+++ b/third_party/WebKit/Source/web/tests/data/composited_selection_bounds_editable.html
@@ -8,6 +8,9 @@
         margin: 0;
         padding: 0;
     }
+    #text {
+        background-color: transparent; /* Prevent scrolling layer promotion to it's own layer */
+    }
 </style>
 <textarea id="text">
     The quick brown fox jumped over the lazy dog.
diff --git a/third_party/WebKit/public/blink.gyp b/third_party/WebKit/public/blink.gyp
index 83edc75..eb8fb5cc 100644
--- a/third_party/WebKit/public/blink.gyp
+++ b/third_party/WebKit/public/blink.gyp
@@ -36,7 +36,6 @@
         'blink_mojo_sources': [
             'platform/mime_registry.mojom',
             'platform/modules/background_sync/background_sync.mojom',
-            'platform/modules/bluetooth/web_bluetooth.mojom',
             'platform/modules/broadcastchannel/broadcast_channel.mojom',
             'platform/modules/geolocation/geolocation.mojom',
             'platform/modules/hyphenation/hyphenation.mojom',
@@ -123,6 +122,7 @@
                 'mojom_files': [
                     '<@(blink_mojo_sources)',
                     '<@(blink_android_mojo_sources)',
+                    'platform/modules/bluetooth/web_bluetooth.mojom',
                 ],
                 'mojom_typemaps': [
                     '../Source/platform/mojo/SecurityOrigin.typemap',
@@ -172,7 +172,6 @@
                     '<@(blink_android_mojo_sources)',
                 ],
                 'mojom_typemaps': [
-                    '../../../device/bluetooth/public/interfaces/bluetooth_uuid.typemap',
                     '<(DEPTH)/url/mojo/origin.typemap',
                     '<@(blink_typemap_sources)',
                 ],
@@ -218,8 +217,8 @@
                 'mojo_bindings_mojom',
                 'new_wrapper_types_mojo_bindings_blink_mojom',
                 'new_wrapper_types_mojo_bindings_mojom',
-                '../../../mojo/mojo_public.gyp:mojo_cpp_bindings',
                 '../../../device/bluetooth/bluetooth.gyp:bluetooth_mojom',
+                '../../../mojo/mojo_public.gyp:mojo_cpp_bindings',
                 '<(DEPTH)/cc/ipc/cc_ipc.gyp:interfaces',
                 '<(DEPTH)/cc/ipc/cc_ipc.gyp:interfaces_blink',
             ],
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom b/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom
index aa83d8d..11e5b16 100644
--- a/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom
+++ b/third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom
@@ -90,8 +90,12 @@
   MULTIPLE
 };
 
+struct WebBluetoothDeviceId {
+  string device_id;
+};
+
 struct WebBluetoothDevice {
-  string id;
+  WebBluetoothDeviceId id;
   string? name;
   array<string> uuids;
 };
@@ -122,18 +126,18 @@
   // connection to the device didn't exist already. If a GATT connection existed
   // already then this function increases the ref count to keep that connection
   // alive.
-  RemoteServerConnect(string device_id) => (WebBluetoothError error);
+  RemoteServerConnect(WebBluetoothDeviceId device_id) => (WebBluetoothError error);
 
   // If a GATT connection exists for Device with |device_id| then decreases
   // the ref count for that connection.
-  RemoteServerDisconnect(string device_id);
+  RemoteServerDisconnect(WebBluetoothDeviceId device_id);
 
   // If |services_uuid| is present, returns services with |services_uuid|.
   // Otherwise returns all non-blacklisted services.
   // If |quantity| == WebBluetoothGATTQueryQuantity::SINGLE, only one
   // service will be returned.
   RemoteServerGetPrimaryServices(
-    string device_id,
+    WebBluetoothDeviceId device_id,
     WebBluetoothGATTQueryQuantity quantity,
     device.mojom.BluetoothUUID? services_uuid) => (
       WebBluetoothError error,
@@ -184,5 +188,5 @@
 interface WebBluetoothServiceClient {
   RemoteCharacteristicValueChanged(string characteristic_instance_id,
                                    array<uint8> value);
-  GattServerDisconnected(string device_id);
+  GattServerDisconnected(WebBluetoothDeviceId device_id);
 };
diff --git a/third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h b/third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h
index bf048ec..468123d5 100644
--- a/third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h
+++ b/third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h
@@ -13,9 +13,9 @@
     enum ErrorType {
         ErrorTypeAbort = 0,
         ErrorTypeNetwork,
+        ErrorTypeNotAllowed,
         ErrorTypeNotFound,
         ErrorTypeNotSupported,
-        ErrorTypePermissionDenied,
         ErrorTypeUnknown,
         ErrorTypeLast = ErrorTypeUnknown
     };
diff --git a/third_party/opus/DEPS b/third_party/opus/DEPS
new file mode 100644
index 0000000..7e5bd26
--- /dev/null
+++ b/third_party/opus/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+arm",
+  "+mips",
+  "+x86",
+]
diff --git a/third_party/opus/README.chromium b/third_party/opus/README.chromium
index 61ebb3a..a69a13e 100644
--- a/third_party/opus/README.chromium
+++ b/third_party/opus/README.chromium
@@ -1,5 +1,5 @@
 Name: opus
-URL: http://git.xiph.org/?p=opus.git
+URL: http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz
 Version: 1.1.3
 License: BSD
 License File: src/COPYING
@@ -12,3 +12,5 @@
 encoding/decoding.
 
 Local changes:
+* copy .gitignore from https://git.xiph.org/?p=opus.git;a=tree
+* set 'x' flags: "chmod 750 win32/genversion.bat"
diff --git a/third_party/opus/src/.gitignore b/third_party/opus/src/.gitignore
new file mode 100644
index 0000000..33127c9f
--- /dev/null
+++ b/third_party/opus/src/.gitignore
@@ -0,0 +1,83 @@
+Doxyfile
+Makefile
+Makefile.in
+TAGS
+aclocal.m4
+autom4te.cache
+*.kdevelop.pcs
+*.kdevses
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+INSTALL
+install-sh
+.deps
+.libs
+.dirstamp
+*.a
+*.exe
+*.la
+*-gnu.S
+testcelt
+libtool
+ltmain.sh
+missing
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+opus_compare
+opus_demo
+repacketizer_demo
+stamp-h1
+test-driver
+*.sw*
+*.o
+*.lo
+*.pc
+*.tar.gz
+*~
+tests/*test
+tests/test_opus_api
+tests/test_opus_decode
+tests/test_opus_encode
+tests/test_opus_padding
+celt/arm/armopts.s
+celt/dump_modes/dump_modes
+celt/tests/test_unit_cwrs32
+celt/tests/test_unit_dft
+celt/tests/test_unit_entropy
+celt/tests/test_unit_laplace
+celt/tests/test_unit_mathops
+celt/tests/test_unit_mdct
+celt/tests/test_unit_rotation
+celt/tests/test_unit_types
+doc/doxygen_sqlite3.db
+doc/doxygen-build.stamp
+doc/html
+doc/latex
+doc/man
+package_version
+version.h
+celt/Debug
+celt/Release
+celt/x64
+silk/Debug
+silk/Release
+silk/x64
+silk/fixed/Debug
+silk/fixed/Release
+silk/fixed/x64
+silk/float/Debug
+silk/float/Release
+silk/float/x64
+src/Debug
+src/Release
+src/x64
diff --git a/third_party/opus/src/AUTHORS b/third_party/opus/src/AUTHORS
new file mode 100644
index 0000000..b3d22a2
--- /dev/null
+++ b/third_party/opus/src/AUTHORS
@@ -0,0 +1,6 @@
+Jean-Marc Valin (jmvalin@jmvalin.ca)
+Koen Vos (koenvos74@gmail.com)
+Timothy Terriberry (tterribe@xiph.org)
+Karsten Vandborg Sorensen (karsten.vandborg.sorensen@skype.net)
+Soren Skak Jensen (ssjensen@gn.com)
+Gregory Maxwell (greg@xiph.org)
diff --git a/third_party/opus/src/COPYING b/third_party/opus/src/COPYING
new file mode 100644
index 0000000..9c739c3
--- /dev/null
+++ b/third_party/opus/src/COPYING
@@ -0,0 +1,44 @@
+Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
+                    Jean-Marc Valin, Timothy B. Terriberry,
+                    CSIRO, Gregory Maxwell, Mark Borgerding,
+                    Erik de Castro Lopo
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Opus is subject to the royalty-free patent licenses which are
+specified at:
+
+Xiph.Org Foundation:
+https://datatracker.ietf.org/ipr/1524/
+
+Microsoft Corporation:
+https://datatracker.ietf.org/ipr/1914/
+
+Broadcom Corporation:
+https://datatracker.ietf.org/ipr/1526/
diff --git a/third_party/opus/src/ChangeLog b/third_party/opus/src/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/opus/src/ChangeLog
diff --git a/third_party/opus/src/Makefile.am b/third_party/opus/src/Makefile.am
new file mode 100644
index 0000000..7a69114
--- /dev/null
+++ b/third_party/opus/src/Makefile.am
@@ -0,0 +1,302 @@
+# Provide the full test output for failed tests when using the parallel
+# test suite (which is enabled by default with automake 1.13+).
+export VERBOSE = yes
+
+AUTOMAKE_OPTIONS = subdir-objects
+ACLOCAL_AMFLAGS = -I m4
+
+lib_LTLIBRARIES = libopus.la
+
+DIST_SUBDIRS = doc
+
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/celt -I$(top_srcdir)/silk \
+              -I$(top_srcdir)/silk/float -I$(top_srcdir)/silk/fixed $(NE10_CFLAGS)
+
+include celt_sources.mk
+include silk_sources.mk
+include opus_sources.mk
+
+if FIXED_POINT
+SILK_SOURCES += $(SILK_SOURCES_FIXED)
+if HAVE_SSE4_1
+SILK_SOURCES += $(SILK_SOURCES_SSE4_1) $(SILK_SOURCES_FIXED_SSE4_1)
+endif
+else
+SILK_SOURCES += $(SILK_SOURCES_FLOAT)
+if HAVE_SSE4_1
+SILK_SOURCES += $(SILK_SOURCES_SSE4_1)
+endif
+endif
+
+if DISABLE_FLOAT_API
+else
+OPUS_SOURCES += $(OPUS_SOURCES_FLOAT)
+endif
+
+if HAVE_SSE
+CELT_SOURCES += $(CELT_SOURCES_SSE)
+endif
+if HAVE_SSE2
+CELT_SOURCES += $(CELT_SOURCES_SSE2)
+endif
+if HAVE_SSE4_1
+CELT_SOURCES += $(CELT_SOURCES_SSE4_1)
+endif
+
+if CPU_ARM
+CELT_SOURCES += $(CELT_SOURCES_ARM)
+SILK_SOURCES += $(SILK_SOURCES_ARM)
+
+if HAVE_ARM_NEON_INTR
+CELT_SOURCES += $(CELT_SOURCES_ARM_NEON_INTR)
+SILK_SOURCES += $(SILK_SOURCES_ARM_NEON_INTR)
+endif
+
+if HAVE_ARM_NE10
+CELT_SOURCES += $(CELT_SOURCES_ARM_NE10)
+endif
+
+if OPUS_ARM_EXTERNAL_ASM
+noinst_LTLIBRARIES = libarmasm.la
+libarmasm_la_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S)
+BUILT_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \
+ $(CELT_AM_SOURCES_ARM_ASM:.s.in=.s) \
+ $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S)
+endif
+endif
+
+CLEANFILES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \
+ $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S)
+
+include celt_headers.mk
+include silk_headers.mk
+include opus_headers.mk
+
+libopus_la_SOURCES = $(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES)
+libopus_la_LDFLAGS = -no-undefined -version-info @OPUS_LT_CURRENT@:@OPUS_LT_REVISION@:@OPUS_LT_AGE@
+libopus_la_LIBADD = $(NE10_LIBS) $(LIBM)
+if OPUS_ARM_EXTERNAL_ASM
+libopus_la_LIBADD += libarmasm.la
+endif
+
+pkginclude_HEADERS = include/opus.h include/opus_multistream.h include/opus_types.h include/opus_defines.h
+
+noinst_HEADERS = $(OPUS_HEAD) $(SILK_HEAD) $(CELT_HEAD)
+
+if EXTRA_PROGRAMS
+noinst_PROGRAMS = opus_demo repacketizer_demo opus_compare tests/test_opus_api tests/test_opus_encode tests/test_opus_decode tests/test_opus_padding celt/tests/test_unit_cwrs32 celt/tests/test_unit_dft celt/tests/test_unit_entropy celt/tests/test_unit_laplace celt/tests/test_unit_mathops celt/tests/test_unit_mdct celt/tests/test_unit_rotation celt/tests/test_unit_types
+
+TESTS = celt/tests/test_unit_types celt/tests/test_unit_mathops celt/tests/test_unit_entropy celt/tests/test_unit_laplace celt/tests/test_unit_dft celt/tests/test_unit_mdct celt/tests/test_unit_rotation celt/tests/test_unit_cwrs32 tests/test_opus_api tests/test_opus_decode tests/test_opus_encode tests/test_opus_padding
+
+opus_demo_SOURCES = src/opus_demo.c
+
+opus_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM)
+
+repacketizer_demo_SOURCES = src/repacketizer_demo.c
+
+repacketizer_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM)
+
+opus_compare_SOURCES = src/opus_compare.c
+opus_compare_LDADD = $(LIBM)
+
+tests_test_opus_api_SOURCES = tests/test_opus_api.c tests/test_opus_common.h
+tests_test_opus_api_LDADD = libopus.la $(NE10_LIBS) $(LIBM)
+
+tests_test_opus_encode_SOURCES = tests/test_opus_encode.c tests/test_opus_common.h
+tests_test_opus_encode_LDADD = libopus.la $(NE10_LIBS) $(LIBM)
+
+tests_test_opus_decode_SOURCES = tests/test_opus_decode.c tests/test_opus_common.h
+tests_test_opus_decode_LDADD = libopus.la $(NE10_LIBS) $(LIBM)
+
+tests_test_opus_padding_SOURCES = tests/test_opus_padding.c tests/test_opus_common.h
+tests_test_opus_padding_LDADD = libopus.la $(NE10_LIBS) $(LIBM)
+
+celt_tests_test_unit_cwrs32_SOURCES = celt/tests/test_unit_cwrs32.c
+celt_tests_test_unit_cwrs32_LDADD = $(LIBM)
+
+celt_tests_test_unit_dft_SOURCES = celt/tests/test_unit_dft.c
+celt_tests_test_unit_dft_LDADD = $(NE10_LIBS) $(LIBM)
+if OPUS_ARM_EXTERNAL_ASM
+celt_tests_test_unit_dft_LDADD += libarmasm.la
+endif
+
+celt_tests_test_unit_entropy_SOURCES = celt/tests/test_unit_entropy.c
+celt_tests_test_unit_entropy_LDADD = $(LIBM)
+
+celt_tests_test_unit_laplace_SOURCES = celt/tests/test_unit_laplace.c
+celt_tests_test_unit_laplace_LDADD = $(LIBM)
+
+celt_tests_test_unit_mathops_SOURCES = celt/tests/test_unit_mathops.c
+celt_tests_test_unit_mathops_LDADD = $(NE10_LIBS) $(LIBM)
+if OPUS_ARM_EXTERNAL_ASM
+celt_tests_test_unit_mathops_LDADD += libarmasm.la
+endif
+
+celt_tests_test_unit_mdct_SOURCES = celt/tests/test_unit_mdct.c
+celt_tests_test_unit_mdct_LDADD = $(NE10_LIBS) $(LIBM)
+if OPUS_ARM_EXTERNAL_ASM
+celt_tests_test_unit_mdct_LDADD += libarmasm.la
+endif
+
+celt_tests_test_unit_rotation_SOURCES = celt/tests/test_unit_rotation.c
+celt_tests_test_unit_rotation_LDADD = $(NE10_LIBS) $(LIBM)
+if OPUS_ARM_EXTERNAL_ASM
+celt_tests_test_unit_rotation_LDADD += libarmasm.la
+endif
+
+celt_tests_test_unit_types_SOURCES = celt/tests/test_unit_types.c
+celt_tests_test_unit_types_LDADD = $(LIBM)
+endif
+
+if CUSTOM_MODES
+pkginclude_HEADERS += include/opus_custom.h
+if EXTRA_PROGRAMS
+noinst_PROGRAMS += opus_custom_demo
+opus_custom_demo_SOURCES = celt/opus_custom_demo.c
+opus_custom_demo_LDADD = libopus.la $(LIBM)
+endif
+endif
+
+EXTRA_DIST = version.mk \
+             opus.pc.in \
+             opus-uninstalled.pc.in \
+             opus.m4 \
+             Makefile.mips \
+             Makefile.unix \
+             tests/run_vectors.sh \
+             celt/arm/arm2gnu.pl \
+             celt/arm/celt_pitch_xcorr_arm.s \
+             win32/VS2015/silk_float.vcxproj \
+             win32/VS2015/celt.vcxproj.filters \
+             win32/VS2015/opus.vcxproj \
+             win32/VS2015/silk_common.vcxproj.filters \
+             win32/VS2015/silk_float.vcxproj.filters \
+             win32/VS2015/test_opus_encode.vcxproj.filters \
+             win32/VS2015/silk_common.vcxproj \
+             win32/VS2015/test_opus_encode.vcxproj \
+             win32/VS2015/opus_demo.vcxproj \
+             win32/VS2015/test_opus_api.vcxproj.filters \
+             win32/VS2015/test_opus_api.vcxproj \
+             win32/VS2015/test_opus_decode.vcxproj.filters \
+             win32/VS2015/silk_fixed.vcxproj.filters \
+             win32/VS2015/opus_demo.vcxproj.filters \
+             win32/VS2015/silk_fixed.vcxproj \
+             win32/VS2015/opus.vcxproj.filters \
+             win32/VS2015/test_opus_decode.vcxproj \
+             win32/VS2015/celt.vcxproj \
+             win32/VS2015/opus.sln \
+             win32/genversion.bat \
+             win32/config.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = opus.pc
+
+m4datadir = $(datadir)/aclocal
+m4data_DATA = opus.m4
+
+# Targets to build and install just the library without the docs
+opus check-opus install-opus: export NO_DOXYGEN = 1
+
+opus: all
+check-opus: check
+install-opus: install
+
+
+# Or just the docs
+docs:
+	( cd doc && $(MAKE) $(AM_MAKEFLAGS) )
+
+install-docs:
+	( cd doc && $(MAKE) $(AM_MAKEFLAGS) install )
+
+
+# Or everything (by default)
+all-local:
+	@[ -n "$(NO_DOXYGEN)" ] || ( cd doc && $(MAKE) $(AM_MAKEFLAGS) )
+
+install-data-local:
+	@[ -n "$(NO_DOXYGEN)" ] || ( cd doc && $(MAKE) $(AM_MAKEFLAGS) install )
+
+clean-local:
+	-( cd doc && $(MAKE) $(AM_MAKEFLAGS) clean )
+
+uninstall-local:
+	( cd doc && $(MAKE) $(AM_MAKEFLAGS) uninstall )
+
+
+# We check this every time make is run, with configure.ac being touched to
+# trigger an update of the build system files if update_version changes the
+# current PACKAGE_VERSION (or if package_version was modified manually by a
+# user with either AUTO_UPDATE=no or no update_version script present - the
+# latter being the normal case for tarball releases).
+#
+# We can't just add the package_version file to CONFIGURE_DEPENDENCIES since
+# simply running autoconf will not actually regenerate configure for us when
+# the content of that file changes (due to autoconf dependency checking not
+# knowing about that without us creating yet another file for it to include).
+#
+# The MAKECMDGOALS check is a gnu-make'ism, but will degrade 'gracefully' for
+# makes that don't support it.  The only loss of functionality is not forcing
+# an update of package_version for `make dist` if AUTO_UPDATE=no, but that is
+# unlikely to be a real problem for any real user.
+$(top_srcdir)/configure.ac: force
+	@case "$(MAKECMDGOALS)" in \
+	    dist-hook)                             exit 0       ;; \
+	    dist-* | dist | distcheck | distclean) _arg=release ;; \
+	esac; \
+	if ! $(top_srcdir)/update_version $$_arg 2> /dev/null; then \
+	    if [ ! -e $(top_srcdir)/package_version ]; then \
+		echo 'PACKAGE_VERSION="unknown"' > $(top_srcdir)/package_version; \
+	    fi; \
+	    . $(top_srcdir)/package_version || exit 1; \
+	    [ "$(PACKAGE_VERSION)" != "$$PACKAGE_VERSION" ] || exit 0; \
+	fi; \
+	touch $@
+
+force:
+
+# Create a minimal package_version file when make dist is run.
+dist-hook:
+	echo 'PACKAGE_VERSION="$(PACKAGE_VERSION)"' > $(top_distdir)/package_version
+
+
+.PHONY: opus check-opus install-opus docs install-docs
+
+# automake doesn't do dependency tracking for asm files, that I can tell
+$(CELT_SOURCES_ARM_ASM:%.s=%-gnu.S): celt/arm/armopts-gnu.S
+$(CELT_SOURCES_ARM_ASM:%.s=%-gnu.S): $(top_srcdir)/celt/arm/arm2gnu.pl
+
+# convert ARM asm to GNU as format
+%-gnu.S: $(top_srcdir)/%.s
+	$(top_srcdir)/celt/arm/arm2gnu.pl @ARM2GNU_PARAMS@ < $< > $@
+# For autoconf-modified sources (e.g., armopts.s)
+%-gnu.S: %.s
+	$(top_srcdir)/celt/arm/arm2gnu.pl @ARM2GNU_PARAMS@ < $< > $@
+
+OPT_UNIT_TEST_OBJ = $(celt_tests_test_unit_mathops_SOURCES:.c=.o) \
+                    $(celt_tests_test_unit_rotation_SOURCES:.c=.o) \
+                    $(celt_tests_test_unit_mdct_SOURCES:.c=.o) \
+                    $(celt_tests_test_unit_dft_SOURCES:.c=.o)
+
+if HAVE_SSE
+SSE_OBJ = $(CELT_SOURCES_SSE:.c=.lo)
+$(SSE_OBJ) $(OPT_UNIT_TEST_OBJ): CFLAGS += $(OPUS_X86_SSE_CFLAGS)
+endif
+
+if HAVE_SSE2
+SSE2_OBJ = $(CELT_SOURCES_SSE2:.c=.lo)
+$(SSE2_OBJ) $(OPT_UNIT_TEST_OBJ): CFLAGS += $(OPUS_X86_SSE2_CFLAGS)
+endif
+
+if HAVE_SSE4_1
+SSE4_1_OBJ = $(CELT_SOURCES_SSE4_1:.c=.lo) \
+             $(SILK_SOURCES_SSE4_1:.c=.lo) \
+             $(SILK_SOURCES_FIXED_SSE4_1:.c=.lo)
+$(SSE4_1_OBJ) $(OPT_UNIT_TEST_OBJ): CFLAGS += $(OPUS_X86_SSE4_1_CFLAGS)
+endif
+
+if HAVE_ARM_NEON_INTR
+ARM_NEON_INTR_OBJ = $(CELT_SOURCES_ARM_NEON_INTR:.c=.lo) $(SILK_SOURCES_ARM_NEON_INTR:.c=.lo)
+$(ARM_NEON_INTR_OBJ) $(OPT_UNIT_TEST_OBJ): CFLAGS += \
+ $(OPUS_ARM_NEON_INTR_CFLAGS)  $(NE10_CFLAGS)
+endif
diff --git a/third_party/opus/src/Makefile.mips b/third_party/opus/src/Makefile.mips
new file mode 100644
index 0000000..56a5062
--- /dev/null
+++ b/third_party/opus/src/Makefile.mips
@@ -0,0 +1,161 @@
+#################### COMPILE OPTIONS #######################
+
+# Uncomment this for fixed-point build
+FIXED_POINT=1
+
+# It is strongly recommended to uncomment one of these
+# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation
+# USE_ALLOCA: Use alloca() for stack allocation
+# If none is defined, then the fallback is a non-threadsafe global array
+CFLAGS := -DUSE_ALLOCA $(CFLAGS)
+#CFLAGS := -DVAR_ARRAYS $(CFLAGS)
+
+# These options affect performance
+# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion
+#CFLAGS := -DHAVE_LRINTF $(CFLAGS)
+
+###################### END OF OPTIONS ######################
+
+-include package_version
+
+include silk_sources.mk
+include celt_sources.mk
+include opus_sources.mk
+
+ifdef FIXED_POINT
+SILK_SOURCES += $(SILK_SOURCES_FIXED)
+else
+SILK_SOURCES += $(SILK_SOURCES_FLOAT)
+OPUS_SOURCES += $(OPUS_SOURCES_FLOAT)
+endif
+
+EXESUFFIX =
+LIBPREFIX = lib
+LIBSUFFIX = .a
+OBJSUFFIX = .o
+
+CC     = $(TOOLCHAIN_PREFIX)cc$(TOOLCHAIN_SUFFIX)
+AR     = $(TOOLCHAIN_PREFIX)ar
+RANLIB = $(TOOLCHAIN_PREFIX)ranlib
+CP     = $(TOOLCHAIN_PREFIX)cp
+
+cppflags-from-defines   = $(addprefix -D,$(1))
+cppflags-from-includes  = $(addprefix -I,$(1))
+ldflags-from-ldlibdirs  = $(addprefix -L,$(1))
+ldlibs-from-libs        = $(addprefix -l,$(1))
+
+WARNINGS = -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow
+
+CFLAGS  += -mips32r2 -mno-mips16 -std=gnu99 -O2 -g $(WARNINGS) -DENABLE_ASSERTIONS -DMIPSr1_ASM -DOPUS_BUILD -mdspr2 -march=74kc -mtune=74kc -mmt -mgp32
+
+CINCLUDES = include silk celt
+
+ifdef FIXED_POINT
+CFLAGS += -DFIXED_POINT=1 -DDISABLE_FLOAT_API
+CINCLUDES += silk/fixed
+else
+CINCLUDES += silk/float
+endif
+
+
+LIBS = m
+
+LDLIBDIRS = ./
+
+CFLAGS  += $(call cppflags-from-defines,$(CDEFINES))
+CFLAGS  += $(call cppflags-from-includes,$(CINCLUDES))
+LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS))
+LDLIBS  += $(call ldlibs-from-libs,$(LIBS))
+
+COMPILE.c.cmdline   = $(CC) -c $(CFLAGS) -o $@ $<
+LINK.o              = $(CC) $(LDPREFLAGS) $(LDFLAGS)
+LINK.o.cmdline      = $(LINK.o) $^ $(LDLIBS) -o $@$(EXESUFFIX)
+
+ARCHIVE.cmdline     = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@
+
+%$(OBJSUFFIX):%.c
+	$(COMPILE.c.cmdline)
+
+%$(OBJSUFFIX):%.cpp
+	$(COMPILE.cpp.cmdline)
+
+# Directives
+
+
+# Variable definitions
+LIB_NAME = opus
+TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX)
+
+SRCS_C = $(SILK_SOURCES) $(CELT_SOURCES) $(OPUS_SOURCES)
+
+OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C))
+
+OPUSDEMO_SRCS_C = src/opus_demo.c
+OPUSDEMO_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSDEMO_SRCS_C))
+
+TESTOPUSAPI_SRCS_C = tests/test_opus_api.c
+TESTOPUSAPI_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSAPI_SRCS_C))
+
+TESTOPUSDECODE_SRCS_C = tests/test_opus_decode.c
+TESTOPUSDECODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSDECODE_SRCS_C))
+
+TESTOPUSENCODE_SRCS_C = tests/test_opus_encode.c
+TESTOPUSENCODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSENCODE_SRCS_C))
+
+TESTOPUSPADDING_SRCS_C = tests/test_opus_padding.c
+TESTOPUSPADDING_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSPADDING_SRCS_C))
+
+OPUSCOMPARE_SRCS_C = src/opus_compare.c
+OPUSCOMPARE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSCOMPARE_SRCS_C))
+
+TESTS := test_opus_api test_opus_decode test_opus_encode test_opus_padding
+
+# Rules
+all: lib opus_demo opus_compare $(TESTS)
+
+lib: $(TARGET)
+
+check: all
+	for test in $(TESTS); do ./$$test; done
+
+$(TARGET): $(OBJS)
+	$(ARCHIVE.cmdline)
+
+opus_demo$(EXESUFFIX): $(OPUSDEMO_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+test_opus_api$(EXESUFFIX): $(TESTOPUSAPI_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+test_opus_decode$(EXESUFFIX): $(TESTOPUSDECODE_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+test_opus_encode$(EXESUFFIX): $(TESTOPUSENCODE_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+test_opus_padding$(EXESUFFIX): $(TESTOPUSPADDING_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+opus_compare$(EXESUFFIX): $(OPUSCOMPARE_OBJS)
+	$(LINK.o.cmdline)
+
+celt/celt.o: CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)'
+celt/celt.o: package_version
+
+package_version: force
+	@if [ -x ./update_version ]; then \
+		./update_version || true; \
+	elif [ ! -e ./package_version ]; then \
+		echo 'PACKAGE_VERSION="unknown"' > ./package_version; \
+	fi
+
+force:
+
+clean:
+	rm -f opus_demo$(EXESUFFIX) opus_compare$(EXESUFFIX) $(TARGET) \
+                test_opus_api$(EXESUFFIX) test_opus_decode$(EXESUFFIX) \
+                test_opus_encode$(EXESUFFIX) test_opus_padding$(EXESUFFIX) \
+		$(OBJS) $(OPUSDEMO_OBJS) $(OPUSCOMPARE_OBJS) $(TESTOPUSAPI_OBJS) \
+                $(TESTOPUSDECODE_OBJS) $(TESTOPUSENCODE_OBJS) $(TESTOPUSPADDING_OBJS)
+
+.PHONY: all lib clean force check
diff --git a/third_party/opus/src/Makefile.unix b/third_party/opus/src/Makefile.unix
new file mode 100644
index 0000000..b13230e
--- /dev/null
+++ b/third_party/opus/src/Makefile.unix
@@ -0,0 +1,159 @@
+#################### COMPILE OPTIONS #######################
+
+# Uncomment this for fixed-point build
+#FIXED_POINT=1
+
+# It is strongly recommended to uncomment one of these
+# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation
+# USE_ALLOCA: Use alloca() for stack allocation
+# If none is defined, then the fallback is a non-threadsafe global array
+CFLAGS := -DUSE_ALLOCA $(CFLAGS)
+#CFLAGS := -DVAR_ARRAYS $(CFLAGS)
+
+# These options affect performance
+# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion
+#CFLAGS := -DHAVE_LRINTF $(CFLAGS)
+
+###################### END OF OPTIONS ######################
+
+-include package_version
+
+include silk_sources.mk
+include celt_sources.mk
+include opus_sources.mk
+
+ifdef FIXED_POINT
+SILK_SOURCES += $(SILK_SOURCES_FIXED)
+else
+SILK_SOURCES += $(SILK_SOURCES_FLOAT)
+OPUS_SOURCES += $(OPUS_SOURCES_FLOAT)
+endif
+
+EXESUFFIX =
+LIBPREFIX = lib
+LIBSUFFIX = .a
+OBJSUFFIX = .o
+
+CC     = $(TOOLCHAIN_PREFIX)cc$(TOOLCHAIN_SUFFIX)
+AR     = $(TOOLCHAIN_PREFIX)ar
+RANLIB = $(TOOLCHAIN_PREFIX)ranlib
+CP     = $(TOOLCHAIN_PREFIX)cp
+
+cppflags-from-defines   = $(addprefix -D,$(1))
+cppflags-from-includes  = $(addprefix -I,$(1))
+ldflags-from-ldlibdirs  = $(addprefix -L,$(1))
+ldlibs-from-libs        = $(addprefix -l,$(1))
+
+WARNINGS = -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow
+CFLAGS  += -O2 -g $(WARNINGS) -DOPUS_BUILD
+CINCLUDES = include silk celt
+
+ifdef FIXED_POINT
+CFLAGS += -DFIXED_POINT=1 -DDISABLE_FLOAT_API
+CINCLUDES += silk/fixed
+else
+CINCLUDES += silk/float
+endif
+
+
+LIBS = m
+
+LDLIBDIRS = ./
+
+CFLAGS  += $(call cppflags-from-defines,$(CDEFINES))
+CFLAGS  += $(call cppflags-from-includes,$(CINCLUDES))
+LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS))
+LDLIBS  += $(call ldlibs-from-libs,$(LIBS))
+
+COMPILE.c.cmdline   = $(CC) -c $(CFLAGS) -o $@ $<
+LINK.o              = $(CC) $(LDPREFLAGS) $(LDFLAGS)
+LINK.o.cmdline      = $(LINK.o) $^ $(LDLIBS) -o $@$(EXESUFFIX)
+
+ARCHIVE.cmdline     = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@
+
+%$(OBJSUFFIX):%.c
+	$(COMPILE.c.cmdline)
+
+%$(OBJSUFFIX):%.cpp
+	$(COMPILE.cpp.cmdline)
+
+# Directives
+
+
+# Variable definitions
+LIB_NAME = opus
+TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX)
+
+SRCS_C = $(SILK_SOURCES) $(CELT_SOURCES) $(OPUS_SOURCES)
+
+OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C))
+
+OPUSDEMO_SRCS_C = src/opus_demo.c
+OPUSDEMO_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSDEMO_SRCS_C))
+
+TESTOPUSAPI_SRCS_C = tests/test_opus_api.c
+TESTOPUSAPI_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSAPI_SRCS_C))
+
+TESTOPUSDECODE_SRCS_C = tests/test_opus_decode.c
+TESTOPUSDECODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSDECODE_SRCS_C))
+
+TESTOPUSENCODE_SRCS_C = tests/test_opus_encode.c
+TESTOPUSENCODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSENCODE_SRCS_C))
+
+TESTOPUSPADDING_SRCS_C = tests/test_opus_padding.c
+TESTOPUSPADDING_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSPADDING_SRCS_C))
+
+OPUSCOMPARE_SRCS_C = src/opus_compare.c
+OPUSCOMPARE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSCOMPARE_SRCS_C))
+
+TESTS := test_opus_api test_opus_decode test_opus_encode test_opus_padding
+
+# Rules
+all: lib opus_demo opus_compare $(TESTS)
+
+lib: $(TARGET)
+
+check: all
+	for test in $(TESTS); do ./$$test; done
+
+$(TARGET): $(OBJS)
+	$(ARCHIVE.cmdline)
+
+opus_demo$(EXESUFFIX): $(OPUSDEMO_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+test_opus_api$(EXESUFFIX): $(TESTOPUSAPI_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+test_opus_decode$(EXESUFFIX): $(TESTOPUSDECODE_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+test_opus_encode$(EXESUFFIX): $(TESTOPUSENCODE_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+test_opus_padding$(EXESUFFIX): $(TESTOPUSPADDING_OBJS) $(TARGET)
+	$(LINK.o.cmdline)
+
+opus_compare$(EXESUFFIX): $(OPUSCOMPARE_OBJS)
+	$(LINK.o.cmdline)
+
+celt/celt.o: CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)'
+celt/celt.o: package_version
+
+package_version: force
+	@if [ -x ./update_version ]; then \
+		./update_version || true; \
+	elif [ ! -e ./package_version ]; then \
+		echo 'PACKAGE_VERSION="unknown"' > ./package_version; \
+	fi
+
+force:
+
+clean:
+	rm -f opus_demo$(EXESUFFIX) opus_compare$(EXESUFFIX) $(TARGET) \
+                test_opus_api$(EXESUFFIX) test_opus_decode$(EXESUFFIX) \
+                test_opus_encode$(EXESUFFIX) test_opus_padding$(EXESUFFIX) \
+		$(OBJS) $(OPUSDEMO_OBJS) $(OPUSCOMPARE_OBJS) $(TESTOPUSAPI_OBJS) \
+                $(TESTOPUSDECODE_OBJS) $(TESTOPUSENCODE_OBJS) $(TESTOPUSPADDING_OBJS)
+
+.PHONY: all lib clean force check
diff --git a/third_party/opus/src/NEWS b/third_party/opus/src/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/opus/src/NEWS
diff --git a/third_party/opus/src/README b/third_party/opus/src/README
new file mode 100644
index 0000000..ac6264ec
--- /dev/null
+++ b/third_party/opus/src/README
@@ -0,0 +1,142 @@
+== Opus audio codec ==
+
+Opus is a codec for interactive speech and audio transmission over the Internet.
+
+  Opus can handle a wide range of interactive audio applications, including
+Voice over IP, videoconferencing, in-game  chat, and even remote live music
+performances. It can scale from low bit-rate narrowband speech to very high
+quality stereo music.
+
+  Opus, when coupled with an appropriate container format, is also suitable
+for non-realtime  stored-file applications such as music distribution, game
+soundtracks, portable music players, jukeboxes, and other applications that
+have historically used high latency formats such as MP3, AAC, or Vorbis.
+
+                    Opus is specified by IETF RFC 6716:
+                    https://tools.ietf.org/html/rfc6716
+
+  The Opus format and this implementation of it are subject to the royalty-
+free patent and copyright licenses specified in the file COPYING.
+
+This package implements a shared library for encoding and decoding raw Opus
+bitstreams. Raw Opus bitstreams should be used over RTP according to
+ https://tools.ietf.org/html/rfc7587
+
+The package also includes a number of test  tools used for testing the
+correct operation of the library. The bitstreams read/written by these
+tools should not be used for Opus file distribution: They include
+additional debugging data and cannot support seeking.
+
+Opus stored in files should use the Ogg encapsulation for Opus which is
+described at:
+ https://wiki.xiph.org/OggOpus
+
+An opus-tools package is available which provides encoding and decoding of
+Ogg encapsulated Opus files and includes a number of useful features.
+
+Opus-tools can be found at:
+ https://git.xiph.org/?p=opus-tools.git
+or on the main Opus website:
+ https://opus-codec.org/
+
+== Compiling libopus ==
+
+To build from a distribution tarball, you only need to do the following:
+
+% ./configure
+% make
+
+To build from the git repository, the following steps are necessary:
+
+1) Clone the repository:
+
+% git clone https://git.xiph.org/opus.git
+% cd opus
+
+2) Compiling the source
+
+% ./autogen.sh
+% ./configure
+% make
+
+3) Install the codec libraries (optional)
+
+% sudo make install
+
+Once you have compiled the codec, there will be a opus_demo executable
+in the top directory.
+
+Usage: opus_demo [-e] <application> <sampling rate (Hz)> <channels (1/2)>
+         <bits per second> [options] <input> <output>
+       opus_demo -d <sampling rate (Hz)> <channels (1/2)> [options]
+         <input> <output>
+
+mode: voip | audio | restricted-lowdelay
+options:
+  -e                : only runs the encoder (output the bit-stream)
+  -d                : only runs the decoder (reads the bit-stream as input)
+  -cbr              : enable constant bitrate; default: variable bitrate
+  -cvbr             : enable constrained variable bitrate; default:
+                      unconstrained
+  -bandwidth <NB|MB|WB|SWB|FB>
+                    : audio bandwidth (from narrowband to fullband);
+                      default: sampling rate
+  -framesize <2.5|5|10|20|40|60>
+                    : frame size in ms; default: 20
+  -max_payload <bytes>
+                    : maximum payload size in bytes, default: 1024
+  -complexity <comp>
+                    : complexity, 0 (lowest) ... 10 (highest); default: 10
+  -inbandfec        : enable SILK inband FEC
+  -forcemono        : force mono encoding, even for stereo input
+  -dtx              : enable SILK DTX
+  -loss <perc>      : simulate packet loss, in percent (0-100); default: 0
+
+input and output are little-endian signed 16-bit PCM files or opus
+bitstreams with simple opus_demo proprietary framing.
+
+== Testing ==
+
+This package includes a collection of automated unit and system tests
+which SHOULD be run after compiling the package especially the first
+time it is run on a new platform.
+
+To run the integrated tests:
+% make check
+
+There is also collection of standard test vectors which are not
+included in this package for size reasons but can be obtained from:
+https://opus-codec.org/testvectors/opus_testvectors.tar.gz
+
+To run compare the code to these test vectors:
+
+% curl -O https://opus-codec.org/testvectors/opus_testvectors.tar.gz
+% tar -zxf opus_testvectors.tar.gz
+% ./tests/run_vectors.sh ./ opus_testvectors 48000
+
+== Portability notes ==
+
+This implementation uses floating-point by default but can be compiled to
+use only fixed-point arithmetic by setting --enable-fixed-point (if using
+autoconf) or by defining the FIXED_POINT macro (if building manually).
+The fixed point implementation has somewhat lower audio quality and is
+slower on platforms with fast FPUs, it is normally only used in embedded
+environments.
+
+The implementation can be compiled with either a C89 or a C99 compiler.
+While it does not rely on any _undefined behavior_ as defined by C89 or
+C99, it relies on common _implementation-defined behavior_ for two's
+complement architectures:
+
+o Right shifts of negative values are consistent with two's
+  complement arithmetic, so that a>>b is equivalent to
+  floor(a/(2^b)),
+
+o For conversion to a signed integer of N bits, the value is reduced
+  modulo 2^N to be within range of the type,
+
+o The result of integer division of a negative value is truncated
+  towards zero, and
+
+o The compiler provides a 64-bit integer type (a C99 requirement
+  which is supported by most C89 compilers).
diff --git a/third_party/opus/src/celt/_kiss_fft_guts.h b/third_party/opus/src/celt/_kiss_fft_guts.h
new file mode 100644
index 0000000..5e3d58f
--- /dev/null
+++ b/third_party/opus/src/celt/_kiss_fft_guts.h
@@ -0,0 +1,182 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+       this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_GUTS_H
+#define KISS_FFT_GUTS_H
+
+#define MIN(a,b) ((a)<(b) ? (a):(b))
+#define MAX(a,b) ((a)>(b) ? (a):(b))
+
+/* kiss_fft.h
+   defines kiss_fft_scalar as either short or a float type
+   and defines
+   typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
+#include "kiss_fft.h"
+
+/*
+  Explanation of macros dealing with complex math:
+
+   C_MUL(m,a,b)         : m = a*b
+   C_FIXDIV( c , div )  : if a fixed point impl., c /= div. noop otherwise
+   C_SUB( res, a,b)     : res = a - b
+   C_SUBFROM( res , a)  : res -= a
+   C_ADDTO( res , a)    : res += a
+ * */
+#ifdef FIXED_POINT
+#include "arch.h"
+
+
+#define SAMP_MAX 2147483647
+#define TWID_MAX 32767
+#define TRIG_UPSCALE 1
+
+#define SAMP_MIN -SAMP_MAX
+
+
+#   define S_MUL(a,b) MULT16_32_Q15(b, a)
+
+#   define C_MUL(m,a,b) \
+      do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
+          (m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
+
+#   define C_MULC(m,a,b) \
+      do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
+          (m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
+
+#   define C_MULBYSCALAR( c, s ) \
+      do{ (c).r =  S_MUL( (c).r , s ) ;\
+          (c).i =  S_MUL( (c).i , s ) ; }while(0)
+
+#   define DIVSCALAR(x,k) \
+        (x) = S_MUL(  x, (TWID_MAX-((k)>>1))/(k)+1 )
+
+#   define C_FIXDIV(c,div) \
+        do {    DIVSCALAR( (c).r , div);  \
+                DIVSCALAR( (c).i  , div); }while (0)
+
+#define  C_ADD( res, a,b)\
+    do {(res).r=ADD32((a).r,(b).r);  (res).i=ADD32((a).i,(b).i); \
+    }while(0)
+#define  C_SUB( res, a,b)\
+    do {(res).r=SUB32((a).r,(b).r);  (res).i=SUB32((a).i,(b).i); \
+    }while(0)
+#define C_ADDTO( res , a)\
+    do {(res).r = ADD32((res).r, (a).r);  (res).i = ADD32((res).i,(a).i);\
+    }while(0)
+
+#define C_SUBFROM( res , a)\
+    do {(res).r = ADD32((res).r,(a).r);  (res).i = SUB32((res).i,(a).i); \
+    }while(0)
+
+#if defined(OPUS_ARM_INLINE_ASM)
+#include "arm/kiss_fft_armv4.h"
+#endif
+
+#if defined(OPUS_ARM_INLINE_EDSP)
+#include "arm/kiss_fft_armv5e.h"
+#endif
+#if defined(MIPSr1_ASM)
+#include "mips/kiss_fft_mipsr1.h"
+#endif
+
+#else  /* not FIXED_POINT*/
+
+#   define S_MUL(a,b) ( (a)*(b) )
+#define C_MUL(m,a,b) \
+    do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
+        (m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
+#define C_MULC(m,a,b) \
+    do{ (m).r = (a).r*(b).r + (a).i*(b).i;\
+        (m).i = (a).i*(b).r - (a).r*(b).i; }while(0)
+
+#define C_MUL4(m,a,b) C_MUL(m,a,b)
+
+#   define C_FIXDIV(c,div) /* NOOP */
+#   define C_MULBYSCALAR( c, s ) \
+    do{ (c).r *= (s);\
+        (c).i *= (s); }while(0)
+#endif
+
+#ifndef CHECK_OVERFLOW_OP
+#  define CHECK_OVERFLOW_OP(a,op,b) /* noop */
+#endif
+
+#ifndef C_ADD
+#define  C_ADD( res, a,b)\
+    do { \
+            CHECK_OVERFLOW_OP((a).r,+,(b).r)\
+            CHECK_OVERFLOW_OP((a).i,+,(b).i)\
+            (res).r=(a).r+(b).r;  (res).i=(a).i+(b).i; \
+    }while(0)
+#define  C_SUB( res, a,b)\
+    do { \
+            CHECK_OVERFLOW_OP((a).r,-,(b).r)\
+            CHECK_OVERFLOW_OP((a).i,-,(b).i)\
+            (res).r=(a).r-(b).r;  (res).i=(a).i-(b).i; \
+    }while(0)
+#define C_ADDTO( res , a)\
+    do { \
+            CHECK_OVERFLOW_OP((res).r,+,(a).r)\
+            CHECK_OVERFLOW_OP((res).i,+,(a).i)\
+            (res).r += (a).r;  (res).i += (a).i;\
+    }while(0)
+
+#define C_SUBFROM( res , a)\
+    do {\
+            CHECK_OVERFLOW_OP((res).r,-,(a).r)\
+            CHECK_OVERFLOW_OP((res).i,-,(a).i)\
+            (res).r -= (a).r;  (res).i -= (a).i; \
+    }while(0)
+#endif /* C_ADD defined */
+
+#ifdef FIXED_POINT
+/*#  define KISS_FFT_COS(phase)  TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase))))
+#  define KISS_FFT_SIN(phase)  TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/
+#  define KISS_FFT_COS(phase)  floor(.5+TWID_MAX*cos (phase))
+#  define KISS_FFT_SIN(phase)  floor(.5+TWID_MAX*sin (phase))
+#  define HALF_OF(x) ((x)>>1)
+#elif defined(USE_SIMD)
+#  define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
+#  define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
+#  define HALF_OF(x) ((x)*_mm_set1_ps(.5f))
+#else
+#  define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
+#  define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
+#  define HALF_OF(x) ((x)*.5f)
+#endif
+
+#define  kf_cexp(x,phase) \
+        do{ \
+                (x)->r = KISS_FFT_COS(phase);\
+                (x)->i = KISS_FFT_SIN(phase);\
+        }while(0)
+
+#define  kf_cexp2(x,phase) \
+   do{ \
+      (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\
+      (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\
+}while(0)
+
+#endif /* KISS_FFT_GUTS_H */
diff --git a/third_party/opus/src/celt/arch.h b/third_party/opus/src/celt/arch.h
new file mode 100644
index 0000000..8ceab5fe
--- /dev/null
+++ b/third_party/opus/src/celt/arch.h
@@ -0,0 +1,252 @@
+/* Copyright (c) 2003-2008 Jean-Marc Valin
+   Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/**
+   @file arch.h
+   @brief Various architecture definitions for CELT
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+# if !defined(__GNUC_PREREQ)
+#  if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+#   define __GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+#  else
+#   define __GNUC_PREREQ(_maj,_min) 0
+#  endif
+# endif
+
+#define CELT_SIG_SCALE 32768.f
+
+#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__);
+#ifdef ENABLE_ASSERTIONS
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __GNUC__
+__attribute__((noreturn))
+#endif
+static OPUS_INLINE void _celt_fatal(const char *str, const char *file, int line)
+{
+   fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
+   abort();
+}
+#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}}
+#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}}
+#else
+#define celt_assert(cond)
+#define celt_assert2(cond, message)
+#endif
+
+#define IMUL32(a,b) ((a)*(b))
+
+#define MIN16(a,b) ((a) < (b) ? (a) : (b))   /**< Minimum 16-bit value.   */
+#define MAX16(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum 16-bit value.   */
+#define MIN32(a,b) ((a) < (b) ? (a) : (b))   /**< Minimum 32-bit value.   */
+#define MAX32(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum 32-bit value.   */
+#define IMIN(a,b) ((a) < (b) ? (a) : (b))   /**< Minimum int value.   */
+#define IMAX(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum int value.   */
+#define UADD32(a,b) ((a)+(b))
+#define USUB32(a,b) ((a)-(b))
+
+/* Set this if opus_int64 is a native type of the CPU. */
+/* Assume that all LP64 architectures have fast 64-bit types; also x86_64
+   (which can be ILP32 for x32) and Win64 (which is LLP64). */
+#if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64)
+#define OPUS_FAST_INT64 1
+#else
+#define OPUS_FAST_INT64 0
+#endif
+
+#define PRINT_MIPS(file)
+
+#ifdef FIXED_POINT
+
+typedef opus_int16 opus_val16;
+typedef opus_int32 opus_val32;
+
+typedef opus_val32 celt_sig;
+typedef opus_val16 celt_norm;
+typedef opus_val32 celt_ener;
+
+#define Q15ONE 32767
+
+#define SIG_SHIFT 12
+
+#define NORM_SCALING 16384
+
+#define DB_SHIFT 10
+
+#define EPSILON 1
+#define VERY_SMALL 0
+#define VERY_LARGE16 ((opus_val16)32767)
+#define Q15_ONE ((opus_val16)32767)
+
+#define SCALEIN(a)      (a)
+#define SCALEOUT(a)     (a)
+
+#define ABS16(x) ((x) < 0 ? (-(x)) : (x))
+#define ABS32(x) ((x) < 0 ? (-(x)) : (x))
+
+static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
+   return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
+}
+
+#ifdef FIXED_DEBUG
+#include "fixed_debug.h"
+#else
+
+#include "fixed_generic.h"
+
+#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR
+#include "arm/fixed_arm64.h"
+#elif OPUS_ARM_INLINE_EDSP
+#include "arm/fixed_armv5e.h"
+#elif defined (OPUS_ARM_INLINE_ASM)
+#include "arm/fixed_armv4.h"
+#elif defined (BFIN_ASM)
+#include "fixed_bfin.h"
+#elif defined (TI_C5X_ASM)
+#include "fixed_c5x.h"
+#elif defined (TI_C6X_ASM)
+#include "fixed_c6x.h"
+#endif
+
+#endif
+
+#else /* FIXED_POINT */
+
+typedef float opus_val16;
+typedef float opus_val32;
+
+typedef float celt_sig;
+typedef float celt_norm;
+typedef float celt_ener;
+
+#ifdef FLOAT_APPROX
+/* This code should reliably detect NaN/inf even when -ffast-math is used.
+   Assumes IEEE 754 format. */
+static OPUS_INLINE int celt_isnan(float x)
+{
+   union {float f; opus_uint32 i;} in;
+   in.f = x;
+   return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0;
+}
+#else
+#ifdef __FAST_MATH__
+#error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input
+#endif
+#define celt_isnan(x) ((x)!=(x))
+#endif
+
+#define Q15ONE 1.0f
+
+#define NORM_SCALING 1.f
+
+#define EPSILON 1e-15f
+#define VERY_SMALL 1e-30f
+#define VERY_LARGE16 1e15f
+#define Q15_ONE ((opus_val16)1.f)
+
+/* This appears to be the same speed as C99's fabsf() but it's more portable. */
+#define ABS16(x) ((float)fabs(x))
+#define ABS32(x) ((float)fabs(x))
+
+#define QCONST16(x,bits) (x)
+#define QCONST32(x,bits) (x)
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) (x)
+#define EXTEND32(x) (x)
+#define SHR16(a,shift) (a)
+#define SHL16(a,shift) (a)
+#define SHR32(a,shift) (a)
+#define SHL32(a,shift) (a)
+#define PSHR32(a,shift) (a)
+#define VSHR32(a,shift) (a)
+
+#define PSHR(a,shift)   (a)
+#define SHR(a,shift)    (a)
+#define SHL(a,shift)    (a)
+#define SATURATE(x,a)   (x)
+#define SATURATE16(x)   (x)
+
+#define ROUND16(a,shift)  (a)
+#define HALF16(x)       (.5f*(x))
+#define HALF32(x)       (.5f*(x))
+
+#define ADD16(a,b) ((a)+(b))
+#define SUB16(a,b) ((a)-(b))
+#define ADD32(a,b) ((a)+(b))
+#define SUB32(a,b) ((a)-(b))
+#define MULT16_16_16(a,b)     ((a)*(b))
+#define MULT16_16(a,b)     ((opus_val32)(a)*(opus_val32)(b))
+#define MAC16_16(c,a,b)     ((c)+(opus_val32)(a)*(opus_val32)(b))
+
+#define MULT16_32_Q15(a,b)     ((a)*(b))
+#define MULT16_32_Q16(a,b)     ((a)*(b))
+
+#define MULT32_32_Q31(a,b)     ((a)*(b))
+
+#define MAC16_32_Q15(c,a,b)     ((c)+(a)*(b))
+#define MAC16_32_Q16(c,a,b)     ((c)+(a)*(b))
+
+#define MULT16_16_Q11_32(a,b)     ((a)*(b))
+#define MULT16_16_Q11(a,b)     ((a)*(b))
+#define MULT16_16_Q13(a,b)     ((a)*(b))
+#define MULT16_16_Q14(a,b)     ((a)*(b))
+#define MULT16_16_Q15(a,b)     ((a)*(b))
+#define MULT16_16_P15(a,b)     ((a)*(b))
+#define MULT16_16_P13(a,b)     ((a)*(b))
+#define MULT16_16_P14(a,b)     ((a)*(b))
+#define MULT16_32_P16(a,b)     ((a)*(b))
+
+#define DIV32_16(a,b)     (((opus_val32)(a))/(opus_val16)(b))
+#define DIV32(a,b)     (((opus_val32)(a))/(opus_val32)(b))
+
+#define SCALEIN(a)      ((a)*CELT_SIG_SCALE)
+#define SCALEOUT(a)     ((a)*(1/CELT_SIG_SCALE))
+
+#define SIG2WORD16(x) (x)
+
+#endif /* !FIXED_POINT */
+
+#ifndef GLOBAL_STACK_SIZE
+#ifdef FIXED_POINT
+#define GLOBAL_STACK_SIZE 100000
+#else
+#define GLOBAL_STACK_SIZE 100000
+#endif
+#endif
+
+#endif /* ARCH_H */
diff --git a/third_party/opus/src/celt/arm/arm2gnu.pl b/third_party/opus/src/celt/arm/arm2gnu.pl
new file mode 100755
index 0000000..6c922ac8
--- /dev/null
+++ b/third_party/opus/src/celt/arm/arm2gnu.pl
@@ -0,0 +1,353 @@
+#!/usr/bin/perl
+# Copyright (C) 2002-2013 Xiph.org Foundation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+my $bigend;  # little/big endian
+my $nxstack;
+my $apple = 0;
+my $symprefix = "";
+
+$nxstack = 0;
+
+eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
+    if $running_under_some_shell;
+
+while ($ARGV[0] =~ /^-/) {
+    $_ = shift;
+  last if /^--$/;
+    if (/^-n$/) {
+    $nflag++;
+    next;
+    }
+    if (/^--apple$/) {
+        $apple = 1;
+        $symprefix = "_";
+        next;
+    }
+    die "I don't recognize this switch: $_\\n";
+}
+$printit++ unless $nflag;
+
+$\ = "\n";      # automatically add newline on print
+$n=0;
+
+$thumb = 0;     # ARM mode by default, not Thumb.
+@proc_stack = ();
+
+printf ("    .syntax unified\n");
+
+LINE:
+while (<>) {
+
+    # For ADRLs we need to add a new line after the substituted one.
+    $addPadding = 0;
+
+    # First, we do not dare to touch *anything* inside double quotes, do we?
+    # Second, if you want a dollar character in the string,
+    # insert two of them -- that's how ARM C and assembler treat strings.
+    s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1:   .ascii \"/   && do { s/\$\$/\$/g; next };
+    s/\bDCB\b[ \t]*\"/.ascii \"/                          && do { s/\$\$/\$/g; next };
+    s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/                    && do { s/\$\$/\$/g; next };
+    # If there's nothing on a line but a comment, don't try to apply any further
+    #  substitutions (this is a cheap hack to avoid mucking up the license header)
+    s/^([ \t]*);/$1@/                                     && do { s/\$\$/\$/g; next };
+    # If substituted -- leave immediately !
+
+    s/@/,:/;
+    s/;/@/;
+    while ( /@.*'/ ) {
+      s/(@.*)'/$1/g;
+    }
+    s/\{FALSE\}/0/g;
+    s/\{TRUE\}/1/g;
+    s/\{(\w\w\w\w+)\}/$1/g;
+    s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/;
+    s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/;
+    s/\bIMPORT\b/.extern/;
+    s/\bEXPORT\b\s*/.global $symprefix/;
+    s/^(\s+)\[/$1IF/;
+    s/^(\s+)\|/$1ELSE/;
+    s/^(\s+)\]/$1ENDIF/;
+    s/IF *:DEF:/ .ifdef/;
+    s/IF *:LNOT: *:DEF:/ .ifndef/;
+    s/ELSE/ .else/;
+    s/ENDIF/ .endif/;
+
+    if( /\bIF\b/ ) {
+      s/\bIF\b/ .if/;
+      s/=/==/;
+    }
+    if ( $n == 2) {
+        s/\$/\\/g;
+    }
+    if ($n == 1) {
+        s/\$//g;
+        s/label//g;
+    $n = 2;
+      }
+    if ( /MACRO/ ) {
+      s/MACRO *\n/.macro/;
+      $n=1;
+    }
+    if ( /\bMEND\b/ ) {
+      s/\bMEND\b/.endm/;
+      $n=0;
+    }
+
+    # ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there.
+    #
+    if ( /\bAREA\b/ ) {
+        my $align;
+        $align = "2";
+        if ( /ALIGN=(\d+)/ ) {
+            $align = $1;
+        }
+        if ( /CODE/ ) {
+            $nxstack = 1;
+        }
+        s/^(.+)CODE(.+)READONLY(.*)/    .text/;
+        s/^(.+)DATA(.+)READONLY(.*)/    .section .rdata/;
+        s/^(.+)\|\|\.data\|\|(.+)/    .data/;
+        s/^(.+)\|\|\.bss\|\|(.+)/    .bss/;
+        s/$/;   .p2align $align/;
+        # Enable NEON instructions but don't produce a binary that requires
+        # ARMv7. RVCT does not have equivalent directives, so we just do this
+        # for all CODE areas.
+        if ( /.text/ ) {
+            # Separating .arch, .fpu, etc., by semicolons does not work (gas
+            # thinks the semicolon is part of the arch name, even when there's
+            # whitespace separating them). Sadly this means our line numbers
+            # won't match the original source file (we could use the .line
+            # directive, which is documented to be obsolete, but then gdb will
+            # show the wrong line in the translated source file).
+            s/$/;   .arch armv7-a\n   .fpu neon\n   .object_arch armv4t/ unless ($apple);
+        }
+    }
+
+    s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/;       # ||.constdata$3||
+    s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/;               # ||.bss$2||
+    s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/;             # ||.data$2||
+    s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/;
+    s/^(\s+)\%(\s)/    .space $1/;
+
+    s/\|(.+)\.(\d+)\|/\.$1_$2/;                     # |L80.123| -> .L80_123
+    s/\bCODE32\b/.code 32/ && do {$thumb = 0};
+    s/\bCODE16\b/.code 16/ && do {$thumb = 1};
+    if (/\bPROC\b/)
+    {
+        my $prefix;
+        my $proc;
+        /^([A-Za-z_\.]\w+)\b/;
+        $proc = $1;
+        $prefix = "";
+        if ($proc)
+        {
+            $prefix = $prefix.sprintf("\t.type\t%s, %%function; ",$proc) unless ($apple);
+            # Make sure we $prefix isn't empty here (for the $apple case).
+            # We handle mangling the label here, make sure it doesn't match
+            # the label handling below (if $prefix would be empty).
+            $prefix = "; ";
+            push(@proc_stack, $proc);
+            s/^[A-Za-z_\.]\w+/$symprefix$&:/;
+        }
+        $prefix = $prefix."\t.thumb_func; " if ($thumb);
+        s/\bPROC\b/@ $&/;
+        $_ = $prefix.$_;
+    }
+    s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/;
+    s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/;
+    if (/\bENDP\b/)
+    {
+        my $proc;
+        s/\bENDP\b/@ $&/;
+        $proc = pop(@proc_stack);
+        $_ = "\t.size $proc, .-$proc".$_ if ($proc && !$apple);
+    }
+    s/\bSUBT\b/@ $&/;
+    s/\bDATA\b/@ $&/;   # DATA directive is deprecated -- Asm guide, p.7-25
+    s/\bKEEP\b/@ $&/;
+    s/\bEXPORTAS\b/@ $&/;
+    s/\|\|(.)+\bEQU\b/@ $&/;
+    s/\|\|([\w\$]+)\|\|/$1/;
+    s/\bENTRY\b/@ $&/;
+    s/\bASSERT\b/@ $&/;
+    s/\bGBLL\b/@ $&/;
+    s/\bGBLA\b/@ $&/;
+    s/^\W+OPT\b/@ $&/;
+    s/:OR:/|/g;
+    s/:SHL:/<</g;
+    s/:SHR:/>>/g;
+    s/:AND:/&/g;
+    s/:LAND:/&&/g;
+    s/CPSR/cpsr/;
+    s/SPSR/spsr/;
+    s/ALIGN$/.balign 4/;
+    s/ALIGN\s+([0-9x]+)$/.balign $1/;
+    s/psr_cxsf/psr_all/;
+    s/LTORG/.ltorg/;
+    s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/;
+    s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/;
+    s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/;
+    s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/;
+
+    #  {PC} + 0xdeadfeed  -->  . + 0xdeadfeed
+    s/\{PC\} \+/ \. +/;
+
+    # Single hex constant on the line !
+    #
+    # >>> NOTE <<<
+    #   Double-precision floats in gcc are always mixed-endian, which means
+    #   bytes in two words are little-endian, but words are big-endian.
+    #   So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address
+    #   and 0xfeed0000 at high address.
+    #
+    s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/;
+    # Only decimal constants on the line, no hex !
+    s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/;
+
+    # Single hex constant on the line !
+#    s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/;
+    # Only decimal constants on the line, no hex !
+#    s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/;
+    s/\bDCFS[ \t]+0x/.word 0x/;
+    s/\bDCFS\b/.float/;
+
+    s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/;
+    s/\bDCD\b/.word/;
+    s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/;
+    s/\bDCW\b/.short/;
+    s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/;
+    s/\bDCB\b/.byte/;
+    s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/;
+    s/^[A-Za-z_\.]\w+/$&:/;
+    s/^(\d+)/$1:/;
+    s/\%(\d+)/$1b_or_f/;
+    s/\%[Bb](\d+)/$1b/;
+    s/\%[Ff](\d+)/$1f/;
+    s/\%[Ff][Tt](\d+)/$1f/;
+    s/&([\dA-Fa-f]+)/0x$1/;
+    if ( /\b2_[01]+\b/ ) {
+      s/\b2_([01]+)\b/conv$1&&&&/g;
+      while ( /[01][01][01][01]&&&&/ ) {
+        s/0000&&&&/&&&&0/g;
+        s/0001&&&&/&&&&1/g;
+        s/0010&&&&/&&&&2/g;
+        s/0011&&&&/&&&&3/g;
+        s/0100&&&&/&&&&4/g;
+        s/0101&&&&/&&&&5/g;
+        s/0110&&&&/&&&&6/g;
+        s/0111&&&&/&&&&7/g;
+        s/1000&&&&/&&&&8/g;
+        s/1001&&&&/&&&&9/g;
+        s/1010&&&&/&&&&A/g;
+        s/1011&&&&/&&&&B/g;
+        s/1100&&&&/&&&&C/g;
+        s/1101&&&&/&&&&D/g;
+        s/1110&&&&/&&&&E/g;
+        s/1111&&&&/&&&&F/g;
+      }
+      s/000&&&&/&&&&0/g;
+      s/001&&&&/&&&&1/g;
+      s/010&&&&/&&&&2/g;
+      s/011&&&&/&&&&3/g;
+      s/100&&&&/&&&&4/g;
+      s/101&&&&/&&&&5/g;
+      s/110&&&&/&&&&6/g;
+      s/111&&&&/&&&&7/g;
+      s/00&&&&/&&&&0/g;
+      s/01&&&&/&&&&1/g;
+      s/10&&&&/&&&&2/g;
+      s/11&&&&/&&&&3/g;
+      s/0&&&&/&&&&0/g;
+      s/1&&&&/&&&&1/g;
+      s/conv&&&&/0x/g;
+    }
+
+    if ( /commandline/)
+    {
+        if( /-bigend/)
+        {
+            $bigend=1;
+        }
+    }
+
+    if ( /\bDCDU\b/ )
+    {
+        my $cmd=$_;
+        my $value;
+        my $prefix;
+        my $w1;
+        my $w2;
+        my $w3;
+        my $w4;
+
+        s/\s+DCDU\b/@ $&/;
+
+        $cmd =~ /\bDCDU\b\s+0x(\d+)/;
+        $value = $1;
+        $value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
+        $w1 = $1;
+        $w2 = $2;
+        $w3 = $3;
+        $w4 = $4;
+
+        if( $bigend ne "")
+        {
+            # big endian
+            $prefix = "\t.byte\t0x".$w1.";".
+                      "\t.byte\t0x".$w2.";".
+                      "\t.byte\t0x".$w3.";".
+                      "\t.byte\t0x".$w4."; ";
+        }
+        else
+        {
+            # little endian
+            $prefix = "\t.byte\t0x".$w4.";".
+                      "\t.byte\t0x".$w3.";".
+                      "\t.byte\t0x".$w2.";".
+                      "\t.byte\t0x".$w1."; ";
+        }
+        $_=$prefix.$_;
+    }
+
+    if ( /\badrl\b/i )
+    {
+        s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i;
+        $addPadding = 1;
+    }
+    s/\bEND\b/@ END/;
+} continue {
+    printf ("%s", $_) if $printit;
+    if ($addPadding != 0)
+    {
+        printf ("   mov r0,r0\n");
+        $addPadding = 0;
+    }
+}
+#If we had a code section, mark that this object doesn't need an executable
+# stack.
+if ($nxstack && !$apple) {
+    printf ("    .section\t.note.GNU-stack,\"\",\%\%progbits\n");
+}
diff --git a/third_party/opus/src/celt/arm/arm_celt_map.c b/third_party/opus/src/celt/arm/arm_celt_map.c
new file mode 100644
index 0000000..4d4d069
--- /dev/null
+++ b/third_party/opus/src/celt/arm/arm_celt_map.c
@@ -0,0 +1,143 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pitch.h"
+#include "kiss_fft.h"
+#include "mdct.h"
+
+#if defined(OPUS_HAVE_RTCD)
+
+# if defined(FIXED_POINT)
+#  if ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \
+    (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \
+    (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP)))
+opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+    const opus_val16 *, opus_val32 *, int , int) = {
+  celt_pitch_xcorr_c,               /* ARMv4 */
+  MAY_HAVE_EDSP(celt_pitch_xcorr),  /* EDSP */
+  MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */
+  MAY_HAVE_NEON(celt_pitch_xcorr)   /* NEON */
+};
+
+#  endif
+# else /* !FIXED_POINT */
+#  if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)
+void (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+    const opus_val16 *, opus_val32 *, int, int) = {
+  celt_pitch_xcorr_c,              /* ARMv4 */
+  celt_pitch_xcorr_c,              /* EDSP */
+  celt_pitch_xcorr_c,              /* Media */
+  celt_pitch_xcorr_float_neon      /* Neon */
+};
+#  endif
+# endif /* FIXED_POINT */
+
+#if defined(FIXED_POINT) && defined(OPUS_HAVE_RTCD) && \
+ defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)
+
+void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+         const opus_val16 *x,
+         const opus_val16 *y,
+         opus_val32       sum[4],
+         int              len
+) = {
+  xcorr_kernel_c,                /* ARMv4 */
+  xcorr_kernel_c,                /* EDSP */
+  xcorr_kernel_c,                /* Media */
+  xcorr_kernel_neon_fixed,       /* Neon */
+};
+
+#endif
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+#  if defined(HAVE_ARM_NE10)
+#   if defined(CUSTOM_MODES)
+int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = {
+   opus_fft_alloc_arch_c,        /* ARMv4 */
+   opus_fft_alloc_arch_c,        /* EDSP */
+   opus_fft_alloc_arch_c,        /* Media */
+   opus_fft_alloc_arm_neon       /* Neon with NE10 library support */
+};
+
+void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = {
+   opus_fft_free_arch_c,         /* ARMv4 */
+   opus_fft_free_arch_c,         /* EDSP */
+   opus_fft_free_arch_c,         /* Media */
+   opus_fft_free_arm_neon        /* Neon with NE10 */
+};
+#   endif /* CUSTOM_MODES */
+
+void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
+                                        const kiss_fft_cpx *fin,
+                                        kiss_fft_cpx *fout) = {
+   opus_fft_c,                   /* ARMv4 */
+   opus_fft_c,                   /* EDSP */
+   opus_fft_c,                   /* Media */
+   opus_fft_neon                 /* Neon with NE10 */
+};
+
+void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
+                                         const kiss_fft_cpx *fin,
+                                         kiss_fft_cpx *fout) = {
+   opus_ifft_c,                   /* ARMv4 */
+   opus_ifft_c,                   /* EDSP */
+   opus_ifft_c,                   /* Media */
+   opus_ifft_neon                 /* Neon with NE10 */
+};
+
+void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l,
+                                                     kiss_fft_scalar *in,
+                                                     kiss_fft_scalar * OPUS_RESTRICT out,
+                                                     const opus_val16 *window,
+                                                     int overlap, int shift,
+                                                     int stride, int arch) = {
+   clt_mdct_forward_c,           /* ARMv4 */
+   clt_mdct_forward_c,           /* EDSP */
+   clt_mdct_forward_c,           /* Media */
+   clt_mdct_forward_neon         /* Neon with NE10 */
+};
+
+void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l,
+                                                      kiss_fft_scalar *in,
+                                                      kiss_fft_scalar * OPUS_RESTRICT out,
+                                                      const opus_val16 *window,
+                                                      int overlap, int shift,
+                                                      int stride, int arch) = {
+   clt_mdct_backward_c,           /* ARMv4 */
+   clt_mdct_backward_c,           /* EDSP */
+   clt_mdct_backward_c,           /* Media */
+   clt_mdct_backward_neon         /* Neon with NE10 */
+};
+
+#  endif /* HAVE_ARM_NE10 */
+# endif /* OPUS_ARM_MAY_HAVE_NEON_INTR */
+
+#endif /* OPUS_HAVE_RTCD */
diff --git a/third_party/opus/src/celt/arm/armcpu.c b/third_party/opus/src/celt/arm/armcpu.c
new file mode 100644
index 0000000..694a63b
--- /dev/null
+++ b/third_party/opus/src/celt/arm/armcpu.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Original code from libtheora modified to suit to Opus */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef OPUS_HAVE_RTCD
+
+#include "armcpu.h"
+#include "cpu_support.h"
+#include "os_support.h"
+#include "opus_types.h"
+#include "arch.h"
+
+#define OPUS_CPU_ARM_V4_FLAG    (1<<OPUS_ARCH_ARM_V4)
+#define OPUS_CPU_ARM_EDSP_FLAG  (1<<OPUS_ARCH_ARM_EDSP)
+#define OPUS_CPU_ARM_MEDIA_FLAG (1<<OPUS_ARCH_ARM_MEDIA)
+#define OPUS_CPU_ARM_NEON_FLAG  (1<<OPUS_ARCH_ARM_NEON)
+
+#if defined(_MSC_VER)
+/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
+# define WIN32_LEAN_AND_MEAN
+# define WIN32_EXTRA_LEAN
+# include <windows.h>
+
+static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){
+  opus_uint32 flags;
+  flags=0;
+  /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit
+   * instructions via their assembled hex code.
+   * All of these instructions should be essentially nops. */
+# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+  __try{
+    /*PLD [r13]*/
+    __emit(0xF5DDF000);
+    flags|=OPUS_CPU_ARM_EDSP_FLAG;
+  }
+  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+    /*Ignore exception.*/
+  }
+#  if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+  __try{
+    /*SHADD8 r3,r3,r3*/
+    __emit(0xE6333F93);
+    flags|=OPUS_CPU_ARM_MEDIA_FLAG;
+  }
+  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+    /*Ignore exception.*/
+  }
+#   if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+  __try{
+    /*VORR q0,q0,q0*/
+    __emit(0xF2200150);
+    flags|=OPUS_CPU_ARM_NEON_FLAG;
+  }
+  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+    /*Ignore exception.*/
+  }
+#   endif
+#  endif
+# endif
+  return flags;
+}
+
+#elif defined(__linux__)
+/* Linux based */
+opus_uint32 opus_cpu_capabilities(void)
+{
+  opus_uint32 flags = 0;
+  FILE *cpuinfo;
+
+  /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on
+   * Android */
+  cpuinfo = fopen("/proc/cpuinfo", "r");
+
+  if(cpuinfo != NULL)
+  {
+    /* 512 should be enough for anybody (it's even enough for all the flags that
+     * x86 has accumulated... so far). */
+    char buf[512];
+
+    while(fgets(buf, 512, cpuinfo) != NULL)
+    {
+# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+      /* Search for edsp and neon flag */
+      if(memcmp(buf, "Features", 8) == 0)
+      {
+        char *p;
+        p = strstr(buf, " edsp");
+        if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
+          flags |= OPUS_CPU_ARM_EDSP_FLAG;
+
+#  if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+        p = strstr(buf, " neon");
+        if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
+          flags |= OPUS_CPU_ARM_NEON_FLAG;
+#  endif
+      }
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+      /* Search for media capabilities (>= ARMv6) */
+      if(memcmp(buf, "CPU architecture:", 17) == 0)
+      {
+        int version;
+        version = atoi(buf+17);
+
+        if(version >= 6)
+          flags |= OPUS_CPU_ARM_MEDIA_FLAG;
+      }
+# endif
+    }
+
+    fclose(cpuinfo);
+  }
+  return flags;
+}
+#else
+/* The feature registers which can tell us what the processor supports are
+ * accessible in priveleged modes only, so we can't have a general user-space
+ * detection method like on x86.*/
+# error "Configured to use ARM asm but no CPU detection method available for " \
+   "your platform.  Reconfigure with --disable-rtcd (or send patches)."
+#endif
+
+int opus_select_arch(void)
+{
+  opus_uint32 flags = opus_cpu_capabilities();
+  int arch = 0;
+
+  if(!(flags & OPUS_CPU_ARM_EDSP_FLAG)) {
+    /* Asserts ensure arch values are sequential */
+    celt_assert(arch == OPUS_ARCH_ARM_V4);
+    return arch;
+  }
+  arch++;
+
+  if(!(flags & OPUS_CPU_ARM_MEDIA_FLAG)) {
+    celt_assert(arch == OPUS_ARCH_ARM_EDSP);
+    return arch;
+  }
+  arch++;
+
+  if(!(flags & OPUS_CPU_ARM_NEON_FLAG)) {
+    celt_assert(arch == OPUS_ARCH_ARM_MEDIA);
+    return arch;
+  }
+  arch++;
+
+  celt_assert(arch == OPUS_ARCH_ARM_NEON);
+  return arch;
+}
+
+#endif
diff --git a/third_party/opus/src/celt/arm/armcpu.h b/third_party/opus/src/celt/arm/armcpu.h
new file mode 100644
index 0000000..820262ff
--- /dev/null
+++ b/third_party/opus/src/celt/arm/armcpu.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(ARMCPU_H)
+# define ARMCPU_H
+
+# if defined(OPUS_ARM_MAY_HAVE_EDSP)
+#  define MAY_HAVE_EDSP(name) name ## _edsp
+# else
+#  define MAY_HAVE_EDSP(name) name ## _c
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
+#  define MAY_HAVE_MEDIA(name) name ## _media
+# else
+#  define MAY_HAVE_MEDIA(name) MAY_HAVE_EDSP(name)
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON)
+#  define MAY_HAVE_NEON(name) name ## _neon
+# else
+#  define MAY_HAVE_NEON(name) MAY_HAVE_MEDIA(name)
+# endif
+
+# if defined(OPUS_ARM_PRESUME_EDSP)
+#  define PRESUME_EDSP(name) name ## _edsp
+# else
+#  define PRESUME_EDSP(name) name ## _c
+# endif
+
+# if defined(OPUS_ARM_PRESUME_MEDIA)
+#  define PRESUME_MEDIA(name) name ## _media
+# else
+#  define PRESUME_MEDIA(name) PRESUME_EDSP(name)
+# endif
+
+# if defined(OPUS_ARM_PRESUME_NEON)
+#  define PRESUME_NEON(name) name ## _neon
+# else
+#  define PRESUME_NEON(name) PRESUME_MEDIA(name)
+# endif
+
+# if defined(OPUS_HAVE_RTCD)
+int opus_select_arch(void);
+
+#define OPUS_ARCH_ARM_V4    (0)
+#define OPUS_ARCH_ARM_EDSP  (1)
+#define OPUS_ARCH_ARM_MEDIA (2)
+#define OPUS_ARCH_ARM_NEON  (3)
+
+# endif
+
+#endif
diff --git a/third_party/opus/src/celt/arm/armopts.s.in b/third_party/opus/src/celt/arm/armopts.s.in
new file mode 100644
index 0000000..3d8aaf27
--- /dev/null
+++ b/third_party/opus/src/celt/arm/armopts.s.in
@@ -0,0 +1,37 @@
+/* Copyright (C) 2013 Mozilla Corporation */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+; Set the following to 1 if we have EDSP instructions
+;  (LDRD/STRD, etc., ARMv5E and later).
+OPUS_ARM_MAY_HAVE_EDSP  * @OPUS_ARM_MAY_HAVE_EDSP@
+
+; Set the following to 1 if we have ARMv6 media instructions.
+OPUS_ARM_MAY_HAVE_MEDIA * @OPUS_ARM_MAY_HAVE_MEDIA@
+
+; Set the following to 1 if we have NEON (some ARMv7)
+OPUS_ARM_MAY_HAVE_NEON  * @OPUS_ARM_MAY_HAVE_NEON@
+
+END
diff --git a/third_party/opus/src/celt/arm/celt_ne10_fft.c b/third_party/opus/src/celt/arm/celt_ne10_fft.c
new file mode 100644
index 0000000..42d96a7
--- /dev/null
+++ b/third_party/opus/src/celt/arm/celt_ne10_fft.c
@@ -0,0 +1,174 @@
+/* Copyright (c) 2015 Xiph.Org Foundation
+   Written by Viswanath Puttagunta */
+/**
+   @file celt_ne10_fft.c
+   @brief ARM Neon optimizations for fft using NE10 library
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+#include <NE10_init.h>
+#include <NE10_dsp.h>
+#include "os_support.h"
+#include "kiss_fft.h"
+#include "stack_alloc.h"
+
+#if !defined(FIXED_POINT)
+# define NE10_FFT_ALLOC_C2C_TYPE_NEON ne10_fft_alloc_c2c_float32_neon
+# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_float32_t
+# define NE10_FFT_STATE_TYPE_T ne10_fft_state_float32_t
+# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_float32
+# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_float32_t
+# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_float32_neon
+#else
+# define NE10_FFT_ALLOC_C2C_TYPE_NEON(nfft) ne10_fft_alloc_c2c_int32_neon(nfft)
+# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_int32_t
+# define NE10_FFT_STATE_TYPE_T ne10_fft_state_int32_t
+# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32
+# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32
+# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_int32_t
+# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_int32_neon
+#endif
+
+#if defined(CUSTOM_MODES)
+
+/* nfft lengths in NE10 that support scaled fft */
+# define NE10_FFTSCALED_SUPPORT_MAX 4
+static const int ne10_fft_scaled_support[NE10_FFTSCALED_SUPPORT_MAX] = {
+   480, 240, 120, 60
+};
+
+int opus_fft_alloc_arm_neon(kiss_fft_state *st)
+{
+   int i;
+   size_t memneeded = sizeof(struct arch_fft_state);
+
+   st->arch_fft = (arch_fft_state *)opus_alloc(memneeded);
+   if (!st->arch_fft)
+      return -1;
+
+   for (i = 0; i < NE10_FFTSCALED_SUPPORT_MAX; i++) {
+      if(st->nfft == ne10_fft_scaled_support[i])
+         break;
+   }
+   if (i == NE10_FFTSCALED_SUPPORT_MAX) {
+      /* This nfft length (scaled fft) is not supported in NE10 */
+      st->arch_fft->is_supported = 0;
+      st->arch_fft->priv = NULL;
+   }
+   else {
+      st->arch_fft->is_supported = 1;
+      st->arch_fft->priv = (void *)NE10_FFT_ALLOC_C2C_TYPE_NEON(st->nfft);
+      if (st->arch_fft->priv == NULL) {
+         return -1;
+      }
+   }
+   return 0;
+}
+
+void opus_fft_free_arm_neon(kiss_fft_state *st)
+{
+   NE10_FFT_CFG_TYPE_T cfg;
+
+   if (!st->arch_fft)
+      return;
+
+   cfg = (NE10_FFT_CFG_TYPE_T)st->arch_fft->priv;
+   if (cfg)
+      NE10_FFT_DESTROY_C2C_TYPE(cfg);
+   opus_free(st->arch_fft);
+}
+#endif
+
+void opus_fft_neon(const kiss_fft_state *st,
+                   const kiss_fft_cpx *fin,
+                   kiss_fft_cpx *fout)
+{
+   NE10_FFT_STATE_TYPE_T state;
+   NE10_FFT_CFG_TYPE_T cfg = &state;
+   VARDECL(NE10_FFT_CPX_TYPE_T, buffer);
+   SAVE_STACK;
+   ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T);
+
+   if (!st->arch_fft->is_supported) {
+      /* This nfft length (scaled fft) not supported in NE10 */
+      opus_fft_c(st, fin, fout);
+   }
+   else {
+      memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T));
+      state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0];
+#if !defined(FIXED_POINT)
+      state.is_forward_scaled = 1;
+
+      NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout,
+                                (NE10_FFT_CPX_TYPE_T *)fin,
+                                cfg, 0);
+#else
+      NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout,
+                                (NE10_FFT_CPX_TYPE_T *)fin,
+                                cfg, 0, 1);
+#endif
+   }
+   RESTORE_STACK;
+}
+
+void opus_ifft_neon(const kiss_fft_state *st,
+                    const kiss_fft_cpx *fin,
+                    kiss_fft_cpx *fout)
+{
+   NE10_FFT_STATE_TYPE_T state;
+   NE10_FFT_CFG_TYPE_T cfg = &state;
+   VARDECL(NE10_FFT_CPX_TYPE_T, buffer);
+   SAVE_STACK;
+   ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T);
+
+   if (!st->arch_fft->is_supported) {
+      /* This nfft length (scaled fft) not supported in NE10 */
+      opus_ifft_c(st, fin, fout);
+   }
+   else {
+      memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T));
+      state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0];
+#if !defined(FIXED_POINT)
+      state.is_backward_scaled = 0;
+
+      NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout,
+                                (NE10_FFT_CPX_TYPE_T *)fin,
+                                cfg, 1);
+#else
+      NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout,
+                                (NE10_FFT_CPX_TYPE_T *)fin,
+                                cfg, 1, 0);
+#endif
+   }
+   RESTORE_STACK;
+}
diff --git a/third_party/opus/src/celt/arm/celt_ne10_mdct.c b/third_party/opus/src/celt/arm/celt_ne10_mdct.c
new file mode 100644
index 0000000..293c3efd
--- /dev/null
+++ b/third_party/opus/src/celt/arm/celt_ne10_mdct.c
@@ -0,0 +1,258 @@
+/* Copyright (c) 2015 Xiph.Org Foundation
+   Written by Viswanath Puttagunta */
+/**
+   @file celt_ne10_mdct.c
+   @brief ARM Neon optimizations for mdct using NE10 library
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+#include "kiss_fft.h"
+#include "_kiss_fft_guts.h"
+#include "mdct.h"
+#include "stack_alloc.h"
+
+void clt_mdct_forward_neon(const mdct_lookup *l,
+                           kiss_fft_scalar *in,
+                           kiss_fft_scalar * OPUS_RESTRICT out,
+                           const opus_val16 *window,
+                           int overlap, int shift, int stride, int arch)
+{
+   int i;
+   int N, N2, N4;
+   VARDECL(kiss_fft_scalar, f);
+   VARDECL(kiss_fft_cpx, f2);
+   const kiss_fft_state *st = l->kfft[shift];
+   const kiss_twiddle_scalar *trig;
+
+   SAVE_STACK;
+
+   N = l->n;
+   trig = l->trig;
+   for (i=0;i<shift;i++)
+   {
+      N >>= 1;
+      trig += N;
+   }
+   N2 = N>>1;
+   N4 = N>>2;
+
+   ALLOC(f, N2, kiss_fft_scalar);
+   ALLOC(f2, N4, kiss_fft_cpx);
+
+   /* Consider the input to be composed of four blocks: [a, b, c, d] */
+   /* Window, shuffle, fold */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
+      const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
+      kiss_fft_scalar * OPUS_RESTRICT yp = f;
+      const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1);
+      const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
+      for(i=0;i<((overlap+3)>>2);i++)
+      {
+         /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+         *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2);
+         *yp++ = MULT16_32_Q15(*wp1, *xp1)    - MULT16_32_Q15(*wp2, xp2[-N2]);
+         xp1+=2;
+         xp2-=2;
+         wp1+=2;
+         wp2-=2;
+      }
+      wp1 = window;
+      wp2 = window+overlap-1;
+      for(;i<N4-((overlap+3)>>2);i++)
+      {
+         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+         *yp++ = *xp2;
+         *yp++ = *xp1;
+         xp1+=2;
+         xp2-=2;
+      }
+      for(;i<N4;i++)
+      {
+         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+         *yp++ =  -MULT16_32_Q15(*wp1, xp1[-N2]) + MULT16_32_Q15(*wp2, *xp2);
+         *yp++ = MULT16_32_Q15(*wp2, *xp1)     + MULT16_32_Q15(*wp1, xp2[N2]);
+         xp1+=2;
+         xp2-=2;
+         wp1+=2;
+         wp2-=2;
+      }
+   }
+   /* Pre-rotation */
+   {
+      kiss_fft_scalar * OPUS_RESTRICT yp = f;
+      const kiss_twiddle_scalar *t = &trig[0];
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_cpx yc;
+         kiss_twiddle_scalar t0, t1;
+         kiss_fft_scalar re, im, yr, yi;
+         t0 = t[i];
+         t1 = t[N4+i];
+         re = *yp++;
+         im = *yp++;
+         yr = S_MUL(re,t0)  -  S_MUL(im,t1);
+         yi = S_MUL(im,t0)  +  S_MUL(re,t1);
+         yc.r = yr;
+         yc.i = yi;
+         f2[i] = yc;
+      }
+   }
+
+   opus_fft(st, f2, (kiss_fft_cpx *)f, arch);
+
+   /* Post-rotate */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_cpx * OPUS_RESTRICT fp = (kiss_fft_cpx *)f;
+      kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+      kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
+      const kiss_twiddle_scalar *t = &trig[0];
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_scalar yr, yi;
+         yr = S_MUL(fp->i,t[N4+i]) - S_MUL(fp->r,t[i]);
+         yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]);
+         *yp1 = yr;
+         *yp2 = yi;
+         fp++;
+         yp1 += 2*stride;
+         yp2 -= 2*stride;
+      }
+   }
+   RESTORE_STACK;
+}
+
+void clt_mdct_backward_neon(const mdct_lookup *l,
+                            kiss_fft_scalar *in,
+                            kiss_fft_scalar * OPUS_RESTRICT out,
+                            const opus_val16 * OPUS_RESTRICT window,
+                            int overlap, int shift, int stride, int arch)
+{
+   int i;
+   int N, N2, N4;
+   VARDECL(kiss_fft_scalar, f);
+   const kiss_twiddle_scalar *trig;
+   const kiss_fft_state *st = l->kfft[shift];
+
+   N = l->n;
+   trig = l->trig;
+   for (i=0;i<shift;i++)
+   {
+      N >>= 1;
+      trig += N;
+   }
+   N2 = N>>1;
+   N4 = N>>2;
+
+   ALLOC(f, N2, kiss_fft_scalar);
+
+   /* Pre-rotate */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
+      const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
+      kiss_fft_scalar * OPUS_RESTRICT yp = f;
+      const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0];
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_scalar yr, yi;
+         yr = S_MUL(*xp2, t[i]) + S_MUL(*xp1, t[N4+i]);
+         yi = S_MUL(*xp1, t[i]) - S_MUL(*xp2, t[N4+i]);
+         yp[2*i] = yr;
+         yp[2*i+1] = yi;
+         xp1+=2*stride;
+         xp2-=2*stride;
+      }
+   }
+
+   opus_ifft(st, (kiss_fft_cpx *)f, (kiss_fft_cpx*)(out+(overlap>>1)), arch);
+
+   /* Post-rotate and de-shuffle from both ends of the buffer at once to make
+      it in-place. */
+   {
+      kiss_fft_scalar * yp0 = out+(overlap>>1);
+      kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2;
+      const kiss_twiddle_scalar *t = &trig[0];
+      /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
+         middle pair will be computed twice. */
+      for(i=0;i<(N4+1)>>1;i++)
+      {
+         kiss_fft_scalar re, im, yr, yi;
+         kiss_twiddle_scalar t0, t1;
+         re = yp0[0];
+         im = yp0[1];
+         t0 = t[i];
+         t1 = t[N4+i];
+         /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+         yr = S_MUL(re,t0) + S_MUL(im,t1);
+         yi = S_MUL(re,t1) - S_MUL(im,t0);
+         re = yp1[0];
+         im = yp1[1];
+         yp0[0] = yr;
+         yp1[1] = yi;
+
+         t0 = t[(N4-i-1)];
+         t1 = t[(N2-i-1)];
+         /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+         yr = S_MUL(re,t0) + S_MUL(im,t1);
+         yi = S_MUL(re,t1) - S_MUL(im,t0);
+         yp1[0] = yr;
+         yp0[1] = yi;
+         yp0 += 2;
+         yp1 -= 2;
+      }
+   }
+
+   /* Mirror on both sides for TDAC */
+   {
+      kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
+      kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+      const opus_val16 * OPUS_RESTRICT wp1 = window;
+      const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1;
+
+      for(i = 0; i < overlap/2; i++)
+      {
+         kiss_fft_scalar x1, x2;
+         x1 = *xp1;
+         x2 = *yp1;
+         *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
+         *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
+         wp1++;
+         wp2--;
+      }
+   }
+   RESTORE_STACK;
+}
diff --git a/third_party/opus/src/celt/arm/celt_neon_intr.c b/third_party/opus/src/celt/arm/celt_neon_intr.c
new file mode 100644
index 0000000..47bbe3d
--- /dev/null
+++ b/third_party/opus/src/celt/arm/celt_neon_intr.c
@@ -0,0 +1,311 @@
+/* Copyright (c) 2014-2015 Xiph.Org Foundation
+   Written by Viswanath Puttagunta */
+/**
+   @file celt_neon_intr.c
+   @brief ARM Neon Intrinsic optimizations for celt
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <arm_neon.h>
+#include "../pitch.h"
+
+#if defined(FIXED_POINT)
+void xcorr_kernel_neon_fixed(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len)
+{
+   int j;
+   int32x4_t a = vld1q_s32(sum);
+   /* Load y[0...3] */
+   /* This requires len>0 to always be valid (which we assert in the C code). */
+   int16x4_t y0 = vld1_s16(y);
+   y += 4;
+
+   for (j = 0; j + 8 <= len; j += 8)
+   {
+      /* Load x[0...7] */
+      int16x8_t xx = vld1q_s16(x);
+      int16x4_t x0 = vget_low_s16(xx);
+      int16x4_t x4 = vget_high_s16(xx);
+      /* Load y[4...11] */
+      int16x8_t yy = vld1q_s16(y);
+      int16x4_t y4 = vget_low_s16(yy);
+      int16x4_t y8 = vget_high_s16(yy);
+      int32x4_t a0 = vmlal_lane_s16(a, y0, x0, 0);
+      int32x4_t a1 = vmlal_lane_s16(a0, y4, x4, 0);
+
+      int16x4_t y1 = vext_s16(y0, y4, 1);
+      int16x4_t y5 = vext_s16(y4, y8, 1);
+      int32x4_t a2 = vmlal_lane_s16(a1, y1, x0, 1);
+      int32x4_t a3 = vmlal_lane_s16(a2, y5, x4, 1);
+
+      int16x4_t y2 = vext_s16(y0, y4, 2);
+      int16x4_t y6 = vext_s16(y4, y8, 2);
+      int32x4_t a4 = vmlal_lane_s16(a3, y2, x0, 2);
+      int32x4_t a5 = vmlal_lane_s16(a4, y6, x4, 2);
+
+      int16x4_t y3 = vext_s16(y0, y4, 3);
+      int16x4_t y7 = vext_s16(y4, y8, 3);
+      int32x4_t a6 = vmlal_lane_s16(a5, y3, x0, 3);
+      int32x4_t a7 = vmlal_lane_s16(a6, y7, x4, 3);
+
+      y0 = y8;
+      a = a7;
+      x += 8;
+      y += 8;
+   }
+
+   for (; j < len; j++)
+   {
+      int16x4_t x0 = vld1_dup_s16(x);  /* load next x */
+      int32x4_t a0 = vmlal_s16(a, y0, x0);
+
+      int16x4_t y4 = vld1_dup_s16(y);  /* load next y */
+      y0 = vext_s16(y0, y4, 1);
+      a = a0;
+      x++;
+      y++;
+   }
+
+   vst1q_s32(sum, a);
+}
+
+#else
+/*
+ * Function: xcorr_kernel_neon_float
+ * ---------------------------------
+ * Computes 4 correlation values and stores them in sum[4]
+ */
+static void xcorr_kernel_neon_float(const float32_t *x, const float32_t *y,
+      float32_t sum[4], int len) {
+   float32x4_t YY[3];
+   float32x4_t YEXT[3];
+   float32x4_t XX[2];
+   float32x2_t XX_2;
+   float32x4_t SUMM;
+   const float32_t *xi = x;
+   const float32_t *yi = y;
+
+   celt_assert(len>0);
+
+   YY[0] = vld1q_f32(yi);
+   SUMM = vdupq_n_f32(0);
+
+   /* Consume 8 elements in x vector and 12 elements in y
+    * vector. However, the 12'th element never really gets
+    * touched in this loop. So, if len == 8, then we only
+    * must access y[0] to y[10]. y[11] must not be accessed
+    * hence make sure len > 8 and not len >= 8
+    */
+   while (len > 8) {
+      yi += 4;
+      YY[1] = vld1q_f32(yi);
+      yi += 4;
+      YY[2] = vld1q_f32(yi);
+
+      XX[0] = vld1q_f32(xi);
+      xi += 4;
+      XX[1] = vld1q_f32(xi);
+      xi += 4;
+
+      SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0);
+      YEXT[0] = vextq_f32(YY[0], YY[1], 1);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1);
+      YEXT[1] = vextq_f32(YY[0], YY[1], 2);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0);
+      YEXT[2] = vextq_f32(YY[0], YY[1], 3);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1);
+
+      SUMM = vmlaq_lane_f32(SUMM, YY[1], vget_low_f32(XX[1]), 0);
+      YEXT[0] = vextq_f32(YY[1], YY[2], 1);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[1]), 1);
+      YEXT[1] = vextq_f32(YY[1], YY[2], 2);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[1]), 0);
+      YEXT[2] = vextq_f32(YY[1], YY[2], 3);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[1]), 1);
+
+      YY[0] = YY[2];
+      len -= 8;
+   }
+
+   /* Consume 4 elements in x vector and 8 elements in y
+    * vector. However, the 8'th element in y never really gets
+    * touched in this loop. So, if len == 4, then we only
+    * must access y[0] to y[6]. y[7] must not be accessed
+    * hence make sure len>4 and not len>=4
+    */
+   if (len > 4) {
+      yi += 4;
+      YY[1] = vld1q_f32(yi);
+
+      XX[0] = vld1q_f32(xi);
+      xi += 4;
+
+      SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0);
+      YEXT[0] = vextq_f32(YY[0], YY[1], 1);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1);
+      YEXT[1] = vextq_f32(YY[0], YY[1], 2);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0);
+      YEXT[2] = vextq_f32(YY[0], YY[1], 3);
+      SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1);
+
+      YY[0] = YY[1];
+      len -= 4;
+   }
+
+   while (--len > 0) {
+      XX_2 = vld1_dup_f32(xi++);
+      SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0);
+      YY[0]= vld1q_f32(++yi);
+   }
+
+   XX_2 = vld1_dup_f32(xi);
+   SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0);
+
+   vst1q_f32(sum, SUMM);
+}
+
+/*
+ * Function: xcorr_kernel_neon_float_process1
+ * ---------------------------------
+ * Computes single correlation values and stores in *sum
+ */
+static void xcorr_kernel_neon_float_process1(const float32_t *x,
+      const float32_t *y, float32_t *sum, int len) {
+   float32x4_t XX[4];
+   float32x4_t YY[4];
+   float32x2_t XX_2;
+   float32x2_t YY_2;
+   float32x4_t SUMM;
+   float32x2_t SUMM_2[2];
+   const float32_t *xi = x;
+   const float32_t *yi = y;
+
+   SUMM = vdupq_n_f32(0);
+
+   /* Work on 16 values per iteration */
+   while (len >= 16) {
+      XX[0] = vld1q_f32(xi);
+      xi += 4;
+      XX[1] = vld1q_f32(xi);
+      xi += 4;
+      XX[2] = vld1q_f32(xi);
+      xi += 4;
+      XX[3] = vld1q_f32(xi);
+      xi += 4;
+
+      YY[0] = vld1q_f32(yi);
+      yi += 4;
+      YY[1] = vld1q_f32(yi);
+      yi += 4;
+      YY[2] = vld1q_f32(yi);
+      yi += 4;
+      YY[3] = vld1q_f32(yi);
+      yi += 4;
+
+      SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
+      SUMM = vmlaq_f32(SUMM, YY[1], XX[1]);
+      SUMM = vmlaq_f32(SUMM, YY[2], XX[2]);
+      SUMM = vmlaq_f32(SUMM, YY[3], XX[3]);
+      len -= 16;
+   }
+
+   /* Work on 8 values */
+   if (len >= 8) {
+      XX[0] = vld1q_f32(xi);
+      xi += 4;
+      XX[1] = vld1q_f32(xi);
+      xi += 4;
+
+      YY[0] = vld1q_f32(yi);
+      yi += 4;
+      YY[1] = vld1q_f32(yi);
+      yi += 4;
+
+      SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
+      SUMM = vmlaq_f32(SUMM, YY[1], XX[1]);
+      len -= 8;
+   }
+
+   /* Work on 4 values */
+   if (len >= 4) {
+      XX[0] = vld1q_f32(xi);
+      xi += 4;
+      YY[0] = vld1q_f32(yi);
+      yi += 4;
+      SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
+      len -= 4;
+   }
+
+   /* Start accumulating results */
+   SUMM_2[0] = vget_low_f32(SUMM);
+   if (len >= 2) {
+      /* While at it, consume 2 more values if available */
+      XX_2 = vld1_f32(xi);
+      xi += 2;
+      YY_2 = vld1_f32(yi);
+      yi += 2;
+      SUMM_2[0] = vmla_f32(SUMM_2[0], YY_2, XX_2);
+      len -= 2;
+   }
+   SUMM_2[1] = vget_high_f32(SUMM);
+   SUMM_2[0] = vadd_f32(SUMM_2[0], SUMM_2[1]);
+   SUMM_2[0] = vpadd_f32(SUMM_2[0], SUMM_2[0]);
+   /* Ok, now we have result accumulated in SUMM_2[0].0 */
+
+   if (len > 0) {
+      /* Case when you have one value left */
+      XX_2 = vld1_dup_f32(xi);
+      YY_2 = vld1_dup_f32(yi);
+      SUMM_2[0] = vmla_f32(SUMM_2[0], XX_2, YY_2);
+   }
+
+   vst1_lane_f32(sum, SUMM_2[0], 0);
+}
+
+void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y,
+                        opus_val32 *xcorr, int len, int max_pitch) {
+   int i;
+   celt_assert(max_pitch > 0);
+   celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
+
+   for (i = 0; i < (max_pitch-3); i += 4) {
+      xcorr_kernel_neon_float((const float32_t *)_x, (const float32_t *)_y+i,
+            (float32_t *)xcorr+i, len);
+   }
+
+   /* In case max_pitch isn't multiple of 4
+    * compute single correlation value per iteration
+    */
+   for (; i < max_pitch; i++) {
+      xcorr_kernel_neon_float_process1((const float32_t *)_x,
+            (const float32_t *)_y+i, (float32_t *)xcorr+i, len);
+   }
+}
+#endif
diff --git a/third_party/opus/src/celt/arm/celt_pitch_xcorr_arm.s b/third_party/opus/src/celt/arm/celt_pitch_xcorr_arm.s
new file mode 100644
index 0000000..f96e0a8
--- /dev/null
+++ b/third_party/opus/src/celt/arm/celt_pitch_xcorr_arm.s
@@ -0,0 +1,547 @@
+; Copyright (c) 2007-2008 CSIRO
+; Copyright (c) 2007-2009 Xiph.Org Foundation
+; Copyright (c) 2013      Parrot
+; Written by Aurélien Zanelli
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+;
+; - Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; - Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+; OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  AREA  |.text|, CODE, READONLY
+
+  GET    celt/arm/armopts.s
+
+IF OPUS_ARM_MAY_HAVE_EDSP
+  EXPORT celt_pitch_xcorr_edsp
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_NEON
+  EXPORT celt_pitch_xcorr_neon
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_NEON
+
+; Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3
+xcorr_kernel_neon PROC
+xcorr_kernel_neon_start
+  ; input:
+  ;   r3     = int         len
+  ;   r4     = opus_val16 *x
+  ;   r5     = opus_val16 *y
+  ;   q0     = opus_val32  sum[4]
+  ; output:
+  ;   q0     = opus_val32  sum[4]
+  ; preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15
+  ; internal usage:
+  ;   r12 = int j
+  ;   d3  = y_3|y_2|y_1|y_0
+  ;   q2  = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4
+  ;   q3  = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0
+  ;   q8  = scratch
+  ;
+  ; Load y[0...3]
+  ; This requires len>0 to always be valid (which we assert in the C code).
+  VLD1.16      {d5}, [r5]!
+  SUBS         r12, r3, #8
+  BLE xcorr_kernel_neon_process4
+; Process 8 samples at a time.
+; This loop loads one y value more than we actually need. Therefore we have to
+; stop as soon as there are 8 or fewer samples left (instead of 7), to avoid
+; reading past the end of the array.
+xcorr_kernel_neon_process8
+  ; This loop has 19 total instructions (10 cycles to issue, minimum), with
+  ; - 2 cycles of ARM insrtuctions,
+  ; - 10 cycles of load/store/byte permute instructions, and
+  ; - 9 cycles of data processing instructions.
+  ; On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the
+  ; latter two categories, meaning the whole loop should run in 10 cycles per
+  ; iteration, barring cache misses.
+  ;
+  ; Load x[0...7]
+  VLD1.16      {d6, d7}, [r4]!
+  ; Unlike VMOV, VAND is a data processsing instruction (and doesn't get
+  ; assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1.
+  VAND         d3, d5, d5
+  SUBS         r12, r12, #8
+  ; Load y[4...11]
+  VLD1.16      {d4, d5}, [r5]!
+  VMLAL.S16    q0, d3, d6[0]
+  VEXT.16      d16, d3, d4, #1
+  VMLAL.S16    q0, d4, d7[0]
+  VEXT.16      d17, d4, d5, #1
+  VMLAL.S16    q0, d16, d6[1]
+  VEXT.16      d16, d3, d4, #2
+  VMLAL.S16    q0, d17, d7[1]
+  VEXT.16      d17, d4, d5, #2
+  VMLAL.S16    q0, d16, d6[2]
+  VEXT.16      d16, d3, d4, #3
+  VMLAL.S16    q0, d17, d7[2]
+  VEXT.16      d17, d4, d5, #3
+  VMLAL.S16    q0, d16, d6[3]
+  VMLAL.S16    q0, d17, d7[3]
+  BGT xcorr_kernel_neon_process8
+; Process 4 samples here if we have > 4 left (still reading one extra y value).
+xcorr_kernel_neon_process4
+  ADDS         r12, r12, #4
+  BLE xcorr_kernel_neon_process2
+  ; Load x[0...3]
+  VLD1.16      d6, [r4]!
+  ; Use VAND since it's a data processing instruction again.
+  VAND         d4, d5, d5
+  SUB          r12, r12, #4
+  ; Load y[4...7]
+  VLD1.16      d5, [r5]!
+  VMLAL.S16    q0, d4, d6[0]
+  VEXT.16      d16, d4, d5, #1
+  VMLAL.S16    q0, d16, d6[1]
+  VEXT.16      d16, d4, d5, #2
+  VMLAL.S16    q0, d16, d6[2]
+  VEXT.16      d16, d4, d5, #3
+  VMLAL.S16    q0, d16, d6[3]
+; Process 2 samples here if we have > 2 left (still reading one extra y value).
+xcorr_kernel_neon_process2
+  ADDS         r12, r12, #2
+  BLE xcorr_kernel_neon_process1
+  ; Load x[0...1]
+  VLD2.16      {d6[],d7[]}, [r4]!
+  ; Use VAND since it's a data processing instruction again.
+  VAND         d4, d5, d5
+  SUB          r12, r12, #2
+  ; Load y[4...5]
+  VLD1.32      {d5[]}, [r5]!
+  VMLAL.S16    q0, d4, d6
+  VEXT.16      d16, d4, d5, #1
+  ; Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI
+  ; instead of VEXT, since it's a data-processing instruction.
+  VSRI.64      d5, d4, #32
+  VMLAL.S16    q0, d16, d7
+; Process 1 sample using the extra y value we loaded above.
+xcorr_kernel_neon_process1
+  ; Load next *x
+  VLD1.16      {d6[]}, [r4]!
+  ADDS         r12, r12, #1
+  ; y[0...3] are left in d5 from prior iteration(s) (if any)
+  VMLAL.S16    q0, d5, d6
+  MOVLE        pc, lr
+; Now process 1 last sample, not reading ahead.
+  ; Load last *y
+  VLD1.16      {d4[]}, [r5]!
+  VSRI.64      d4, d5, #16
+  ; Load last *x
+  VLD1.16      {d6[]}, [r4]!
+  VMLAL.S16    q0, d4, d6
+  MOV          pc, lr
+  ENDP
+
+; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y,
+;  opus_val32 *xcorr, int len, int max_pitch)
+celt_pitch_xcorr_neon PROC
+  ; input:
+  ;   r0  = opus_val16 *_x
+  ;   r1  = opus_val16 *_y
+  ;   r2  = opus_val32 *xcorr
+  ;   r3  = int         len
+  ; output:
+  ;   r0  = int         maxcorr
+  ; internal usage:
+  ;   r4  = opus_val16 *x (for xcorr_kernel_neon())
+  ;   r5  = opus_val16 *y (for xcorr_kernel_neon())
+  ;   r6  = int         max_pitch
+  ;   r12 = int         j
+  ;   q15 = int         maxcorr[4] (q15 is not used by xcorr_kernel_neon())
+  STMFD        sp!, {r4-r6, lr}
+  LDR          r6, [sp, #16]
+  VMOV.S32     q15, #1
+  ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
+  SUBS         r6, r6, #4
+  BLT celt_pitch_xcorr_neon_process4_done
+celt_pitch_xcorr_neon_process4
+  ; xcorr_kernel_neon parameters:
+  ; r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0}
+  MOV          r4, r0
+  MOV          r5, r1
+  VEOR         q0, q0, q0
+  ; xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3.
+  ; So we don't save/restore any other registers.
+  BL xcorr_kernel_neon_start
+  SUBS         r6, r6, #4
+  VST1.32      {q0}, [r2]!
+  ; _y += 4
+  ADD          r1, r1, #8
+  VMAX.S32     q15, q15, q0
+  ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
+  BGE celt_pitch_xcorr_neon_process4
+; We have less than 4 sums left to compute.
+celt_pitch_xcorr_neon_process4_done
+  ADDS         r6, r6, #4
+  ; Reduce maxcorr to a single value
+  VMAX.S32     d30, d30, d31
+  VPMAX.S32    d30, d30, d30
+  ; if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done
+  BLE celt_pitch_xcorr_neon_done
+; Now compute each remaining sum one at a time.
+celt_pitch_xcorr_neon_process_remaining
+  MOV          r4, r0
+  MOV          r5, r1
+  VMOV.I32     q0, #0
+  SUBS         r12, r3, #8
+  BLT celt_pitch_xcorr_neon_process_remaining4
+; Sum terms 8 at a time.
+celt_pitch_xcorr_neon_process_remaining_loop8
+  ; Load x[0...7]
+  VLD1.16      {q1}, [r4]!
+  ; Load y[0...7]
+  VLD1.16      {q2}, [r5]!
+  SUBS         r12, r12, #8
+  VMLAL.S16    q0, d4, d2
+  VMLAL.S16    q0, d5, d3
+  BGE celt_pitch_xcorr_neon_process_remaining_loop8
+; Sum terms 4 at a time.
+celt_pitch_xcorr_neon_process_remaining4
+  ADDS         r12, r12, #4
+  BLT celt_pitch_xcorr_neon_process_remaining4_done
+  ; Load x[0...3]
+  VLD1.16      {d2}, [r4]!
+  ; Load y[0...3]
+  VLD1.16      {d3}, [r5]!
+  SUB          r12, r12, #4
+  VMLAL.S16    q0, d3, d2
+celt_pitch_xcorr_neon_process_remaining4_done
+  ; Reduce the sum to a single value.
+  VADD.S32     d0, d0, d1
+  VPADDL.S32   d0, d0
+  ADDS         r12, r12, #4
+  BLE celt_pitch_xcorr_neon_process_remaining_loop_done
+; Sum terms 1 at a time.
+celt_pitch_xcorr_neon_process_remaining_loop1
+  VLD1.16      {d2[]}, [r4]!
+  VLD1.16      {d3[]}, [r5]!
+  SUBS         r12, r12, #1
+  VMLAL.S16    q0, d2, d3
+  BGT celt_pitch_xcorr_neon_process_remaining_loop1
+celt_pitch_xcorr_neon_process_remaining_loop_done
+  VST1.32      {d0[0]}, [r2]!
+  VMAX.S32     d30, d30, d0
+  SUBS         r6, r6, #1
+  ; _y++
+  ADD          r1, r1, #2
+  ; if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining
+  BGT celt_pitch_xcorr_neon_process_remaining
+celt_pitch_xcorr_neon_done
+  VMOV.32      r0, d30[0]
+  LDMFD        sp!, {r4-r6, pc}
+  ENDP
+
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_EDSP
+
+; This will get used on ARMv7 devices without NEON, so it has been optimized
+; to take advantage of dual-issuing where possible.
+xcorr_kernel_edsp PROC
+xcorr_kernel_edsp_start
+  ; input:
+  ;   r3      = int         len
+  ;   r4      = opus_val16 *_x (must be 32-bit aligned)
+  ;   r5      = opus_val16 *_y (must be 32-bit aligned)
+  ;   r6...r9 = opus_val32  sum[4]
+  ; output:
+  ;   r6...r9 = opus_val32  sum[4]
+  ; preserved: r0-r5
+  ; internal usage
+  ;   r2      = int         j
+  ;   r12,r14 = opus_val16  x[4]
+  ;   r10,r11 = opus_val16  y[4]
+  STMFD        sp!, {r2,r4,r5,lr}
+  LDR          r10, [r5], #4      ; Load y[0...1]
+  SUBS         r2, r3, #4         ; j = len-4
+  LDR          r11, [r5], #4      ; Load y[2...3]
+  BLE xcorr_kernel_edsp_process4_done
+  LDR          r12, [r4], #4      ; Load x[0...1]
+  ; Stall
+xcorr_kernel_edsp_process4
+  ; The multiplies must issue from pipeline 0, and can't dual-issue with each
+  ; other. Every other instruction here dual-issues with a multiply, and is
+  ; thus "free". There should be no stalls in the body of the loop.
+  SMLABB       r6, r12, r10, r6   ; sum[0] = MAC16_16(sum[0],x_0,y_0)
+  LDR          r14, [r4], #4      ; Load x[2...3]
+  SMLABT       r7, r12, r10, r7   ; sum[1] = MAC16_16(sum[1],x_0,y_1)
+  SUBS         r2, r2, #4         ; j-=4
+  SMLABB       r8, r12, r11, r8   ; sum[2] = MAC16_16(sum[2],x_0,y_2)
+  SMLABT       r9, r12, r11, r9   ; sum[3] = MAC16_16(sum[3],x_0,y_3)
+  SMLATT       r6, r12, r10, r6   ; sum[0] = MAC16_16(sum[0],x_1,y_1)
+  LDR          r10, [r5], #4      ; Load y[4...5]
+  SMLATB       r7, r12, r11, r7   ; sum[1] = MAC16_16(sum[1],x_1,y_2)
+  SMLATT       r8, r12, r11, r8   ; sum[2] = MAC16_16(sum[2],x_1,y_3)
+  SMLATB       r9, r12, r10, r9   ; sum[3] = MAC16_16(sum[3],x_1,y_4)
+  LDRGT        r12, [r4], #4      ; Load x[0...1]
+  SMLABB       r6, r14, r11, r6   ; sum[0] = MAC16_16(sum[0],x_2,y_2)
+  SMLABT       r7, r14, r11, r7   ; sum[1] = MAC16_16(sum[1],x_2,y_3)
+  SMLABB       r8, r14, r10, r8   ; sum[2] = MAC16_16(sum[2],x_2,y_4)
+  SMLABT       r9, r14, r10, r9   ; sum[3] = MAC16_16(sum[3],x_2,y_5)
+  SMLATT       r6, r14, r11, r6   ; sum[0] = MAC16_16(sum[0],x_3,y_3)
+  LDR          r11, [r5], #4      ; Load y[6...7]
+  SMLATB       r7, r14, r10, r7   ; sum[1] = MAC16_16(sum[1],x_3,y_4)
+  SMLATT       r8, r14, r10, r8   ; sum[2] = MAC16_16(sum[2],x_3,y_5)
+  SMLATB       r9, r14, r11, r9   ; sum[3] = MAC16_16(sum[3],x_3,y_6)
+  BGT xcorr_kernel_edsp_process4
+xcorr_kernel_edsp_process4_done
+  ADDS         r2, r2, #4
+  BLE xcorr_kernel_edsp_done
+  LDRH         r12, [r4], #2      ; r12 = *x++
+  SUBS         r2, r2, #1         ; j--
+  ; Stall
+  SMLABB       r6, r12, r10, r6   ; sum[0] = MAC16_16(sum[0],x,y_0)
+  LDRHGT       r14, [r4], #2      ; r14 = *x++
+  SMLABT       r7, r12, r10, r7   ; sum[1] = MAC16_16(sum[1],x,y_1)
+  SMLABB       r8, r12, r11, r8   ; sum[2] = MAC16_16(sum[2],x,y_2)
+  SMLABT       r9, r12, r11, r9   ; sum[3] = MAC16_16(sum[3],x,y_3)
+  BLE xcorr_kernel_edsp_done
+  SMLABT       r6, r14, r10, r6   ; sum[0] = MAC16_16(sum[0],x,y_1)
+  SUBS         r2, r2, #1         ; j--
+  SMLABB       r7, r14, r11, r7   ; sum[1] = MAC16_16(sum[1],x,y_2)
+  LDRH         r10, [r5], #2      ; r10 = y_4 = *y++
+  SMLABT       r8, r14, r11, r8   ; sum[2] = MAC16_16(sum[2],x,y_3)
+  LDRHGT       r12, [r4], #2      ; r12 = *x++
+  SMLABB       r9, r14, r10, r9   ; sum[3] = MAC16_16(sum[3],x,y_4)
+  BLE xcorr_kernel_edsp_done
+  SMLABB       r6, r12, r11, r6   ; sum[0] = MAC16_16(sum[0],tmp,y_2)
+  CMP          r2, #1             ; j--
+  SMLABT       r7, r12, r11, r7   ; sum[1] = MAC16_16(sum[1],tmp,y_3)
+  LDRH         r2, [r5], #2       ; r2 = y_5 = *y++
+  SMLABB       r8, r12, r10, r8   ; sum[2] = MAC16_16(sum[2],tmp,y_4)
+  LDRHGT       r14, [r4]          ; r14 = *x
+  SMLABB       r9, r12, r2, r9    ; sum[3] = MAC16_16(sum[3],tmp,y_5)
+  BLE xcorr_kernel_edsp_done
+  SMLABT       r6, r14, r11, r6   ; sum[0] = MAC16_16(sum[0],tmp,y_3)
+  LDRH         r11, [r5]          ; r11 = y_6 = *y
+  SMLABB       r7, r14, r10, r7   ; sum[1] = MAC16_16(sum[1],tmp,y_4)
+  SMLABB       r8, r14, r2, r8    ; sum[2] = MAC16_16(sum[2],tmp,y_5)
+  SMLABB       r9, r14, r11, r9   ; sum[3] = MAC16_16(sum[3],tmp,y_6)
+xcorr_kernel_edsp_done
+  LDMFD        sp!, {r2,r4,r5,pc}
+  ENDP
+
+celt_pitch_xcorr_edsp PROC
+  ; input:
+  ;   r0  = opus_val16 *_x (must be 32-bit aligned)
+  ;   r1  = opus_val16 *_y (only needs to be 16-bit aligned)
+  ;   r2  = opus_val32 *xcorr
+  ;   r3  = int         len
+  ; output:
+  ;   r0  = maxcorr
+  ; internal usage
+  ;   r4  = opus_val16 *x
+  ;   r5  = opus_val16 *y
+  ;   r6  = opus_val32  sum0
+  ;   r7  = opus_val32  sum1
+  ;   r8  = opus_val32  sum2
+  ;   r9  = opus_val32  sum3
+  ;   r1  = int         max_pitch
+  ;   r12 = int         j
+  STMFD        sp!, {r4-r11, lr}
+  MOV          r5, r1
+  LDR          r1, [sp, #36]
+  MOV          r4, r0
+  TST          r5, #3
+  ; maxcorr = 1
+  MOV          r0, #1
+  BEQ          celt_pitch_xcorr_edsp_process1u_done
+; Compute one sum at the start to make y 32-bit aligned.
+  SUBS         r12, r3, #4
+  ; r14 = sum = 0
+  MOV          r14, #0
+  LDRH         r8, [r5], #2
+  BLE celt_pitch_xcorr_edsp_process1u_loop4_done
+  LDR          r6, [r4], #4
+  MOV          r8, r8, LSL #16
+celt_pitch_xcorr_edsp_process1u_loop4
+  LDR          r9, [r5], #4
+  SMLABT       r14, r6, r8, r14     ; sum = MAC16_16(sum, x_0, y_0)
+  LDR          r7, [r4], #4
+  SMLATB       r14, r6, r9, r14     ; sum = MAC16_16(sum, x_1, y_1)
+  LDR          r8, [r5], #4
+  SMLABT       r14, r7, r9, r14     ; sum = MAC16_16(sum, x_2, y_2)
+  SUBS         r12, r12, #4         ; j-=4
+  SMLATB       r14, r7, r8, r14     ; sum = MAC16_16(sum, x_3, y_3)
+  LDRGT        r6, [r4], #4
+  BGT celt_pitch_xcorr_edsp_process1u_loop4
+  MOV          r8, r8, LSR #16
+celt_pitch_xcorr_edsp_process1u_loop4_done
+  ADDS         r12, r12, #4
+celt_pitch_xcorr_edsp_process1u_loop1
+  LDRHGE       r6, [r4], #2
+  ; Stall
+  SMLABBGE     r14, r6, r8, r14    ; sum = MAC16_16(sum, *x, *y)
+  SUBSGE       r12, r12, #1
+  LDRHGT       r8, [r5], #2
+  BGT celt_pitch_xcorr_edsp_process1u_loop1
+  ; Restore _x
+  SUB          r4, r4, r3, LSL #1
+  ; Restore and advance _y
+  SUB          r5, r5, r3, LSL #1
+  ; maxcorr = max(maxcorr, sum)
+  CMP          r0, r14
+  ADD          r5, r5, #2
+  MOVLT        r0, r14
+  SUBS         r1, r1, #1
+  ; xcorr[i] = sum
+  STR          r14, [r2], #4
+  BLE celt_pitch_xcorr_edsp_done
+celt_pitch_xcorr_edsp_process1u_done
+  ; if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2
+  SUBS         r1, r1, #4
+  BLT celt_pitch_xcorr_edsp_process2
+celt_pitch_xcorr_edsp_process4
+  ; xcorr_kernel_edsp parameters:
+  ; r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0}
+  MOV          r6, #0
+  MOV          r7, #0
+  MOV          r8, #0
+  MOV          r9, #0
+  BL xcorr_kernel_edsp_start  ; xcorr_kernel_edsp(_x, _y+i, xcorr+i, len)
+  ; maxcorr = max(maxcorr, sum0, sum1, sum2, sum3)
+  CMP          r0, r6
+  ; _y+=4
+  ADD          r5, r5, #8
+  MOVLT        r0, r6
+  CMP          r0, r7
+  MOVLT        r0, r7
+  CMP          r0, r8
+  MOVLT        r0, r8
+  CMP          r0, r9
+  MOVLT        r0, r9
+  STMIA        r2!, {r6-r9}
+  SUBS         r1, r1, #4
+  BGE celt_pitch_xcorr_edsp_process4
+celt_pitch_xcorr_edsp_process2
+  ADDS         r1, r1, #2
+  BLT celt_pitch_xcorr_edsp_process1a
+  SUBS         r12, r3, #4
+  ; {r10, r11} = {sum0, sum1} = {0, 0}
+  MOV          r10, #0
+  MOV          r11, #0
+  LDR          r8, [r5], #4
+  BLE celt_pitch_xcorr_edsp_process2_loop_done
+  LDR          r6, [r4], #4
+  LDR          r9, [r5], #4
+celt_pitch_xcorr_edsp_process2_loop4
+  SMLABB       r10, r6, r8, r10     ; sum0 = MAC16_16(sum0, x_0, y_0)
+  LDR          r7, [r4], #4
+  SMLABT       r11, r6, r8, r11     ; sum1 = MAC16_16(sum1, x_0, y_1)
+  SUBS         r12, r12, #4         ; j-=4
+  SMLATT       r10, r6, r8, r10     ; sum0 = MAC16_16(sum0, x_1, y_1)
+  LDR          r8, [r5], #4
+  SMLATB       r11, r6, r9, r11     ; sum1 = MAC16_16(sum1, x_1, y_2)
+  LDRGT        r6, [r4], #4
+  SMLABB       r10, r7, r9, r10     ; sum0 = MAC16_16(sum0, x_2, y_2)
+  SMLABT       r11, r7, r9, r11     ; sum1 = MAC16_16(sum1, x_2, y_3)
+  SMLATT       r10, r7, r9, r10     ; sum0 = MAC16_16(sum0, x_3, y_3)
+  LDRGT        r9, [r5], #4
+  SMLATB       r11, r7, r8, r11     ; sum1 = MAC16_16(sum1, x_3, y_4)
+  BGT celt_pitch_xcorr_edsp_process2_loop4
+celt_pitch_xcorr_edsp_process2_loop_done
+  ADDS         r12, r12, #2
+  BLE  celt_pitch_xcorr_edsp_process2_1
+  LDR          r6, [r4], #4
+  ; Stall
+  SMLABB       r10, r6, r8, r10     ; sum0 = MAC16_16(sum0, x_0, y_0)
+  LDR          r9, [r5], #4
+  SMLABT       r11, r6, r8, r11     ; sum1 = MAC16_16(sum1, x_0, y_1)
+  SUB          r12, r12, #2
+  SMLATT       r10, r6, r8, r10     ; sum0 = MAC16_16(sum0, x_1, y_1)
+  MOV          r8, r9
+  SMLATB       r11, r6, r9, r11     ; sum1 = MAC16_16(sum1, x_1, y_2)
+celt_pitch_xcorr_edsp_process2_1
+  LDRH         r6, [r4], #2
+  ADDS         r12, r12, #1
+  ; Stall
+  SMLABB       r10, r6, r8, r10     ; sum0 = MAC16_16(sum0, x_0, y_0)
+  LDRHGT       r7, [r4], #2
+  SMLABT       r11, r6, r8, r11     ; sum1 = MAC16_16(sum1, x_0, y_1)
+  BLE celt_pitch_xcorr_edsp_process2_done
+  LDRH         r9, [r5], #2
+  SMLABT       r10, r7, r8, r10     ; sum0 = MAC16_16(sum0, x_0, y_1)
+  SMLABB       r11, r7, r9, r11     ; sum1 = MAC16_16(sum1, x_0, y_2)
+celt_pitch_xcorr_edsp_process2_done
+  ; Restore _x
+  SUB          r4, r4, r3, LSL #1
+  ; Restore and advance _y
+  SUB          r5, r5, r3, LSL #1
+  ; maxcorr = max(maxcorr, sum0)
+  CMP          r0, r10
+  ADD          r5, r5, #2
+  MOVLT        r0, r10
+  SUB          r1, r1, #2
+  ; maxcorr = max(maxcorr, sum1)
+  CMP          r0, r11
+  ; xcorr[i] = sum
+  STR          r10, [r2], #4
+  MOVLT        r0, r11
+  STR          r11, [r2], #4
+celt_pitch_xcorr_edsp_process1a
+  ADDS         r1, r1, #1
+  BLT celt_pitch_xcorr_edsp_done
+  SUBS         r12, r3, #4
+  ; r14 = sum = 0
+  MOV          r14, #0
+  BLT celt_pitch_xcorr_edsp_process1a_loop_done
+  LDR          r6, [r4], #4
+  LDR          r8, [r5], #4
+  LDR          r7, [r4], #4
+  LDR          r9, [r5], #4
+celt_pitch_xcorr_edsp_process1a_loop4
+  SMLABB       r14, r6, r8, r14     ; sum = MAC16_16(sum, x_0, y_0)
+  SUBS         r12, r12, #4         ; j-=4
+  SMLATT       r14, r6, r8, r14     ; sum = MAC16_16(sum, x_1, y_1)
+  LDRGE        r6, [r4], #4
+  SMLABB       r14, r7, r9, r14     ; sum = MAC16_16(sum, x_2, y_2)
+  LDRGE        r8, [r5], #4
+  SMLATT       r14, r7, r9, r14     ; sum = MAC16_16(sum, x_3, y_3)
+  LDRGE        r7, [r4], #4
+  LDRGE        r9, [r5], #4
+  BGE celt_pitch_xcorr_edsp_process1a_loop4
+celt_pitch_xcorr_edsp_process1a_loop_done
+  ADDS         r12, r12, #2
+  LDRGE        r6, [r4], #4
+  LDRGE        r8, [r5], #4
+  ; Stall
+  SMLABBGE     r14, r6, r8, r14     ; sum = MAC16_16(sum, x_0, y_0)
+  SUBGE        r12, r12, #2
+  SMLATTGE     r14, r6, r8, r14     ; sum = MAC16_16(sum, x_1, y_1)
+  ADDS         r12, r12, #1
+  LDRHGE       r6, [r4], #2
+  LDRHGE       r8, [r5], #2
+  ; Stall
+  SMLABBGE     r14, r6, r8, r14     ; sum = MAC16_16(sum, *x, *y)
+  ; maxcorr = max(maxcorr, sum)
+  CMP          r0, r14
+  ; xcorr[i] = sum
+  STR          r14, [r2], #4
+  MOVLT        r0, r14
+celt_pitch_xcorr_edsp_done
+  LDMFD        sp!, {r4-r11, pc}
+  ENDP
+
+ENDIF
+
+END
diff --git a/third_party/opus/src/celt/arm/fft_arm.h b/third_party/opus/src/celt/arm/fft_arm.h
new file mode 100644
index 0000000..0cb55d8e
--- /dev/null
+++ b/third_party/opus/src/celt/arm/fft_arm.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2015 Xiph.Org Foundation
+   Written by Viswanath Puttagunta */
+/**
+   @file fft_arm.h
+   @brief ARM Neon Intrinsic optimizations for fft using NE10 library
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#if !defined(FFT_ARM_H)
+#define FFT_ARM_H
+
+#include "config.h"
+#include "kiss_fft.h"
+
+#if defined(HAVE_ARM_NE10)
+
+int opus_fft_alloc_arm_neon(kiss_fft_state *st);
+void opus_fft_free_arm_neon(kiss_fft_state *st);
+
+void opus_fft_neon(const kiss_fft_state *st,
+                   const kiss_fft_cpx *fin,
+                   kiss_fft_cpx *fout);
+
+void opus_ifft_neon(const kiss_fft_state *st,
+                    const kiss_fft_cpx *fin,
+                    kiss_fft_cpx *fout);
+
+#if !defined(OPUS_HAVE_RTCD)
+#define OVERRIDE_OPUS_FFT (1)
+
+#define opus_fft_alloc_arch(_st, arch) \
+   ((void)(arch), opus_fft_alloc_arm_neon(_st))
+
+#define opus_fft_free_arch(_st, arch) \
+   ((void)(arch), opus_fft_free_arm_neon(_st))
+
+#define opus_fft(_st, _fin, _fout, arch) \
+   ((void)(arch), opus_fft_neon(_st, _fin, _fout))
+
+#define opus_ifft(_st, _fin, _fout, arch) \
+   ((void)(arch), opus_ifft_neon(_st, _fin, _fout))
+
+#endif /* OPUS_HAVE_RTCD */
+
+#endif /* HAVE_ARM_NE10 */
+
+#endif
diff --git a/third_party/opus/src/celt/arm/fixed_arm64.h b/third_party/opus/src/celt/arm/fixed_arm64.h
new file mode 100644
index 0000000..c6fbd3d
--- /dev/null
+++ b/third_party/opus/src/celt/arm/fixed_arm64.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2015 Vidyo */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_ARM64_H
+#define FIXED_ARM64_H
+
+#include <arm_neon.h>
+
+#undef SIG2WORD16
+#define SIG2WORD16(x) (vqmovns_s32(PSHR32((x), SIG_SHIFT)))
+
+#endif
diff --git a/third_party/opus/src/celt/arm/fixed_armv4.h b/third_party/opus/src/celt/arm/fixed_armv4.h
new file mode 100644
index 0000000..efb3b189
--- /dev/null
+++ b/third_party/opus/src/celt/arm/fixed_armv4.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2013 Xiph.Org Foundation and contributors */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_ARMv4_H
+#define FIXED_ARMv4_H
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q16
+static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b)
+{
+  unsigned rd_lo;
+  int rd_hi;
+  __asm__(
+      "#MULT16_32_Q16\n\t"
+      "smull %0, %1, %2, %3\n\t"
+      : "=&r"(rd_lo), "=&r"(rd_hi)
+      : "%r"(b),"r"(a<<16)
+  );
+  return rd_hi;
+}
+#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv4(a, b))
+
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q15
+static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b)
+{
+  unsigned rd_lo;
+  int rd_hi;
+  __asm__(
+      "#MULT16_32_Q15\n\t"
+      "smull %0, %1, %2, %3\n\t"
+      : "=&r"(rd_lo), "=&r"(rd_hi)
+      : "%r"(b), "r"(a<<16)
+  );
+  /*We intentionally don't OR in the high bit of rd_lo for speed.*/
+  return rd_hi<<1;
+}
+#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b))
+
+
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+    b must fit in 31 bits.
+    Result fits in 32 bits. */
+#undef MAC16_32_Q15
+#define MAC16_32_Q15(c, a, b) ADD32(c, MULT16_32_Q15(a, b))
+
+/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add.
+    Result fits in 32 bits. */
+#undef MAC16_32_Q16
+#define MAC16_32_Q16(c, a, b) ADD32(c, MULT16_32_Q16(a, b))
+
+/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
+#undef MULT32_32_Q31
+#define MULT32_32_Q31(a,b) (opus_val32)((((opus_int64)(a)) * ((opus_int64)(b)))>>31)
+
+#endif
diff --git a/third_party/opus/src/celt/arm/fixed_armv5e.h b/third_party/opus/src/celt/arm/fixed_armv5e.h
new file mode 100644
index 0000000..36a6321
--- /dev/null
+++ b/third_party/opus/src/celt/arm/fixed_armv5e.h
@@ -0,0 +1,151 @@
+/* Copyright (C) 2007-2009 Xiph.Org Foundation
+   Copyright (C) 2003-2008 Jean-Marc Valin
+   Copyright (C) 2007-2008 CSIRO
+   Copyright (C) 2013      Parrot */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_ARMv5E_H
+#define FIXED_ARMv5E_H
+
+#include "fixed_armv4.h"
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q16
+static OPUS_INLINE opus_val32 MULT16_32_Q16_armv5e(opus_val16 a, opus_val32 b)
+{
+  int res;
+  __asm__(
+      "#MULT16_32_Q16\n\t"
+      "smulwb %0, %1, %2\n\t"
+      : "=r"(res)
+      : "r"(b),"r"(a)
+  );
+  return res;
+}
+#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv5e(a, b))
+
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q15
+static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b)
+{
+  int res;
+  __asm__(
+      "#MULT16_32_Q15\n\t"
+      "smulwb %0, %1, %2\n\t"
+      : "=r"(res)
+      : "r"(b), "r"(a)
+  );
+  return res<<1;
+}
+#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b))
+
+
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+    b must fit in 31 bits.
+    Result fits in 32 bits. */
+#undef MAC16_32_Q15
+static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a,
+ opus_val32 b)
+{
+  int res;
+  __asm__(
+      "#MAC16_32_Q15\n\t"
+      "smlawb %0, %1, %2, %3;\n"
+      : "=r"(res)
+      : "r"(b<<1), "r"(a), "r"(c)
+  );
+  return res;
+}
+#define MAC16_32_Q15(c, a, b) (MAC16_32_Q15_armv5e(c, a, b))
+
+/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add.
+    Result fits in 32 bits. */
+#undef MAC16_32_Q16
+static OPUS_INLINE opus_val32 MAC16_32_Q16_armv5e(opus_val32 c, opus_val16 a,
+ opus_val32 b)
+{
+  int res;
+  __asm__(
+      "#MAC16_32_Q16\n\t"
+      "smlawb %0, %1, %2, %3;\n"
+      : "=r"(res)
+      : "r"(b), "r"(a), "r"(c)
+  );
+  return res;
+}
+#define MAC16_32_Q16(c, a, b) (MAC16_32_Q16_armv5e(c, a, b))
+
+/** 16x16 multiply-add where the result fits in 32 bits */
+#undef MAC16_16
+static OPUS_INLINE opus_val32 MAC16_16_armv5e(opus_val32 c, opus_val16 a,
+ opus_val16 b)
+{
+  int res;
+  __asm__(
+      "#MAC16_16\n\t"
+      "smlabb %0, %1, %2, %3;\n"
+      : "=r"(res)
+      : "r"(a), "r"(b), "r"(c)
+  );
+  return res;
+}
+#define MAC16_16(c, a, b) (MAC16_16_armv5e(c, a, b))
+
+/** 16x16 multiplication where the result fits in 32 bits */
+#undef MULT16_16
+static OPUS_INLINE opus_val32 MULT16_16_armv5e(opus_val16 a, opus_val16 b)
+{
+  int res;
+  __asm__(
+      "#MULT16_16\n\t"
+      "smulbb %0, %1, %2;\n"
+      : "=r"(res)
+      : "r"(a), "r"(b)
+  );
+  return res;
+}
+#define MULT16_16(a, b) (MULT16_16_armv5e(a, b))
+
+#ifdef OPUS_ARM_INLINE_MEDIA
+
+#undef SIG2WORD16
+static OPUS_INLINE opus_val16 SIG2WORD16_armv6(opus_val32 x)
+{
+   celt_sig res;
+   __asm__(
+       "#SIG2WORD16\n\t"
+       "ssat %0, #16, %1, ASR #12\n\t"
+       : "=r"(res)
+       : "r"(x+2048)
+   );
+   return EXTRACT16(res);
+}
+#define SIG2WORD16(x) (SIG2WORD16_armv6(x))
+
+#endif /* OPUS_ARM_INLINE_MEDIA */
+
+#endif
diff --git a/third_party/opus/src/celt/arm/kiss_fft_armv4.h b/third_party/opus/src/celt/arm/kiss_fft_armv4.h
new file mode 100644
index 0000000..e4faad6
--- /dev/null
+++ b/third_party/opus/src/celt/arm/kiss_fft_armv4.h
@@ -0,0 +1,121 @@
+/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+       this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_ARMv4_H
+#define KISS_FFT_ARMv4_H
+
+#if !defined(KISS_FFT_GUTS_H)
+#error "This file should only be included from _kiss_fft_guts.h"
+#endif
+
+#ifdef FIXED_POINT
+
+#undef C_MUL
+#define C_MUL(m,a,b) \
+    do{ \
+       int br__; \
+       int bi__; \
+       int tt__; \
+        __asm__ __volatile__( \
+            "#C_MUL\n\t" \
+            "ldrsh %[br], [%[bp], #0]\n\t" \
+            "ldm %[ap], {r0,r1}\n\t" \
+            "ldrsh %[bi], [%[bp], #2]\n\t" \
+            "smull %[tt], %[mi], r1, %[br]\n\t" \
+            "smlal %[tt], %[mi], r0, %[bi]\n\t" \
+            "rsb %[bi], %[bi], #0\n\t" \
+            "smull %[br], %[mr], r0, %[br]\n\t" \
+            "mov %[tt], %[tt], lsr #15\n\t" \
+            "smlal %[br], %[mr], r1, %[bi]\n\t" \
+            "orr %[mi], %[tt], %[mi], lsl #17\n\t" \
+            "mov %[br], %[br], lsr #15\n\t" \
+            "orr %[mr], %[br], %[mr], lsl #17\n\t" \
+            : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+              [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+            : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+            : "r0", "r1" \
+        ); \
+    } \
+    while(0)
+
+#undef C_MUL4
+#define C_MUL4(m,a,b) \
+    do{ \
+       int br__; \
+       int bi__; \
+       int tt__; \
+        __asm__ __volatile__( \
+            "#C_MUL4\n\t" \
+            "ldrsh %[br], [%[bp], #0]\n\t" \
+            "ldm %[ap], {r0,r1}\n\t" \
+            "ldrsh %[bi], [%[bp], #2]\n\t" \
+            "smull %[tt], %[mi], r1, %[br]\n\t" \
+            "smlal %[tt], %[mi], r0, %[bi]\n\t" \
+            "rsb %[bi], %[bi], #0\n\t" \
+            "smull %[br], %[mr], r0, %[br]\n\t" \
+            "mov %[tt], %[tt], lsr #17\n\t" \
+            "smlal %[br], %[mr], r1, %[bi]\n\t" \
+            "orr %[mi], %[tt], %[mi], lsl #15\n\t" \
+            "mov %[br], %[br], lsr #17\n\t" \
+            "orr %[mr], %[br], %[mr], lsl #15\n\t" \
+            : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+              [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+            : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+            : "r0", "r1" \
+        ); \
+    } \
+    while(0)
+
+#undef C_MULC
+#define C_MULC(m,a,b) \
+    do{ \
+       int br__; \
+       int bi__; \
+       int tt__; \
+        __asm__ __volatile__( \
+            "#C_MULC\n\t" \
+            "ldrsh %[br], [%[bp], #0]\n\t" \
+            "ldm %[ap], {r0,r1}\n\t" \
+            "ldrsh %[bi], [%[bp], #2]\n\t" \
+            "smull %[tt], %[mr], r0, %[br]\n\t" \
+            "smlal %[tt], %[mr], r1, %[bi]\n\t" \
+            "rsb %[bi], %[bi], #0\n\t" \
+            "smull %[br], %[mi], r1, %[br]\n\t" \
+            "mov %[tt], %[tt], lsr #15\n\t" \
+            "smlal %[br], %[mi], r0, %[bi]\n\t" \
+            "orr %[mr], %[tt], %[mr], lsl #17\n\t" \
+            "mov %[br], %[br], lsr #15\n\t" \
+            "orr %[mi], %[br], %[mi], lsl #17\n\t" \
+            : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+              [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+            : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+            : "r0", "r1" \
+        ); \
+    } \
+    while(0)
+
+#endif /* FIXED_POINT */
+
+#endif /* KISS_FFT_ARMv4_H */
diff --git a/third_party/opus/src/celt/arm/kiss_fft_armv5e.h b/third_party/opus/src/celt/arm/kiss_fft_armv5e.h
new file mode 100644
index 0000000..9eca183
--- /dev/null
+++ b/third_party/opus/src/celt/arm/kiss_fft_armv5e.h
@@ -0,0 +1,118 @@
+/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+       this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_ARMv5E_H
+#define KISS_FFT_ARMv5E_H
+
+#if !defined(KISS_FFT_GUTS_H)
+#error "This file should only be included from _kiss_fft_guts.h"
+#endif
+
+#ifdef FIXED_POINT
+
+#if defined(__thumb__)||defined(__thumb2__)
+#define LDRD_CONS "Q"
+#else
+#define LDRD_CONS "Uq"
+#endif
+
+#undef C_MUL
+#define C_MUL(m,a,b) \
+    do{ \
+        int mr1__; \
+        int mr2__; \
+        int mi__; \
+        long long aval__; \
+        int bval__; \
+        __asm__( \
+            "#C_MUL\n\t" \
+            "ldrd %[aval], %H[aval], %[ap]\n\t" \
+            "ldr %[bval], %[bp]\n\t" \
+            "smulwb %[mi], %H[aval], %[bval]\n\t" \
+            "smulwb %[mr1], %[aval], %[bval]\n\t" \
+            "smulwt %[mr2], %H[aval], %[bval]\n\t" \
+            "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
+            : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
+              [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+            : [ap]LDRD_CONS(a), [bp]"m"(b) \
+        ); \
+        (m).r = SHL32(SUB32(mr1__, mr2__), 1); \
+        (m).i = SHL32(mi__, 1); \
+    } \
+    while(0)
+
+#undef C_MUL4
+#define C_MUL4(m,a,b) \
+    do{ \
+        int mr1__; \
+        int mr2__; \
+        int mi__; \
+        long long aval__; \
+        int bval__; \
+        __asm__( \
+            "#C_MUL4\n\t" \
+            "ldrd %[aval], %H[aval], %[ap]\n\t" \
+            "ldr %[bval], %[bp]\n\t" \
+            "smulwb %[mi], %H[aval], %[bval]\n\t" \
+            "smulwb %[mr1], %[aval], %[bval]\n\t" \
+            "smulwt %[mr2], %H[aval], %[bval]\n\t" \
+            "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
+            : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
+              [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+            : [ap]LDRD_CONS(a), [bp]"m"(b) \
+        ); \
+        (m).r = SHR32(SUB32(mr1__, mr2__), 1); \
+        (m).i = SHR32(mi__, 1); \
+    } \
+    while(0)
+
+#undef C_MULC
+#define C_MULC(m,a,b) \
+    do{ \
+        int mr__; \
+        int mi1__; \
+        int mi2__; \
+        long long aval__; \
+        int bval__; \
+        __asm__( \
+            "#C_MULC\n\t" \
+            "ldrd %[aval], %H[aval], %[ap]\n\t" \
+            "ldr %[bval], %[bp]\n\t" \
+            "smulwb %[mr], %[aval], %[bval]\n\t" \
+            "smulwb %[mi1], %H[aval], %[bval]\n\t" \
+            "smulwt %[mi2], %[aval], %[bval]\n\t" \
+            "smlawt %[mr], %H[aval], %[bval], %[mr]\n\t" \
+            : [mr]"=r"(mr__), [mi1]"=r"(mi1__), [mi2]"=r"(mi2__), \
+              [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+            : [ap]LDRD_CONS(a), [bp]"m"(b) \
+        ); \
+        (m).r = SHL32(mr__, 1); \
+        (m).i = SHL32(SUB32(mi1__, mi2__), 1); \
+    } \
+    while(0)
+
+#endif /* FIXED_POINT */
+
+#endif /* KISS_FFT_GUTS_H */
diff --git a/third_party/opus/src/celt/arm/mdct_arm.h b/third_party/opus/src/celt/arm/mdct_arm.h
new file mode 100644
index 0000000..49cbb44
--- /dev/null
+++ b/third_party/opus/src/celt/arm/mdct_arm.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2015 Xiph.Org Foundation
+   Written by Viswanath Puttagunta */
+/**
+   @file arm_mdct.h
+   @brief ARM Neon Intrinsic optimizations for mdct using NE10 library
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(MDCT_ARM_H)
+#define MDCT_ARM_H
+
+#include "config.h"
+#include "mdct.h"
+
+#if defined(HAVE_ARM_NE10)
+/** Compute a forward MDCT and scale by 4/N, trashes the input array */
+void clt_mdct_forward_neon(const mdct_lookup *l, kiss_fft_scalar *in,
+                           kiss_fft_scalar * OPUS_RESTRICT out,
+                           const opus_val16 *window, int overlap,
+                           int shift, int stride, int arch);
+
+void clt_mdct_backward_neon(const mdct_lookup *l, kiss_fft_scalar *in,
+                            kiss_fft_scalar * OPUS_RESTRICT out,
+                            const opus_val16 *window, int overlap,
+                            int shift, int stride, int arch);
+
+#if !defined(OPUS_HAVE_RTCD)
+#define OVERRIDE_OPUS_MDCT (1)
+#define clt_mdct_forward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \
+      clt_mdct_forward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch)
+#define clt_mdct_backward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \
+      clt_mdct_backward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch)
+#endif /* OPUS_HAVE_RTCD */
+#endif /* HAVE_ARM_NE10 */
+
+#endif
diff --git a/third_party/opus/src/celt/arm/pitch_arm.h b/third_party/opus/src/celt/arm/pitch_arm.h
new file mode 100644
index 0000000..1433116
--- /dev/null
+++ b/third_party/opus/src/celt/arm/pitch_arm.h
@@ -0,0 +1,126 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(PITCH_ARM_H)
+# define PITCH_ARM_H
+
+# include "armcpu.h"
+
+# if defined(FIXED_POINT)
+
+#  if defined(OPUS_ARM_MAY_HAVE_NEON)
+opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y,
+    opus_val32 *xcorr, int len, int max_pitch);
+#  endif
+
+#  if defined(OPUS_ARM_MAY_HAVE_MEDIA)
+#   define celt_pitch_xcorr_media MAY_HAVE_EDSP(celt_pitch_xcorr)
+#  endif
+
+#  if defined(OPUS_ARM_MAY_HAVE_EDSP)
+opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y,
+    opus_val32 *xcorr, int len, int max_pitch);
+#  endif
+
+#  if defined(OPUS_HAVE_RTCD) && \
+    ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \
+     (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \
+     (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP)))
+extern opus_val32
+(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+      const opus_val16 *, opus_val32 *, int, int);
+#   define OVERRIDE_PITCH_XCORR (1)
+#   define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+  ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \
+        xcorr, len, max_pitch))
+
+#  elif defined(OPUS_ARM_PRESUME_EDSP) || \
+    defined(OPUS_ARM_PRESUME_MEDIA) || \
+    defined(OPUS_ARM_PRESUME_NEON)
+#   define OVERRIDE_PITCH_XCORR (1)
+#   define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+  ((void)(arch),PRESUME_NEON(celt_pitch_xcorr)(_x, _y, xcorr, len, max_pitch))
+
+#  endif
+
+#  if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+void xcorr_kernel_neon_fixed(
+                    const opus_val16 *x,
+                    const opus_val16 *y,
+                    opus_val32       sum[4],
+                    int              len);
+#  endif
+
+#  if defined(OPUS_HAVE_RTCD) && \
+    (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
+
+extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+                    const opus_val16 *x,
+                    const opus_val16 *y,
+                    opus_val32       sum[4],
+                    int              len);
+
+#   define OVERRIDE_XCORR_KERNEL (1)
+#   define xcorr_kernel(x, y, sum, len, arch) \
+     ((*XCORR_KERNEL_IMPL[(arch) & OPUS_ARCHMASK])(x, y, sum, len))
+
+#  elif defined(OPUS_ARM_PRESUME_NEON_INTR)
+#   define OVERRIDE_XCORR_KERNEL (1)
+#   define xcorr_kernel(x, y, sum, len, arch) \
+      ((void)arch, xcorr_kernel_neon_fixed(x, y, sum, len))
+
+#  endif
+
+#else /* Start !FIXED_POINT */
+/* Float case */
+#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y,
+                                 opus_val32 *xcorr, int len, int max_pitch);
+#endif
+
+#  if defined(OPUS_HAVE_RTCD) && \
+    (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
+extern void
+(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+      const opus_val16 *, opus_val32 *, int, int);
+
+#  define OVERRIDE_PITCH_XCORR (1)
+#  define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+  ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \
+        xcorr, len, max_pitch))
+
+#  elif defined(OPUS_ARM_PRESUME_NEON_INTR)
+
+#   define OVERRIDE_PITCH_XCORR (1)
+#   define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+   ((void)(arch),celt_pitch_xcorr_float_neon(_x, _y, xcorr, len, max_pitch))
+
+#  endif
+
+#endif /* end !FIXED_POINT */
+
+#endif
diff --git a/third_party/opus/src/celt/bands.c b/third_party/opus/src/celt/bands.c
new file mode 100644
index 0000000..87eaa6c0
--- /dev/null
+++ b/third_party/opus/src/celt/bands.c
@@ -0,0 +1,1529 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Copyright (c) 2008-2009 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "bands.h"
+#include "modes.h"
+#include "vq.h"
+#include "cwrs.h"
+#include "stack_alloc.h"
+#include "os_support.h"
+#include "mathops.h"
+#include "rate.h"
+#include "quant_bands.h"
+#include "pitch.h"
+
+int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev)
+{
+   int i;
+   for (i=0;i<N;i++)
+   {
+      if (val < thresholds[i])
+         break;
+   }
+   if (i>prev && val < thresholds[prev]+hysteresis[prev])
+      i=prev;
+   if (i<prev && val > thresholds[prev-1]-hysteresis[prev-1])
+      i=prev;
+   return i;
+}
+
+opus_uint32 celt_lcg_rand(opus_uint32 seed)
+{
+   return 1664525 * seed + 1013904223;
+}
+
+/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness
+   with this approximation is important because it has an impact on the bit allocation */
+static opus_int16 bitexact_cos(opus_int16 x)
+{
+   opus_int32 tmp;
+   opus_int16 x2;
+   tmp = (4096+((opus_int32)(x)*(x)))>>13;
+   celt_assert(tmp<=32767);
+   x2 = tmp;
+   x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2)))));
+   celt_assert(x2<=32766);
+   return 1+x2;
+}
+
+static int bitexact_log2tan(int isin,int icos)
+{
+   int lc;
+   int ls;
+   lc=EC_ILOG(icos);
+   ls=EC_ILOG(isin);
+   icos<<=15-lc;
+   isin<<=15-ls;
+   return (ls-lc)*(1<<11)
+         +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932)
+         -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932);
+}
+
+#ifdef FIXED_POINT
+/* Compute the amplitude (sqrt energy) in each of the bands */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM)
+{
+   int i, c, N;
+   const opus_int16 *eBands = m->eBands;
+   N = m->shortMdctSize<<LM;
+   c=0; do {
+      for (i=0;i<end;i++)
+      {
+         int j;
+         opus_val32 maxval=0;
+         opus_val32 sum = 0;
+
+         maxval = celt_maxabs32(&X[c*N+(eBands[i]<<LM)], (eBands[i+1]-eBands[i])<<LM);
+         if (maxval > 0)
+         {
+            int shift = celt_ilog2(maxval) - 14 + (((m->logN[i]>>BITRES)+LM+1)>>1);
+            j=eBands[i]<<LM;
+            if (shift>0)
+            {
+               do {
+                  sum = MAC16_16(sum, EXTRACT16(SHR32(X[j+c*N],shift)),
+                        EXTRACT16(SHR32(X[j+c*N],shift)));
+               } while (++j<eBands[i+1]<<LM);
+            } else {
+               do {
+                  sum = MAC16_16(sum, EXTRACT16(SHL32(X[j+c*N],-shift)),
+                        EXTRACT16(SHL32(X[j+c*N],-shift)));
+               } while (++j<eBands[i+1]<<LM);
+            }
+            /* We're adding one here to ensure the normalized band isn't larger than unity norm */
+            bandE[i+c*m->nbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift);
+         } else {
+            bandE[i+c*m->nbEBands] = EPSILON;
+         }
+         /*printf ("%f ", bandE[i+c*m->nbEBands]);*/
+      }
+   } while (++c<C);
+   /*printf ("\n");*/
+}
+
+/* Normalise each band such that the energy is one. */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M)
+{
+   int i, c, N;
+   const opus_int16 *eBands = m->eBands;
+   N = M*m->shortMdctSize;
+   c=0; do {
+      i=0; do {
+         opus_val16 g;
+         int j,shift;
+         opus_val16 E;
+         shift = celt_zlog2(bandE[i+c*m->nbEBands])-13;
+         E = VSHR32(bandE[i+c*m->nbEBands], shift);
+         g = EXTRACT16(celt_rcp(SHL32(E,3)));
+         j=M*eBands[i]; do {
+            X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g);
+         } while (++j<M*eBands[i+1]);
+      } while (++i<end);
+   } while (++c<C);
+}
+
+#else /* FIXED_POINT */
+/* Compute the amplitude (sqrt energy) in each of the bands */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM)
+{
+   int i, c, N;
+   const opus_int16 *eBands = m->eBands;
+   N = m->shortMdctSize<<LM;
+   c=0; do {
+      for (i=0;i<end;i++)
+      {
+         opus_val32 sum;
+         sum = 1e-27f + celt_inner_prod_c(&X[c*N+(eBands[i]<<LM)], &X[c*N+(eBands[i]<<LM)], (eBands[i+1]-eBands[i])<<LM);
+         bandE[i+c*m->nbEBands] = celt_sqrt(sum);
+         /*printf ("%f ", bandE[i+c*m->nbEBands]);*/
+      }
+   } while (++c<C);
+   /*printf ("\n");*/
+}
+
+/* Normalise each band such that the energy is one. */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M)
+{
+   int i, c, N;
+   const opus_int16 *eBands = m->eBands;
+   N = M*m->shortMdctSize;
+   c=0; do {
+      for (i=0;i<end;i++)
+      {
+         int j;
+         opus_val16 g = 1.f/(1e-27f+bandE[i+c*m->nbEBands]);
+         for (j=M*eBands[i];j<M*eBands[i+1];j++)
+            X[j+c*N] = freq[j+c*N]*g;
+      }
+   } while (++c<C);
+}
+
+#endif /* FIXED_POINT */
+
+/* De-normalise the energy to produce the synthesis from the unit-energy bands */
+void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
+      celt_sig * OPUS_RESTRICT freq, const opus_val16 *bandLogE, int start,
+      int end, int M, int downsample, int silence)
+{
+   int i, N;
+   int bound;
+   celt_sig * OPUS_RESTRICT f;
+   const celt_norm * OPUS_RESTRICT x;
+   const opus_int16 *eBands = m->eBands;
+   N = M*m->shortMdctSize;
+   bound = M*eBands[end];
+   if (downsample!=1)
+      bound = IMIN(bound, N/downsample);
+   if (silence)
+   {
+      bound = 0;
+      start = end = 0;
+   }
+   f = freq;
+   x = X+M*eBands[start];
+   for (i=0;i<M*eBands[start];i++)
+      *f++ = 0;
+   for (i=start;i<end;i++)
+   {
+      int j, band_end;
+      opus_val16 g;
+      opus_val16 lg;
+#ifdef FIXED_POINT
+      int shift;
+#endif
+      j=M*eBands[i];
+      band_end = M*eBands[i+1];
+      lg = ADD16(bandLogE[i], SHL16((opus_val16)eMeans[i],6));
+#ifndef FIXED_POINT
+      g = celt_exp2(lg);
+#else
+      /* Handle the integer part of the log energy */
+      shift = 16-(lg>>DB_SHIFT);
+      if (shift>31)
+      {
+         shift=0;
+         g=0;
+      } else {
+         /* Handle the fractional part. */
+         g = celt_exp2_frac(lg&((1<<DB_SHIFT)-1));
+      }
+      /* Handle extreme gains with negative shift. */
+      if (shift<0)
+      {
+         /* For shift < -2 we'd be likely to overflow, so we're capping
+               the gain here. This shouldn't happen unless the bitstream is
+               already corrupted. */
+         if (shift < -2)
+         {
+            g = 32767;
+            shift = -2;
+         }
+         do {
+            *f++ = SHL32(MULT16_16(*x++, g), -shift);
+         } while (++j<band_end);
+      } else
+#endif
+         /* Be careful of the fixed-point "else" just above when changing this code */
+         do {
+            *f++ = SHR32(MULT16_16(*x++, g), shift);
+         } while (++j<band_end);
+   }
+   celt_assert(start <= end);
+   OPUS_CLEAR(&freq[bound], N-bound);
+}
+
+/* This prevents energy collapse for transients with multiple short MDCTs */
+void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_masks, int LM, int C, int size,
+      int start, int end, const opus_val16 *logE, const opus_val16 *prev1logE,
+      const opus_val16 *prev2logE, const int *pulses, opus_uint32 seed, int arch)
+{
+   int c, i, j, k;
+   for (i=start;i<end;i++)
+   {
+      int N0;
+      opus_val16 thresh, sqrt_1;
+      int depth;
+#ifdef FIXED_POINT
+      int shift;
+      opus_val32 thresh32;
+#endif
+
+      N0 = m->eBands[i+1]-m->eBands[i];
+      /* depth in 1/8 bits */
+      celt_assert(pulses[i]>=0);
+      depth = celt_udiv(1+pulses[i], (m->eBands[i+1]-m->eBands[i]))>>LM;
+
+#ifdef FIXED_POINT
+      thresh32 = SHR32(celt_exp2(-SHL16(depth, 10-BITRES)),1);
+      thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,thresh32));
+      {
+         opus_val32 t;
+         t = N0<<LM;
+         shift = celt_ilog2(t)>>1;
+         t = SHL32(t, (7-shift)<<1);
+         sqrt_1 = celt_rsqrt_norm(t);
+      }
+#else
+      thresh = .5f*celt_exp2(-.125f*depth);
+      sqrt_1 = celt_rsqrt(N0<<LM);
+#endif
+
+      c=0; do
+      {
+         celt_norm *X;
+         opus_val16 prev1;
+         opus_val16 prev2;
+         opus_val32 Ediff;
+         opus_val16 r;
+         int renormalize=0;
+         prev1 = prev1logE[c*m->nbEBands+i];
+         prev2 = prev2logE[c*m->nbEBands+i];
+         if (C==1)
+         {
+            prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]);
+            prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]);
+         }
+         Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2));
+         Ediff = MAX32(0, Ediff);
+
+#ifdef FIXED_POINT
+         if (Ediff < 16384)
+         {
+            opus_val32 r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)),1);
+            r = 2*MIN16(16383,r32);
+         } else {
+            r = 0;
+         }
+         if (LM==3)
+            r = MULT16_16_Q14(23170, MIN32(23169, r));
+         r = SHR16(MIN16(thresh, r),1);
+         r = SHR32(MULT16_16_Q15(sqrt_1, r),shift);
+#else
+         /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because
+            short blocks don't have the same energy as long */
+         r = 2.f*celt_exp2(-Ediff);
+         if (LM==3)
+            r *= 1.41421356f;
+         r = MIN16(thresh, r);
+         r = r*sqrt_1;
+#endif
+         X = X_+c*size+(m->eBands[i]<<LM);
+         for (k=0;k<1<<LM;k++)
+         {
+            /* Detect collapse */
+            if (!(collapse_masks[i*C+c]&1<<k))
+            {
+               /* Fill with noise */
+               for (j=0;j<N0;j++)
+               {
+                  seed = celt_lcg_rand(seed);
+                  X[(j<<LM)+k] = (seed&0x8000 ? r : -r);
+               }
+               renormalize = 1;
+            }
+         }
+         /* We just added some energy, so we need to renormalise */
+         if (renormalize)
+            renormalise_vector(X, N0<<LM, Q15ONE, arch);
+      } while (++c<C);
+   }
+}
+
+static void intensity_stereo(const CELTMode *m, celt_norm * OPUS_RESTRICT X, const celt_norm * OPUS_RESTRICT Y, const celt_ener *bandE, int bandID, int N)
+{
+   int i = bandID;
+   int j;
+   opus_val16 a1, a2;
+   opus_val16 left, right;
+   opus_val16 norm;
+#ifdef FIXED_POINT
+   int shift = celt_zlog2(MAX32(bandE[i], bandE[i+m->nbEBands]))-13;
+#endif
+   left = VSHR32(bandE[i],shift);
+   right = VSHR32(bandE[i+m->nbEBands],shift);
+   norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right));
+   a1 = DIV32_16(SHL32(EXTEND32(left),14),norm);
+   a2 = DIV32_16(SHL32(EXTEND32(right),14),norm);
+   for (j=0;j<N;j++)
+   {
+      celt_norm r, l;
+      l = X[j];
+      r = Y[j];
+      X[j] = EXTRACT16(SHR32(MAC16_16(MULT16_16(a1, l), a2, r), 14));
+      /* Side is not encoded, no need to calculate */
+   }
+}
+
+static void stereo_split(celt_norm * OPUS_RESTRICT X, celt_norm * OPUS_RESTRICT Y, int N)
+{
+   int j;
+   for (j=0;j<N;j++)
+   {
+      opus_val32 r, l;
+      l = MULT16_16(QCONST16(.70710678f, 15), X[j]);
+      r = MULT16_16(QCONST16(.70710678f, 15), Y[j]);
+      X[j] = EXTRACT16(SHR32(ADD32(l, r), 15));
+      Y[j] = EXTRACT16(SHR32(SUB32(r, l), 15));
+   }
+}
+
+static void stereo_merge(celt_norm * OPUS_RESTRICT X, celt_norm * OPUS_RESTRICT Y, opus_val16 mid, int N, int arch)
+{
+   int j;
+   opus_val32 xp=0, side=0;
+   opus_val32 El, Er;
+   opus_val16 mid2;
+#ifdef FIXED_POINT
+   int kl, kr;
+#endif
+   opus_val32 t, lgain, rgain;
+
+   /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */
+   dual_inner_prod(Y, X, Y, N, &xp, &side, arch);
+   /* Compensating for the mid normalization */
+   xp = MULT16_32_Q15(mid, xp);
+   /* mid and side are in Q15, not Q14 like X and Y */
+   mid2 = SHR16(mid, 1);
+   El = MULT16_16(mid2, mid2) + side - 2*xp;
+   Er = MULT16_16(mid2, mid2) + side + 2*xp;
+   if (Er < QCONST32(6e-4f, 28) || El < QCONST32(6e-4f, 28))
+   {
+      OPUS_COPY(Y, X, N);
+      return;
+   }
+
+#ifdef FIXED_POINT
+   kl = celt_ilog2(El)>>1;
+   kr = celt_ilog2(Er)>>1;
+#endif
+   t = VSHR32(El, (kl-7)<<1);
+   lgain = celt_rsqrt_norm(t);
+   t = VSHR32(Er, (kr-7)<<1);
+   rgain = celt_rsqrt_norm(t);
+
+#ifdef FIXED_POINT
+   if (kl < 7)
+      kl = 7;
+   if (kr < 7)
+      kr = 7;
+#endif
+
+   for (j=0;j<N;j++)
+   {
+      celt_norm r, l;
+      /* Apply mid scaling (side is already scaled) */
+      l = MULT16_16_P15(mid, X[j]);
+      r = Y[j];
+      X[j] = EXTRACT16(PSHR32(MULT16_16(lgain, SUB16(l,r)), kl+1));
+      Y[j] = EXTRACT16(PSHR32(MULT16_16(rgain, ADD16(l,r)), kr+1));
+   }
+}
+
+/* Decide whether we should spread the pulses in the current frame */
+int spreading_decision(const CELTMode *m, const celt_norm *X, int *average,
+      int last_decision, int *hf_average, int *tapset_decision, int update_hf,
+      int end, int C, int M)
+{
+   int i, c, N0;
+   int sum = 0, nbBands=0;
+   const opus_int16 * OPUS_RESTRICT eBands = m->eBands;
+   int decision;
+   int hf_sum=0;
+
+   celt_assert(end>0);
+
+   N0 = M*m->shortMdctSize;
+
+   if (M*(eBands[end]-eBands[end-1]) <= 8)
+      return SPREAD_NONE;
+   c=0; do {
+      for (i=0;i<end;i++)
+      {
+         int j, N, tmp=0;
+         int tcount[3] = {0,0,0};
+         const celt_norm * OPUS_RESTRICT x = X+M*eBands[i]+c*N0;
+         N = M*(eBands[i+1]-eBands[i]);
+         if (N<=8)
+            continue;
+         /* Compute rough CDF of |x[j]| */
+         for (j=0;j<N;j++)
+         {
+            opus_val32 x2N; /* Q13 */
+
+            x2N = MULT16_16(MULT16_16_Q15(x[j], x[j]), N);
+            if (x2N < QCONST16(0.25f,13))
+               tcount[0]++;
+            if (x2N < QCONST16(0.0625f,13))
+               tcount[1]++;
+            if (x2N < QCONST16(0.015625f,13))
+               tcount[2]++;
+         }
+
+         /* Only include four last bands (8 kHz and up) */
+         if (i>m->nbEBands-4)
+            hf_sum += celt_udiv(32*(tcount[1]+tcount[0]), N);
+         tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N);
+         sum += tmp*256;
+         nbBands++;
+      }
+   } while (++c<C);
+
+   if (update_hf)
+   {
+      if (hf_sum)
+         hf_sum = celt_udiv(hf_sum, C*(4-m->nbEBands+end));
+      *hf_average = (*hf_average+hf_sum)>>1;
+      hf_sum = *hf_average;
+      if (*tapset_decision==2)
+         hf_sum += 4;
+      else if (*tapset_decision==0)
+         hf_sum -= 4;
+      if (hf_sum > 22)
+         *tapset_decision=2;
+      else if (hf_sum > 18)
+         *tapset_decision=1;
+      else
+         *tapset_decision=0;
+   }
+   /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/
+   celt_assert(nbBands>0); /* end has to be non-zero */
+   celt_assert(sum>=0);
+   sum = celt_udiv(sum, nbBands);
+   /* Recursive averaging */
+   sum = (sum+*average)>>1;
+   *average = sum;
+   /* Hysteresis */
+   sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2;
+   if (sum < 80)
+   {
+      decision = SPREAD_AGGRESSIVE;
+   } else if (sum < 256)
+   {
+      decision = SPREAD_NORMAL;
+   } else if (sum < 384)
+   {
+      decision = SPREAD_LIGHT;
+   } else {
+      decision = SPREAD_NONE;
+   }
+#ifdef FUZZING
+   decision = rand()&0x3;
+   *tapset_decision=rand()%3;
+#endif
+   return decision;
+}
+
+/* Indexing table for converting from natural Hadamard to ordery Hadamard
+   This is essentially a bit-reversed Gray, on top of which we've added
+   an inversion of the order because we want the DC at the end rather than
+   the beginning. The lines are for N=2, 4, 8, 16 */
+static const int ordery_table[] = {
+       1,  0,
+       3,  0,  2,  1,
+       7,  0,  4,  3,  6,  1,  5,  2,
+      15,  0,  8,  7, 12,  3, 11,  4, 14,  1,  9,  6, 13,  2, 10,  5,
+};
+
+static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard)
+{
+   int i,j;
+   VARDECL(celt_norm, tmp);
+   int N;
+   SAVE_STACK;
+   N = N0*stride;
+   ALLOC(tmp, N, celt_norm);
+   celt_assert(stride>0);
+   if (hadamard)
+   {
+      const int *ordery = ordery_table+stride-2;
+      for (i=0;i<stride;i++)
+      {
+         for (j=0;j<N0;j++)
+            tmp[ordery[i]*N0+j] = X[j*stride+i];
+      }
+   } else {
+      for (i=0;i<stride;i++)
+         for (j=0;j<N0;j++)
+            tmp[i*N0+j] = X[j*stride+i];
+   }
+   OPUS_COPY(X, tmp, N);
+   RESTORE_STACK;
+}
+
+static void interleave_hadamard(celt_norm *X, int N0, int stride, int hadamard)
+{
+   int i,j;
+   VARDECL(celt_norm, tmp);
+   int N;
+   SAVE_STACK;
+   N = N0*stride;
+   ALLOC(tmp, N, celt_norm);
+   if (hadamard)
+   {
+      const int *ordery = ordery_table+stride-2;
+      for (i=0;i<stride;i++)
+         for (j=0;j<N0;j++)
+            tmp[j*stride+i] = X[ordery[i]*N0+j];
+   } else {
+      for (i=0;i<stride;i++)
+         for (j=0;j<N0;j++)
+            tmp[j*stride+i] = X[i*N0+j];
+   }
+   OPUS_COPY(X, tmp, N);
+   RESTORE_STACK;
+}
+
+void haar1(celt_norm *X, int N0, int stride)
+{
+   int i, j;
+   N0 >>= 1;
+   for (i=0;i<stride;i++)
+      for (j=0;j<N0;j++)
+      {
+         opus_val32 tmp1, tmp2;
+         tmp1 = MULT16_16(QCONST16(.70710678f,15), X[stride*2*j+i]);
+         tmp2 = MULT16_16(QCONST16(.70710678f,15), X[stride*(2*j+1)+i]);
+         X[stride*2*j+i] = EXTRACT16(PSHR32(ADD32(tmp1, tmp2), 15));
+         X[stride*(2*j+1)+i] = EXTRACT16(PSHR32(SUB32(tmp1, tmp2), 15));
+      }
+}
+
+static int compute_qn(int N, int b, int offset, int pulse_cap, int stereo)
+{
+   static const opus_int16 exp2_table8[8] =
+      {16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048};
+   int qn, qb;
+   int N2 = 2*N-1;
+   if (stereo && N==2)
+      N2--;
+   /* The upper limit ensures that in a stereo split with itheta==16384, we'll
+       always have enough bits left over to code at least one pulse in the
+       side; otherwise it would collapse, since it doesn't get folded. */
+   qb = celt_sudiv(b+N2*offset, N2);
+   qb = IMIN(b-pulse_cap-(4<<BITRES), qb);
+
+   qb = IMIN(8<<BITRES, qb);
+
+   if (qb<(1<<BITRES>>1)) {
+      qn = 1;
+   } else {
+      qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES));
+      qn = (qn+1)>>1<<1;
+   }
+   celt_assert(qn <= 256);
+   return qn;
+}
+
+struct band_ctx {
+   int encode;
+   const CELTMode *m;
+   int i;
+   int intensity;
+   int spread;
+   int tf_change;
+   ec_ctx *ec;
+   opus_int32 remaining_bits;
+   const celt_ener *bandE;
+   opus_uint32 seed;
+   int arch;
+};
+
+struct split_ctx {
+   int inv;
+   int imid;
+   int iside;
+   int delta;
+   int itheta;
+   int qalloc;
+};
+
+static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
+      celt_norm *X, celt_norm *Y, int N, int *b, int B, int B0,
+      int LM,
+      int stereo, int *fill)
+{
+   int qn;
+   int itheta=0;
+   int delta;
+   int imid, iside;
+   int qalloc;
+   int pulse_cap;
+   int offset;
+   opus_int32 tell;
+   int inv=0;
+   int encode;
+   const CELTMode *m;
+   int i;
+   int intensity;
+   ec_ctx *ec;
+   const celt_ener *bandE;
+
+   encode = ctx->encode;
+   m = ctx->m;
+   i = ctx->i;
+   intensity = ctx->intensity;
+   ec = ctx->ec;
+   bandE = ctx->bandE;
+
+   /* Decide on the resolution to give to the split parameter theta */
+   pulse_cap = m->logN[i]+LM*(1<<BITRES);
+   offset = (pulse_cap>>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET);
+   qn = compute_qn(N, *b, offset, pulse_cap, stereo);
+   if (stereo && i>=intensity)
+      qn = 1;
+   if (encode)
+   {
+      /* theta is the atan() of the ratio between the (normalized)
+         side and mid. With just that parameter, we can re-scale both
+         mid and side because we know that 1) they have unit norm and
+         2) they are orthogonal. */
+      itheta = stereo_itheta(X, Y, stereo, N, ctx->arch);
+   }
+   tell = ec_tell_frac(ec);
+   if (qn!=1)
+   {
+      if (encode)
+         itheta = (itheta*(opus_int32)qn+8192)>>14;
+
+      /* Entropy coding of the angle. We use a uniform pdf for the
+         time split, a step for stereo, and a triangular one for the rest. */
+      if (stereo && N>2)
+      {
+         int p0 = 3;
+         int x = itheta;
+         int x0 = qn/2;
+         int ft = p0*(x0+1) + x0;
+         /* Use a probability of p0 up to itheta=8192 and then use 1 after */
+         if (encode)
+         {
+            ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft);
+         } else {
+            int fs;
+            fs=ec_decode(ec,ft);
+            if (fs<(x0+1)*p0)
+               x=fs/p0;
+            else
+               x=x0+1+(fs-(x0+1)*p0);
+            ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft);
+            itheta = x;
+         }
+      } else if (B0>1 || stereo) {
+         /* Uniform pdf */
+         if (encode)
+            ec_enc_uint(ec, itheta, qn+1);
+         else
+            itheta = ec_dec_uint(ec, qn+1);
+      } else {
+         int fs=1, ft;
+         ft = ((qn>>1)+1)*((qn>>1)+1);
+         if (encode)
+         {
+            int fl;
+
+            fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta;
+            fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 :
+             ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1);
+
+            ec_encode(ec, fl, fl+fs, ft);
+         } else {
+            /* Triangular pdf */
+            int fl=0;
+            int fm;
+            fm = ec_decode(ec, ft);
+
+            if (fm < ((qn>>1)*((qn>>1) + 1)>>1))
+            {
+               itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1;
+               fs = itheta + 1;
+               fl = itheta*(itheta + 1)>>1;
+            }
+            else
+            {
+               itheta = (2*(qn + 1)
+                - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1;
+               fs = qn + 1 - itheta;
+               fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1);
+            }
+
+            ec_dec_update(ec, fl, fl+fs, ft);
+         }
+      }
+      celt_assert(itheta>=0);
+      itheta = celt_udiv((opus_int32)itheta*16384, qn);
+      if (encode && stereo)
+      {
+         if (itheta==0)
+            intensity_stereo(m, X, Y, bandE, i, N);
+         else
+            stereo_split(X, Y, N);
+      }
+      /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate.
+               Let's do that at higher complexity */
+   } else if (stereo) {
+      if (encode)
+      {
+         inv = itheta > 8192;
+         if (inv)
+         {
+            int j;
+            for (j=0;j<N;j++)
+               Y[j] = -Y[j];
+         }
+         intensity_stereo(m, X, Y, bandE, i, N);
+      }
+      if (*b>2<<BITRES && ctx->remaining_bits > 2<<BITRES)
+      {
+         if (encode)
+            ec_enc_bit_logp(ec, inv, 2);
+         else
+            inv = ec_dec_bit_logp(ec, 2);
+      } else
+         inv = 0;
+      itheta = 0;
+   }
+   qalloc = ec_tell_frac(ec) - tell;
+   *b -= qalloc;
+
+   if (itheta == 0)
+   {
+      imid = 32767;
+      iside = 0;
+      *fill &= (1<<B)-1;
+      delta = -16384;
+   } else if (itheta == 16384)
+   {
+      imid = 0;
+      iside = 32767;
+      *fill &= ((1<<B)-1)<<B;
+      delta = 16384;
+   } else {
+      imid = bitexact_cos((opus_int16)itheta);
+      iside = bitexact_cos((opus_int16)(16384-itheta));
+      /* This is the mid vs side allocation that minimizes squared error
+         in that band. */
+      delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid));
+   }
+
+   sctx->inv = inv;
+   sctx->imid = imid;
+   sctx->iside = iside;
+   sctx->delta = delta;
+   sctx->itheta = itheta;
+   sctx->qalloc = qalloc;
+}
+static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b,
+      celt_norm *lowband_out)
+{
+#ifdef RESYNTH
+   int resynth = 1;
+#else
+   int resynth = !ctx->encode;
+#endif
+   int c;
+   int stereo;
+   celt_norm *x = X;
+   int encode;
+   ec_ctx *ec;
+
+   encode = ctx->encode;
+   ec = ctx->ec;
+
+   stereo = Y != NULL;
+   c=0; do {
+      int sign=0;
+      if (ctx->remaining_bits>=1<<BITRES)
+      {
+         if (encode)
+         {
+            sign = x[0]<0;
+            ec_enc_bits(ec, sign, 1);
+         } else {
+            sign = ec_dec_bits(ec, 1);
+         }
+         ctx->remaining_bits -= 1<<BITRES;
+         b-=1<<BITRES;
+      }
+      if (resynth)
+         x[0] = sign ? -NORM_SCALING : NORM_SCALING;
+      x = Y;
+   } while (++c<1+stereo);
+   if (lowband_out)
+      lowband_out[0] = SHR16(X[0],4);
+   return 1;
+}
+
+/* This function is responsible for encoding and decoding a mono partition.
+   It can split the band in two and transmit the energy difference with
+   the two half-bands. It can be called recursively so bands can end up being
+   split in 8 parts. */
+static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X,
+      int N, int b, int B, celt_norm *lowband,
+      int LM,
+      opus_val16 gain, int fill)
+{
+   const unsigned char *cache;
+   int q;
+   int curr_bits;
+   int imid=0, iside=0;
+   int B0=B;
+   opus_val16 mid=0, side=0;
+   unsigned cm=0;
+#ifdef RESYNTH
+   int resynth = 1;
+#else
+   int resynth = !ctx->encode;
+#endif
+   celt_norm *Y=NULL;
+   int encode;
+   const CELTMode *m;
+   int i;
+   int spread;
+   ec_ctx *ec;
+
+   encode = ctx->encode;
+   m = ctx->m;
+   i = ctx->i;
+   spread = ctx->spread;
+   ec = ctx->ec;
+
+   /* If we need 1.5 more bit than we can produce, split the band in two. */
+   cache = m->cache.bits + m->cache.index[(LM+1)*m->nbEBands+i];
+   if (LM != -1 && b > cache[cache[0]]+12 && N>2)
+   {
+      int mbits, sbits, delta;
+      int itheta;
+      int qalloc;
+      struct split_ctx sctx;
+      celt_norm *next_lowband2=NULL;
+      opus_int32 rebalance;
+
+      N >>= 1;
+      Y = X+N;
+      LM -= 1;
+      if (B==1)
+         fill = (fill&1)|(fill<<1);
+      B = (B+1)>>1;
+
+      compute_theta(ctx, &sctx, X, Y, N, &b, B, B0,
+            LM, 0, &fill);
+      imid = sctx.imid;
+      iside = sctx.iside;
+      delta = sctx.delta;
+      itheta = sctx.itheta;
+      qalloc = sctx.qalloc;
+#ifdef FIXED_POINT
+      mid = imid;
+      side = iside;
+#else
+      mid = (1.f/32768)*imid;
+      side = (1.f/32768)*iside;
+#endif
+
+      /* Give more bits to low-energy MDCTs than they would otherwise deserve */
+      if (B0>1 && (itheta&0x3fff))
+      {
+         if (itheta > 8192)
+            /* Rough approximation for pre-echo masking */
+            delta -= delta>>(4-LM);
+         else
+            /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */
+            delta = IMIN(0, delta + (N<<BITRES>>(5-LM)));
+      }
+      mbits = IMAX(0, IMIN(b, (b-delta)/2));
+      sbits = b-mbits;
+      ctx->remaining_bits -= qalloc;
+
+      if (lowband)
+         next_lowband2 = lowband+N; /* >32-bit split case */
+
+      rebalance = ctx->remaining_bits;
+      if (mbits >= sbits)
+      {
+         cm = quant_partition(ctx, X, N, mbits, B,
+               lowband, LM,
+               MULT16_16_P15(gain,mid), fill);
+         rebalance = mbits - (rebalance-ctx->remaining_bits);
+         if (rebalance > 3<<BITRES && itheta!=0)
+            sbits += rebalance - (3<<BITRES);
+         cm |= quant_partition(ctx, Y, N, sbits, B,
+               next_lowband2, LM,
+               MULT16_16_P15(gain,side), fill>>B)<<(B0>>1);
+      } else {
+         cm = quant_partition(ctx, Y, N, sbits, B,
+               next_lowband2, LM,
+               MULT16_16_P15(gain,side), fill>>B)<<(B0>>1);
+         rebalance = sbits - (rebalance-ctx->remaining_bits);
+         if (rebalance > 3<<BITRES && itheta!=16384)
+            mbits += rebalance - (3<<BITRES);
+         cm |= quant_partition(ctx, X, N, mbits, B,
+               lowband, LM,
+               MULT16_16_P15(gain,mid), fill);
+      }
+   } else {
+      /* This is the basic no-split case */
+      q = bits2pulses(m, i, LM, b);
+      curr_bits = pulses2bits(m, i, LM, q);
+      ctx->remaining_bits -= curr_bits;
+
+      /* Ensures we can never bust the budget */
+      while (ctx->remaining_bits < 0 && q > 0)
+      {
+         ctx->remaining_bits += curr_bits;
+         q--;
+         curr_bits = pulses2bits(m, i, LM, q);
+         ctx->remaining_bits -= curr_bits;
+      }
+
+      if (q!=0)
+      {
+         int K = get_pulses(q);
+
+         /* Finally do the actual quantization */
+         if (encode)
+         {
+            cm = alg_quant(X, N, K, spread, B, ec
+#ifdef RESYNTH
+                 , gain
+#endif
+                 );
+         } else {
+            cm = alg_unquant(X, N, K, spread, B, ec, gain);
+         }
+      } else {
+         /* If there's no pulse, fill the band anyway */
+         int j;
+         if (resynth)
+         {
+            unsigned cm_mask;
+            /* B can be as large as 16, so this shift might overflow an int on a
+               16-bit platform; use a long to get defined behavior.*/
+            cm_mask = (unsigned)(1UL<<B)-1;
+            fill &= cm_mask;
+            if (!fill)
+            {
+               OPUS_CLEAR(X, N);
+            } else {
+               if (lowband == NULL)
+               {
+                  /* Noise */
+                  for (j=0;j<N;j++)
+                  {
+                     ctx->seed = celt_lcg_rand(ctx->seed);
+                     X[j] = (celt_norm)((opus_int32)ctx->seed>>20);
+                  }
+                  cm = cm_mask;
+               } else {
+                  /* Folded spectrum */
+                  for (j=0;j<N;j++)
+                  {
+                     opus_val16 tmp;
+                     ctx->seed = celt_lcg_rand(ctx->seed);
+                     /* About 48 dB below the "normal" folding level */
+                     tmp = QCONST16(1.0f/256, 10);
+                     tmp = (ctx->seed)&0x8000 ? tmp : -tmp;
+                     X[j] = lowband[j]+tmp;
+                  }
+                  cm = fill;
+               }
+               renormalise_vector(X, N, gain, ctx->arch);
+            }
+         }
+      }
+   }
+
+   return cm;
+}
+
+
+/* This function is responsible for encoding and decoding a band for the mono case. */
+static unsigned quant_band(struct band_ctx *ctx, celt_norm *X,
+      int N, int b, int B, celt_norm *lowband,
+      int LM, celt_norm *lowband_out,
+      opus_val16 gain, celt_norm *lowband_scratch, int fill)
+{
+   int N0=N;
+   int N_B=N;
+   int N_B0;
+   int B0=B;
+   int time_divide=0;
+   int recombine=0;
+   int longBlocks;
+   unsigned cm=0;
+#ifdef RESYNTH
+   int resynth = 1;
+#else
+   int resynth = !ctx->encode;
+#endif
+   int k;
+   int encode;
+   int tf_change;
+
+   encode = ctx->encode;
+   tf_change = ctx->tf_change;
+
+   longBlocks = B0==1;
+
+   N_B = celt_udiv(N_B, B);
+
+   /* Special case for one sample */
+   if (N==1)
+   {
+      return quant_band_n1(ctx, X, NULL, b, lowband_out);
+   }
+
+   if (tf_change>0)
+      recombine = tf_change;
+   /* Band recombining to increase frequency resolution */
+
+   if (lowband_scratch && lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1))
+   {
+      OPUS_COPY(lowband_scratch, lowband, N);
+      lowband = lowband_scratch;
+   }
+
+   for (k=0;k<recombine;k++)
+   {
+      static const unsigned char bit_interleave_table[16]={
+            0,1,1,1,2,3,3,3,2,3,3,3,2,3,3,3
+      };
+      if (encode)
+         haar1(X, N>>k, 1<<k);
+      if (lowband)
+         haar1(lowband, N>>k, 1<<k);
+      fill = bit_interleave_table[fill&0xF]|bit_interleave_table[fill>>4]<<2;
+   }
+   B>>=recombine;
+   N_B<<=recombine;
+
+   /* Increasing the time resolution */
+   while ((N_B&1) == 0 && tf_change<0)
+   {
+      if (encode)
+         haar1(X, N_B, B);
+      if (lowband)
+         haar1(lowband, N_B, B);
+      fill |= fill<<B;
+      B <<= 1;
+      N_B >>= 1;
+      time_divide++;
+      tf_change++;
+   }
+   B0=B;
+   N_B0 = N_B;
+
+   /* Reorganize the samples in time order instead of frequency order */
+   if (B0>1)
+   {
+      if (encode)
+         deinterleave_hadamard(X, N_B>>recombine, B0<<recombine, longBlocks);
+      if (lowband)
+         deinterleave_hadamard(lowband, N_B>>recombine, B0<<recombine, longBlocks);
+   }
+
+   cm = quant_partition(ctx, X, N, b, B, lowband,
+         LM, gain, fill);
+
+   /* This code is used by the decoder and by the resynthesis-enabled encoder */
+   if (resynth)
+   {
+      /* Undo the sample reorganization going from time order to frequency order */
+      if (B0>1)
+         interleave_hadamard(X, N_B>>recombine, B0<<recombine, longBlocks);
+
+      /* Undo time-freq changes that we did earlier */
+      N_B = N_B0;
+      B = B0;
+      for (k=0;k<time_divide;k++)
+      {
+         B >>= 1;
+         N_B <<= 1;
+         cm |= cm>>B;
+         haar1(X, N_B, B);
+      }
+
+      for (k=0;k<recombine;k++)
+      {
+         static const unsigned char bit_deinterleave_table[16]={
+               0x00,0x03,0x0C,0x0F,0x30,0x33,0x3C,0x3F,
+               0xC0,0xC3,0xCC,0xCF,0xF0,0xF3,0xFC,0xFF
+         };
+         cm = bit_deinterleave_table[cm];
+         haar1(X, N0>>k, 1<<k);
+      }
+      B<<=recombine;
+
+      /* Scale output for later folding */
+      if (lowband_out)
+      {
+         int j;
+         opus_val16 n;
+         n = celt_sqrt(SHL32(EXTEND32(N0),22));
+         for (j=0;j<N0;j++)
+            lowband_out[j] = MULT16_16_Q15(n,X[j]);
+      }
+      cm &= (1<<B)-1;
+   }
+   return cm;
+}
+
+
+/* This function is responsible for encoding and decoding a band for the stereo case. */
+static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm *Y,
+      int N, int b, int B, celt_norm *lowband,
+      int LM, celt_norm *lowband_out,
+      celt_norm *lowband_scratch, int fill)
+{
+   int imid=0, iside=0;
+   int inv = 0;
+   opus_val16 mid=0, side=0;
+   unsigned cm=0;
+#ifdef RESYNTH
+   int resynth = 1;
+#else
+   int resynth = !ctx->encode;
+#endif
+   int mbits, sbits, delta;
+   int itheta;
+   int qalloc;
+   struct split_ctx sctx;
+   int orig_fill;
+   int encode;
+   ec_ctx *ec;
+
+   encode = ctx->encode;
+   ec = ctx->ec;
+
+   /* Special case for one sample */
+   if (N==1)
+   {
+      return quant_band_n1(ctx, X, Y, b, lowband_out);
+   }
+
+   orig_fill = fill;
+
+   compute_theta(ctx, &sctx, X, Y, N, &b, B, B,
+         LM, 1, &fill);
+   inv = sctx.inv;
+   imid = sctx.imid;
+   iside = sctx.iside;
+   delta = sctx.delta;
+   itheta = sctx.itheta;
+   qalloc = sctx.qalloc;
+#ifdef FIXED_POINT
+   mid = imid;
+   side = iside;
+#else
+   mid = (1.f/32768)*imid;
+   side = (1.f/32768)*iside;
+#endif
+
+   /* This is a special case for N=2 that only works for stereo and takes
+      advantage of the fact that mid and side are orthogonal to encode
+      the side with just one bit. */
+   if (N==2)
+   {
+      int c;
+      int sign=0;
+      celt_norm *x2, *y2;
+      mbits = b;
+      sbits = 0;
+      /* Only need one bit for the side. */
+      if (itheta != 0 && itheta != 16384)
+         sbits = 1<<BITRES;
+      mbits -= sbits;
+      c = itheta > 8192;
+      ctx->remaining_bits -= qalloc+sbits;
+
+      x2 = c ? Y : X;
+      y2 = c ? X : Y;
+      if (sbits)
+      {
+         if (encode)
+         {
+            /* Here we only need to encode a sign for the side. */
+            sign = x2[0]*y2[1] - x2[1]*y2[0] < 0;
+            ec_enc_bits(ec, sign, 1);
+         } else {
+            sign = ec_dec_bits(ec, 1);
+         }
+      }
+      sign = 1-2*sign;
+      /* We use orig_fill here because we want to fold the side, but if
+         itheta==16384, we'll have cleared the low bits of fill. */
+      cm = quant_band(ctx, x2, N, mbits, B, lowband,
+            LM, lowband_out, Q15ONE, lowband_scratch, orig_fill);
+      /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse),
+         and there's no need to worry about mixing with the other channel. */
+      y2[0] = -sign*x2[1];
+      y2[1] = sign*x2[0];
+      if (resynth)
+      {
+         celt_norm tmp;
+         X[0] = MULT16_16_Q15(mid, X[0]);
+         X[1] = MULT16_16_Q15(mid, X[1]);
+         Y[0] = MULT16_16_Q15(side, Y[0]);
+         Y[1] = MULT16_16_Q15(side, Y[1]);
+         tmp = X[0];
+         X[0] = SUB16(tmp,Y[0]);
+         Y[0] = ADD16(tmp,Y[0]);
+         tmp = X[1];
+         X[1] = SUB16(tmp,Y[1]);
+         Y[1] = ADD16(tmp,Y[1]);
+      }
+   } else {
+      /* "Normal" split code */
+      opus_int32 rebalance;
+
+      mbits = IMAX(0, IMIN(b, (b-delta)/2));
+      sbits = b-mbits;
+      ctx->remaining_bits -= qalloc;
+
+      rebalance = ctx->remaining_bits;
+      if (mbits >= sbits)
+      {
+         /* In stereo mode, we do not apply a scaling to the mid because we need the normalized
+            mid for folding later. */
+         cm = quant_band(ctx, X, N, mbits, B,
+               lowband, LM, lowband_out,
+               Q15ONE, lowband_scratch, fill);
+         rebalance = mbits - (rebalance-ctx->remaining_bits);
+         if (rebalance > 3<<BITRES && itheta!=0)
+            sbits += rebalance - (3<<BITRES);
+
+         /* For a stereo split, the high bits of fill are always zero, so no
+            folding will be done to the side. */
+         cm |= quant_band(ctx, Y, N, sbits, B,
+               NULL, LM, NULL,
+               side, NULL, fill>>B);
+      } else {
+         /* For a stereo split, the high bits of fill are always zero, so no
+            folding will be done to the side. */
+         cm = quant_band(ctx, Y, N, sbits, B,
+               NULL, LM, NULL,
+               side, NULL, fill>>B);
+         rebalance = sbits - (rebalance-ctx->remaining_bits);
+         if (rebalance > 3<<BITRES && itheta!=16384)
+            mbits += rebalance - (3<<BITRES);
+         /* In stereo mode, we do not apply a scaling to the mid because we need the normalized
+            mid for folding later. */
+         cm |= quant_band(ctx, X, N, mbits, B,
+               lowband, LM, lowband_out,
+               Q15ONE, lowband_scratch, fill);
+      }
+   }
+
+
+   /* This code is used by the decoder and by the resynthesis-enabled encoder */
+   if (resynth)
+   {
+      if (N!=2)
+         stereo_merge(X, Y, mid, N, ctx->arch);
+      if (inv)
+      {
+         int j;
+         for (j=0;j<N;j++)
+            Y[j] = -Y[j];
+      }
+   }
+   return cm;
+}
+
+
+void quant_all_bands(int encode, const CELTMode *m, int start, int end,
+      celt_norm *X_, celt_norm *Y_, unsigned char *collapse_masks,
+      const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
+      int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
+      opus_int32 balance, ec_ctx *ec, int LM, int codedBands,
+      opus_uint32 *seed, int arch)
+{
+   int i;
+   opus_int32 remaining_bits;
+   const opus_int16 * OPUS_RESTRICT eBands = m->eBands;
+   celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2;
+   VARDECL(celt_norm, _norm);
+   celt_norm *lowband_scratch;
+   int B;
+   int M;
+   int lowband_offset;
+   int update_lowband = 1;
+   int C = Y_ != NULL ? 2 : 1;
+   int norm_offset;
+#ifdef RESYNTH
+   int resynth = 1;
+#else
+   int resynth = !encode;
+#endif
+   struct band_ctx ctx;
+   SAVE_STACK;
+
+   M = 1<<LM;
+   B = shortBlocks ? M : 1;
+   norm_offset = M*eBands[start];
+   /* No need to allocate norm for the last band because we don't need an
+      output in that band. */
+   ALLOC(_norm, C*(M*eBands[m->nbEBands-1]-norm_offset), celt_norm);
+   norm = _norm;
+   norm2 = norm + M*eBands[m->nbEBands-1]-norm_offset;
+   /* We can use the last band as scratch space because we don't need that
+      scratch space for the last band. */
+   lowband_scratch = X_+M*eBands[m->nbEBands-1];
+
+   lowband_offset = 0;
+   ctx.bandE = bandE;
+   ctx.ec = ec;
+   ctx.encode = encode;
+   ctx.intensity = intensity;
+   ctx.m = m;
+   ctx.seed = *seed;
+   ctx.spread = spread;
+   ctx.arch = arch;
+   for (i=start;i<end;i++)
+   {
+      opus_int32 tell;
+      int b;
+      int N;
+      opus_int32 curr_balance;
+      int effective_lowband=-1;
+      celt_norm * OPUS_RESTRICT X, * OPUS_RESTRICT Y;
+      int tf_change=0;
+      unsigned x_cm;
+      unsigned y_cm;
+      int last;
+
+      ctx.i = i;
+      last = (i==end-1);
+
+      X = X_+M*eBands[i];
+      if (Y_!=NULL)
+         Y = Y_+M*eBands[i];
+      else
+         Y = NULL;
+      N = M*eBands[i+1]-M*eBands[i];
+      tell = ec_tell_frac(ec);
+
+      /* Compute how many bits we want to allocate to this band */
+      if (i != start)
+         balance -= tell;
+      remaining_bits = total_bits-tell-1;
+      ctx.remaining_bits = remaining_bits;
+      if (i <= codedBands-1)
+      {
+         curr_balance = celt_sudiv(balance, IMIN(3, codedBands-i));
+         b = IMAX(0, IMIN(16383, IMIN(remaining_bits+1,pulses[i]+curr_balance)));
+      } else {
+         b = 0;
+      }
+
+      if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0))
+            lowband_offset = i;
+
+      tf_change = tf_res[i];
+      ctx.tf_change = tf_change;
+      if (i>=m->effEBands)
+      {
+         X=norm;
+         if (Y_!=NULL)
+            Y = norm;
+         lowband_scratch = NULL;
+      }
+      if (i==end-1)
+         lowband_scratch = NULL;
+
+      /* Get a conservative estimate of the collapse_mask's for the bands we're
+         going to be folding from. */
+      if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0))
+      {
+         int fold_start;
+         int fold_end;
+         int fold_i;
+         /* This ensures we never repeat spectral content within one band */
+         effective_lowband = IMAX(0, M*eBands[lowband_offset]-norm_offset-N);
+         fold_start = lowband_offset;
+         while(M*eBands[--fold_start] > effective_lowband+norm_offset);
+         fold_end = lowband_offset-1;
+         while(M*eBands[++fold_end] < effective_lowband+norm_offset+N);
+         x_cm = y_cm = 0;
+         fold_i = fold_start; do {
+           x_cm |= collapse_masks[fold_i*C+0];
+           y_cm |= collapse_masks[fold_i*C+C-1];
+         } while (++fold_i<fold_end);
+      }
+      /* Otherwise, we'll be using the LCG to fold, so all blocks will (almost
+         always) be non-zero. */
+      else
+         x_cm = y_cm = (1<<B)-1;
+
+      if (dual_stereo && i==intensity)
+      {
+         int j;
+
+         /* Switch off dual stereo to do intensity. */
+         dual_stereo = 0;
+         if (resynth)
+            for (j=0;j<M*eBands[i]-norm_offset;j++)
+               norm[j] = HALF32(norm[j]+norm2[j]);
+      }
+      if (dual_stereo)
+      {
+         x_cm = quant_band(&ctx, X, N, b/2, B,
+               effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+               last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm);
+         y_cm = quant_band(&ctx, Y, N, b/2, B,
+               effective_lowband != -1 ? norm2+effective_lowband : NULL, LM,
+               last?NULL:norm2+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, y_cm);
+      } else {
+         if (Y!=NULL)
+         {
+            x_cm = quant_band_stereo(&ctx, X, Y, N, b, B,
+                  effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+                        last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm);
+         } else {
+            x_cm = quant_band(&ctx, X, N, b, B,
+                  effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+                        last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm);
+         }
+         y_cm = x_cm;
+      }
+      collapse_masks[i*C+0] = (unsigned char)x_cm;
+      collapse_masks[i*C+C-1] = (unsigned char)y_cm;
+      balance += pulses[i] + tell;
+
+      /* Update the folding position only as long as we have 1 bit/sample depth. */
+      update_lowband = b>(N<<BITRES);
+   }
+   *seed = ctx.seed;
+
+   RESTORE_STACK;
+}
+
diff --git a/third_party/opus/src/celt/bands.h b/third_party/opus/src/celt/bands.h
new file mode 100644
index 0000000..e8bef4ba
--- /dev/null
+++ b/third_party/opus/src/celt/bands.h
@@ -0,0 +1,120 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Copyright (c) 2008-2009 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef BANDS_H
+#define BANDS_H
+
+#include "arch.h"
+#include "modes.h"
+#include "entenc.h"
+#include "entdec.h"
+#include "rate.h"
+
+/** Compute the amplitude (sqrt energy) in each of the bands
+ * @param m Mode data
+ * @param X Spectrum
+ * @param bandE Square root of the energy for each band (returned)
+ */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM);
+
+/*void compute_noise_energies(const CELTMode *m, const celt_sig *X, const opus_val16 *tonality, celt_ener *bandE);*/
+
+/** Normalise each band of X such that the energy in each band is
+    equal to 1
+ * @param m Mode data
+ * @param X Spectrum (returned normalised)
+ * @param bandE Square root of the energy for each band
+ */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M);
+
+/** Denormalise each band of X to restore full amplitude
+ * @param m Mode data
+ * @param X Spectrum (returned de-normalised)
+ * @param bandE Square root of the energy for each band
+ */
+void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
+      celt_sig * OPUS_RESTRICT freq, const opus_val16 *bandE, int start,
+      int end, int M, int downsample, int silence);
+
+#define SPREAD_NONE       (0)
+#define SPREAD_LIGHT      (1)
+#define SPREAD_NORMAL     (2)
+#define SPREAD_AGGRESSIVE (3)
+
+int spreading_decision(const CELTMode *m, const celt_norm *X, int *average,
+      int last_decision, int *hf_average, int *tapset_decision, int update_hf,
+      int end, int C, int M);
+
+#ifdef MEASURE_NORM_MSE
+void measure_norm_mse(const CELTMode *m, float *X, float *X0, float *bandE, float *bandE0, int M, int N, int C);
+#endif
+
+void haar1(celt_norm *X, int N0, int stride);
+
+/** Quantisation/encoding of the residual spectrum
+ * @param encode flag that indicates whether we're encoding (1) or decoding (0)
+ * @param m Mode data
+ * @param start First band to process
+ * @param end Last band to process + 1
+ * @param X Residual (normalised)
+ * @param Y Residual (normalised) for second channel (or NULL for mono)
+ * @param collapse_masks Anti-collapse tracking mask
+ * @param bandE Square root of the energy for each band
+ * @param pulses Bit allocation (per band) for PVQ
+ * @param shortBlocks Zero for long blocks, non-zero for short blocks
+ * @param spread Amount of spreading to use
+ * @param dual_stereo Zero for MS stereo, non-zero for dual stereo
+ * @param intensity First band to use intensity stereo
+ * @param tf_res Time-frequency resolution change
+ * @param total_bits Total number of bits that can be used for the frame (including the ones already spent)
+ * @param balance Number of unallocated bits
+ * @param en Entropy coder state
+ * @param LM log2() of the number of 2.5 subframes in the frame
+ * @param codedBands Last band to receive bits + 1
+ * @param seed Random generator seed
+ * @param arch Run-time architecture (see opus_select_arch())
+ */
+void quant_all_bands(int encode, const CELTMode *m, int start, int end,
+      celt_norm * X, celt_norm * Y, unsigned char *collapse_masks,
+      const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
+      int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
+      opus_int32 balance, ec_ctx *ec, int M, int codedBands, opus_uint32 *seed,
+      int arch);
+
+void anti_collapse(const CELTMode *m, celt_norm *X_,
+      unsigned char *collapse_masks, int LM, int C, int size, int start,
+      int end, const opus_val16 *logE, const opus_val16 *prev1logE,
+      const opus_val16 *prev2logE, const int *pulses, opus_uint32 seed,
+      int arch);
+
+opus_uint32 celt_lcg_rand(opus_uint32 seed);
+
+int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev);
+
+#endif /* BANDS_H */
diff --git a/third_party/opus/src/celt/celt.c b/third_party/opus/src/celt/celt.c
new file mode 100644
index 0000000..b121c51
--- /dev/null
+++ b/third_party/opus/src/celt/celt.c
@@ -0,0 +1,299 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2010 Xiph.Org Foundation
+   Copyright (c) 2008 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_C
+
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+#ifndef PACKAGE_VERSION
+#define PACKAGE_VERSION "unknown"
+#endif
+
+#if defined(MIPSr1_ASM)
+#include "mips/celt_mipsr1.h"
+#endif
+
+
+int resampling_factor(opus_int32 rate)
+{
+   int ret;
+   switch (rate)
+   {
+   case 48000:
+      ret = 1;
+      break;
+   case 24000:
+      ret = 2;
+      break;
+   case 16000:
+      ret = 3;
+      break;
+   case 12000:
+      ret = 4;
+      break;
+   case 8000:
+      ret = 6;
+      break;
+   default:
+#ifndef CUSTOM_MODES
+      celt_assert(0);
+#endif
+      ret = 0;
+      break;
+   }
+   return ret;
+}
+
+#if !defined(OVERRIDE_COMB_FILTER_CONST) || defined(NON_STATIC_COMB_FILTER_CONST_C)
+/* This version should be faster on ARM */
+#ifdef OPUS_ARM_ASM
+#ifndef NON_STATIC_COMB_FILTER_CONST_C
+static
+#endif
+void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
+      opus_val16 g10, opus_val16 g11, opus_val16 g12)
+{
+   opus_val32 x0, x1, x2, x3, x4;
+   int i;
+   x4 = SHL32(x[-T-2], 1);
+   x3 = SHL32(x[-T-1], 1);
+   x2 = SHL32(x[-T], 1);
+   x1 = SHL32(x[-T+1], 1);
+   for (i=0;i<N-4;i+=5)
+   {
+      opus_val32 t;
+      x0=SHL32(x[i-T+2],1);
+      t = MAC16_32_Q16(x[i], g10, x2);
+      t = MAC16_32_Q16(t, g11, ADD32(x1,x3));
+      t = MAC16_32_Q16(t, g12, ADD32(x0,x4));
+      y[i] = t;
+      x4=SHL32(x[i-T+3],1);
+      t = MAC16_32_Q16(x[i+1], g10, x1);
+      t = MAC16_32_Q16(t, g11, ADD32(x0,x2));
+      t = MAC16_32_Q16(t, g12, ADD32(x4,x3));
+      y[i+1] = t;
+      x3=SHL32(x[i-T+4],1);
+      t = MAC16_32_Q16(x[i+2], g10, x0);
+      t = MAC16_32_Q16(t, g11, ADD32(x4,x1));
+      t = MAC16_32_Q16(t, g12, ADD32(x3,x2));
+      y[i+2] = t;
+      x2=SHL32(x[i-T+5],1);
+      t = MAC16_32_Q16(x[i+3], g10, x4);
+      t = MAC16_32_Q16(t, g11, ADD32(x3,x0));
+      t = MAC16_32_Q16(t, g12, ADD32(x2,x1));
+      y[i+3] = t;
+      x1=SHL32(x[i-T+6],1);
+      t = MAC16_32_Q16(x[i+4], g10, x3);
+      t = MAC16_32_Q16(t, g11, ADD32(x2,x4));
+      t = MAC16_32_Q16(t, g12, ADD32(x1,x0));
+      y[i+4] = t;
+   }
+#ifdef CUSTOM_MODES
+   for (;i<N;i++)
+   {
+      opus_val32 t;
+      x0=SHL32(x[i-T+2],1);
+      t = MAC16_32_Q16(x[i], g10, x2);
+      t = MAC16_32_Q16(t, g11, ADD32(x1,x3));
+      t = MAC16_32_Q16(t, g12, ADD32(x0,x4));
+      y[i] = t;
+      x4=x3;
+      x3=x2;
+      x2=x1;
+      x1=x0;
+   }
+#endif
+}
+#else
+#ifndef NON_STATIC_COMB_FILTER_CONST_C
+static
+#endif
+void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
+      opus_val16 g10, opus_val16 g11, opus_val16 g12)
+{
+   opus_val32 x0, x1, x2, x3, x4;
+   int i;
+   x4 = x[-T-2];
+   x3 = x[-T-1];
+   x2 = x[-T];
+   x1 = x[-T+1];
+   for (i=0;i<N;i++)
+   {
+      x0=x[i-T+2];
+      y[i] = x[i]
+               + MULT16_32_Q15(g10,x2)
+               + MULT16_32_Q15(g11,ADD32(x1,x3))
+               + MULT16_32_Q15(g12,ADD32(x0,x4));
+      x4=x3;
+      x3=x2;
+      x2=x1;
+      x1=x0;
+   }
+
+}
+#endif
+#endif
+
+#ifndef OVERRIDE_comb_filter
+void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
+      opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
+      const opus_val16 *window, int overlap, int arch)
+{
+   int i;
+   /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */
+   opus_val16 g00, g01, g02, g10, g11, g12;
+   opus_val32 x0, x1, x2, x3, x4;
+   static const opus_val16 gains[3][3] = {
+         {QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)},
+         {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)},
+         {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}};
+
+   if (g0==0 && g1==0)
+   {
+      /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+      if (x!=y)
+         OPUS_MOVE(y, x, N);
+      return;
+   }
+   g00 = MULT16_16_P15(g0, gains[tapset0][0]);
+   g01 = MULT16_16_P15(g0, gains[tapset0][1]);
+   g02 = MULT16_16_P15(g0, gains[tapset0][2]);
+   g10 = MULT16_16_P15(g1, gains[tapset1][0]);
+   g11 = MULT16_16_P15(g1, gains[tapset1][1]);
+   g12 = MULT16_16_P15(g1, gains[tapset1][2]);
+   x1 = x[-T1+1];
+   x2 = x[-T1  ];
+   x3 = x[-T1-1];
+   x4 = x[-T1-2];
+   /* If the filter didn't change, we don't need the overlap */
+   if (g0==g1 && T0==T1 && tapset0==tapset1)
+      overlap=0;
+   for (i=0;i<overlap;i++)
+   {
+      opus_val16 f;
+      x0=x[i-T1+2];
+      f = MULT16_16_Q15(window[i],window[i]);
+      y[i] = x[i]
+               + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g00),x[i-T0])
+               + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g01),ADD32(x[i-T0+1],x[i-T0-1]))
+               + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g02),ADD32(x[i-T0+2],x[i-T0-2]))
+               + MULT16_32_Q15(MULT16_16_Q15(f,g10),x2)
+               + MULT16_32_Q15(MULT16_16_Q15(f,g11),ADD32(x1,x3))
+               + MULT16_32_Q15(MULT16_16_Q15(f,g12),ADD32(x0,x4));
+      x4=x3;
+      x3=x2;
+      x2=x1;
+      x1=x0;
+
+   }
+   if (g1==0)
+   {
+      /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+      if (x!=y)
+         OPUS_MOVE(y+overlap, x+overlap, N-overlap);
+      return;
+   }
+
+   /* Compute the part with the constant filter. */
+   comb_filter_const(y+i, x+i, T1, N-i, g10, g11, g12, arch);
+}
+#endif /* OVERRIDE_comb_filter */
+
+const signed char tf_select_table[4][8] = {
+      {0, -1, 0, -1,    0,-1, 0,-1},
+      {0, -1, 0, -2,    1, 0, 1,-1},
+      {0, -2, 0, -3,    2, 0, 1,-1},
+      {0, -2, 0, -3,    3, 0, 1,-1},
+};
+
+
+void init_caps(const CELTMode *m,int *cap,int LM,int C)
+{
+   int i;
+   for (i=0;i<m->nbEBands;i++)
+   {
+      int N;
+      N=(m->eBands[i+1]-m->eBands[i])<<LM;
+      cap[i] = (m->cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2;
+   }
+}
+
+
+
+const char *opus_strerror(int error)
+{
+   static const char * const error_strings[8] = {
+      "success",
+      "invalid argument",
+      "buffer too small",
+      "internal error",
+      "corrupted stream",
+      "request not implemented",
+      "invalid state",
+      "memory allocation failed"
+   };
+   if (error > 0 || error < -7)
+      return "unknown error";
+   else
+      return error_strings[-error];
+}
+
+const char *opus_get_version_string(void)
+{
+    return "libopus " PACKAGE_VERSION
+    /* Applications may rely on the presence of this substring in the version
+       string to determine if they have a fixed-point or floating-point build
+       at runtime. */
+#ifdef FIXED_POINT
+          "-fixed"
+#endif
+#ifdef FUZZING
+          "-fuzzing"
+#endif
+          ;
+}
diff --git a/third_party/opus/src/celt/celt.h b/third_party/opus/src/celt/celt.h
new file mode 100644
index 0000000..d1f7eb690
--- /dev/null
+++ b/third_party/opus/src/celt/celt.h
@@ -0,0 +1,229 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Copyright (c) 2008 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/**
+  @file celt.h
+  @brief Contains all the functions for encoding and decoding audio
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CELT_H
+#define CELT_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+#include "opus_custom.h"
+#include "entenc.h"
+#include "entdec.h"
+#include "arch.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CELTEncoder OpusCustomEncoder
+#define CELTDecoder OpusCustomDecoder
+#define CELTMode OpusCustomMode
+
+typedef struct {
+   int valid;
+   float tonality;
+   float tonality_slope;
+   float noisiness;
+   float activity;
+   float music_prob;
+   int        bandwidth;
+}AnalysisInfo;
+
+#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr)))
+
+#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr)))
+
+/* Encoder/decoder Requests */
+
+/* Expose this option again when variable framesize actually works */
+#define OPUS_FRAMESIZE_VARIABLE              5010 /**< Optimize the frame size dynamically */
+
+
+#define CELT_SET_PREDICTION_REQUEST    10002
+/** Controls the use of interframe prediction.
+    0=Independent frames
+    1=Short term interframe prediction allowed
+    2=Long term prediction allowed
+ */
+#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_INPUT_CLIPPING_REQUEST    10004
+#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x)
+
+#define CELT_GET_AND_CLEAR_ERROR_REQUEST   10007
+#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x)
+
+#define CELT_SET_CHANNELS_REQUEST    10008
+#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x)
+
+
+/* Internal */
+#define CELT_SET_START_BAND_REQUEST    10010
+#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_END_BAND_REQUEST    10012
+#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x)
+
+#define CELT_GET_MODE_REQUEST    10015
+/** Get the CELTMode used by an encoder or decoder */
+#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x)
+
+#define CELT_SET_SIGNALLING_REQUEST    10016
+#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_TONALITY_REQUEST    10018
+#define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x)
+#define CELT_SET_TONALITY_SLOPE_REQUEST    10020
+#define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_ANALYSIS_REQUEST    10022
+#define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x)
+
+#define OPUS_SET_LFE_REQUEST    10024
+#define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x)
+
+#define OPUS_SET_ENERGY_MASK_REQUEST    10026
+#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x)
+
+/* Encoder stuff */
+
+int celt_encoder_get_size(int channels);
+
+int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
+
+int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
+                      int arch);
+
+
+
+/* Decoder stuff */
+
+int celt_decoder_get_size(int channels);
+
+
+int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels);
+
+int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data,
+      int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum);
+
+#define celt_encoder_ctl opus_custom_encoder_ctl
+#define celt_decoder_ctl opus_custom_decoder_ctl
+
+
+#ifdef CUSTOM_MODES
+#define OPUS_CUSTOM_NOSTATIC
+#else
+#define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE
+#endif
+
+static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0};
+/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */
+static const unsigned char spread_icdf[4] = {25, 23, 2, 0};
+
+static const unsigned char tapset_icdf[3]={2,1,0};
+
+#ifdef CUSTOM_MODES
+static const unsigned char toOpusTable[20] = {
+      0xE0, 0xE8, 0xF0, 0xF8,
+      0xC0, 0xC8, 0xD0, 0xD8,
+      0xA0, 0xA8, 0xB0, 0xB8,
+      0x00, 0x00, 0x00, 0x00,
+      0x80, 0x88, 0x90, 0x98,
+};
+
+static const unsigned char fromOpusTable[16] = {
+      0x80, 0x88, 0x90, 0x98,
+      0x40, 0x48, 0x50, 0x58,
+      0x20, 0x28, 0x30, 0x38,
+      0x00, 0x08, 0x10, 0x18
+};
+
+static OPUS_INLINE int toOpus(unsigned char c)
+{
+   int ret=0;
+   if (c<0xA0)
+      ret = toOpusTable[c>>3];
+   if (ret == 0)
+      return -1;
+   else
+      return ret|(c&0x7);
+}
+
+static OPUS_INLINE int fromOpus(unsigned char c)
+{
+   if (c<0x80)
+      return -1;
+   else
+      return fromOpusTable[(c>>3)-16] | (c&0x7);
+}
+#endif /* CUSTOM_MODES */
+
+#define COMBFILTER_MAXPERIOD 1024
+#define COMBFILTER_MINPERIOD 15
+
+extern const signed char tf_select_table[4][8];
+
+int resampling_factor(opus_int32 rate);
+
+void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
+                        int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip);
+
+void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
+      opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
+      const opus_val16 *window, int overlap, int arch);
+
+#ifdef NON_STATIC_COMB_FILTER_CONST_C
+void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
+                         opus_val16 g10, opus_val16 g11, opus_val16 g12);
+#endif
+
+#ifndef OVERRIDE_COMB_FILTER_CONST
+# define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \
+    ((void)(arch),comb_filter_const_c(y, x, T, N, g10, g11, g12))
+#endif
+
+void init_caps(const CELTMode *m,int *cap,int LM,int C);
+
+#ifdef RESYNTH
+void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem);
+void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[],
+      opus_val16 *oldBandE, int start, int effEnd, int C, int CC, int isTransient,
+      int LM, int downsample, int silence);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CELT_H */
diff --git a/third_party/opus/src/celt/celt_decoder.c b/third_party/opus/src/celt/celt_decoder.c
new file mode 100644
index 0000000..b978bb34
--- /dev/null
+++ b/third_party/opus/src/celt/celt_decoder.c
@@ -0,0 +1,1248 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2010 Xiph.Org Foundation
+   Copyright (c) 2008 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_DECODER_C
+
+#include "cpu_support.h"
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+#if defined(SMALL_FOOTPRINT) && defined(FIXED_POINT)
+#define NORM_ALIASING_HACK
+#endif
+/**********************************************************************/
+/*                                                                    */
+/*                             DECODER                                */
+/*                                                                    */
+/**********************************************************************/
+#define DECODE_BUFFER_SIZE 2048
+
+/** Decoder state
+ @brief Decoder state
+ */
+struct OpusCustomDecoder {
+   const OpusCustomMode *mode;
+   int overlap;
+   int channels;
+   int stream_channels;
+
+   int downsample;
+   int start, end;
+   int signalling;
+   int arch;
+
+   /* Everything beyond this point gets cleared on a reset */
+#define DECODER_RESET_START rng
+
+   opus_uint32 rng;
+   int error;
+   int last_pitch_index;
+   int loss_count;
+   int skip_plc;
+   int postfilter_period;
+   int postfilter_period_old;
+   opus_val16 postfilter_gain;
+   opus_val16 postfilter_gain_old;
+   int postfilter_tapset;
+   int postfilter_tapset_old;
+
+   celt_sig preemph_memD[2];
+
+   celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */
+   /* opus_val16 lpc[],  Size = channels*LPC_ORDER */
+   /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */
+   /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */
+   /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */
+   /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */
+};
+
+int celt_decoder_get_size(int channels)
+{
+   const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL);
+   return opus_custom_decoder_get_size(mode, channels);
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels)
+{
+   int size = sizeof(struct CELTDecoder)
+            + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig)
+            + channels*LPC_ORDER*sizeof(opus_val16)
+            + 4*2*mode->nbEBands*sizeof(opus_val16);
+   return size;
+}
+
+#ifdef CUSTOM_MODES
+CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error)
+{
+   int ret;
+   CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels));
+   ret = opus_custom_decoder_init(st, mode, channels);
+   if (ret != OPUS_OK)
+   {
+      opus_custom_decoder_destroy(st);
+      st = NULL;
+   }
+   if (error)
+      *error = ret;
+   return st;
+}
+#endif /* CUSTOM_MODES */
+
+int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels)
+{
+   int ret;
+   ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels);
+   if (ret != OPUS_OK)
+      return ret;
+   st->downsample = resampling_factor(sampling_rate);
+   if (st->downsample==0)
+      return OPUS_BAD_ARG;
+   else
+      return OPUS_OK;
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels)
+{
+   if (channels < 0 || channels > 2)
+      return OPUS_BAD_ARG;
+
+   if (st==NULL)
+      return OPUS_ALLOC_FAIL;
+
+   OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels));
+
+   st->mode = mode;
+   st->overlap = mode->overlap;
+   st->stream_channels = st->channels = channels;
+
+   st->downsample = 1;
+   st->start = 0;
+   st->end = st->mode->effEBands;
+   st->signalling = 1;
+   st->arch = opus_select_arch();
+
+   opus_custom_decoder_ctl(st, OPUS_RESET_STATE);
+
+   return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_decoder_destroy(CELTDecoder *st)
+{
+   opus_free(st);
+}
+#endif /* CUSTOM_MODES */
+
+
+#ifndef RESYNTH
+static
+#endif
+void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef,
+      celt_sig *mem, int accum)
+{
+   int c;
+   int Nd;
+   int apply_downsampling=0;
+   opus_val16 coef0;
+   VARDECL(celt_sig, scratch);
+   SAVE_STACK;
+#ifndef FIXED_POINT
+   (void)accum;
+   celt_assert(accum==0);
+#endif
+   ALLOC(scratch, N, celt_sig);
+   coef0 = coef[0];
+   Nd = N/downsample;
+   c=0; do {
+      int j;
+      celt_sig * OPUS_RESTRICT x;
+      opus_val16  * OPUS_RESTRICT y;
+      celt_sig m = mem[c];
+      x =in[c];
+      y = pcm+c;
+#ifdef CUSTOM_MODES
+      if (coef[1] != 0)
+      {
+         opus_val16 coef1 = coef[1];
+         opus_val16 coef3 = coef[3];
+         for (j=0;j<N;j++)
+         {
+            celt_sig tmp = x[j] + m + VERY_SMALL;
+            m = MULT16_32_Q15(coef0, tmp)
+                          - MULT16_32_Q15(coef1, x[j]);
+            tmp = SHL32(MULT16_32_Q15(coef3, tmp), 2);
+            scratch[j] = tmp;
+         }
+         apply_downsampling=1;
+      } else
+#endif
+      if (downsample>1)
+      {
+         /* Shortcut for the standard (non-custom modes) case */
+         for (j=0;j<N;j++)
+         {
+            celt_sig tmp = x[j] + m + VERY_SMALL;
+            m = MULT16_32_Q15(coef0, tmp);
+            scratch[j] = tmp;
+         }
+         apply_downsampling=1;
+      } else {
+         /* Shortcut for the standard (non-custom modes) case */
+#ifdef FIXED_POINT
+         if (accum)
+         {
+            for (j=0;j<N;j++)
+            {
+               celt_sig tmp = x[j] + m + VERY_SMALL;
+               m = MULT16_32_Q15(coef0, tmp);
+               y[j*C] = SAT16(ADD32(y[j*C], SCALEOUT(SIG2WORD16(tmp))));
+            }
+         } else
+#endif
+         {
+            for (j=0;j<N;j++)
+            {
+               celt_sig tmp = x[j] + m + VERY_SMALL;
+               m = MULT16_32_Q15(coef0, tmp);
+               y[j*C] = SCALEOUT(SIG2WORD16(tmp));
+            }
+         }
+      }
+      mem[c] = m;
+
+      if (apply_downsampling)
+      {
+         /* Perform down-sampling */
+#ifdef FIXED_POINT
+         if (accum)
+         {
+            for (j=0;j<Nd;j++)
+               y[j*C] = SAT16(ADD32(y[j*C], SCALEOUT(SIG2WORD16(scratch[j*downsample]))));
+         } else
+#endif
+         {
+            for (j=0;j<Nd;j++)
+               y[j*C] = SCALEOUT(SIG2WORD16(scratch[j*downsample]));
+         }
+      }
+   } while (++c<C);
+   RESTORE_STACK;
+}
+
+#ifndef RESYNTH
+static
+#endif
+void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[],
+                    opus_val16 *oldBandE, int start, int effEnd, int C, int CC,
+                    int isTransient, int LM, int downsample,
+                    int silence, int arch)
+{
+   int c, i;
+   int M;
+   int b;
+   int B;
+   int N, NB;
+   int shift;
+   int nbEBands;
+   int overlap;
+   VARDECL(celt_sig, freq);
+   SAVE_STACK;
+
+   overlap = mode->overlap;
+   nbEBands = mode->nbEBands;
+   N = mode->shortMdctSize<<LM;
+   ALLOC(freq, N, celt_sig); /**< Interleaved signal MDCTs */
+   M = 1<<LM;
+
+   if (isTransient)
+   {
+      B = M;
+      NB = mode->shortMdctSize;
+      shift = mode->maxLM;
+   } else {
+      B = 1;
+      NB = mode->shortMdctSize<<LM;
+      shift = mode->maxLM-LM;
+   }
+
+   if (CC==2&&C==1)
+   {
+      /* Copying a mono streams to two channels */
+      celt_sig *freq2;
+      denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M,
+            downsample, silence);
+      /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */
+      freq2 = out_syn[1]+overlap/2;
+      OPUS_COPY(freq2, freq, N);
+      for (b=0;b<B;b++)
+         clt_mdct_backward(&mode->mdct, &freq2[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch);
+      for (b=0;b<B;b++)
+         clt_mdct_backward(&mode->mdct, &freq[b], out_syn[1]+NB*b, mode->window, overlap, shift, B, arch);
+   } else if (CC==1&&C==2)
+   {
+      /* Downmixing a stereo stream to mono */
+      celt_sig *freq2;
+      freq2 = out_syn[0]+overlap/2;
+      denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M,
+            downsample, silence);
+      /* Use the output buffer as temp array before downmixing. */
+      denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M,
+            downsample, silence);
+      for (i=0;i<N;i++)
+         freq[i] = HALF32(ADD32(freq[i],freq2[i]));
+      for (b=0;b<B;b++)
+         clt_mdct_backward(&mode->mdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch);
+   } else {
+      /* Normal case (mono or stereo) */
+      c=0; do {
+         denormalise_bands(mode, X+c*N, freq, oldBandE+c*nbEBands, start, effEnd, M,
+               downsample, silence);
+         for (b=0;b<B;b++)
+            clt_mdct_backward(&mode->mdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch);
+      } while (++c<CC);
+   }
+   RESTORE_STACK;
+}
+
+static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM, ec_dec *dec)
+{
+   int i, curr, tf_select;
+   int tf_select_rsv;
+   int tf_changed;
+   int logp;
+   opus_uint32 budget;
+   opus_uint32 tell;
+
+   budget = dec->storage*8;
+   tell = ec_tell(dec);
+   logp = isTransient ? 2 : 4;
+   tf_select_rsv = LM>0 && tell+logp+1<=budget;
+   budget -= tf_select_rsv;
+   tf_changed = curr = 0;
+   for (i=start;i<end;i++)
+   {
+      if (tell+logp<=budget)
+      {
+         curr ^= ec_dec_bit_logp(dec, logp);
+         tell = ec_tell(dec);
+         tf_changed |= curr;
+      }
+      tf_res[i] = curr;
+      logp = isTransient ? 4 : 5;
+   }
+   tf_select = 0;
+   if (tf_select_rsv &&
+     tf_select_table[LM][4*isTransient+0+tf_changed] !=
+     tf_select_table[LM][4*isTransient+2+tf_changed])
+   {
+      tf_select = ec_dec_bit_logp(dec, 1);
+   }
+   for (i=start;i<end;i++)
+   {
+      tf_res[i] = tf_select_table[LM][4*isTransient+2*tf_select+tf_res[i]];
+   }
+}
+
+/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save
+   CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The
+   current value corresponds to a pitch of 66.67 Hz. */
+#define PLC_PITCH_LAG_MAX (720)
+/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a
+   pitch of 480 Hz. */
+#define PLC_PITCH_LAG_MIN (100)
+
+static int celt_plc_pitch_search(celt_sig *decode_mem[2], int C, int arch)
+{
+   int pitch_index;
+   VARDECL( opus_val16, lp_pitch_buf );
+   SAVE_STACK;
+   ALLOC( lp_pitch_buf, DECODE_BUFFER_SIZE>>1, opus_val16 );
+   pitch_downsample(decode_mem, lp_pitch_buf,
+         DECODE_BUFFER_SIZE, C, arch);
+   pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf,
+         DECODE_BUFFER_SIZE-PLC_PITCH_LAG_MAX,
+         PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch);
+   pitch_index = PLC_PITCH_LAG_MAX-pitch_index;
+   RESTORE_STACK;
+   return pitch_index;
+}
+
+static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
+{
+   int c;
+   int i;
+   const int C = st->channels;
+   celt_sig *decode_mem[2];
+   celt_sig *out_syn[2];
+   opus_val16 *lpc;
+   opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE;
+   const OpusCustomMode *mode;
+   int nbEBands;
+   int overlap;
+   int start;
+   int loss_count;
+   int noise_based;
+   const opus_int16 *eBands;
+   SAVE_STACK;
+
+   mode = st->mode;
+   nbEBands = mode->nbEBands;
+   overlap = mode->overlap;
+   eBands = mode->eBands;
+
+   c=0; do {
+      decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap);
+      out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N;
+   } while (++c<C);
+   lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*C);
+   oldBandE = lpc+C*LPC_ORDER;
+   oldLogE = oldBandE + 2*nbEBands;
+   oldLogE2 = oldLogE + 2*nbEBands;
+   backgroundLogE = oldLogE2  + 2*nbEBands;
+
+   loss_count = st->loss_count;
+   start = st->start;
+   noise_based = loss_count >= 5 || start != 0 || st->skip_plc;
+   if (noise_based)
+   {
+      /* Noise-based PLC/CNG */
+#ifdef NORM_ALIASING_HACK
+      celt_norm *X;
+#else
+      VARDECL(celt_norm, X);
+#endif
+      opus_uint32 seed;
+      int end;
+      int effEnd;
+      opus_val16 decay;
+      end = st->end;
+      effEnd = IMAX(start, IMIN(end, mode->effEBands));
+
+#ifdef NORM_ALIASING_HACK
+      /* This is an ugly hack that breaks aliasing rules and would be easily broken,
+         but it saves almost 4kB of stack. */
+      X = (celt_norm*)(out_syn[C-1]+overlap/2);
+#else
+      ALLOC(X, C*N, celt_norm);   /**< Interleaved normalised MDCTs */
+#endif
+
+      /* Energy decay */
+      decay = loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT);
+      c=0; do
+      {
+         for (i=start;i<end;i++)
+            oldBandE[c*nbEBands+i] = MAX16(backgroundLogE[c*nbEBands+i], oldBandE[c*nbEBands+i] - decay);
+      } while (++c<C);
+      seed = st->rng;
+      for (c=0;c<C;c++)
+      {
+         for (i=start;i<effEnd;i++)
+         {
+            int j;
+            int boffs;
+            int blen;
+            boffs = N*c+(eBands[i]<<LM);
+            blen = (eBands[i+1]-eBands[i])<<LM;
+            for (j=0;j<blen;j++)
+            {
+               seed = celt_lcg_rand(seed);
+               X[boffs+j] = (celt_norm)((opus_int32)seed>>20);
+            }
+            renormalise_vector(X+boffs, blen, Q15ONE, st->arch);
+         }
+      }
+      st->rng = seed;
+
+      c=0; do {
+         OPUS_MOVE(decode_mem[c], decode_mem[c]+N,
+               DECODE_BUFFER_SIZE-N+(overlap>>1));
+      } while (++c<C);
+
+      celt_synthesis(mode, X, out_syn, oldBandE, start, effEnd, C, C, 0, LM, st->downsample, 0, st->arch);
+   } else {
+      /* Pitch-based PLC */
+      const opus_val16 *window;
+      opus_val16 fade = Q15ONE;
+      int pitch_index;
+      VARDECL(opus_val32, etmp);
+      VARDECL(opus_val16, exc);
+
+      if (loss_count == 0)
+      {
+         st->last_pitch_index = pitch_index = celt_plc_pitch_search(decode_mem, C, st->arch);
+      } else {
+         pitch_index = st->last_pitch_index;
+         fade = QCONST16(.8f,15);
+      }
+
+      ALLOC(etmp, overlap, opus_val32);
+      ALLOC(exc, MAX_PERIOD, opus_val16);
+      window = mode->window;
+      c=0; do {
+         opus_val16 decay;
+         opus_val16 attenuation;
+         opus_val32 S1=0;
+         celt_sig *buf;
+         int extrapolation_offset;
+         int extrapolation_len;
+         int exc_length;
+         int j;
+
+         buf = decode_mem[c];
+         for (i=0;i<MAX_PERIOD;i++) {
+            exc[i] = ROUND16(buf[DECODE_BUFFER_SIZE-MAX_PERIOD+i], SIG_SHIFT);
+         }
+
+         if (loss_count == 0)
+         {
+            opus_val32 ac[LPC_ORDER+1];
+            /* Compute LPC coefficients for the last MAX_PERIOD samples before
+               the first loss so we can work in the excitation-filter domain. */
+            _celt_autocorr(exc, ac, window, overlap,
+                   LPC_ORDER, MAX_PERIOD, st->arch);
+            /* Add a noise floor of -40 dB. */
+#ifdef FIXED_POINT
+            ac[0] += SHR32(ac[0],13);
+#else
+            ac[0] *= 1.0001f;
+#endif
+            /* Use lag windowing to stabilize the Levinson-Durbin recursion. */
+            for (i=1;i<=LPC_ORDER;i++)
+            {
+               /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+#ifdef FIXED_POINT
+               ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
+#else
+               ac[i] -= ac[i]*(0.008f*0.008f)*i*i;
+#endif
+            }
+            _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER);
+         }
+         /* We want the excitation for 2 pitch periods in order to look for a
+            decaying signal, but we can't get more than MAX_PERIOD. */
+         exc_length = IMIN(2*pitch_index, MAX_PERIOD);
+         /* Initialize the LPC history with the samples just before the start
+            of the region for which we're computing the excitation. */
+         {
+            opus_val16 lpc_mem[LPC_ORDER];
+            for (i=0;i<LPC_ORDER;i++)
+            {
+               lpc_mem[i] =
+                     ROUND16(buf[DECODE_BUFFER_SIZE-exc_length-1-i], SIG_SHIFT);
+            }
+            /* Compute the excitation for exc_length samples before the loss. */
+            celt_fir(exc+MAX_PERIOD-exc_length, lpc+c*LPC_ORDER,
+                  exc+MAX_PERIOD-exc_length, exc_length, LPC_ORDER, lpc_mem, st->arch);
+         }
+
+         /* Check if the waveform is decaying, and if so how fast.
+            We do this to avoid adding energy when concealing in a segment
+            with decaying energy. */
+         {
+            opus_val32 E1=1, E2=1;
+            int decay_length;
+#ifdef FIXED_POINT
+            int shift = IMAX(0,2*celt_zlog2(celt_maxabs16(&exc[MAX_PERIOD-exc_length], exc_length))-20);
+#endif
+            decay_length = exc_length>>1;
+            for (i=0;i<decay_length;i++)
+            {
+               opus_val16 e;
+               e = exc[MAX_PERIOD-decay_length+i];
+               E1 += SHR32(MULT16_16(e, e), shift);
+               e = exc[MAX_PERIOD-2*decay_length+i];
+               E2 += SHR32(MULT16_16(e, e), shift);
+            }
+            E1 = MIN32(E1, E2);
+            decay = celt_sqrt(frac_div32(SHR32(E1, 1), E2));
+         }
+
+         /* Move the decoder memory one frame to the left to give us room to
+            add the data for the new frame. We ignore the overlap that extends
+            past the end of the buffer, because we aren't going to use it. */
+         OPUS_MOVE(buf, buf+N, DECODE_BUFFER_SIZE-N);
+
+         /* Extrapolate from the end of the excitation with a period of
+            "pitch_index", scaling down each period by an additional factor of
+            "decay". */
+         extrapolation_offset = MAX_PERIOD-pitch_index;
+         /* We need to extrapolate enough samples to cover a complete MDCT
+            window (including overlap/2 samples on both sides). */
+         extrapolation_len = N+overlap;
+         /* We also apply fading if this is not the first loss. */
+         attenuation = MULT16_16_Q15(fade, decay);
+         for (i=j=0;i<extrapolation_len;i++,j++)
+         {
+            opus_val16 tmp;
+            if (j >= pitch_index) {
+               j -= pitch_index;
+               attenuation = MULT16_16_Q15(attenuation, decay);
+            }
+            buf[DECODE_BUFFER_SIZE-N+i] =
+                  SHL32(EXTEND32(MULT16_16_Q15(attenuation,
+                        exc[extrapolation_offset+j])), SIG_SHIFT);
+            /* Compute the energy of the previously decoded signal whose
+               excitation we're copying. */
+            tmp = ROUND16(
+                  buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j],
+                  SIG_SHIFT);
+            S1 += SHR32(MULT16_16(tmp, tmp), 8);
+         }
+
+         {
+            opus_val16 lpc_mem[LPC_ORDER];
+            /* Copy the last decoded samples (prior to the overlap region) to
+               synthesis filter memory so we can have a continuous signal. */
+            for (i=0;i<LPC_ORDER;i++)
+               lpc_mem[i] = ROUND16(buf[DECODE_BUFFER_SIZE-N-1-i], SIG_SHIFT);
+            /* Apply the synthesis filter to convert the excitation back into
+               the signal domain. */
+            celt_iir(buf+DECODE_BUFFER_SIZE-N, lpc+c*LPC_ORDER,
+                  buf+DECODE_BUFFER_SIZE-N, extrapolation_len, LPC_ORDER,
+                  lpc_mem, st->arch);
+         }
+
+         /* Check if the synthesis energy is higher than expected, which can
+            happen with the signal changes during our window. If so,
+            attenuate. */
+         {
+            opus_val32 S2=0;
+            for (i=0;i<extrapolation_len;i++)
+            {
+               opus_val16 tmp = ROUND16(buf[DECODE_BUFFER_SIZE-N+i], SIG_SHIFT);
+               S2 += SHR32(MULT16_16(tmp, tmp), 8);
+            }
+            /* This checks for an "explosion" in the synthesis. */
+#ifdef FIXED_POINT
+            if (!(S1 > SHR32(S2,2)))
+#else
+            /* The float test is written this way to catch NaNs in the output
+               of the IIR filter at the same time. */
+            if (!(S1 > 0.2f*S2))
+#endif
+            {
+               for (i=0;i<extrapolation_len;i++)
+                  buf[DECODE_BUFFER_SIZE-N+i] = 0;
+            } else if (S1 < S2)
+            {
+               opus_val16 ratio = celt_sqrt(frac_div32(SHR32(S1,1)+1,S2+1));
+               for (i=0;i<overlap;i++)
+               {
+                  opus_val16 tmp_g = Q15ONE
+                        - MULT16_16_Q15(window[i], Q15ONE-ratio);
+                  buf[DECODE_BUFFER_SIZE-N+i] =
+                        MULT16_32_Q15(tmp_g, buf[DECODE_BUFFER_SIZE-N+i]);
+               }
+               for (i=overlap;i<extrapolation_len;i++)
+               {
+                  buf[DECODE_BUFFER_SIZE-N+i] =
+                        MULT16_32_Q15(ratio, buf[DECODE_BUFFER_SIZE-N+i]);
+               }
+            }
+         }
+
+         /* Apply the pre-filter to the MDCT overlap for the next frame because
+            the post-filter will be re-applied in the decoder after the MDCT
+            overlap. */
+         comb_filter(etmp, buf+DECODE_BUFFER_SIZE,
+              st->postfilter_period, st->postfilter_period, overlap,
+              -st->postfilter_gain, -st->postfilter_gain,
+              st->postfilter_tapset, st->postfilter_tapset, NULL, 0, st->arch);
+
+         /* Simulate TDAC on the concealed audio so that it blends with the
+            MDCT of the next frame. */
+         for (i=0;i<overlap/2;i++)
+         {
+            buf[DECODE_BUFFER_SIZE+i] =
+               MULT16_32_Q15(window[i], etmp[overlap-1-i])
+               + MULT16_32_Q15(window[overlap-i-1], etmp[i]);
+         }
+      } while (++c<C);
+   }
+
+   st->loss_count = loss_count+1;
+
+   RESTORE_STACK;
+}
+
+int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data,
+      int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum)
+{
+   int c, i, N;
+   int spread_decision;
+   opus_int32 bits;
+   ec_dec _dec;
+#ifdef NORM_ALIASING_HACK
+   celt_norm *X;
+#else
+   VARDECL(celt_norm, X);
+#endif
+   VARDECL(int, fine_quant);
+   VARDECL(int, pulses);
+   VARDECL(int, cap);
+   VARDECL(int, offsets);
+   VARDECL(int, fine_priority);
+   VARDECL(int, tf_res);
+   VARDECL(unsigned char, collapse_masks);
+   celt_sig *decode_mem[2];
+   celt_sig *out_syn[2];
+   opus_val16 *lpc;
+   opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE;
+
+   int shortBlocks;
+   int isTransient;
+   int intra_ener;
+   const int CC = st->channels;
+   int LM, M;
+   int start;
+   int end;
+   int effEnd;
+   int codedBands;
+   int alloc_trim;
+   int postfilter_pitch;
+   opus_val16 postfilter_gain;
+   int intensity=0;
+   int dual_stereo=0;
+   opus_int32 total_bits;
+   opus_int32 balance;
+   opus_int32 tell;
+   int dynalloc_logp;
+   int postfilter_tapset;
+   int anti_collapse_rsv;
+   int anti_collapse_on=0;
+   int silence;
+   int C = st->stream_channels;
+   const OpusCustomMode *mode;
+   int nbEBands;
+   int overlap;
+   const opus_int16 *eBands;
+   ALLOC_STACK;
+
+   mode = st->mode;
+   nbEBands = mode->nbEBands;
+   overlap = mode->overlap;
+   eBands = mode->eBands;
+   start = st->start;
+   end = st->end;
+   frame_size *= st->downsample;
+
+   lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*CC);
+   oldBandE = lpc+CC*LPC_ORDER;
+   oldLogE = oldBandE + 2*nbEBands;
+   oldLogE2 = oldLogE + 2*nbEBands;
+   backgroundLogE = oldLogE2  + 2*nbEBands;
+
+#ifdef CUSTOM_MODES
+   if (st->signalling && data!=NULL)
+   {
+      int data0=data[0];
+      /* Convert "standard mode" to Opus header */
+      if (mode->Fs==48000 && mode->shortMdctSize==120)
+      {
+         data0 = fromOpus(data0);
+         if (data0<0)
+            return OPUS_INVALID_PACKET;
+      }
+      st->end = end = IMAX(1, mode->effEBands-2*(data0>>5));
+      LM = (data0>>3)&0x3;
+      C = 1 + ((data0>>2)&0x1);
+      data++;
+      len--;
+      if (LM>mode->maxLM)
+         return OPUS_INVALID_PACKET;
+      if (frame_size < mode->shortMdctSize<<LM)
+         return OPUS_BUFFER_TOO_SMALL;
+      else
+         frame_size = mode->shortMdctSize<<LM;
+   } else {
+#else
+   {
+#endif
+      for (LM=0;LM<=mode->maxLM;LM++)
+         if (mode->shortMdctSize<<LM==frame_size)
+            break;
+      if (LM>mode->maxLM)
+         return OPUS_BAD_ARG;
+   }
+   M=1<<LM;
+
+   if (len<0 || len>1275 || pcm==NULL)
+      return OPUS_BAD_ARG;
+
+   N = M*mode->shortMdctSize;
+   c=0; do {
+      decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap);
+      out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N;
+   } while (++c<CC);
+
+   effEnd = end;
+   if (effEnd > mode->effEBands)
+      effEnd = mode->effEBands;
+
+   if (data == NULL || len<=1)
+   {
+      celt_decode_lost(st, N, LM);
+      deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum);
+      RESTORE_STACK;
+      return frame_size/st->downsample;
+   }
+
+   /* Check if there are at least two packets received consecutively before
+    * turning on the pitch-based PLC */
+   st->skip_plc = st->loss_count != 0;
+
+   if (dec == NULL)
+   {
+      ec_dec_init(&_dec,(unsigned char*)data,len);
+      dec = &_dec;
+   }
+
+   if (C==1)
+   {
+      for (i=0;i<nbEBands;i++)
+         oldBandE[i]=MAX16(oldBandE[i],oldBandE[nbEBands+i]);
+   }
+
+   total_bits = len*8;
+   tell = ec_tell(dec);
+
+   if (tell >= total_bits)
+      silence = 1;
+   else if (tell==1)
+      silence = ec_dec_bit_logp(dec, 15);
+   else
+      silence = 0;
+   if (silence)
+   {
+      /* Pretend we've read all the remaining bits */
+      tell = len*8;
+      dec->nbits_total+=tell-ec_tell(dec);
+   }
+
+   postfilter_gain = 0;
+   postfilter_pitch = 0;
+   postfilter_tapset = 0;
+   if (start==0 && tell+16 <= total_bits)
+   {
+      if(ec_dec_bit_logp(dec, 1))
+      {
+         int qg, octave;
+         octave = ec_dec_uint(dec, 6);
+         postfilter_pitch = (16<<octave)+ec_dec_bits(dec, 4+octave)-1;
+         qg = ec_dec_bits(dec, 3);
+         if (ec_tell(dec)+2<=total_bits)
+            postfilter_tapset = ec_dec_icdf(dec, tapset_icdf, 2);
+         postfilter_gain = QCONST16(.09375f,15)*(qg+1);
+      }
+      tell = ec_tell(dec);
+   }
+
+   if (LM > 0 && tell+3 <= total_bits)
+   {
+      isTransient = ec_dec_bit_logp(dec, 3);
+      tell = ec_tell(dec);
+   }
+   else
+      isTransient = 0;
+
+   if (isTransient)
+      shortBlocks = M;
+   else
+      shortBlocks = 0;
+
+   /* Decode the global flags (first symbols in the stream) */
+   intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0;
+   /* Get band energies */
+   unquant_coarse_energy(mode, start, end, oldBandE,
+         intra_ener, dec, C, LM);
+
+   ALLOC(tf_res, nbEBands, int);
+   tf_decode(start, end, isTransient, tf_res, LM, dec);
+
+   tell = ec_tell(dec);
+   spread_decision = SPREAD_NORMAL;
+   if (tell+4 <= total_bits)
+      spread_decision = ec_dec_icdf(dec, spread_icdf, 5);
+
+   ALLOC(cap, nbEBands, int);
+
+   init_caps(mode,cap,LM,C);
+
+   ALLOC(offsets, nbEBands, int);
+
+   dynalloc_logp = 6;
+   total_bits<<=BITRES;
+   tell = ec_tell_frac(dec);
+   for (i=start;i<end;i++)
+   {
+      int width, quanta;
+      int dynalloc_loop_logp;
+      int boost;
+      width = C*(eBands[i+1]-eBands[i])<<LM;
+      /* quanta is 6 bits, but no more than 1 bit/sample
+         and no less than 1/8 bit/sample */
+      quanta = IMIN(width<<BITRES, IMAX(6<<BITRES, width));
+      dynalloc_loop_logp = dynalloc_logp;
+      boost = 0;
+      while (tell+(dynalloc_loop_logp<<BITRES) < total_bits && boost < cap[i])
+      {
+         int flag;
+         flag = ec_dec_bit_logp(dec, dynalloc_loop_logp);
+         tell = ec_tell_frac(dec);
+         if (!flag)
+            break;
+         boost += quanta;
+         total_bits -= quanta;
+         dynalloc_loop_logp = 1;
+      }
+      offsets[i] = boost;
+      /* Making dynalloc more likely */
+      if (boost>0)
+         dynalloc_logp = IMAX(2, dynalloc_logp-1);
+   }
+
+   ALLOC(fine_quant, nbEBands, int);
+   alloc_trim = tell+(6<<BITRES) <= total_bits ?
+         ec_dec_icdf(dec, trim_icdf, 7) : 5;
+
+   bits = (((opus_int32)len*8)<<BITRES) - ec_tell_frac(dec) - 1;
+   anti_collapse_rsv = isTransient&&LM>=2&&bits>=((LM+2)<<BITRES) ? (1<<BITRES) : 0;
+   bits -= anti_collapse_rsv;
+
+   ALLOC(pulses, nbEBands, int);
+   ALLOC(fine_priority, nbEBands, int);
+
+   codedBands = compute_allocation(mode, start, end, offsets, cap,
+         alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses,
+         fine_quant, fine_priority, C, LM, dec, 0, 0, 0);
+
+   unquant_fine_energy(mode, start, end, oldBandE, fine_quant, dec, C);
+
+   c=0; do {
+      OPUS_MOVE(decode_mem[c], decode_mem[c]+N, DECODE_BUFFER_SIZE-N+overlap/2);
+   } while (++c<CC);
+
+   /* Decode fixed codebook */
+   ALLOC(collapse_masks, C*nbEBands, unsigned char);
+
+#ifdef NORM_ALIASING_HACK
+   /* This is an ugly hack that breaks aliasing rules and would be easily broken,
+      but it saves almost 4kB of stack. */
+   X = (celt_norm*)(out_syn[CC-1]+overlap/2);
+#else
+   ALLOC(X, C*N, celt_norm);   /**< Interleaved normalised MDCTs */
+#endif
+
+   quant_all_bands(0, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
+         NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
+         len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, st->arch);
+
+   if (anti_collapse_rsv > 0)
+   {
+      anti_collapse_on = ec_dec_bits(dec, 1);
+   }
+
+   unquant_energy_finalise(mode, start, end, oldBandE,
+         fine_quant, fine_priority, len*8-ec_tell(dec), dec, C);
+
+   if (anti_collapse_on)
+      anti_collapse(mode, X, collapse_masks, LM, C, N,
+            start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng, st->arch);
+
+   if (silence)
+   {
+      for (i=0;i<C*nbEBands;i++)
+         oldBandE[i] = -QCONST16(28.f,DB_SHIFT);
+   }
+
+   celt_synthesis(mode, X, out_syn, oldBandE, start, effEnd,
+                  C, CC, isTransient, LM, st->downsample, silence, st->arch);
+
+   c=0; do {
+      st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD);
+      st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD);
+      comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, mode->shortMdctSize,
+            st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset,
+            mode->window, overlap, st->arch);
+      if (LM!=0)
+         comb_filter(out_syn[c]+mode->shortMdctSize, out_syn[c]+mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-mode->shortMdctSize,
+               st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset,
+               mode->window, overlap, st->arch);
+
+   } while (++c<CC);
+   st->postfilter_period_old = st->postfilter_period;
+   st->postfilter_gain_old = st->postfilter_gain;
+   st->postfilter_tapset_old = st->postfilter_tapset;
+   st->postfilter_period = postfilter_pitch;
+   st->postfilter_gain = postfilter_gain;
+   st->postfilter_tapset = postfilter_tapset;
+   if (LM!=0)
+   {
+      st->postfilter_period_old = st->postfilter_period;
+      st->postfilter_gain_old = st->postfilter_gain;
+      st->postfilter_tapset_old = st->postfilter_tapset;
+   }
+
+   if (C==1)
+      OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands);
+
+   /* In case start or end were to change */
+   if (!isTransient)
+   {
+      opus_val16 max_background_increase;
+      OPUS_COPY(oldLogE2, oldLogE, 2*nbEBands);
+      OPUS_COPY(oldLogE, oldBandE, 2*nbEBands);
+      /* In normal circumstances, we only allow the noise floor to increase by
+         up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB
+         increase for each update.*/
+      if (st->loss_count < 10)
+         max_background_increase = M*QCONST16(0.001f,DB_SHIFT);
+      else
+         max_background_increase = QCONST16(1.f,DB_SHIFT);
+      for (i=0;i<2*nbEBands;i++)
+         backgroundLogE[i] = MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]);
+   } else {
+      for (i=0;i<2*nbEBands;i++)
+         oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
+   }
+   c=0; do
+   {
+      for (i=0;i<start;i++)
+      {
+         oldBandE[c*nbEBands+i]=0;
+         oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+      }
+      for (i=end;i<nbEBands;i++)
+      {
+         oldBandE[c*nbEBands+i]=0;
+         oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+      }
+   } while (++c<2);
+   st->rng = dec->rng;
+
+   deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum);
+   st->loss_count = 0;
+   RESTORE_STACK;
+   if (ec_tell(dec) > 8*len)
+      return OPUS_INTERNAL_ERROR;
+   if(ec_get_error(dec))
+      st->error = 1;
+   return frame_size/st->downsample;
+}
+
+
+#ifdef CUSTOM_MODES
+
+#ifdef FIXED_POINT
+int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
+{
+   return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size)
+{
+   int j, ret, C, N;
+   VARDECL(opus_int16, out);
+   ALLOC_STACK;
+
+   if (pcm==NULL)
+      return OPUS_BAD_ARG;
+
+   C = st->channels;
+   N = frame_size;
+
+   ALLOC(out, C*N, opus_int16);
+   ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0);
+   if (ret>0)
+      for (j=0;j<C*ret;j++)
+         pcm[j]=out[j]*(1.f/32768.f);
+
+   RESTORE_STACK;
+   return ret;
+}
+#endif /* DISABLE_FLOAT_API */
+
+#else
+
+int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size)
+{
+   return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0);
+}
+
+int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
+{
+   int j, ret, C, N;
+   VARDECL(celt_sig, out);
+   ALLOC_STACK;
+
+   if (pcm==NULL)
+      return OPUS_BAD_ARG;
+
+   C = st->channels;
+   N = frame_size;
+   ALLOC(out, C*N, celt_sig);
+
+   ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0);
+
+   if (ret>0)
+      for (j=0;j<C*ret;j++)
+         pcm[j] = FLOAT2INT16 (out[j]);
+
+   RESTORE_STACK;
+   return ret;
+}
+
+#endif
+#endif /* CUSTOM_MODES */
+
+int opus_custom_decoder_ctl(CELTDecoder * OPUS_RESTRICT st, int request, ...)
+{
+   va_list ap;
+
+   va_start(ap, request);
+   switch (request)
+   {
+      case CELT_SET_START_BAND_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         if (value<0 || value>=st->mode->nbEBands)
+            goto bad_arg;
+         st->start = value;
+      }
+      break;
+      case CELT_SET_END_BAND_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         if (value<1 || value>st->mode->nbEBands)
+            goto bad_arg;
+         st->end = value;
+      }
+      break;
+      case CELT_SET_CHANNELS_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         if (value<1 || value>2)
+            goto bad_arg;
+         st->stream_channels = value;
+      }
+      break;
+      case CELT_GET_AND_CLEAR_ERROR_REQUEST:
+      {
+         opus_int32 *value = va_arg(ap, opus_int32*);
+         if (value==NULL)
+            goto bad_arg;
+         *value=st->error;
+         st->error = 0;
+      }
+      break;
+      case OPUS_GET_LOOKAHEAD_REQUEST:
+      {
+         opus_int32 *value = va_arg(ap, opus_int32*);
+         if (value==NULL)
+            goto bad_arg;
+         *value = st->overlap/st->downsample;
+      }
+      break;
+      case OPUS_RESET_STATE:
+      {
+         int i;
+         opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2;
+         lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels);
+         oldBandE = lpc+st->channels*LPC_ORDER;
+         oldLogE = oldBandE + 2*st->mode->nbEBands;
+         oldLogE2 = oldLogE + 2*st->mode->nbEBands;
+         OPUS_CLEAR((char*)&st->DECODER_RESET_START,
+               opus_custom_decoder_get_size(st->mode, st->channels)-
+               ((char*)&st->DECODER_RESET_START - (char*)st));
+         for (i=0;i<2*st->mode->nbEBands;i++)
+            oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT);
+         st->skip_plc = 1;
+      }
+      break;
+      case OPUS_GET_PITCH_REQUEST:
+      {
+         opus_int32 *value = va_arg(ap, opus_int32*);
+         if (value==NULL)
+            goto bad_arg;
+         *value = st->postfilter_period;
+      }
+      break;
+      case CELT_GET_MODE_REQUEST:
+      {
+         const CELTMode ** value = va_arg(ap, const CELTMode**);
+         if (value==0)
+            goto bad_arg;
+         *value=st->mode;
+      }
+      break;
+      case CELT_SET_SIGNALLING_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         st->signalling = value;
+      }
+      break;
+      case OPUS_GET_FINAL_RANGE_REQUEST:
+      {
+         opus_uint32 * value = va_arg(ap, opus_uint32 *);
+         if (value==0)
+            goto bad_arg;
+         *value=st->rng;
+      }
+      break;
+      default:
+         goto bad_request;
+   }
+   va_end(ap);
+   return OPUS_OK;
+bad_arg:
+   va_end(ap);
+   return OPUS_BAD_ARG;
+bad_request:
+      va_end(ap);
+  return OPUS_UNIMPLEMENTED;
+}
diff --git a/third_party/opus/src/celt/celt_encoder.c b/third_party/opus/src/celt/celt_encoder.c
new file mode 100644
index 0000000..3ee7a4d3
--- /dev/null
+++ b/third_party/opus/src/celt/celt_encoder.c
@@ -0,0 +1,2410 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2010 Xiph.Org Foundation
+   Copyright (c) 2008 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_ENCODER_C
+
+#include "cpu_support.h"
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+
+/** Encoder state
+ @brief Encoder state
+ */
+struct OpusCustomEncoder {
+   const OpusCustomMode *mode;     /**< Mode used by the encoder */
+   int channels;
+   int stream_channels;
+
+   int force_intra;
+   int clip;
+   int disable_pf;
+   int complexity;
+   int upsample;
+   int start, end;
+
+   opus_int32 bitrate;
+   int vbr;
+   int signalling;
+   int constrained_vbr;      /* If zero, VBR can do whatever it likes with the rate */
+   int loss_rate;
+   int lsb_depth;
+   int variable_duration;
+   int lfe;
+   int arch;
+
+   /* Everything beyond this point gets cleared on a reset */
+#define ENCODER_RESET_START rng
+
+   opus_uint32 rng;
+   int spread_decision;
+   opus_val32 delayedIntra;
+   int tonal_average;
+   int lastCodedBands;
+   int hf_average;
+   int tapset_decision;
+
+   int prefilter_period;
+   opus_val16 prefilter_gain;
+   int prefilter_tapset;
+#ifdef RESYNTH
+   int prefilter_period_old;
+   opus_val16 prefilter_gain_old;
+   int prefilter_tapset_old;
+#endif
+   int consec_transient;
+   AnalysisInfo analysis;
+
+   opus_val32 preemph_memE[2];
+   opus_val32 preemph_memD[2];
+
+   /* VBR-related parameters */
+   opus_int32 vbr_reservoir;
+   opus_int32 vbr_drift;
+   opus_int32 vbr_offset;
+   opus_int32 vbr_count;
+   opus_val32 overlap_max;
+   opus_val16 stereo_saving;
+   int intensity;
+   opus_val16 *energy_mask;
+   opus_val16 spec_avg;
+
+#ifdef RESYNTH
+   /* +MAX_PERIOD/2 to make space for overlap */
+   celt_sig syn_mem[2][2*MAX_PERIOD+MAX_PERIOD/2];
+#endif
+
+   celt_sig in_mem[1]; /* Size = channels*mode->overlap */
+   /* celt_sig prefilter_mem[],  Size = channels*COMBFILTER_MAXPERIOD */
+   /* opus_val16 oldBandE[],     Size = channels*mode->nbEBands */
+   /* opus_val16 oldLogE[],      Size = channels*mode->nbEBands */
+   /* opus_val16 oldLogE2[],     Size = channels*mode->nbEBands */
+};
+
+int celt_encoder_get_size(int channels)
+{
+   CELTMode *mode = opus_custom_mode_create(48000, 960, NULL);
+   return opus_custom_encoder_get_size(mode, channels);
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels)
+{
+   int size = sizeof(struct CELTEncoder)
+         + (channels*mode->overlap-1)*sizeof(celt_sig)    /* celt_sig in_mem[channels*mode->overlap]; */
+         + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */
+         + 3*channels*mode->nbEBands*sizeof(opus_val16);  /* opus_val16 oldBandE[channels*mode->nbEBands]; */
+                                                          /* opus_val16 oldLogE[channels*mode->nbEBands]; */
+                                                          /* opus_val16 oldLogE2[channels*mode->nbEBands]; */
+   return size;
+}
+
+#ifdef CUSTOM_MODES
+CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error)
+{
+   int ret;
+   CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels));
+   /* init will handle the NULL case */
+   ret = opus_custom_encoder_init(st, mode, channels);
+   if (ret != OPUS_OK)
+   {
+      opus_custom_encoder_destroy(st);
+      st = NULL;
+   }
+   if (error)
+      *error = ret;
+   return st;
+}
+#endif /* CUSTOM_MODES */
+
+static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode,
+                                         int channels, int arch)
+{
+   if (channels < 0 || channels > 2)
+      return OPUS_BAD_ARG;
+
+   if (st==NULL || mode==NULL)
+      return OPUS_ALLOC_FAIL;
+
+   OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels));
+
+   st->mode = mode;
+   st->stream_channels = st->channels = channels;
+
+   st->upsample = 1;
+   st->start = 0;
+   st->end = st->mode->effEBands;
+   st->signalling = 1;
+
+   st->arch = arch;
+
+   st->constrained_vbr = 1;
+   st->clip = 1;
+
+   st->bitrate = OPUS_BITRATE_MAX;
+   st->vbr = 0;
+   st->force_intra  = 0;
+   st->complexity = 5;
+   st->lsb_depth=24;
+
+   opus_custom_encoder_ctl(st, OPUS_RESET_STATE);
+
+   return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels)
+{
+   return opus_custom_encoder_init_arch(st, mode, channels, opus_select_arch());
+}
+#endif
+
+int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
+                      int arch)
+{
+   int ret;
+   ret = opus_custom_encoder_init_arch(st,
+           opus_custom_mode_create(48000, 960, NULL), channels, arch);
+   if (ret != OPUS_OK)
+      return ret;
+   st->upsample = resampling_factor(sampling_rate);
+   return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_encoder_destroy(CELTEncoder *st)
+{
+   opus_free(st);
+}
+#endif /* CUSTOM_MODES */
+
+
+static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C,
+                              opus_val16 *tf_estimate, int *tf_chan)
+{
+   int i;
+   VARDECL(opus_val16, tmp);
+   opus_val32 mem0,mem1;
+   int is_transient = 0;
+   opus_int32 mask_metric = 0;
+   int c;
+   opus_val16 tf_max;
+   int len2;
+   /* Table of 6*64/x, trained on real data to minimize the average error */
+   static const unsigned char inv_table[128] = {
+         255,255,156,110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25,
+          23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
+          12, 12, 11, 11, 11, 10, 10, 10,  9,  9,  9,  9,  9,  9,  8,  8,
+           8,  8,  8,  7,  7,  7,  7,  7,  7,  6,  6,  6,  6,  6,  6,  6,
+           6,  6,  6,  6,  6,  6,  6,  6,  6,  5,  5,  5,  5,  5,  5,  5,
+           5,  5,  5,  5,  5,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+           4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  3,  3,
+           3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,
+   };
+   SAVE_STACK;
+   ALLOC(tmp, len, opus_val16);
+
+   len2=len/2;
+   for (c=0;c<C;c++)
+   {
+      opus_val32 mean;
+      opus_int32 unmask=0;
+      opus_val32 norm;
+      opus_val16 maxE;
+      mem0=0;
+      mem1=0;
+      /* High-pass filter: (1 - 2*z^-1 + z^-2) / (1 - z^-1 + .5*z^-2) */
+      for (i=0;i<len;i++)
+      {
+         opus_val32 x,y;
+         x = SHR32(in[i+c*len],SIG_SHIFT);
+         y = ADD32(mem0, x);
+#ifdef FIXED_POINT
+         mem0 = mem1 + y - SHL32(x,1);
+         mem1 = x - SHR32(y,1);
+#else
+         mem0 = mem1 + y - 2*x;
+         mem1 = x - .5f*y;
+#endif
+         tmp[i] = EXTRACT16(SHR32(y,2));
+         /*printf("%f ", tmp[i]);*/
+      }
+      /*printf("\n");*/
+      /* First few samples are bad because we don't propagate the memory */
+      OPUS_CLEAR(tmp, 12);
+
+#ifdef FIXED_POINT
+      /* Normalize tmp to max range */
+      {
+         int shift=0;
+         shift = 14-celt_ilog2(1+celt_maxabs16(tmp, len));
+         if (shift!=0)
+         {
+            for (i=0;i<len;i++)
+               tmp[i] = SHL16(tmp[i], shift);
+         }
+      }
+#endif
+
+      mean=0;
+      mem0=0;
+      /* Grouping by two to reduce complexity */
+      /* Forward pass to compute the post-echo threshold*/
+      for (i=0;i<len2;i++)
+      {
+         opus_val16 x2 = PSHR32(MULT16_16(tmp[2*i],tmp[2*i]) + MULT16_16(tmp[2*i+1],tmp[2*i+1]),16);
+         mean += x2;
+#ifdef FIXED_POINT
+         /* FIXME: Use PSHR16() instead */
+         tmp[i] = mem0 + PSHR32(x2-mem0,4);
+#else
+         tmp[i] = mem0 + MULT16_16_P15(QCONST16(.0625f,15),x2-mem0);
+#endif
+         mem0 = tmp[i];
+      }
+
+      mem0=0;
+      maxE=0;
+      /* Backward pass to compute the pre-echo threshold */
+      for (i=len2-1;i>=0;i--)
+      {
+#ifdef FIXED_POINT
+         /* FIXME: Use PSHR16() instead */
+         tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3);
+#else
+         tmp[i] = mem0 + MULT16_16_P15(QCONST16(0.125f,15),tmp[i]-mem0);
+#endif
+         mem0 = tmp[i];
+         maxE = MAX16(maxE, mem0);
+      }
+      /*for (i=0;i<len2;i++)printf("%f ", tmp[i]/mean);printf("\n");*/
+
+      /* Compute the ratio of the "frame energy" over the harmonic mean of the energy.
+         This essentially corresponds to a bitrate-normalized temporal noise-to-mask
+         ratio */
+
+      /* As a compromise with the old transient detector, frame energy is the
+         geometric mean of the energy and half the max */
+#ifdef FIXED_POINT
+      /* Costs two sqrt() to avoid overflows */
+      mean = MULT16_16(celt_sqrt(mean), celt_sqrt(MULT16_16(maxE,len2>>1)));
+#else
+      mean = celt_sqrt(mean * maxE*.5*len2);
+#endif
+      /* Inverse of the mean energy in Q15+6 */
+      norm = SHL32(EXTEND32(len2),6+14)/ADD32(EPSILON,SHR32(mean,1));
+      /* Compute harmonic mean discarding the unreliable boundaries
+         The data is smooth, so we only take 1/4th of the samples */
+      unmask=0;
+      for (i=12;i<len2-5;i+=4)
+      {
+         int id;
+#ifdef FIXED_POINT
+         id = MAX32(0,MIN32(127,MULT16_32_Q15(tmp[i]+EPSILON,norm))); /* Do not round to nearest */
+#else
+         id = (int)MAX32(0,MIN32(127,floor(64*norm*(tmp[i]+EPSILON)))); /* Do not round to nearest */
+#endif
+         unmask += inv_table[id];
+      }
+      /*printf("%d\n", unmask);*/
+      /* Normalize, compensate for the 1/4th of the sample and the factor of 6 in the inverse table */
+      unmask = 64*unmask*4/(6*(len2-17));
+      if (unmask>mask_metric)
+      {
+         *tf_chan = c;
+         mask_metric = unmask;
+      }
+   }
+   is_transient = mask_metric>200;
+
+   /* Arbitrary metric for VBR boost */
+   tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42);
+   /* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */
+   *tf_estimate = celt_sqrt(MAX32(0, SHL32(MULT16_16(QCONST16(0.0069,14),MIN16(163,tf_max)),14)-QCONST32(0.139,28)));
+   /*printf("%d %f\n", tf_max, mask_metric);*/
+   RESTORE_STACK;
+#ifdef FUZZING
+   is_transient = rand()&0x1;
+#endif
+   /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/
+   return is_transient;
+}
+
+/* Looks for sudden increases of energy to decide whether we need to patch
+   the transient decision */
+static int patch_transient_decision(opus_val16 *newE, opus_val16 *oldE, int nbEBands,
+      int start, int end, int C)
+{
+   int i, c;
+   opus_val32 mean_diff=0;
+   opus_val16 spread_old[26];
+   /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to
+      avoid false detection caused by irrelevant bands */
+   if (C==1)
+   {
+      spread_old[start] = oldE[start];
+      for (i=start+1;i<end;i++)
+         spread_old[i] = MAX16(spread_old[i-1]-QCONST16(1.0f, DB_SHIFT), oldE[i]);
+   } else {
+      spread_old[start] = MAX16(oldE[start],oldE[start+nbEBands]);
+      for (i=start+1;i<end;i++)
+         spread_old[i] = MAX16(spread_old[i-1]-QCONST16(1.0f, DB_SHIFT),
+                               MAX16(oldE[i],oldE[i+nbEBands]));
+   }
+   for (i=end-2;i>=start;i--)
+      spread_old[i] = MAX16(spread_old[i], spread_old[i+1]-QCONST16(1.0f, DB_SHIFT));
+   /* Compute mean increase */
+   c=0; do {
+      for (i=IMAX(2,start);i<end-1;i++)
+      {
+         opus_val16 x1, x2;
+         x1 = MAX16(0, newE[i + c*nbEBands]);
+         x2 = MAX16(0, spread_old[i]);
+         mean_diff = ADD32(mean_diff, EXTEND32(MAX16(0, SUB16(x1, x2))));
+      }
+   } while (++c<C);
+   mean_diff = DIV32(mean_diff, C*(end-1-IMAX(2,start)));
+   /*printf("%f %f %d\n", mean_diff, max_diff, count);*/
+   return mean_diff > QCONST16(1.f, DB_SHIFT);
+}
+
+/** Apply window and compute the MDCT for all sub-frames and
+    all channels in a frame */
+static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in,
+                          celt_sig * OPUS_RESTRICT out, int C, int CC, int LM, int upsample,
+                          int arch)
+{
+   const int overlap = mode->overlap;
+   int N;
+   int B;
+   int shift;
+   int i, b, c;
+   if (shortBlocks)
+   {
+      B = shortBlocks;
+      N = mode->shortMdctSize;
+      shift = mode->maxLM;
+   } else {
+      B = 1;
+      N = mode->shortMdctSize<<LM;
+      shift = mode->maxLM-LM;
+   }
+   c=0; do {
+      for (b=0;b<B;b++)
+      {
+         /* Interleaving the sub-frames while doing the MDCTs */
+         clt_mdct_forward(&mode->mdct, in+c*(B*N+overlap)+b*N,
+                          &out[b+c*N*B], mode->window, overlap, shift, B,
+                          arch);
+      }
+   } while (++c<CC);
+   if (CC==2&&C==1)
+   {
+      for (i=0;i<B*N;i++)
+         out[i] = ADD32(HALF32(out[i]), HALF32(out[B*N+i]));
+   }
+   if (upsample != 1)
+   {
+      c=0; do
+      {
+         int bound = B*N/upsample;
+         for (i=0;i<bound;i++)
+            out[c*B*N+i] *= upsample;
+         OPUS_CLEAR(&out[c*B*N+bound], B*N-bound);
+      } while (++c<C);
+   }
+}
+
+
+void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
+                        int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip)
+{
+   int i;
+   opus_val16 coef0;
+   celt_sig m;
+   int Nu;
+
+   coef0 = coef[0];
+   m = *mem;
+
+   /* Fast path for the normal 48kHz case and no clipping */
+   if (coef[1] == 0 && upsample == 1 && !clip)
+   {
+      for (i=0;i<N;i++)
+      {
+         opus_val16 x;
+         x = SCALEIN(pcmp[CC*i]);
+         /* Apply pre-emphasis */
+         inp[i] = SHL32(x, SIG_SHIFT) - m;
+         m = SHR32(MULT16_16(coef0, x), 15-SIG_SHIFT);
+      }
+      *mem = m;
+      return;
+   }
+
+   Nu = N/upsample;
+   if (upsample!=1)
+   {
+      OPUS_CLEAR(inp, N);
+   }
+   for (i=0;i<Nu;i++)
+      inp[i*upsample] = SCALEIN(pcmp[CC*i]);
+
+#ifndef FIXED_POINT
+   if (clip)
+   {
+      /* Clip input to avoid encoding non-portable files */
+      for (i=0;i<Nu;i++)
+         inp[i*upsample] = MAX32(-65536.f, MIN32(65536.f,inp[i*upsample]));
+   }
+#else
+   (void)clip; /* Avoids a warning about clip being unused. */
+#endif
+#ifdef CUSTOM_MODES
+   if (coef[1] != 0)
+   {
+      opus_val16 coef1 = coef[1];
+      opus_val16 coef2 = coef[2];
+      for (i=0;i<N;i++)
+      {
+         celt_sig x, tmp;
+         x = inp[i];
+         /* Apply pre-emphasis */
+         tmp = MULT16_16(coef2, x);
+         inp[i] = tmp + m;
+         m = MULT16_32_Q15(coef1, inp[i]) - MULT16_32_Q15(coef0, tmp);
+      }
+   } else
+#endif
+   {
+      for (i=0;i<N;i++)
+      {
+         opus_val16 x;
+         x = inp[i];
+         /* Apply pre-emphasis */
+         inp[i] = SHL32(x, SIG_SHIFT) - m;
+         m = SHR32(MULT16_16(coef0, x), 15-SIG_SHIFT);
+      }
+   }
+   *mem = m;
+}
+
+
+
+static opus_val32 l1_metric(const celt_norm *tmp, int N, int LM, opus_val16 bias)
+{
+   int i;
+   opus_val32 L1;
+   L1 = 0;
+   for (i=0;i<N;i++)
+      L1 += EXTEND32(ABS16(tmp[i]));
+   /* When in doubt, prefer good freq resolution */
+   L1 = MAC16_32_Q15(L1, LM*bias, L1);
+   return L1;
+
+}
+
+static int tf_analysis(const CELTMode *m, int len, int isTransient,
+      int *tf_res, int lambda, celt_norm *X, int N0, int LM,
+      int *tf_sum, opus_val16 tf_estimate, int tf_chan)
+{
+   int i;
+   VARDECL(int, metric);
+   int cost0;
+   int cost1;
+   VARDECL(int, path0);
+   VARDECL(int, path1);
+   VARDECL(celt_norm, tmp);
+   VARDECL(celt_norm, tmp_1);
+   int sel;
+   int selcost[2];
+   int tf_select=0;
+   opus_val16 bias;
+
+   SAVE_STACK;
+   bias = MULT16_16_Q14(QCONST16(.04f,15), MAX16(-QCONST16(.25f,14), QCONST16(.5f,14)-tf_estimate));
+   /*printf("%f ", bias);*/
+
+   ALLOC(metric, len, int);
+   ALLOC(tmp, (m->eBands[len]-m->eBands[len-1])<<LM, celt_norm);
+   ALLOC(tmp_1, (m->eBands[len]-m->eBands[len-1])<<LM, celt_norm);
+   ALLOC(path0, len, int);
+   ALLOC(path1, len, int);
+
+   *tf_sum = 0;
+   for (i=0;i<len;i++)
+   {
+      int k, N;
+      int narrow;
+      opus_val32 L1, best_L1;
+      int best_level=0;
+      N = (m->eBands[i+1]-m->eBands[i])<<LM;
+      /* band is too narrow to be split down to LM=-1 */
+      narrow = (m->eBands[i+1]-m->eBands[i])==1;
+      OPUS_COPY(tmp, &X[tf_chan*N0 + (m->eBands[i]<<LM)], N);
+      /* Just add the right channel if we're in stereo */
+      /*if (C==2)
+         for (j=0;j<N;j++)
+            tmp[j] = ADD16(SHR16(tmp[j], 1),SHR16(X[N0+j+(m->eBands[i]<<LM)], 1));*/
+      L1 = l1_metric(tmp, N, isTransient ? LM : 0, bias);
+      best_L1 = L1;
+      /* Check the -1 case for transients */
+      if (isTransient && !narrow)
+      {
+         OPUS_COPY(tmp_1, tmp, N);
+         haar1(tmp_1, N>>LM, 1<<LM);
+         L1 = l1_metric(tmp_1, N, LM+1, bias);
+         if (L1<best_L1)
+         {
+            best_L1 = L1;
+            best_level = -1;
+         }
+      }
+      /*printf ("%f ", L1);*/
+      for (k=0;k<LM+!(isTransient||narrow);k++)
+      {
+         int B;
+
+         if (isTransient)
+            B = (LM-k-1);
+         else
+            B = k+1;
+
+         haar1(tmp, N>>k, 1<<k);
+
+         L1 = l1_metric(tmp, N, B, bias);
+
+         if (L1 < best_L1)
+         {
+            best_L1 = L1;
+            best_level = k+1;
+         }
+      }
+      /*printf ("%d ", isTransient ? LM-best_level : best_level);*/
+      /* metric is in Q1 to be able to select the mid-point (-0.5) for narrower bands */
+      if (isTransient)
+         metric[i] = 2*best_level;
+      else
+         metric[i] = -2*best_level;
+      *tf_sum += (isTransient ? LM : 0) - metric[i]/2;
+      /* For bands that can't be split to -1, set the metric to the half-way point to avoid
+         biasing the decision */
+      if (narrow && (metric[i]==0 || metric[i]==-2*LM))
+         metric[i]-=1;
+      /*printf("%d ", metric[i]);*/
+   }
+   /*printf("\n");*/
+   /* Search for the optimal tf resolution, including tf_select */
+   tf_select = 0;
+   for (sel=0;sel<2;sel++)
+   {
+      cost0 = 0;
+      cost1 = isTransient ? 0 : lambda;
+      for (i=1;i<len;i++)
+      {
+         int curr0, curr1;
+         curr0 = IMIN(cost0, cost1 + lambda);
+         curr1 = IMIN(cost0 + lambda, cost1);
+         cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
+         cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]);
+      }
+      cost0 = IMIN(cost0, cost1);
+      selcost[sel]=cost0;
+   }
+   /* For now, we're conservative and only allow tf_select=1 for transients.
+    * If tests confirm it's useful for non-transients, we could allow it. */
+   if (selcost[1]<selcost[0] && isTransient)
+      tf_select=1;
+   cost0 = 0;
+   cost1 = isTransient ? 0 : lambda;
+   /* Viterbi forward pass */
+   for (i=1;i<len;i++)
+   {
+      int curr0, curr1;
+      int from0, from1;
+
+      from0 = cost0;
+      from1 = cost1 + lambda;
+      if (from0 < from1)
+      {
+         curr0 = from0;
+         path0[i]= 0;
+      } else {
+         curr0 = from1;
+         path0[i]= 1;
+      }
+
+      from0 = cost0 + lambda;
+      from1 = cost1;
+      if (from0 < from1)
+      {
+         curr1 = from0;
+         path1[i]= 0;
+      } else {
+         curr1 = from1;
+         path1[i]= 1;
+      }
+      cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
+      cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]);
+   }
+   tf_res[len-1] = cost0 < cost1 ? 0 : 1;
+   /* Viterbi backward pass to check the decisions */
+   for (i=len-2;i>=0;i--)
+   {
+      if (tf_res[i+1] == 1)
+         tf_res[i] = path1[i+1];
+      else
+         tf_res[i] = path0[i+1];
+   }
+   /*printf("%d %f\n", *tf_sum, tf_estimate);*/
+   RESTORE_STACK;
+#ifdef FUZZING
+   tf_select = rand()&0x1;
+   tf_res[0] = rand()&0x1;
+   for (i=1;i<len;i++)
+      tf_res[i] = tf_res[i-1] ^ ((rand()&0xF) == 0);
+#endif
+   return tf_select;
+}
+
+static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM, int tf_select, ec_enc *enc)
+{
+   int curr, i;
+   int tf_select_rsv;
+   int tf_changed;
+   int logp;
+   opus_uint32 budget;
+   opus_uint32 tell;
+   budget = enc->storage*8;
+   tell = ec_tell(enc);
+   logp = isTransient ? 2 : 4;
+   /* Reserve space to code the tf_select decision. */
+   tf_select_rsv = LM>0 && tell+logp+1 <= budget;
+   budget -= tf_select_rsv;
+   curr = tf_changed = 0;
+   for (i=start;i<end;i++)
+   {
+      if (tell+logp<=budget)
+      {
+         ec_enc_bit_logp(enc, tf_res[i] ^ curr, logp);
+         tell = ec_tell(enc);
+         curr = tf_res[i];
+         tf_changed |= curr;
+      }
+      else
+         tf_res[i] = curr;
+      logp = isTransient ? 4 : 5;
+   }
+   /* Only code tf_select if it would actually make a difference. */
+   if (tf_select_rsv &&
+         tf_select_table[LM][4*isTransient+0+tf_changed]!=
+         tf_select_table[LM][4*isTransient+2+tf_changed])
+      ec_enc_bit_logp(enc, tf_select, 1);
+   else
+      tf_select = 0;
+   for (i=start;i<end;i++)
+      tf_res[i] = tf_select_table[LM][4*isTransient+2*tf_select+tf_res[i]];
+   /*for(i=0;i<end;i++)printf("%d ", isTransient ? tf_res[i] : LM+tf_res[i]);printf("\n");*/
+}
+
+
+static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
+      const opus_val16 *bandLogE, int end, int LM, int C, int N0,
+      AnalysisInfo *analysis, opus_val16 *stereo_saving, opus_val16 tf_estimate,
+      int intensity, opus_val16 surround_trim, int arch)
+{
+   int i;
+   opus_val32 diff=0;
+   int c;
+   int trim_index;
+   opus_val16 trim = QCONST16(5.f, 8);
+   opus_val16 logXC, logXC2;
+   if (C==2)
+   {
+      opus_val16 sum = 0; /* Q10 */
+      opus_val16 minXC; /* Q10 */
+      /* Compute inter-channel correlation for low frequencies */
+      for (i=0;i<8;i++)
+      {
+         opus_val32 partial;
+         partial = celt_inner_prod(&X[m->eBands[i]<<LM], &X[N0+(m->eBands[i]<<LM)],
+               (m->eBands[i+1]-m->eBands[i])<<LM, arch);
+         sum = ADD16(sum, EXTRACT16(SHR32(partial, 18)));
+      }
+      sum = MULT16_16_Q15(QCONST16(1.f/8, 15), sum);
+      sum = MIN16(QCONST16(1.f, 10), ABS16(sum));
+      minXC = sum;
+      for (i=8;i<intensity;i++)
+      {
+         opus_val32 partial;
+         partial = celt_inner_prod(&X[m->eBands[i]<<LM], &X[N0+(m->eBands[i]<<LM)],
+               (m->eBands[i+1]-m->eBands[i])<<LM, arch);
+         minXC = MIN16(minXC, ABS16(EXTRACT16(SHR32(partial, 18))));
+      }
+      minXC = MIN16(QCONST16(1.f, 10), ABS16(minXC));
+      /*printf ("%f\n", sum);*/
+      /* mid-side savings estimations based on the LF average*/
+      logXC = celt_log2(QCONST32(1.001f, 20)-MULT16_16(sum, sum));
+      /* mid-side savings estimations based on min correlation */
+      logXC2 = MAX16(HALF16(logXC), celt_log2(QCONST32(1.001f, 20)-MULT16_16(minXC, minXC)));
+#ifdef FIXED_POINT
+      /* Compensate for Q20 vs Q14 input and convert output to Q8 */
+      logXC = PSHR32(logXC-QCONST16(6.f, DB_SHIFT),DB_SHIFT-8);
+      logXC2 = PSHR32(logXC2-QCONST16(6.f, DB_SHIFT),DB_SHIFT-8);
+#endif
+
+      trim += MAX16(-QCONST16(4.f, 8), MULT16_16_Q15(QCONST16(.75f,15),logXC));
+      *stereo_saving = MIN16(*stereo_saving + QCONST16(0.25f, 8), -HALF16(logXC2));
+   }
+
+   /* Estimate spectral tilt */
+   c=0; do {
+      for (i=0;i<end-1;i++)
+      {
+         diff += bandLogE[i+c*m->nbEBands]*(opus_int32)(2+2*i-end);
+      }
+   } while (++c<C);
+   diff /= C*(end-1);
+   /*printf("%f\n", diff);*/
+   trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), SHR16(diff+QCONST16(1.f, DB_SHIFT),DB_SHIFT-8)/6 ));
+   trim -= SHR16(surround_trim, DB_SHIFT-8);
+   trim -= 2*SHR16(tf_estimate, 14-8);
+#ifndef DISABLE_FLOAT_API
+   if (analysis->valid)
+   {
+      trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8),
+            (opus_val16)(QCONST16(2.f, 8)*(analysis->tonality_slope+.05f))));
+   }
+#else
+   (void)analysis;
+#endif
+
+#ifdef FIXED_POINT
+   trim_index = PSHR32(trim, 8);
+#else
+   trim_index = (int)floor(.5f+trim);
+#endif
+   trim_index = IMAX(0, IMIN(10, trim_index));
+   /*printf("%d\n", trim_index);*/
+#ifdef FUZZING
+   trim_index = rand()%11;
+#endif
+   return trim_index;
+}
+
+static int stereo_analysis(const CELTMode *m, const celt_norm *X,
+      int LM, int N0)
+{
+   int i;
+   int thetas;
+   opus_val32 sumLR = EPSILON, sumMS = EPSILON;
+
+   /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */
+   for (i=0;i<13;i++)
+   {
+      int j;
+      for (j=m->eBands[i]<<LM;j<m->eBands[i+1]<<LM;j++)
+      {
+         opus_val32 L, R, M, S;
+         /* We cast to 32-bit first because of the -32768 case */
+         L = EXTEND32(X[j]);
+         R = EXTEND32(X[N0+j]);
+         M = ADD32(L, R);
+         S = SUB32(L, R);
+         sumLR = ADD32(sumLR, ADD32(ABS32(L), ABS32(R)));
+         sumMS = ADD32(sumMS, ADD32(ABS32(M), ABS32(S)));
+      }
+   }
+   sumMS = MULT16_32_Q15(QCONST16(0.707107f, 15), sumMS);
+   thetas = 13;
+   /* We don't need thetas for lower bands with LM<=1 */
+   if (LM<=1)
+      thetas -= 8;
+   return MULT16_32_Q15((m->eBands[13]<<(LM+1))+thetas, sumMS)
+         > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
+}
+
+#define MSWAP(a,b) do {opus_val16 tmp = a;a=b;b=tmp;} while(0)
+static opus_val16 median_of_5(const opus_val16 *x)
+{
+   opus_val16 t0, t1, t2, t3, t4;
+   t2 = x[2];
+   if (x[0] > x[1])
+   {
+      t0 = x[1];
+      t1 = x[0];
+   } else {
+      t0 = x[0];
+      t1 = x[1];
+   }
+   if (x[3] > x[4])
+   {
+      t3 = x[4];
+      t4 = x[3];
+   } else {
+      t3 = x[3];
+      t4 = x[4];
+   }
+   if (t0 > t3)
+   {
+      MSWAP(t0, t3);
+      MSWAP(t1, t4);
+   }
+   if (t2 > t1)
+   {
+      if (t1 < t3)
+         return MIN16(t2, t3);
+      else
+         return MIN16(t4, t1);
+   } else {
+      if (t2 < t3)
+         return MIN16(t1, t3);
+      else
+         return MIN16(t2, t4);
+   }
+}
+
+static opus_val16 median_of_3(const opus_val16 *x)
+{
+   opus_val16 t0, t1, t2;
+   if (x[0] > x[1])
+   {
+      t0 = x[1];
+      t1 = x[0];
+   } else {
+      t0 = x[0];
+      t1 = x[1];
+   }
+   t2 = x[2];
+   if (t1 < t2)
+      return t1;
+   else if (t0 < t2)
+      return t2;
+   else
+      return t0;
+}
+
+static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2,
+      int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN,
+      int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM,
+      int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc)
+{
+   int i, c;
+   opus_int32 tot_boost=0;
+   opus_val16 maxDepth;
+   VARDECL(opus_val16, follower);
+   VARDECL(opus_val16, noise_floor);
+   SAVE_STACK;
+   ALLOC(follower, C*nbEBands, opus_val16);
+   ALLOC(noise_floor, C*nbEBands, opus_val16);
+   OPUS_CLEAR(offsets, nbEBands);
+   /* Dynamic allocation code */
+   maxDepth=-QCONST16(31.9f, DB_SHIFT);
+   for (i=0;i<end;i++)
+   {
+      /* Noise floor must take into account eMeans, the depth, the width of the bands
+         and the preemphasis filter (approx. square of bark band ID) */
+      noise_floor[i] = MULT16_16(QCONST16(0.0625f, DB_SHIFT),logN[i])
+            +QCONST16(.5f,DB_SHIFT)+SHL16(9-lsb_depth,DB_SHIFT)-SHL16(eMeans[i],6)
+            +MULT16_16(QCONST16(.0062,DB_SHIFT),(i+5)*(i+5));
+   }
+   c=0;do
+   {
+      for (i=0;i<end;i++)
+         maxDepth = MAX16(maxDepth, bandLogE[c*nbEBands+i]-noise_floor[i]);
+   } while (++c<C);
+   /* Make sure that dynamic allocation can't make us bust the budget */
+   if (effectiveBytes > 50 && LM>=1 && !lfe)
+   {
+      int last=0;
+      c=0;do
+      {
+         opus_val16 offset;
+         opus_val16 tmp;
+         opus_val16 *f;
+         f = &follower[c*nbEBands];
+         f[0] = bandLogE2[c*nbEBands];
+         for (i=1;i<end;i++)
+         {
+            /* The last band to be at least 3 dB higher than the previous one
+               is the last we'll consider. Otherwise, we run into problems on
+               bandlimited signals. */
+            if (bandLogE2[c*nbEBands+i] > bandLogE2[c*nbEBands+i-1]+QCONST16(.5f,DB_SHIFT))
+               last=i;
+            f[i] = MIN16(f[i-1]+QCONST16(1.5f,DB_SHIFT), bandLogE2[c*nbEBands+i]);
+         }
+         for (i=last-1;i>=0;i--)
+            f[i] = MIN16(f[i], MIN16(f[i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*nbEBands+i]));
+
+         /* Combine with a median filter to avoid dynalloc triggering unnecessarily.
+            The "offset" value controls how conservative we are -- a higher offset
+            reduces the impact of the median filter and makes dynalloc use more bits. */
+         offset = QCONST16(1.f, DB_SHIFT);
+         for (i=2;i<end-2;i++)
+            f[i] = MAX16(f[i], median_of_5(&bandLogE2[c*nbEBands+i-2])-offset);
+         tmp = median_of_3(&bandLogE2[c*nbEBands])-offset;
+         f[0] = MAX16(f[0], tmp);
+         f[1] = MAX16(f[1], tmp);
+         tmp = median_of_3(&bandLogE2[c*nbEBands+end-3])-offset;
+         f[end-2] = MAX16(f[end-2], tmp);
+         f[end-1] = MAX16(f[end-1], tmp);
+
+         for (i=0;i<end;i++)
+            f[i] = MAX16(f[i], noise_floor[i]);
+      } while (++c<C);
+      if (C==2)
+      {
+         for (i=start;i<end;i++)
+         {
+            /* Consider 24 dB "cross-talk" */
+            follower[nbEBands+i] = MAX16(follower[nbEBands+i], follower[         i]-QCONST16(4.f,DB_SHIFT));
+            follower[         i] = MAX16(follower[         i], follower[nbEBands+i]-QCONST16(4.f,DB_SHIFT));
+            follower[i] = HALF16(MAX16(0, bandLogE[i]-follower[i]) + MAX16(0, bandLogE[nbEBands+i]-follower[nbEBands+i]));
+         }
+      } else {
+         for (i=start;i<end;i++)
+         {
+            follower[i] = MAX16(0, bandLogE[i]-follower[i]);
+         }
+      }
+      for (i=start;i<end;i++)
+         follower[i] = MAX16(follower[i], surround_dynalloc[i]);
+      /* For non-transient CBR/CVBR frames, halve the dynalloc contribution */
+      if ((!vbr || constrained_vbr)&&!isTransient)
+      {
+         for (i=start;i<end;i++)
+            follower[i] = HALF16(follower[i]);
+      }
+      for (i=start;i<end;i++)
+      {
+         int width;
+         int boost;
+         int boost_bits;
+
+         if (i<8)
+            follower[i] *= 2;
+         if (i>=12)
+            follower[i] = HALF16(follower[i]);
+         follower[i] = MIN16(follower[i], QCONST16(4, DB_SHIFT));
+
+         width = C*(eBands[i+1]-eBands[i])<<LM;
+         if (width<6)
+         {
+            boost = (int)SHR32(EXTEND32(follower[i]),DB_SHIFT);
+            boost_bits = boost*width<<BITRES;
+         } else if (width > 48) {
+            boost = (int)SHR32(EXTEND32(follower[i])*8,DB_SHIFT);
+            boost_bits = (boost*width<<BITRES)/8;
+         } else {
+            boost = (int)SHR32(EXTEND32(follower[i])*width/6,DB_SHIFT);
+            boost_bits = boost*6<<BITRES;
+         }
+         /* For CBR and non-transient CVBR frames, limit dynalloc to 1/4 of the bits */
+         if ((!vbr || (constrained_vbr&&!isTransient))
+               && (tot_boost+boost_bits)>>BITRES>>3 > effectiveBytes/4)
+         {
+            opus_int32 cap = ((effectiveBytes/4)<<BITRES<<3);
+            offsets[i] = cap-tot_boost;
+            tot_boost = cap;
+            break;
+         } else {
+            offsets[i] = boost;
+            tot_boost += boost_bits;
+         }
+      }
+   }
+   *tot_boost_ = tot_boost;
+   RESTORE_STACK;
+   return maxDepth;
+}
+
+
+static int run_prefilter(CELTEncoder *st, celt_sig *in, celt_sig *prefilter_mem, int CC, int N,
+      int prefilter_tapset, int *pitch, opus_val16 *gain, int *qgain, int enabled, int nbAvailableBytes)
+{
+   int c;
+   VARDECL(celt_sig, _pre);
+   celt_sig *pre[2];
+   const CELTMode *mode;
+   int pitch_index;
+   opus_val16 gain1;
+   opus_val16 pf_threshold;
+   int pf_on;
+   int qg;
+   int overlap;
+   SAVE_STACK;
+
+   mode = st->mode;
+   overlap = mode->overlap;
+   ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig);
+
+   pre[0] = _pre;
+   pre[1] = _pre + (N+COMBFILTER_MAXPERIOD);
+
+
+   c=0; do {
+      OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD);
+      OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+overlap)+overlap, N);
+   } while (++c<CC);
+
+   if (enabled)
+   {
+      VARDECL(opus_val16, pitch_buf);
+      ALLOC(pitch_buf, (COMBFILTER_MAXPERIOD+N)>>1, opus_val16);
+
+      pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC, st->arch);
+      /* Don't search for the fir last 1.5 octave of the range because
+         there's too many false-positives due to short-term correlation */
+      pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N,
+            COMBFILTER_MAXPERIOD-3*COMBFILTER_MINPERIOD, &pitch_index,
+            st->arch);
+      pitch_index = COMBFILTER_MAXPERIOD-pitch_index;
+
+      gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD,
+            N, &pitch_index, st->prefilter_period, st->prefilter_gain, st->arch);
+      if (pitch_index > COMBFILTER_MAXPERIOD-2)
+         pitch_index = COMBFILTER_MAXPERIOD-2;
+      gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1);
+      /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st->analysis.tonality);*/
+      if (st->loss_rate>2)
+         gain1 = HALF32(gain1);
+      if (st->loss_rate>4)
+         gain1 = HALF32(gain1);
+      if (st->loss_rate>8)
+         gain1 = 0;
+   } else {
+      gain1 = 0;
+      pitch_index = COMBFILTER_MINPERIOD;
+   }
+
+   /* Gain threshold for enabling the prefilter/postfilter */
+   pf_threshold = QCONST16(.2f,15);
+
+   /* Adjusting the threshold based on rate and continuity */
+   if (abs(pitch_index-st->prefilter_period)*10>pitch_index)
+      pf_threshold += QCONST16(.2f,15);
+   if (nbAvailableBytes<25)
+      pf_threshold += QCONST16(.1f,15);
+   if (nbAvailableBytes<35)
+      pf_threshold += QCONST16(.1f,15);
+   if (st->prefilter_gain > QCONST16(.4f,15))
+      pf_threshold -= QCONST16(.1f,15);
+   if (st->prefilter_gain > QCONST16(.55f,15))
+      pf_threshold -= QCONST16(.1f,15);
+
+   /* Hard threshold at 0.2 */
+   pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15));
+   if (gain1<pf_threshold)
+   {
+      gain1 = 0;
+      pf_on = 0;
+      qg = 0;
+   } else {
+      /*This block is not gated by a total bits check only because
+        of the nbAvailableBytes check above.*/
+      if (ABS16(gain1-st->prefilter_gain)<QCONST16(.1f,15))
+         gain1=st->prefilter_gain;
+
+#ifdef FIXED_POINT
+      qg = ((gain1+1536)>>10)/3-1;
+#else
+      qg = (int)floor(.5f+gain1*32/3)-1;
+#endif
+      qg = IMAX(0, IMIN(7, qg));
+      gain1 = QCONST16(0.09375f,15)*(qg+1);
+      pf_on = 1;
+   }
+   /*printf("%d %f\n", pitch_index, gain1);*/
+
+   c=0; do {
+      int offset = mode->shortMdctSize-overlap;
+      st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
+      OPUS_COPY(in+c*(N+overlap), st->in_mem+c*(overlap), overlap);
+      if (offset)
+         comb_filter(in+c*(N+overlap)+overlap, pre[c]+COMBFILTER_MAXPERIOD,
+               st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain,
+               st->prefilter_tapset, st->prefilter_tapset, NULL, 0, st->arch);
+
+      comb_filter(in+c*(N+overlap)+overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset,
+            st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1,
+            st->prefilter_tapset, prefilter_tapset, mode->window, overlap, st->arch);
+      OPUS_COPY(st->in_mem+c*(overlap), in+c*(N+overlap)+N, overlap);
+
+      if (N>COMBFILTER_MAXPERIOD)
+      {
+         OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD);
+      } else {
+         OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N);
+         OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N);
+      }
+   } while (++c<CC);
+
+   RESTORE_STACK;
+   *gain = gain1;
+   *pitch = pitch_index;
+   *qgain = qg;
+   return pf_on;
+}
+
+static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32 base_target,
+      int LM, opus_int32 bitrate, int lastCodedBands, int C, int intensity,
+      int constrained_vbr, opus_val16 stereo_saving, int tot_boost,
+      opus_val16 tf_estimate, int pitch_change, opus_val16 maxDepth,
+      int variable_duration, int lfe, int has_surround_mask, opus_val16 surround_masking,
+      opus_val16 temporal_vbr)
+{
+   /* The target rate in 8th bits per frame */
+   opus_int32 target;
+   int coded_bins;
+   int coded_bands;
+   opus_val16 tf_calibration;
+   int nbEBands;
+   const opus_int16 *eBands;
+
+   nbEBands = mode->nbEBands;
+   eBands = mode->eBands;
+
+   coded_bands = lastCodedBands ? lastCodedBands : nbEBands;
+   coded_bins = eBands[coded_bands]<<LM;
+   if (C==2)
+      coded_bins += eBands[IMIN(intensity, coded_bands)]<<LM;
+
+   target = base_target;
+
+   /*printf("%f %f %f %f %d %d ", st->analysis.activity, st->analysis.tonality, tf_estimate, st->stereo_saving, tot_boost, coded_bands);*/
+#ifndef DISABLE_FLOAT_API
+   if (analysis->valid && analysis->activity<.4)
+      target -= (opus_int32)((coded_bins<<BITRES)*(.4f-analysis->activity));
+#endif
+   /* Stereo savings */
+   if (C==2)
+   {
+      int coded_stereo_bands;
+      int coded_stereo_dof;
+      opus_val16 max_frac;
+      coded_stereo_bands = IMIN(intensity, coded_bands);
+      coded_stereo_dof = (eBands[coded_stereo_bands]<<LM)-coded_stereo_bands;
+      /* Maximum fraction of the bits we can save if the signal is mono. */
+      max_frac = DIV32_16(MULT16_16(QCONST16(0.8f, 15), coded_stereo_dof), coded_bins);
+      stereo_saving = MIN16(stereo_saving, QCONST16(1.f, 8));
+      /*printf("%d %d %d ", coded_stereo_dof, coded_bins, tot_boost);*/
+      target -= (opus_int32)MIN32(MULT16_32_Q15(max_frac,target),
+                      SHR32(MULT16_16(stereo_saving-QCONST16(0.1f,8),(coded_stereo_dof<<BITRES)),8));
+   }
+   /* Boost the rate according to dynalloc (minus the dynalloc average for calibration). */
+   target += tot_boost-(16<<LM);
+   /* Apply transient boost, compensating for average boost. */
+   tf_calibration = variable_duration==OPUS_FRAMESIZE_VARIABLE ?
+                    QCONST16(0.02f,14) : QCONST16(0.04f,14);
+   target += (opus_int32)SHL32(MULT16_32_Q15(tf_estimate-tf_calibration, target),1);
+
+#ifndef DISABLE_FLOAT_API
+   /* Apply tonality boost */
+   if (analysis->valid && !lfe)
+   {
+      opus_int32 tonal_target;
+      float tonal;
+
+      /* Tonality boost (compensating for the average). */
+      tonal = MAX16(0.f,analysis->tonality-.15f)-0.09f;
+      tonal_target = target + (opus_int32)((coded_bins<<BITRES)*1.2f*tonal);
+      if (pitch_change)
+         tonal_target +=  (opus_int32)((coded_bins<<BITRES)*.8f);
+      /*printf("%f %f ", analysis->tonality, tonal);*/
+      target = tonal_target;
+   }
+#else
+   (void)analysis;
+   (void)pitch_change;
+#endif
+
+   if (has_surround_mask&&!lfe)
+   {
+      opus_int32 surround_target = target + (opus_int32)SHR32(MULT16_16(surround_masking,coded_bins<<BITRES), DB_SHIFT);
+      /*printf("%f %d %d %d %d %d %d ", surround_masking, coded_bins, st->end, st->intensity, surround_target, target, st->bitrate);*/
+      target = IMAX(target/4, surround_target);
+   }
+
+   {
+      opus_int32 floor_depth;
+      int bins;
+      bins = eBands[nbEBands-2]<<LM;
+      /*floor_depth = SHR32(MULT16_16((C*bins<<BITRES),celt_log2(SHL32(MAX16(1,sample_max),13))), DB_SHIFT);*/
+      floor_depth = (opus_int32)SHR32(MULT16_16((C*bins<<BITRES),maxDepth), DB_SHIFT);
+      floor_depth = IMAX(floor_depth, target>>2);
+      target = IMIN(target, floor_depth);
+      /*printf("%f %d\n", maxDepth, floor_depth);*/
+   }
+
+   if ((!has_surround_mask||lfe) && (constrained_vbr || bitrate<64000))
+   {
+      opus_val16 rate_factor = Q15ONE;
+      if (bitrate < 64000)
+      {
+#ifdef FIXED_POINT
+         rate_factor = MAX16(0,(bitrate-32000));
+#else
+         rate_factor = MAX16(0,(1.f/32768)*(bitrate-32000));
+#endif
+      }
+      if (constrained_vbr)
+         rate_factor = MIN16(rate_factor, QCONST16(0.67f, 15));
+      target = base_target + (opus_int32)MULT16_32_Q15(rate_factor, target-base_target);
+
+   }
+
+   if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14))
+   {
+      opus_val16 amount;
+      opus_val16 tvbr_factor;
+      amount = MULT16_16_Q15(QCONST16(.0000031f, 30), IMAX(0, IMIN(32000, 96000-bitrate)));
+      tvbr_factor = SHR32(MULT16_16(temporal_vbr, amount), DB_SHIFT);
+      target += (opus_int32)MULT16_32_Q15(tvbr_factor, target);
+   }
+
+   /* Don't allow more than doubling the rate */
+   target = IMIN(2*base_target, target);
+
+   return target;
+}
+
+int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
+{
+   int i, c, N;
+   opus_int32 bits;
+   ec_enc _enc;
+   VARDECL(celt_sig, in);
+   VARDECL(celt_sig, freq);
+   VARDECL(celt_norm, X);
+   VARDECL(celt_ener, bandE);
+   VARDECL(opus_val16, bandLogE);
+   VARDECL(opus_val16, bandLogE2);
+   VARDECL(int, fine_quant);
+   VARDECL(opus_val16, error);
+   VARDECL(int, pulses);
+   VARDECL(int, cap);
+   VARDECL(int, offsets);
+   VARDECL(int, fine_priority);
+   VARDECL(int, tf_res);
+   VARDECL(unsigned char, collapse_masks);
+   celt_sig *prefilter_mem;
+   opus_val16 *oldBandE, *oldLogE, *oldLogE2;
+   int shortBlocks=0;
+   int isTransient=0;
+   const int CC = st->channels;
+   const int C = st->stream_channels;
+   int LM, M;
+   int tf_select;
+   int nbFilledBytes, nbAvailableBytes;
+   int start;
+   int end;
+   int effEnd;
+   int codedBands;
+   int tf_sum;
+   int alloc_trim;
+   int pitch_index=COMBFILTER_MINPERIOD;
+   opus_val16 gain1 = 0;
+   int dual_stereo=0;
+   int effectiveBytes;
+   int dynalloc_logp;
+   opus_int32 vbr_rate;
+   opus_int32 total_bits;
+   opus_int32 total_boost;
+   opus_int32 balance;
+   opus_int32 tell;
+   int prefilter_tapset=0;
+   int pf_on;
+   int anti_collapse_rsv;
+   int anti_collapse_on=0;
+   int silence=0;
+   int tf_chan = 0;
+   opus_val16 tf_estimate;
+   int pitch_change=0;
+   opus_int32 tot_boost;
+   opus_val32 sample_max;
+   opus_val16 maxDepth;
+   const OpusCustomMode *mode;
+   int nbEBands;
+   int overlap;
+   const opus_int16 *eBands;
+   int secondMdct;
+   int signalBandwidth;
+   int transient_got_disabled=0;
+   opus_val16 surround_masking=0;
+   opus_val16 temporal_vbr=0;
+   opus_val16 surround_trim = 0;
+   opus_int32 equiv_rate = 510000;
+   VARDECL(opus_val16, surround_dynalloc);
+   ALLOC_STACK;
+
+   mode = st->mode;
+   nbEBands = mode->nbEBands;
+   overlap = mode->overlap;
+   eBands = mode->eBands;
+   start = st->start;
+   end = st->end;
+   tf_estimate = 0;
+   if (nbCompressedBytes<2 || pcm==NULL)
+   {
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   }
+
+   frame_size *= st->upsample;
+   for (LM=0;LM<=mode->maxLM;LM++)
+      if (mode->shortMdctSize<<LM==frame_size)
+         break;
+   if (LM>mode->maxLM)
+   {
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   }
+   M=1<<LM;
+   N = M*mode->shortMdctSize;
+
+   prefilter_mem = st->in_mem+CC*(overlap);
+   oldBandE = (opus_val16*)(st->in_mem+CC*(overlap+COMBFILTER_MAXPERIOD));
+   oldLogE = oldBandE + CC*nbEBands;
+   oldLogE2 = oldLogE + CC*nbEBands;
+
+   if (enc==NULL)
+   {
+      tell=1;
+      nbFilledBytes=0;
+   } else {
+      tell=ec_tell(enc);
+      nbFilledBytes=(tell+4)>>3;
+   }
+
+#ifdef CUSTOM_MODES
+   if (st->signalling && enc==NULL)
+   {
+      int tmp = (mode->effEBands-end)>>1;
+      end = st->end = IMAX(1, mode->effEBands-tmp);
+      compressed[0] = tmp<<5;
+      compressed[0] |= LM<<3;
+      compressed[0] |= (C==2)<<2;
+      /* Convert "standard mode" to Opus header */
+      if (mode->Fs==48000 && mode->shortMdctSize==120)
+      {
+         int c0 = toOpus(compressed[0]);
+         if (c0<0)
+         {
+            RESTORE_STACK;
+            return OPUS_BAD_ARG;
+         }
+         compressed[0] = c0;
+      }
+      compressed++;
+      nbCompressedBytes--;
+   }
+#else
+   celt_assert(st->signalling==0);
+#endif
+
+   /* Can't produce more than 1275 output bytes */
+   nbCompressedBytes = IMIN(nbCompressedBytes,1275);
+   nbAvailableBytes = nbCompressedBytes - nbFilledBytes;
+
+   if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX)
+   {
+      opus_int32 den=mode->Fs>>BITRES;
+      vbr_rate=(st->bitrate*frame_size+(den>>1))/den;
+#ifdef CUSTOM_MODES
+      if (st->signalling)
+         vbr_rate -= 8<<BITRES;
+#endif
+      effectiveBytes = vbr_rate>>(3+BITRES);
+   } else {
+      opus_int32 tmp;
+      vbr_rate = 0;
+      tmp = st->bitrate*frame_size;
+      if (tell>1)
+         tmp += tell;
+      if (st->bitrate!=OPUS_BITRATE_MAX)
+         nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes,
+               (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling));
+      effectiveBytes = nbCompressedBytes;
+   }
+   if (st->bitrate != OPUS_BITRATE_MAX)
+      equiv_rate = st->bitrate - (40*C+20)*((400>>LM) - 50);
+
+   if (enc==NULL)
+   {
+      ec_enc_init(&_enc, compressed, nbCompressedBytes);
+      enc = &_enc;
+   }
+
+   if (vbr_rate>0)
+   {
+      /* Computes the max bit-rate allowed in VBR mode to avoid violating the
+          target rate and buffering.
+         We must do this up front so that bust-prevention logic triggers
+          correctly if we don't have enough bits. */
+      if (st->constrained_vbr)
+      {
+         opus_int32 vbr_bound;
+         opus_int32 max_allowed;
+         /* We could use any multiple of vbr_rate as bound (depending on the
+             delay).
+            This is clamped to ensure we use at least two bytes if the encoder
+             was entirely empty, but to allow 0 in hybrid mode. */
+         vbr_bound = vbr_rate;
+         max_allowed = IMIN(IMAX(tell==1?2:0,
+               (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)),
+               nbAvailableBytes);
+         if(max_allowed < nbAvailableBytes)
+         {
+            nbCompressedBytes = nbFilledBytes+max_allowed;
+            nbAvailableBytes = max_allowed;
+            ec_enc_shrink(enc, nbCompressedBytes);
+         }
+      }
+   }
+   total_bits = nbCompressedBytes*8;
+
+   effEnd = end;
+   if (effEnd > mode->effEBands)
+      effEnd = mode->effEBands;
+
+   ALLOC(in, CC*(N+overlap), celt_sig);
+
+   sample_max=MAX32(st->overlap_max, celt_maxabs16(pcm, C*(N-overlap)/st->upsample));
+   st->overlap_max=celt_maxabs16(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample);
+   sample_max=MAX32(sample_max, st->overlap_max);
+#ifdef FIXED_POINT
+   silence = (sample_max==0);
+#else
+   silence = (sample_max <= (opus_val16)1/(1<<st->lsb_depth));
+#endif
+#ifdef FUZZING
+   if ((rand()&0x3F)==0)
+      silence = 1;
+#endif
+   if (tell==1)
+      ec_enc_bit_logp(enc, silence, 15);
+   else
+      silence=0;
+   if (silence)
+   {
+      /*In VBR mode there is no need to send more than the minimum. */
+      if (vbr_rate>0)
+      {
+         effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2);
+         total_bits=nbCompressedBytes*8;
+         nbAvailableBytes=2;
+         ec_enc_shrink(enc, nbCompressedBytes);
+      }
+      /* Pretend we've filled all the remaining bits with zeros
+            (that's what the initialiser did anyway) */
+      tell = nbCompressedBytes*8;
+      enc->nbits_total+=tell-ec_tell(enc);
+   }
+   c=0; do {
+      int need_clip=0;
+#ifndef FIXED_POINT
+      need_clip = st->clip && sample_max>65536.f;
+#endif
+      celt_preemphasis(pcm+c, in+c*(N+overlap)+overlap, N, CC, st->upsample,
+                  mode->preemph, st->preemph_memE+c, need_clip);
+   } while (++c<CC);
+
+
+
+   /* Find pitch period and gain */
+   {
+      int enabled;
+      int qg;
+      enabled = ((st->lfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && start==0 && !silence && !st->disable_pf
+            && st->complexity >= 5 && !(st->consec_transient && LM!=3 && st->variable_duration==OPUS_FRAMESIZE_VARIABLE);
+
+      prefilter_tapset = st->tapset_decision;
+      pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes);
+      if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3)
+            && (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period))
+         pitch_change = 1;
+      if (pf_on==0)
+      {
+         if(start==0 && tell+16<=total_bits)
+            ec_enc_bit_logp(enc, 0, 1);
+      } else {
+         /*This block is not gated by a total bits check only because
+           of the nbAvailableBytes check above.*/
+         int octave;
+         ec_enc_bit_logp(enc, 1, 1);
+         pitch_index += 1;
+         octave = EC_ILOG(pitch_index)-5;
+         ec_enc_uint(enc, octave, 6);
+         ec_enc_bits(enc, pitch_index-(16<<octave), 4+octave);
+         pitch_index -= 1;
+         ec_enc_bits(enc, qg, 3);
+         ec_enc_icdf(enc, prefilter_tapset, tapset_icdf, 2);
+      }
+   }
+
+   isTransient = 0;
+   shortBlocks = 0;
+   if (st->complexity >= 1 && !st->lfe)
+   {
+      isTransient = transient_analysis(in, N+overlap, CC,
+            &tf_estimate, &tf_chan);
+   }
+   if (LM>0 && ec_tell(enc)+3<=total_bits)
+   {
+      if (isTransient)
+         shortBlocks = M;
+   } else {
+      isTransient = 0;
+      transient_got_disabled=1;
+   }
+
+   ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */
+   ALLOC(bandE,nbEBands*CC, celt_ener);
+   ALLOC(bandLogE,nbEBands*CC, opus_val16);
+
+   secondMdct = shortBlocks && st->complexity>=8;
+   ALLOC(bandLogE2, C*nbEBands, opus_val16);
+   if (secondMdct)
+   {
+      compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample, st->arch);
+      compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+      amp2Log2(mode, effEnd, end, bandE, bandLogE2, C);
+      for (i=0;i<C*nbEBands;i++)
+         bandLogE2[i] += HALF16(SHL16(LM, DB_SHIFT));
+   }
+
+   compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch);
+   if (CC==2&&C==1)
+      tf_chan = 0;
+   compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+
+   if (st->lfe)
+   {
+      for (i=2;i<end;i++)
+      {
+         bandE[i] = IMIN(bandE[i], MULT16_32_Q15(QCONST16(1e-4f,15),bandE[0]));
+         bandE[i] = MAX32(bandE[i], EPSILON);
+      }
+   }
+   amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
+
+   ALLOC(surround_dynalloc, C*nbEBands, opus_val16);
+   OPUS_CLEAR(surround_dynalloc, end);
+   /* This computes how much masking takes place between surround channels */
+   if (start==0&&st->energy_mask&&!st->lfe)
+   {
+      int mask_end;
+      int midband;
+      int count_dynalloc;
+      opus_val32 mask_avg=0;
+      opus_val32 diff=0;
+      int count=0;
+      mask_end = IMAX(2,st->lastCodedBands);
+      for (c=0;c<C;c++)
+      {
+         for(i=0;i<mask_end;i++)
+         {
+            opus_val16 mask;
+            mask = MAX16(MIN16(st->energy_mask[nbEBands*c+i],
+                   QCONST16(.25f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT));
+            if (mask > 0)
+               mask = HALF16(mask);
+            mask_avg += MULT16_16(mask, eBands[i+1]-eBands[i]);
+            count += eBands[i+1]-eBands[i];
+            diff += MULT16_16(mask, 1+2*i-mask_end);
+         }
+      }
+      celt_assert(count>0);
+      mask_avg = DIV32_16(mask_avg,count);
+      mask_avg += QCONST16(.2f, DB_SHIFT);
+      diff = diff*6/(C*(mask_end-1)*(mask_end+1)*mask_end);
+      /* Again, being conservative */
+      diff = HALF32(diff);
+      diff = MAX32(MIN32(diff, QCONST32(.031f, DB_SHIFT)), -QCONST32(.031f, DB_SHIFT));
+      /* Find the band that's in the middle of the coded spectrum */
+      for (midband=0;eBands[midband+1] < eBands[mask_end]/2;midband++);
+      count_dynalloc=0;
+      for(i=0;i<mask_end;i++)
+      {
+         opus_val32 lin;
+         opus_val16 unmask;
+         lin = mask_avg + diff*(i-midband);
+         if (C==2)
+            unmask = MAX16(st->energy_mask[i], st->energy_mask[nbEBands+i]);
+         else
+            unmask = st->energy_mask[i];
+         unmask = MIN16(unmask, QCONST16(.0f, DB_SHIFT));
+         unmask -= lin;
+         if (unmask > QCONST16(.25f, DB_SHIFT))
+         {
+            surround_dynalloc[i] = unmask - QCONST16(.25f, DB_SHIFT);
+            count_dynalloc++;
+         }
+      }
+      if (count_dynalloc>=3)
+      {
+         /* If we need dynalloc in many bands, it's probably because our
+            initial masking rate was too low. */
+         mask_avg += QCONST16(.25f, DB_SHIFT);
+         if (mask_avg>0)
+         {
+            /* Something went really wrong in the original calculations,
+               disabling masking. */
+            mask_avg = 0;
+            diff = 0;
+            OPUS_CLEAR(surround_dynalloc, mask_end);
+         } else {
+            for(i=0;i<mask_end;i++)
+               surround_dynalloc[i] = MAX16(0, surround_dynalloc[i]-QCONST16(.25f, DB_SHIFT));
+         }
+      }
+      mask_avg += QCONST16(.2f, DB_SHIFT);
+      /* Convert to 1/64th units used for the trim */
+      surround_trim = 64*diff;
+      /*printf("%d %d ", mask_avg, surround_trim);*/
+      surround_masking = mask_avg;
+   }
+   /* Temporal VBR (but not for LFE) */
+   if (!st->lfe)
+   {
+      opus_val16 follow=-QCONST16(10.0f,DB_SHIFT);
+      opus_val32 frame_avg=0;
+      opus_val16 offset = shortBlocks?HALF16(SHL16(LM, DB_SHIFT)):0;
+      for(i=start;i<end;i++)
+      {
+         follow = MAX16(follow-QCONST16(1.f, DB_SHIFT), bandLogE[i]-offset);
+         if (C==2)
+            follow = MAX16(follow, bandLogE[i+nbEBands]-offset);
+         frame_avg += follow;
+      }
+      frame_avg /= (end-start);
+      temporal_vbr = SUB16(frame_avg,st->spec_avg);
+      temporal_vbr = MIN16(QCONST16(3.f, DB_SHIFT), MAX16(-QCONST16(1.5f, DB_SHIFT), temporal_vbr));
+      st->spec_avg += MULT16_16_Q15(QCONST16(.02f, 15), temporal_vbr);
+   }
+   /*for (i=0;i<21;i++)
+      printf("%f ", bandLogE[i]);
+   printf("\n");*/
+
+   if (!secondMdct)
+   {
+      OPUS_COPY(bandLogE2, bandLogE, C*nbEBands);
+   }
+
+   /* Last chance to catch any transient we might have missed in the
+      time-domain analysis */
+   if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe)
+   {
+      if (patch_transient_decision(bandLogE, oldBandE, nbEBands, start, end, C))
+      {
+         isTransient = 1;
+         shortBlocks = M;
+         compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch);
+         compute_band_energies(mode, freq, bandE, effEnd, C, LM);
+         amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
+         /* Compensate for the scaling of short vs long mdcts */
+         for (i=0;i<C*nbEBands;i++)
+            bandLogE2[i] += HALF16(SHL16(LM, DB_SHIFT));
+         tf_estimate = QCONST16(.2f,14);
+      }
+   }
+
+   if (LM>0 && ec_tell(enc)+3<=total_bits)
+      ec_enc_bit_logp(enc, isTransient, 3);
+
+   ALLOC(X, C*N, celt_norm);         /**< Interleaved normalised MDCTs */
+
+   /* Band normalisation */
+   normalise_bands(mode, freq, X, bandE, effEnd, C, M);
+
+   ALLOC(tf_res, nbEBands, int);
+   /* Disable variable tf resolution for hybrid and at very low bitrate */
+   if (effectiveBytes>=15*C && start==0 && st->complexity>=2 && !st->lfe)
+   {
+      int lambda;
+      if (effectiveBytes<40)
+         lambda = 12;
+      else if (effectiveBytes<60)
+         lambda = 6;
+      else if (effectiveBytes<100)
+         lambda = 4;
+      else
+         lambda = 3;
+      lambda*=2;
+      tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, &tf_sum, tf_estimate, tf_chan);
+      for (i=effEnd;i<end;i++)
+         tf_res[i] = tf_res[effEnd-1];
+   } else {
+      tf_sum = 0;
+      for (i=0;i<end;i++)
+         tf_res[i] = isTransient;
+      tf_select=0;
+   }
+
+   ALLOC(error, C*nbEBands, opus_val16);
+   quant_coarse_energy(mode, start, end, effEnd, bandLogE,
+         oldBandE, total_bits, error, enc,
+         C, LM, nbAvailableBytes, st->force_intra,
+         &st->delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe);
+
+   tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc);
+
+   if (ec_tell(enc)+4<=total_bits)
+   {
+      if (st->lfe)
+      {
+         st->tapset_decision = 0;
+         st->spread_decision = SPREAD_NORMAL;
+      } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C || start != 0)
+      {
+         if (st->complexity == 0)
+            st->spread_decision = SPREAD_NONE;
+         else
+            st->spread_decision = SPREAD_NORMAL;
+      } else {
+         /* Disable new spreading+tapset estimator until we can show it works
+            better than the old one. So far it seems like spreading_decision()
+            works best. */
+#if 0
+         if (st->analysis.valid)
+         {
+            static const opus_val16 spread_thresholds[3] = {-QCONST16(.6f, 15), -QCONST16(.2f, 15), -QCONST16(.07f, 15)};
+            static const opus_val16 spread_histeresis[3] = {QCONST16(.15f, 15), QCONST16(.07f, 15), QCONST16(.02f, 15)};
+            static const opus_val16 tapset_thresholds[2] = {QCONST16(.0f, 15), QCONST16(.15f, 15)};
+            static const opus_val16 tapset_histeresis[2] = {QCONST16(.1f, 15), QCONST16(.05f, 15)};
+            st->spread_decision = hysteresis_decision(-st->analysis.tonality, spread_thresholds, spread_histeresis, 3, st->spread_decision);
+            st->tapset_decision = hysteresis_decision(st->analysis.tonality_slope, tapset_thresholds, tapset_histeresis, 2, st->tapset_decision);
+         } else
+#endif
+         {
+            st->spread_decision = spreading_decision(mode, X,
+                  &st->tonal_average, st->spread_decision, &st->hf_average,
+                  &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M);
+         }
+         /*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/
+         /*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/
+      }
+      ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5);
+   }
+
+   ALLOC(offsets, nbEBands, int);
+
+   maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets,
+         st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr,
+         eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc);
+   /* For LFE, everything interesting is in the first band */
+   if (st->lfe)
+      offsets[0] = IMIN(8, effectiveBytes/3);
+   ALLOC(cap, nbEBands, int);
+   init_caps(mode,cap,LM,C);
+
+   dynalloc_logp = 6;
+   total_bits<<=BITRES;
+   total_boost = 0;
+   tell = ec_tell_frac(enc);
+   for (i=start;i<end;i++)
+   {
+      int width, quanta;
+      int dynalloc_loop_logp;
+      int boost;
+      int j;
+      width = C*(eBands[i+1]-eBands[i])<<LM;
+      /* quanta is 6 bits, but no more than 1 bit/sample
+         and no less than 1/8 bit/sample */
+      quanta = IMIN(width<<BITRES, IMAX(6<<BITRES, width));
+      dynalloc_loop_logp = dynalloc_logp;
+      boost = 0;
+      for (j = 0; tell+(dynalloc_loop_logp<<BITRES) < total_bits-total_boost
+            && boost < cap[i]; j++)
+      {
+         int flag;
+         flag = j<offsets[i];
+         ec_enc_bit_logp(enc, flag, dynalloc_loop_logp);
+         tell = ec_tell_frac(enc);
+         if (!flag)
+            break;
+         boost += quanta;
+         total_boost += quanta;
+         dynalloc_loop_logp = 1;
+      }
+      /* Making dynalloc more likely */
+      if (j)
+         dynalloc_logp = IMAX(2, dynalloc_logp-1);
+      offsets[i] = boost;
+   }
+
+   if (C==2)
+   {
+      static const opus_val16 intensity_thresholds[21]=
+      /* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19  20  off*/
+        {  1, 2, 3, 4, 5, 6, 7, 8,16,24,36,44,50,56,62,67,72,79,88,106,134};
+      static const opus_val16 intensity_histeresis[21]=
+        {  1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 6,  8, 8};
+
+      /* Always use MS for 2.5 ms frames until we can do a better analysis */
+      if (LM!=0)
+         dual_stereo = stereo_analysis(mode, X, LM, N);
+
+      st->intensity = hysteresis_decision((opus_val16)(equiv_rate/1000),
+            intensity_thresholds, intensity_histeresis, 21, st->intensity);
+      st->intensity = IMIN(end,IMAX(start, st->intensity));
+   }
+
+   alloc_trim = 5;
+   if (tell+(6<<BITRES) <= total_bits - total_boost)
+   {
+      if (st->lfe)
+         alloc_trim = 5;
+      else
+         alloc_trim = alloc_trim_analysis(mode, X, bandLogE,
+            end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate,
+            st->intensity, surround_trim, st->arch);
+      ec_enc_icdf(enc, alloc_trim, trim_icdf, 7);
+      tell = ec_tell_frac(enc);
+   }
+
+   /* Variable bitrate */
+   if (vbr_rate>0)
+   {
+     opus_val16 alpha;
+     opus_int32 delta;
+     /* The target rate in 8th bits per frame */
+     opus_int32 target, base_target;
+     opus_int32 min_allowed;
+     int lm_diff = mode->maxLM - LM;
+
+     /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms.
+        The CELT allocator will just not be able to use more than that anyway. */
+     nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM));
+     base_target = vbr_rate - ((40*C+20)<<BITRES);
+
+     if (st->constrained_vbr)
+        base_target += (st->vbr_offset>>lm_diff);
+
+     target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate,
+           st->lastCodedBands, C, st->intensity, st->constrained_vbr,
+           st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth,
+           st->variable_duration, st->lfe, st->energy_mask!=NULL, surround_masking,
+           temporal_vbr);
+
+     /* The current offset is removed from the target and the space used
+        so far is added*/
+     target=target+tell;
+     /* In VBR mode the frame size must not be reduced so much that it would
+         result in the encoder running out of bits.
+        The margin of 2 bytes ensures that none of the bust-prevention logic
+         in the decoder will have triggered so far. */
+     min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2 - nbFilledBytes;
+
+     nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3);
+     nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes);
+     nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes;
+
+     /* By how much did we "miss" the target on that frame */
+     delta = target - vbr_rate;
+
+     target=nbAvailableBytes<<(BITRES+3);
+
+     /*If the frame is silent we don't adjust our drift, otherwise
+       the encoder will shoot to very high rates after hitting a
+       span of silence, but we do allow the bitres to refill.
+       This means that we'll undershoot our target in CVBR/VBR modes
+       on files with lots of silence. */
+     if(silence)
+     {
+       nbAvailableBytes = 2;
+       target = 2*8<<BITRES;
+       delta = 0;
+     }
+
+     if (st->vbr_count < 970)
+     {
+        st->vbr_count++;
+        alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16));
+     } else
+        alpha = QCONST16(.001f,15);
+     /* How many bits have we used in excess of what we're allowed */
+     if (st->constrained_vbr)
+        st->vbr_reservoir += target - vbr_rate;
+     /*printf ("%d\n", st->vbr_reservoir);*/
+
+     /* Compute the offset we need to apply in order to reach the target */
+     if (st->constrained_vbr)
+     {
+        st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<<lm_diff))-st->vbr_offset-st->vbr_drift);
+        st->vbr_offset = -st->vbr_drift;
+     }
+     /*printf ("%d\n", st->vbr_drift);*/
+
+     if (st->constrained_vbr && st->vbr_reservoir < 0)
+     {
+        /* We're under the min value -- increase rate */
+        int adjust = (-st->vbr_reservoir)/(8<<BITRES);
+        /* Unless we're just coding silence */
+        nbAvailableBytes += silence?0:adjust;
+        st->vbr_reservoir = 0;
+        /*printf ("+%d\n", adjust);*/
+     }
+     nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes);
+     /*printf("%d\n", nbCompressedBytes*50*8);*/
+     /* This moves the raw bits to take into account the new compressed size */
+     ec_enc_shrink(enc, nbCompressedBytes);
+   }
+
+   /* Bit allocation */
+   ALLOC(fine_quant, nbEBands, int);
+   ALLOC(pulses, nbEBands, int);
+   ALLOC(fine_priority, nbEBands, int);
+
+   /* bits =           packet size                    - where we are - safety*/
+   bits = (((opus_int32)nbCompressedBytes*8)<<BITRES) - ec_tell_frac(enc) - 1;
+   anti_collapse_rsv = isTransient&&LM>=2&&bits>=((LM+2)<<BITRES) ? (1<<BITRES) : 0;
+   bits -= anti_collapse_rsv;
+   signalBandwidth = end-1;
+#ifndef DISABLE_FLOAT_API
+   if (st->analysis.valid)
+   {
+      int min_bandwidth;
+      if (equiv_rate < (opus_int32)32000*C)
+         min_bandwidth = 13;
+      else if (equiv_rate < (opus_int32)48000*C)
+         min_bandwidth = 16;
+      else if (equiv_rate < (opus_int32)60000*C)
+         min_bandwidth = 18;
+      else  if (equiv_rate < (opus_int32)80000*C)
+         min_bandwidth = 19;
+      else
+         min_bandwidth = 20;
+      signalBandwidth = IMAX(st->analysis.bandwidth, min_bandwidth);
+   }
+#endif
+   if (st->lfe)
+      signalBandwidth = 1;
+   codedBands = compute_allocation(mode, start, end, offsets, cap,
+         alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses,
+         fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth);
+   if (st->lastCodedBands)
+      st->lastCodedBands = IMIN(st->lastCodedBands+1,IMAX(st->lastCodedBands-1,codedBands));
+   else
+      st->lastCodedBands = codedBands;
+
+   quant_fine_energy(mode, start, end, oldBandE, error, fine_quant, enc, C);
+
+   /* Residual quantisation */
+   ALLOC(collapse_masks, C*nbEBands, unsigned char);
+   quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
+         bandE, pulses, shortBlocks, st->spread_decision,
+         dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv,
+         balance, enc, LM, codedBands, &st->rng, st->arch);
+
+   if (anti_collapse_rsv > 0)
+   {
+      anti_collapse_on = st->consec_transient<2;
+#ifdef FUZZING
+      anti_collapse_on = rand()&0x1;
+#endif
+      ec_enc_bits(enc, anti_collapse_on, 1);
+   }
+   quant_energy_finalise(mode, start, end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C);
+
+   if (silence)
+   {
+      for (i=0;i<C*nbEBands;i++)
+         oldBandE[i] = -QCONST16(28.f,DB_SHIFT);
+   }
+
+#ifdef RESYNTH
+   /* Re-synthesis of the coded audio if required */
+   {
+      celt_sig *out_mem[2];
+
+      if (anti_collapse_on)
+      {
+         anti_collapse(mode, X, collapse_masks, LM, C, N,
+               start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng);
+      }
+
+      c=0; do {
+         OPUS_MOVE(st->syn_mem[c], st->syn_mem[c]+N, 2*MAX_PERIOD-N+overlap/2);
+      } while (++c<CC);
+
+      c=0; do {
+         out_mem[c] = st->syn_mem[c]+2*MAX_PERIOD-N;
+      } while (++c<CC);
+
+      celt_synthesis(mode, X, out_mem, oldBandE, start, effEnd,
+                     C, CC, isTransient, LM, st->upsample, silence, st->arch);
+
+      c=0; do {
+         st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
+         st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD);
+         comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, mode->shortMdctSize,
+               st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset,
+               mode->window, overlap);
+         if (LM!=0)
+            comb_filter(out_mem[c]+mode->shortMdctSize, out_mem[c]+mode->shortMdctSize, st->prefilter_period, pitch_index, N-mode->shortMdctSize,
+                  st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset,
+                  mode->window, overlap);
+      } while (++c<CC);
+
+      /* We reuse freq[] as scratch space for the de-emphasis */
+      deemphasis(out_mem, (opus_val16*)pcm, N, CC, st->upsample, mode->preemph, st->preemph_memD);
+      st->prefilter_period_old = st->prefilter_period;
+      st->prefilter_gain_old = st->prefilter_gain;
+      st->prefilter_tapset_old = st->prefilter_tapset;
+   }
+#endif
+
+   st->prefilter_period = pitch_index;
+   st->prefilter_gain = gain1;
+   st->prefilter_tapset = prefilter_tapset;
+#ifdef RESYNTH
+   if (LM!=0)
+   {
+      st->prefilter_period_old = st->prefilter_period;
+      st->prefilter_gain_old = st->prefilter_gain;
+      st->prefilter_tapset_old = st->prefilter_tapset;
+   }
+#endif
+
+   if (CC==2&&C==1) {
+      OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands);
+   }
+
+   if (!isTransient)
+   {
+      OPUS_COPY(oldLogE2, oldLogE, CC*nbEBands);
+      OPUS_COPY(oldLogE, oldBandE, CC*nbEBands);
+   } else {
+      for (i=0;i<CC*nbEBands;i++)
+         oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
+   }
+   /* In case start or end were to change */
+   c=0; do
+   {
+      for (i=0;i<start;i++)
+      {
+         oldBandE[c*nbEBands+i]=0;
+         oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+      }
+      for (i=end;i<nbEBands;i++)
+      {
+         oldBandE[c*nbEBands+i]=0;
+         oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+      }
+   } while (++c<CC);
+
+   if (isTransient || transient_got_disabled)
+      st->consec_transient++;
+   else
+      st->consec_transient=0;
+   st->rng = enc->rng;
+
+   /* If there's any room left (can only happen for very high rates),
+      it's already filled with zeros */
+   ec_enc_done(enc);
+
+#ifdef CUSTOM_MODES
+   if (st->signalling)
+      nbCompressedBytes++;
+#endif
+
+   RESTORE_STACK;
+   if (ec_get_error(enc))
+      return OPUS_INTERNAL_ERROR;
+   else
+      return nbCompressedBytes;
+}
+
+
+#ifdef CUSTOM_MODES
+
+#ifdef FIXED_POINT
+int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+   return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+   int j, ret, C, N;
+   VARDECL(opus_int16, in);
+   ALLOC_STACK;
+
+   if (pcm==NULL)
+      return OPUS_BAD_ARG;
+
+   C = st->channels;
+   N = frame_size;
+   ALLOC(in, C*N, opus_int16);
+
+   for (j=0;j<C*N;j++)
+     in[j] = FLOAT2INT16(pcm[j]);
+
+   ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+   for (j=0;j<C*N;j++)
+      ((float*)pcm)[j]=in[j]*(1.f/32768.f);
+#endif
+   RESTORE_STACK;
+   return ret;
+}
+#endif /* DISABLE_FLOAT_API */
+#else
+
+int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+   int j, ret, C, N;
+   VARDECL(celt_sig, in);
+   ALLOC_STACK;
+
+   if (pcm==NULL)
+      return OPUS_BAD_ARG;
+
+   C=st->channels;
+   N=frame_size;
+   ALLOC(in, C*N, celt_sig);
+   for (j=0;j<C*N;j++) {
+     in[j] = SCALEOUT(pcm[j]);
+   }
+
+   ret = celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+   for (j=0;j<C*N;j++)
+      ((opus_int16*)pcm)[j] = FLOAT2INT16(in[j]);
+#endif
+   RESTORE_STACK;
+   return ret;
+}
+
+int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+   return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+
+#endif
+
+#endif /* CUSTOM_MODES */
+
+int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...)
+{
+   va_list ap;
+
+   va_start(ap, request);
+   switch (request)
+   {
+      case OPUS_SET_COMPLEXITY_REQUEST:
+      {
+         int value = va_arg(ap, opus_int32);
+         if (value<0 || value>10)
+            goto bad_arg;
+         st->complexity = value;
+      }
+      break;
+      case CELT_SET_START_BAND_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         if (value<0 || value>=st->mode->nbEBands)
+            goto bad_arg;
+         st->start = value;
+      }
+      break;
+      case CELT_SET_END_BAND_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         if (value<1 || value>st->mode->nbEBands)
+            goto bad_arg;
+         st->end = value;
+      }
+      break;
+      case CELT_SET_PREDICTION_REQUEST:
+      {
+         int value = va_arg(ap, opus_int32);
+         if (value<0 || value>2)
+            goto bad_arg;
+         st->disable_pf = value<=1;
+         st->force_intra = value==0;
+      }
+      break;
+      case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+      {
+         int value = va_arg(ap, opus_int32);
+         if (value<0 || value>100)
+            goto bad_arg;
+         st->loss_rate = value;
+      }
+      break;
+      case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         st->constrained_vbr = value;
+      }
+      break;
+      case OPUS_SET_VBR_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         st->vbr = value;
+      }
+      break;
+      case OPUS_SET_BITRATE_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         if (value<=500 && value!=OPUS_BITRATE_MAX)
+            goto bad_arg;
+         value = IMIN(value, 260000*st->channels);
+         st->bitrate = value;
+      }
+      break;
+      case CELT_SET_CHANNELS_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         if (value<1 || value>2)
+            goto bad_arg;
+         st->stream_channels = value;
+      }
+      break;
+      case OPUS_SET_LSB_DEPTH_REQUEST:
+      {
+          opus_int32 value = va_arg(ap, opus_int32);
+          if (value<8 || value>24)
+             goto bad_arg;
+          st->lsb_depth=value;
+      }
+      break;
+      case OPUS_GET_LSB_DEPTH_REQUEST:
+      {
+          opus_int32 *value = va_arg(ap, opus_int32*);
+          *value=st->lsb_depth;
+      }
+      break;
+      case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+      {
+          opus_int32 value = va_arg(ap, opus_int32);
+          st->variable_duration = value;
+      }
+      break;
+      case OPUS_RESET_STATE:
+      {
+         int i;
+         opus_val16 *oldBandE, *oldLogE, *oldLogE2;
+         oldBandE = (opus_val16*)(st->in_mem+st->channels*(st->mode->overlap+COMBFILTER_MAXPERIOD));
+         oldLogE = oldBandE + st->channels*st->mode->nbEBands;
+         oldLogE2 = oldLogE + st->channels*st->mode->nbEBands;
+         OPUS_CLEAR((char*)&st->ENCODER_RESET_START,
+               opus_custom_encoder_get_size(st->mode, st->channels)-
+               ((char*)&st->ENCODER_RESET_START - (char*)st));
+         for (i=0;i<st->channels*st->mode->nbEBands;i++)
+            oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT);
+         st->vbr_offset = 0;
+         st->delayedIntra = 1;
+         st->spread_decision = SPREAD_NORMAL;
+         st->tonal_average = 256;
+         st->hf_average = 0;
+         st->tapset_decision = 0;
+      }
+      break;
+#ifdef CUSTOM_MODES
+      case CELT_SET_INPUT_CLIPPING_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         st->clip = value;
+      }
+      break;
+#endif
+      case CELT_SET_SIGNALLING_REQUEST:
+      {
+         opus_int32 value = va_arg(ap, opus_int32);
+         st->signalling = value;
+      }
+      break;
+      case CELT_SET_ANALYSIS_REQUEST:
+      {
+         AnalysisInfo *info = va_arg(ap, AnalysisInfo *);
+         if (info)
+            OPUS_COPY(&st->analysis, info, 1);
+      }
+      break;
+      case CELT_GET_MODE_REQUEST:
+      {
+         const CELTMode ** value = va_arg(ap, const CELTMode**);
+         if (value==0)
+            goto bad_arg;
+         *value=st->mode;
+      }
+      break;
+      case OPUS_GET_FINAL_RANGE_REQUEST:
+      {
+         opus_uint32 * value = va_arg(ap, opus_uint32 *);
+         if (value==0)
+            goto bad_arg;
+         *value=st->rng;
+      }
+      break;
+      case OPUS_SET_LFE_REQUEST:
+      {
+          opus_int32 value = va_arg(ap, opus_int32);
+          st->lfe = value;
+      }
+      break;
+      case OPUS_SET_ENERGY_MASK_REQUEST:
+      {
+          opus_val16 *value = va_arg(ap, opus_val16*);
+          st->energy_mask = value;
+      }
+      break;
+      default:
+         goto bad_request;
+   }
+   va_end(ap);
+   return OPUS_OK;
+bad_arg:
+   va_end(ap);
+   return OPUS_BAD_ARG;
+bad_request:
+   va_end(ap);
+   return OPUS_UNIMPLEMENTED;
+}
diff --git a/third_party/opus/src/celt/celt_lpc.c b/third_party/opus/src/celt/celt_lpc.c
new file mode 100644
index 0000000..b410a21c
--- /dev/null
+++ b/third_party/opus/src/celt/celt_lpc.c
@@ -0,0 +1,314 @@
+/* Copyright (c) 2009-2010 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+
+void _celt_lpc(
+      opus_val16       *_lpc, /* out: [0...p-1] LPC coefficients      */
+const opus_val32 *ac,  /* in:  [0...p] autocorrelation values  */
+int          p
+)
+{
+   int i, j;
+   opus_val32 r;
+   opus_val32 error = ac[0];
+#ifdef FIXED_POINT
+   opus_val32 lpc[LPC_ORDER];
+#else
+   float *lpc = _lpc;
+#endif
+
+   OPUS_CLEAR(lpc, p);
+   if (ac[0] != 0)
+   {
+      for (i = 0; i < p; i++) {
+         /* Sum up this iteration's reflection coefficient */
+         opus_val32 rr = 0;
+         for (j = 0; j < i; j++)
+            rr += MULT32_32_Q31(lpc[j],ac[i - j]);
+         rr += SHR32(ac[i + 1],3);
+         r = -frac_div32(SHL32(rr,3), error);
+         /*  Update LPC coefficients and total error */
+         lpc[i] = SHR32(r,3);
+         for (j = 0; j < (i+1)>>1; j++)
+         {
+            opus_val32 tmp1, tmp2;
+            tmp1 = lpc[j];
+            tmp2 = lpc[i-1-j];
+            lpc[j]     = tmp1 + MULT32_32_Q31(r,tmp2);
+            lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1);
+         }
+
+         error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error);
+         /* Bail out once we get 30 dB gain */
+#ifdef FIXED_POINT
+         if (error<SHR32(ac[0],10))
+            break;
+#else
+         if (error<.001f*ac[0])
+            break;
+#endif
+      }
+   }
+#ifdef FIXED_POINT
+   for (i=0;i<p;i++)
+      _lpc[i] = ROUND16(lpc[i],16);
+#endif
+}
+
+
+void celt_fir_c(
+         const opus_val16 *_x,
+         const opus_val16 *num,
+         opus_val16 *_y,
+         int N,
+         int ord,
+         opus_val16 *mem,
+         int arch)
+{
+   int i,j;
+   VARDECL(opus_val16, rnum);
+   VARDECL(opus_val16, x);
+   SAVE_STACK;
+
+   ALLOC(rnum, ord, opus_val16);
+   ALLOC(x, N+ord, opus_val16);
+   for(i=0;i<ord;i++)
+      rnum[i] = num[ord-i-1];
+   for(i=0;i<ord;i++)
+      x[i] = mem[ord-i-1];
+   for (i=0;i<N;i++)
+      x[i+ord]=_x[i];
+   for(i=0;i<ord;i++)
+      mem[i] = _x[N-i-1];
+#ifdef SMALL_FOOTPRINT
+   (void)arch;
+   for (i=0;i<N;i++)
+   {
+      opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT);
+      for (j=0;j<ord;j++)
+      {
+         sum = MAC16_16(sum,rnum[j],x[i+j]);
+      }
+      _y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT));
+   }
+#else
+   for (i=0;i<N-3;i+=4)
+   {
+      opus_val32 sum[4]={0,0,0,0};
+      xcorr_kernel(rnum, x+i, sum, ord, arch);
+      _y[i  ] = SATURATE16(ADD32(EXTEND32(_x[i  ]), PSHR32(sum[0], SIG_SHIFT)));
+      _y[i+1] = SATURATE16(ADD32(EXTEND32(_x[i+1]), PSHR32(sum[1], SIG_SHIFT)));
+      _y[i+2] = SATURATE16(ADD32(EXTEND32(_x[i+2]), PSHR32(sum[2], SIG_SHIFT)));
+      _y[i+3] = SATURATE16(ADD32(EXTEND32(_x[i+3]), PSHR32(sum[3], SIG_SHIFT)));
+   }
+   for (;i<N;i++)
+   {
+      opus_val32 sum = 0;
+      for (j=0;j<ord;j++)
+         sum = MAC16_16(sum,rnum[j],x[i+j]);
+      _y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT)));
+   }
+#endif
+   RESTORE_STACK;
+}
+
+void celt_iir(const opus_val32 *_x,
+         const opus_val16 *den,
+         opus_val32 *_y,
+         int N,
+         int ord,
+         opus_val16 *mem,
+         int arch)
+{
+#ifdef SMALL_FOOTPRINT
+   int i,j;
+   (void)arch;
+   for (i=0;i<N;i++)
+   {
+      opus_val32 sum = _x[i];
+      for (j=0;j<ord;j++)
+      {
+         sum -= MULT16_16(den[j],mem[j]);
+      }
+      for (j=ord-1;j>=1;j--)
+      {
+         mem[j]=mem[j-1];
+      }
+      mem[0] = ROUND16(sum,SIG_SHIFT);
+      _y[i] = sum;
+   }
+#else
+   int i,j;
+   VARDECL(opus_val16, rden);
+   VARDECL(opus_val16, y);
+   SAVE_STACK;
+
+   celt_assert((ord&3)==0);
+   ALLOC(rden, ord, opus_val16);
+   ALLOC(y, N+ord, opus_val16);
+   for(i=0;i<ord;i++)
+      rden[i] = den[ord-i-1];
+   for(i=0;i<ord;i++)
+      y[i] = -mem[ord-i-1];
+   for(;i<N+ord;i++)
+      y[i]=0;
+   for (i=0;i<N-3;i+=4)
+   {
+      /* Unroll by 4 as if it were an FIR filter */
+      opus_val32 sum[4];
+      sum[0]=_x[i];
+      sum[1]=_x[i+1];
+      sum[2]=_x[i+2];
+      sum[3]=_x[i+3];
+      xcorr_kernel(rden, y+i, sum, ord, arch);
+
+      /* Patch up the result to compensate for the fact that this is an IIR */
+      y[i+ord  ] = -ROUND16(sum[0],SIG_SHIFT);
+      _y[i  ] = sum[0];
+      sum[1] = MAC16_16(sum[1], y[i+ord  ], den[0]);
+      y[i+ord+1] = -ROUND16(sum[1],SIG_SHIFT);
+      _y[i+1] = sum[1];
+      sum[2] = MAC16_16(sum[2], y[i+ord+1], den[0]);
+      sum[2] = MAC16_16(sum[2], y[i+ord  ], den[1]);
+      y[i+ord+2] = -ROUND16(sum[2],SIG_SHIFT);
+      _y[i+2] = sum[2];
+
+      sum[3] = MAC16_16(sum[3], y[i+ord+2], den[0]);
+      sum[3] = MAC16_16(sum[3], y[i+ord+1], den[1]);
+      sum[3] = MAC16_16(sum[3], y[i+ord  ], den[2]);
+      y[i+ord+3] = -ROUND16(sum[3],SIG_SHIFT);
+      _y[i+3] = sum[3];
+   }
+   for (;i<N;i++)
+   {
+      opus_val32 sum = _x[i];
+      for (j=0;j<ord;j++)
+         sum -= MULT16_16(rden[j],y[i+j]);
+      y[i+ord] = ROUND16(sum,SIG_SHIFT);
+      _y[i] = sum;
+   }
+   for(i=0;i<ord;i++)
+      mem[i] = _y[N-i-1];
+   RESTORE_STACK;
+#endif
+}
+
+int _celt_autocorr(
+                   const opus_val16 *x,   /*  in: [0...n-1] samples x   */
+                   opus_val32       *ac,  /* out: [0...lag-1] ac values */
+                   const opus_val16       *window,
+                   int          overlap,
+                   int          lag,
+                   int          n,
+                   int          arch
+                  )
+{
+   opus_val32 d;
+   int i, k;
+   int fastN=n-lag;
+   int shift;
+   const opus_val16 *xptr;
+   VARDECL(opus_val16, xx);
+   SAVE_STACK;
+   ALLOC(xx, n, opus_val16);
+   celt_assert(n>0);
+   celt_assert(overlap>=0);
+   if (overlap == 0)
+   {
+      xptr = x;
+   } else {
+      for (i=0;i<n;i++)
+         xx[i] = x[i];
+      for (i=0;i<overlap;i++)
+      {
+         xx[i] = MULT16_16_Q15(x[i],window[i]);
+         xx[n-i-1] = MULT16_16_Q15(x[n-i-1],window[i]);
+      }
+      xptr = xx;
+   }
+   shift=0;
+#ifdef FIXED_POINT
+   {
+      opus_val32 ac0;
+      ac0 = 1+(n<<7);
+      if (n&1) ac0 += SHR32(MULT16_16(xptr[0],xptr[0]),9);
+      for(i=(n&1);i<n;i+=2)
+      {
+         ac0 += SHR32(MULT16_16(xptr[i],xptr[i]),9);
+         ac0 += SHR32(MULT16_16(xptr[i+1],xptr[i+1]),9);
+      }
+
+      shift = celt_ilog2(ac0)-30+10;
+      shift = (shift)/2;
+      if (shift>0)
+      {
+         for(i=0;i<n;i++)
+            xx[i] = PSHR32(xptr[i], shift);
+         xptr = xx;
+      } else
+         shift = 0;
+   }
+#endif
+   celt_pitch_xcorr(xptr, xptr, ac, fastN, lag+1, arch);
+   for (k=0;k<=lag;k++)
+   {
+      for (i = k+fastN, d = 0; i < n; i++)
+         d = MAC16_16(d, xptr[i], xptr[i-k]);
+      ac[k] += d;
+   }
+#ifdef FIXED_POINT
+   shift = 2*shift;
+   if (shift<=0)
+      ac[0] += SHL32((opus_int32)1, -shift);
+   if (ac[0] < 268435456)
+   {
+      int shift2 = 29 - EC_ILOG(ac[0]);
+      for (i=0;i<=lag;i++)
+         ac[i] = SHL32(ac[i], shift2);
+      shift -= shift2;
+   } else if (ac[0] >= 536870912)
+   {
+      int shift2=1;
+      if (ac[0] >= 1073741824)
+         shift2++;
+      for (i=0;i<=lag;i++)
+         ac[i] = SHR32(ac[i], shift2);
+      shift += shift2;
+   }
+#endif
+
+   RESTORE_STACK;
+   return shift;
+}
diff --git a/third_party/opus/src/celt/celt_lpc.h b/third_party/opus/src/celt/celt_lpc.h
new file mode 100644
index 0000000..323459eb
--- /dev/null
+++ b/third_party/opus/src/celt/celt_lpc.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2009-2010 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PLC_H
+#define PLC_H
+
+#include "arch.h"
+#include "cpu_support.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#include "x86/celt_lpc_sse.h"
+#endif
+
+#define LPC_ORDER 24
+
+void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p);
+
+void celt_fir_c(
+         const opus_val16 *x,
+         const opus_val16 *num,
+         opus_val16 *y,
+         int N,
+         int ord,
+         opus_val16 *mem,
+         int arch);
+
+#if !defined(OVERRIDE_CELT_FIR)
+#define celt_fir(x, num, y, N, ord, mem, arch) \
+    (celt_fir_c(x, num, y, N, ord, mem, arch))
+#endif
+
+void celt_iir(const opus_val32 *x,
+         const opus_val16 *den,
+         opus_val32 *y,
+         int N,
+         int ord,
+         opus_val16 *mem,
+         int arch);
+
+int _celt_autocorr(const opus_val16 *x, opus_val32 *ac,
+         const opus_val16 *window, int overlap, int lag, int n, int arch);
+
+#endif /* PLC_H */
diff --git a/third_party/opus/src/celt/cpu_support.h b/third_party/opus/src/celt/cpu_support.h
new file mode 100644
index 0000000..68fc6067
--- /dev/null
+++ b/third_party/opus/src/celt/cpu_support.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CPU_SUPPORT_H
+#define CPU_SUPPORT_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#if defined(OPUS_HAVE_RTCD) && \
+  (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
+#include "arm/armcpu.h"
+
+/* We currently support 4 ARM variants:
+ * arch[0] -> ARMv4
+ * arch[1] -> ARMv5E
+ * arch[2] -> ARMv6
+ * arch[3] -> NEON
+ */
+#define OPUS_ARCHMASK 3
+
+#elif (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)) || \
+  (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)) || \
+  (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \
+  (defined(OPUS_X86_MAY_HAVE_AVX) && !defined(OPUS_X86_PRESUME_AVX))
+
+#include "x86/x86cpu.h"
+/* We currently support 5 x86 variants:
+ * arch[0] -> non-sse
+ * arch[1] -> sse
+ * arch[2] -> sse2
+ * arch[3] -> sse4.1
+ * arch[4] -> avx
+ */
+#define OPUS_ARCHMASK 7
+int opus_select_arch(void);
+
+#else
+#define OPUS_ARCHMASK 0
+
+static OPUS_INLINE int opus_select_arch(void)
+{
+  return 0;
+}
+#endif
+#endif
diff --git a/third_party/opus/src/celt/cwrs.c b/third_party/opus/src/celt/cwrs.c
new file mode 100644
index 0000000..9722f0a
--- /dev/null
+++ b/third_party/opus/src/celt/cwrs.c
@@ -0,0 +1,715 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Copyright (c) 2007-2009 Timothy B. Terriberry
+   Written by Timothy B. Terriberry and Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "os_support.h"
+#include "cwrs.h"
+#include "mathops.h"
+#include "arch.h"
+
+#ifdef CUSTOM_MODES
+
+/*Guaranteed to return a conservatively large estimate of the binary logarithm
+   with frac bits of fractional precision.
+  Tested for all possible 32-bit inputs with frac=4, where the maximum
+   overestimation is 0.06254243 bits.*/
+int log2_frac(opus_uint32 val, int frac)
+{
+  int l;
+  l=EC_ILOG(val);
+  if(val&(val-1)){
+    /*This is (val>>l-16), but guaranteed to round up, even if adding a bias
+       before the shift would cause overflow (e.g., for 0xFFFFxxxx).
+       Doesn't work for val=0, but that case fails the test above.*/
+    if(l>16)val=((val-1)>>(l-16))+1;
+    else val<<=16-l;
+    l=(l-1)<<frac;
+    /*Note that we always need one iteration, since the rounding up above means
+       that we might need to adjust the integer part of the logarithm.*/
+    do{
+      int b;
+      b=(int)(val>>16);
+      l+=b<<frac;
+      val=(val+b)>>b;
+      val=(val*val+0x7FFF)>>15;
+    }
+    while(frac-->0);
+    /*If val is not exactly 0x8000, then we have to round up the remainder.*/
+    return l+(val>0x8000);
+  }
+  /*Exact powers of two require no rounding.*/
+  else return (l-1)<<frac;
+}
+#endif
+
+/*Although derived separately, the pulse vector coding scheme is equivalent to
+   a Pyramid Vector Quantizer \cite{Fis86}.
+  Some additional notes about an early version appear at
+   https://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering
+   and the definitions of some terms have evolved since that was written.
+
+  The conversion from a pulse vector to an integer index (encoding) and back
+   (decoding) is governed by two related functions, V(N,K) and U(N,K).
+
+  V(N,K) = the number of combinations, with replacement, of N items, taken K
+   at a time, when a sign bit is added to each item taken at least once (i.e.,
+   the number of N-dimensional unit pulse vectors with K pulses).
+  One way to compute this is via
+    V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1,
+   where choose() is the binomial function.
+  A table of values for N<10 and K<10 looks like:
+  V[10][10] = {
+    {1,  0,   0,    0,    0,     0,     0,      0,      0,       0},
+    {1,  2,   2,    2,    2,     2,     2,      2,      2,       2},
+    {1,  4,   8,   12,   16,    20,    24,     28,     32,      36},
+    {1,  6,  18,   38,   66,   102,   146,    198,    258,     326},
+    {1,  8,  32,   88,  192,   360,   608,    952,   1408,    1992},
+    {1, 10,  50,  170,  450,  1002,  1970,   3530,   5890,    9290},
+    {1, 12,  72,  292,  912,  2364,  5336,  10836,  20256,   35436},
+    {1, 14,  98,  462, 1666,  4942, 12642,  28814,  59906,  115598},
+    {1, 16, 128,  688, 2816,  9424, 27008,  68464, 157184,  332688},
+    {1, 18, 162,  978, 4482, 16722, 53154, 148626, 374274,  864146}
+  };
+
+  U(N,K) = the number of such combinations wherein N-1 objects are taken at
+   most K-1 at a time.
+  This is given by
+    U(N,K) = sum(k=0...K-1,V(N-1,k))
+           = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0.
+  The latter expression also makes clear that U(N,K) is half the number of such
+   combinations wherein the first object is taken at least once.
+  Although it may not be clear from either of these definitions, U(N,K) is the
+   natural function to work with when enumerating the pulse vector codebooks,
+   not V(N,K).
+  U(N,K) is not well-defined for N=0, but with the extension
+    U(0,K) = K>0 ? 0 : 1,
+   the function becomes symmetric: U(N,K) = U(K,N), with a similar table:
+  U[10][10] = {
+    {1, 0,  0,   0,    0,    0,     0,     0,      0,      0},
+    {0, 1,  1,   1,    1,    1,     1,     1,      1,      1},
+    {0, 1,  3,   5,    7,    9,    11,    13,     15,     17},
+    {0, 1,  5,  13,   25,   41,    61,    85,    113,    145},
+    {0, 1,  7,  25,   63,  129,   231,   377,    575,    833},
+    {0, 1,  9,  41,  129,  321,   681,  1289,   2241,   3649},
+    {0, 1, 11,  61,  231,  681,  1683,  3653,   7183,  13073},
+    {0, 1, 13,  85,  377, 1289,  3653,  8989,  19825,  40081},
+    {0, 1, 15, 113,  575, 2241,  7183, 19825,  48639, 108545},
+    {0, 1, 17, 145,  833, 3649, 13073, 40081, 108545, 265729}
+  };
+
+  With this extension, V(N,K) may be written in terms of U(N,K):
+    V(N,K) = U(N,K) + U(N,K+1)
+   for all N>=0, K>=0.
+  Thus U(N,K+1) represents the number of combinations where the first element
+   is positive or zero, and U(N,K) represents the number of combinations where
+   it is negative.
+  With a large enough table of U(N,K) values, we could write O(N) encoding
+   and O(min(N*log(K),N+K)) decoding routines, but such a table would be
+   prohibitively large for small embedded devices (K may be as large as 32767
+   for small N, and N may be as large as 200).
+
+  Both functions obey the same recurrence relation:
+    V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1),
+    U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1),
+   for all N>0, K>0, with different initial conditions at N=0 or K=0.
+  This allows us to construct a row of one of the tables above given the
+   previous row or the next row.
+  Thus we can derive O(NK) encoding and decoding routines with O(K) memory
+   using only addition and subtraction.
+
+  When encoding, we build up from the U(2,K) row and work our way forwards.
+  When decoding, we need to start at the U(N,K) row and work our way backwards,
+   which requires a means of computing U(N,K).
+  U(N,K) may be computed from two previous values with the same N:
+    U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2)
+   for all N>1, and since U(N,K) is symmetric, a similar relation holds for two
+   previous values with the same K:
+    U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K)
+   for all K>1.
+  This allows us to construct an arbitrary row of the U(N,K) table by starting
+   with the first two values, which are constants.
+  This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K)
+   multiplications.
+  Similar relations can be derived for V(N,K), but are not used here.
+
+  For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree
+   polynomial for fixed N.
+  The first few are
+    U(1,K) = 1,
+    U(2,K) = 2*K-1,
+    U(3,K) = (2*K-2)*K+1,
+    U(4,K) = (((4*K-6)*K+8)*K-3)/3,
+    U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3,
+   and
+    V(1,K) = 2,
+    V(2,K) = 4*K,
+    V(3,K) = 4*K*K+2,
+    V(4,K) = 8*(K*K+2)*K/3,
+    V(5,K) = ((4*K*K+20)*K*K+6)/3,
+   for all K>0.
+  This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for
+   small N (and indeed decoding is also O(N) for N<3).
+
+  @ARTICLE{Fis86,
+    author="Thomas R. Fischer",
+    title="A Pyramid Vector Quantizer",
+    journal="IEEE Transactions on Information Theory",
+    volume="IT-32",
+    number=4,
+    pages="568--583",
+    month=Jul,
+    year=1986
+  }*/
+
+#if !defined(SMALL_FOOTPRINT)
+
+/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/
+# define CELT_PVQ_U(_n,_k) (CELT_PVQ_U_ROW[IMIN(_n,_k)][IMAX(_n,_k)])
+/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N
+   with K pulses allocated to it.*/
+# define CELT_PVQ_V(_n,_k) (CELT_PVQ_U(_n,_k)+CELT_PVQ_U(_n,(_k)+1))
+
+/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)).
+  Thus, the number of entries in row I is the larger of the maximum number of
+   pulses we will ever allocate for a given N=I (K=128, or however many fit in
+   32 bits, whichever is smaller), plus one, and the maximum N for which
+   K=I-1 pulses fit in 32 bits.
+  The largest band size in an Opus Custom mode is 208.
+  Otherwise, we can limit things to the set of N which can be achieved by
+   splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48,
+   44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/
+#if defined(CUSTOM_MODES)
+static const opus_uint32 CELT_PVQ_U_DATA[1488]={
+#else
+static const opus_uint32 CELT_PVQ_U_DATA[1272]={
+#endif
+  /*N=0, K=0...176:*/
+  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#if defined(CUSTOM_MODES)
+  /*...208:*/
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0,
+#endif
+  /*N=1, K=1...176:*/
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+#if defined(CUSTOM_MODES)
+  /*...208:*/
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1,
+#endif
+  /*N=2, K=2...176:*/
+  3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41,
+  43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,
+  81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113,
+  115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143,
+  145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
+  175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203,
+  205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233,
+  235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263,
+  265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293,
+  295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323,
+  325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351,
+#if defined(CUSTOM_MODES)
+  /*...208:*/
+  353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381,
+  383, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 411,
+  413, 415,
+#endif
+  /*N=3, K=3...176:*/
+  13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613,
+  685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861,
+  1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785,
+  3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385,
+  6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661,
+  9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961,
+  13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745,
+  17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013,
+  21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765,
+  26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001,
+  31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721,
+  37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925,
+  43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613,
+  50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785,
+  57461, 58141, 58825, 59513, 60205, 60901, 61601,
+#if defined(CUSTOM_MODES)
+  /*...208:*/
+  62305, 63013, 63725, 64441, 65161, 65885, 66613, 67345, 68081, 68821, 69565,
+  70313, 71065, 71821, 72581, 73345, 74113, 74885, 75661, 76441, 77225, 78013,
+  78805, 79601, 80401, 81205, 82013, 82825, 83641, 84461, 85285, 86113,
+#endif
+  /*N=4, K=4...176:*/
+  63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017,
+  7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775,
+  30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153,
+  82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193,
+  161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575,
+  267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217,
+  410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951,
+  597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609,
+  833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023,
+  1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407,
+  1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759,
+  1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175,
+  2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751,
+  2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583,
+  3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767,
+  3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399,
+  4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575,
+  5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391,
+  6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943,
+  7085049, 7207551,
+#if defined(CUSTOM_MODES)
+  /*...208:*/
+  7331457, 7456775, 7583513, 7711679, 7841281, 7972327, 8104825, 8238783,
+  8374209, 8511111, 8649497, 8789375, 8930753, 9073639, 9218041, 9363967,
+  9511425, 9660423, 9810969, 9963071, 10116737, 10271975, 10428793, 10587199,
+  10747201, 10908807, 11072025, 11236863, 11403329, 11571431, 11741177,
+  11912575,
+#endif
+  /*N=5, K=5...176:*/
+  321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041,
+  50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401,
+  330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241,
+  1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241,
+  2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801,
+  4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849,
+  8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849,
+  13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809,
+  20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881,
+  29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641,
+  40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081,
+  55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609,
+  73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049,
+  95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641,
+  122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041,
+  155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321,
+  193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969,
+  238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889,
+  290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401,
+  351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241,
+  420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561,
+  500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929,
+  590359041, 604167209, 618216201, 632508801,
+#if defined(CUSTOM_MODES)
+  /*...208:*/
+  647047809, 661836041, 676876329, 692171521, 707724481, 723538089, 739615241,
+  755958849, 772571841, 789457161, 806617769, 824056641, 841776769, 859781161,
+  878072841, 896654849, 915530241, 934702089, 954173481, 973947521, 994027329,
+  1014416041, 1035116809, 1056132801, 1077467201, 1099123209, 1121104041,
+  1143412929, 1166053121, 1189027881, 1212340489, 1235994241,
+#endif
+  /*N=6, K=6...96:*/
+  1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047,
+  335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409,
+  2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793,
+  11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455,
+  29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189,
+  64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651,
+  128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185,
+  235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647,
+  402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229,
+  655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283,
+  1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135,
+  1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187,
+  2011371957, 2120032959,
+#if defined(CUSTOM_MODES)
+  /*...109:*/
+  2233340609U, 2351442379U, 2474488829U, 2602633639U, 2736033641U, 2874848851U,
+  3019242501U, 3169381071U, 3325434321U, 3487575323U, 3655980493U, 3830829623U,
+  4012305913U,
+#endif
+  /*N=7, K=7...54*/
+  8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777,
+  1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233,
+  19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013,
+  88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805,
+  292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433,
+  793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821,
+  1667010073, 1870535785, 2094367717,
+#if defined(CUSTOM_MODES)
+  /*...60:*/
+  2340095869U, 2609401873U, 2904062449U, 3225952925U, 3577050821U, 3959439497U,
+#endif
+  /*N=8, K=8...37*/
+  48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767,
+  9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017,
+  104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351,
+  638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615,
+  2229491905U,
+#if defined(CUSTOM_MODES)
+  /*...40:*/
+  2691463695U, 3233240945U, 3866006015U,
+#endif
+  /*N=9, K=9...28:*/
+  265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777,
+  39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145,
+  628496897, 872893441, 1196924561, 1621925137, 2173806145U,
+#if defined(CUSTOM_MODES)
+  /*...29:*/
+  2883810113U,
+#endif
+  /*N=10, K=10...24:*/
+  1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073,
+  254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U,
+  3375210671U,
+  /*N=11, K=11...19:*/
+  8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585,
+  948062325, 1616336765,
+#if defined(CUSTOM_MODES)
+  /*...20:*/
+  2684641785U,
+#endif
+  /*N=12, K=12...18:*/
+  45046719, 103274625, 224298231, 464387817, 921406335, 1759885185,
+  3248227095U,
+  /*N=13, K=13...16:*/
+  251595969, 579168825, 1267854873, 2653649025U,
+  /*N=14, K=14:*/
+  1409933619
+};
+
+#if defined(CUSTOM_MODES)
+static const opus_uint32 *const CELT_PVQ_U_ROW[15]={
+  CELT_PVQ_U_DATA+   0,CELT_PVQ_U_DATA+ 208,CELT_PVQ_U_DATA+ 415,
+  CELT_PVQ_U_DATA+ 621,CELT_PVQ_U_DATA+ 826,CELT_PVQ_U_DATA+1030,
+  CELT_PVQ_U_DATA+1233,CELT_PVQ_U_DATA+1336,CELT_PVQ_U_DATA+1389,
+  CELT_PVQ_U_DATA+1421,CELT_PVQ_U_DATA+1441,CELT_PVQ_U_DATA+1455,
+  CELT_PVQ_U_DATA+1464,CELT_PVQ_U_DATA+1470,CELT_PVQ_U_DATA+1473
+};
+#else
+static const opus_uint32 *const CELT_PVQ_U_ROW[15]={
+  CELT_PVQ_U_DATA+   0,CELT_PVQ_U_DATA+ 176,CELT_PVQ_U_DATA+ 351,
+  CELT_PVQ_U_DATA+ 525,CELT_PVQ_U_DATA+ 698,CELT_PVQ_U_DATA+ 870,
+  CELT_PVQ_U_DATA+1041,CELT_PVQ_U_DATA+1131,CELT_PVQ_U_DATA+1178,
+  CELT_PVQ_U_DATA+1207,CELT_PVQ_U_DATA+1226,CELT_PVQ_U_DATA+1240,
+  CELT_PVQ_U_DATA+1248,CELT_PVQ_U_DATA+1254,CELT_PVQ_U_DATA+1257
+};
+#endif
+
+#if defined(CUSTOM_MODES)
+void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
+  int k;
+  /*_maxk==0 => there's nothing to do.*/
+  celt_assert(_maxk>0);
+  _bits[0]=0;
+  for(k=1;k<=_maxk;k++)_bits[k]=log2_frac(CELT_PVQ_V(_n,k),_frac);
+}
+#endif
+
+static opus_uint32 icwrs(int _n,const int *_y){
+  opus_uint32 i;
+  int         j;
+  int         k;
+  celt_assert(_n>=2);
+  j=_n-1;
+  i=_y[j]<0;
+  k=abs(_y[j]);
+  do{
+    j--;
+    i+=CELT_PVQ_U(_n-j,k);
+    k+=abs(_y[j]);
+    if(_y[j]<0)i+=CELT_PVQ_U(_n-j,k+1);
+  }
+  while(j>0);
+  return i;
+}
+
+void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
+  celt_assert(_k>0);
+  ec_enc_uint(_enc,icwrs(_n,_y),CELT_PVQ_V(_n,_k));
+}
+
+static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y){
+  opus_uint32 p;
+  int         s;
+  int         k0;
+  opus_int16  val;
+  opus_val32  yy=0;
+  celt_assert(_k>0);
+  celt_assert(_n>1);
+  while(_n>2){
+    opus_uint32 q;
+    /*Lots of pulses case:*/
+    if(_k>=_n){
+      const opus_uint32 *row;
+      row=CELT_PVQ_U_ROW[_n];
+      /*Are the pulses in this dimension negative?*/
+      p=row[_k+1];
+      s=-(_i>=p);
+      _i-=p&s;
+      /*Count how many pulses were placed in this dimension.*/
+      k0=_k;
+      q=row[_n];
+      if(q>_i){
+        celt_assert(p>q);
+        _k=_n;
+        do p=CELT_PVQ_U_ROW[--_k][_n];
+        while(p>_i);
+      }
+      else for(p=row[_k];p>_i;p=row[_k])_k--;
+      _i-=p;
+      val=(k0-_k+s)^s;
+      *_y++=val;
+      yy=MAC16_16(yy,val,val);
+    }
+    /*Lots of dimensions case:*/
+    else{
+      /*Are there any pulses in this dimension at all?*/
+      p=CELT_PVQ_U_ROW[_k][_n];
+      q=CELT_PVQ_U_ROW[_k+1][_n];
+      if(p<=_i&&_i<q){
+        _i-=p;
+        *_y++=0;
+      }
+      else{
+        /*Are the pulses in this dimension negative?*/
+        s=-(_i>=q);
+        _i-=q&s;
+        /*Count how many pulses were placed in this dimension.*/
+        k0=_k;
+        do p=CELT_PVQ_U_ROW[--_k][_n];
+        while(p>_i);
+        _i-=p;
+        val=(k0-_k+s)^s;
+        *_y++=val;
+        yy=MAC16_16(yy,val,val);
+      }
+    }
+    _n--;
+  }
+  /*_n==2*/
+  p=2*_k+1;
+  s=-(_i>=p);
+  _i-=p&s;
+  k0=_k;
+  _k=(_i+1)>>1;
+  if(_k)_i-=2*_k-1;
+  val=(k0-_k+s)^s;
+  *_y++=val;
+  yy=MAC16_16(yy,val,val);
+  /*_n==1*/
+  s=-(int)_i;
+  val=(_k+s)^s;
+  *_y=val;
+  yy=MAC16_16(yy,val,val);
+  return yy;
+}
+
+opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){
+  return cwrsi(_n,_k,ec_dec_uint(_dec,CELT_PVQ_V(_n,_k)),_y);
+}
+
+#else /* SMALL_FOOTPRINT */
+
+/*Computes the next row/column of any recurrence that obeys the relation
+   u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1].
+  _ui0 is the base case for the new row/column.*/
+static OPUS_INLINE void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){
+  opus_uint32 ui1;
+  unsigned      j;
+  /*This do-while will overrun the array if we don't have storage for at least
+     2 values.*/
+  j=1; do {
+    ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0);
+    _ui[j-1]=_ui0;
+    _ui0=ui1;
+  } while (++j<_len);
+  _ui[j-1]=_ui0;
+}
+
+/*Computes the previous row/column of any recurrence that obeys the relation
+   u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1].
+  _ui0 is the base case for the new row/column.*/
+static OPUS_INLINE void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){
+  opus_uint32 ui1;
+  unsigned      j;
+  /*This do-while will overrun the array if we don't have storage for at least
+     2 values.*/
+  j=1; do {
+    ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0);
+    _ui[j-1]=_ui0;
+    _ui0=ui1;
+  } while (++j<_n);
+  _ui[j-1]=_ui0;
+}
+
+/*Compute V(_n,_k), as well as U(_n,0..._k+1).
+  _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/
+static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){
+  opus_uint32 um2;
+  unsigned      len;
+  unsigned      k;
+  len=_k+2;
+  /*We require storage at least 3 values (e.g., _k>0).*/
+  celt_assert(len>=3);
+  _u[0]=0;
+  _u[1]=um2=1;
+  /*If _n==0, _u[0] should be 1 and the rest should be 0.*/
+  /*If _n==1, _u[i] should be 1 for i>1.*/
+  celt_assert(_n>=2);
+  /*If _k==0, the following do-while loop will overflow the buffer.*/
+  celt_assert(_k>0);
+  k=2;
+  do _u[k]=(k<<1)-1;
+  while(++k<len);
+  for(k=2;k<_n;k++)unext(_u+1,_k+1,1);
+  return _u[_k]+_u[_k+1];
+}
+
+/*Returns the _i'th combination of _k elements chosen from a set of size _n
+   with associated sign bits.
+  _y: Returns the vector of pulses.
+  _u: Must contain entries [0..._k+1] of row _n of U() on input.
+      Its contents will be destructively modified.*/
+static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y,opus_uint32 *_u){
+  int j;
+  opus_int16 val;
+  opus_val32 yy=0;
+  celt_assert(_n>0);
+  j=0;
+  do{
+    opus_uint32 p;
+    int           s;
+    int           yj;
+    p=_u[_k+1];
+    s=-(_i>=p);
+    _i-=p&s;
+    yj=_k;
+    p=_u[_k];
+    while(p>_i)p=_u[--_k];
+    _i-=p;
+    yj-=_k;
+    val=(yj+s)^s;
+    _y[j]=val;
+    yy=MAC16_16(yy,val,val);
+    uprev(_u,_k+2,0);
+  }
+  while(++j<_n);
+  return yy;
+}
+
+/*Returns the index of the given combination of K elements chosen from a set
+   of size 1 with associated sign bits.
+  _y: The vector of pulses, whose sum of absolute values is K.
+  _k: Returns K.*/
+static OPUS_INLINE opus_uint32 icwrs1(const int *_y,int *_k){
+  *_k=abs(_y[0]);
+  return _y[0]<0;
+}
+
+/*Returns the index of the given combination of K elements chosen from a set
+   of size _n with associated sign bits.
+  _y:  The vector of pulses, whose sum of absolute values must be _k.
+  _nc: Returns V(_n,_k).*/
+static OPUS_INLINE opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y,
+ opus_uint32 *_u){
+  opus_uint32 i;
+  int         j;
+  int         k;
+  /*We can't unroll the first two iterations of the loop unless _n>=2.*/
+  celt_assert(_n>=2);
+  _u[0]=0;
+  for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1;
+  i=icwrs1(_y+_n-1,&k);
+  j=_n-2;
+  i+=_u[k];
+  k+=abs(_y[j]);
+  if(_y[j]<0)i+=_u[k+1];
+  while(j-->0){
+    unext(_u,_k+2,0);
+    i+=_u[k];
+    k+=abs(_y[j]);
+    if(_y[j]<0)i+=_u[k+1];
+  }
+  *_nc=_u[k]+_u[k+1];
+  return i;
+}
+
+#ifdef CUSTOM_MODES
+void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
+  int k;
+  /*_maxk==0 => there's nothing to do.*/
+  celt_assert(_maxk>0);
+  _bits[0]=0;
+  if (_n==1)
+  {
+    for (k=1;k<=_maxk;k++)
+      _bits[k] = 1<<_frac;
+  }
+  else {
+    VARDECL(opus_uint32,u);
+    SAVE_STACK;
+    ALLOC(u,_maxk+2U,opus_uint32);
+    ncwrs_urow(_n,_maxk,u);
+    for(k=1;k<=_maxk;k++)
+      _bits[k]=log2_frac(u[k]+u[k+1],_frac);
+    RESTORE_STACK;
+  }
+}
+#endif /* CUSTOM_MODES */
+
+void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
+  opus_uint32 i;
+  VARDECL(opus_uint32,u);
+  opus_uint32 nc;
+  SAVE_STACK;
+  celt_assert(_k>0);
+  ALLOC(u,_k+2U,opus_uint32);
+  i=icwrs(_n,_k,&nc,_y,u);
+  ec_enc_uint(_enc,i,nc);
+  RESTORE_STACK;
+}
+
+opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){
+  VARDECL(opus_uint32,u);
+  int ret;
+  SAVE_STACK;
+  celt_assert(_k>0);
+  ALLOC(u,_k+2U,opus_uint32);
+  ret = cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u);
+  RESTORE_STACK;
+  return ret;
+}
+
+#endif /* SMALL_FOOTPRINT */
diff --git a/third_party/opus/src/celt/cwrs.h b/third_party/opus/src/celt/cwrs.h
new file mode 100644
index 0000000..7cd47174
--- /dev/null
+++ b/third_party/opus/src/celt/cwrs.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Copyright (c) 2007-2009 Timothy B. Terriberry
+   Written by Timothy B. Terriberry and Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CWRS_H
+#define CWRS_H
+
+#include "arch.h"
+#include "stack_alloc.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#ifdef CUSTOM_MODES
+int log2_frac(opus_uint32 val, int frac);
+#endif
+
+void get_required_bits(opus_int16 *bits, int N, int K, int frac);
+
+void encode_pulses(const int *_y, int N, int K, ec_enc *enc);
+
+opus_val32 decode_pulses(int *_y, int N, int K, ec_dec *dec);
+
+#endif /* CWRS_H */
diff --git a/third_party/opus/src/celt/ecintrin.h b/third_party/opus/src/celt/ecintrin.h
new file mode 100644
index 0000000..2263cff
--- /dev/null
+++ b/third_party/opus/src/celt/ecintrin.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2003-2008 Timothy B. Terriberry
+   Copyright (c) 2008 Xiph.Org Foundation */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*Some common macros for potential platform-specific optimization.*/
+#include "opus_types.h"
+#include <math.h>
+#include <limits.h>
+#include "arch.h"
+#if !defined(_ecintrin_H)
+# define _ecintrin_H (1)
+
+/*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly
+   versions of these functions which can substantially improve performance.
+  We define macros for them to allow easy incorporation of these non-ANSI
+   features.*/
+
+/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if
+   given an appropriate architecture, but the branchless bit-twiddling versions
+   are just as fast, and do not require any special target architecture.
+  Earlier gcc versions (3.x) compiled both code to the same assembly
+   instructions, because of the way they represented ((_b)>(_a)) internally.*/
+# define EC_MINI(_a,_b)      ((_a)+(((_b)-(_a))&-((_b)<(_a))))
+
+/*Count leading zeros.
+  This macro should only be used for implementing ec_ilog(), if it is defined.
+  All other code should use EC_ILOG() instead.*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+# include <intrin.h>
+/*In _DEBUG mode this is not an intrinsic by default.*/
+# pragma intrinsic(_BitScanReverse)
+
+static __inline int ec_bsr(unsigned long _x){
+  unsigned long ret;
+  _BitScanReverse(&ret,_x);
+  return (int)ret;
+}
+# define EC_CLZ0    (1)
+# define EC_CLZ(_x) (-ec_bsr(_x))
+#elif defined(ENABLE_TI_DSPLIB)
+# include "dsplib.h"
+# define EC_CLZ0    (31)
+# define EC_CLZ(_x) (_lnorm(_x))
+#elif __GNUC_PREREQ(3,4)
+# if INT_MAX>=2147483647
+#  define EC_CLZ0    ((int)sizeof(unsigned)*CHAR_BIT)
+#  define EC_CLZ(_x) (__builtin_clz(_x))
+# elif LONG_MAX>=2147483647L
+#  define EC_CLZ0    ((int)sizeof(unsigned long)*CHAR_BIT)
+#  define EC_CLZ(_x) (__builtin_clzl(_x))
+# endif
+#endif
+
+#if defined(EC_CLZ)
+/*Note that __builtin_clz is not defined when _x==0, according to the gcc
+   documentation (and that of the BSR instruction that implements it on x86).
+  The majority of the time we can never pass it zero.
+  When we need to, it can be special cased.*/
+# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x))
+#else
+int ec_ilog(opus_uint32 _v);
+# define EC_ILOG(_x) (ec_ilog(_x))
+#endif
+#endif
diff --git a/third_party/opus/src/celt/entcode.c b/third_party/opus/src/celt/entcode.c
new file mode 100644
index 0000000..70f32016
--- /dev/null
+++ b/third_party/opus/src/celt/entcode.c
@@ -0,0 +1,153 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "entcode.h"
+#include "arch.h"
+
+#if !defined(EC_CLZ)
+/*This is a fallback for systems where we don't know how to access
+   a BSR or CLZ instruction (see ecintrin.h).
+  If you are optimizing Opus on a new platform and it has a native CLZ or
+   BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be
+   an easy performance win.*/
+int ec_ilog(opus_uint32 _v){
+  /*On a Pentium M, this branchless version tested as the fastest on
+     1,000,000,000 random 32-bit integers, edging out a similar version with
+     branches, and a 256-entry LUT version.*/
+  int ret;
+  int m;
+  ret=!!_v;
+  m=!!(_v&0xFFFF0000)<<4;
+  _v>>=m;
+  ret|=m;
+  m=!!(_v&0xFF00)<<3;
+  _v>>=m;
+  ret|=m;
+  m=!!(_v&0xF0)<<2;
+  _v>>=m;
+  ret|=m;
+  m=!!(_v&0xC)<<1;
+  _v>>=m;
+  ret|=m;
+  ret+=!!(_v&0x2);
+  return ret;
+}
+#endif
+
+#if 1
+/* This is a faster version of ec_tell_frac() that takes advantage
+   of the low (1/8 bit) resolution to use just a linear function
+   followed by a lookup to determine the exact transition thresholds. */
+opus_uint32 ec_tell_frac(ec_ctx *_this){
+  static const unsigned correction[8] =
+    {35733, 38967, 42495, 46340,
+     50535, 55109, 60097, 65535};
+  opus_uint32 nbits;
+  opus_uint32 r;
+  int         l;
+  unsigned    b;
+  nbits=_this->nbits_total<<BITRES;
+  l=EC_ILOG(_this->rng);
+  r=_this->rng>>(l-16);
+  b = (r>>12)-8;
+  b += r>correction[b];
+  l = (l<<3)+b;
+  return nbits-l;
+}
+#else
+opus_uint32 ec_tell_frac(ec_ctx *_this){
+  opus_uint32 nbits;
+  opus_uint32 r;
+  int         l;
+  int         i;
+  /*To handle the non-integral number of bits still left in the encoder/decoder
+     state, we compute the worst-case number of bits of val that must be
+     encoded to ensure that the value is inside the range for any possible
+     subsequent bits.
+    The computation here is independent of val itself (the decoder does not
+     even track that value), even though the real number of bits used after
+     ec_enc_done() may be 1 smaller if rng is a power of two and the
+     corresponding trailing bits of val are all zeros.
+    If we did try to track that special case, then coding a value with a
+     probability of 1/(1<<n) might sometimes appear to use more than n bits.
+    This may help explain the surprising result that a newly initialized
+     encoder or decoder claims to have used 1 bit.*/
+  nbits=_this->nbits_total<<BITRES;
+  l=EC_ILOG(_this->rng);
+  r=_this->rng>>(l-16);
+  for(i=BITRES;i-->0;){
+    int b;
+    r=r*r>>15;
+    b=(int)(r>>16);
+    l=l<<1|b;
+    r>>=b;
+  }
+  return nbits-l;
+}
+#endif
+
+#ifdef USE_SMALL_DIV_TABLE
+/* Result of 2^32/(2*i+1), except for i=0. */
+const opus_uint32 SMALL_DIV_TABLE[129] = {
+   0xFFFFFFFF, 0x55555555, 0x33333333, 0x24924924,
+   0x1C71C71C, 0x1745D174, 0x13B13B13, 0x11111111,
+   0x0F0F0F0F, 0x0D79435E, 0x0C30C30C, 0x0B21642C,
+   0x0A3D70A3, 0x097B425E, 0x08D3DCB0, 0x08421084,
+   0x07C1F07C, 0x07507507, 0x06EB3E45, 0x06906906,
+   0x063E7063, 0x05F417D0, 0x05B05B05, 0x0572620A,
+   0x05397829, 0x05050505, 0x04D4873E, 0x04A7904A,
+   0x047DC11F, 0x0456C797, 0x04325C53, 0x04104104,
+   0x03F03F03, 0x03D22635, 0x03B5CC0E, 0x039B0AD1,
+   0x0381C0E0, 0x0369D036, 0x03531DEC, 0x033D91D2,
+   0x0329161F, 0x03159721, 0x03030303, 0x02F14990,
+   0x02E05C0B, 0x02D02D02, 0x02C0B02C, 0x02B1DA46,
+   0x02A3A0FD, 0x0295FAD4, 0x0288DF0C, 0x027C4597,
+   0x02702702, 0x02647C69, 0x02593F69, 0x024E6A17,
+   0x0243F6F0, 0x0239E0D5, 0x02302302, 0x0226B902,
+   0x021D9EAD, 0x0214D021, 0x020C49BA, 0x02040810,
+   0x01FC07F0, 0x01F44659, 0x01ECC07B, 0x01E573AC,
+   0x01DE5D6E, 0x01D77B65, 0x01D0CB58, 0x01CA4B30,
+   0x01C3F8F0, 0x01BDD2B8, 0x01B7D6C3, 0x01B20364,
+   0x01AC5701, 0x01A6D01A, 0x01A16D3F, 0x019C2D14,
+   0x01970E4F, 0x01920FB4, 0x018D3018, 0x01886E5F,
+   0x0183C977, 0x017F405F, 0x017AD220, 0x01767DCE,
+   0x01724287, 0x016E1F76, 0x016A13CD, 0x01661EC6,
+   0x01623FA7, 0x015E75BB, 0x015AC056, 0x01571ED3,
+   0x01539094, 0x01501501, 0x014CAB88, 0x0149539E,
+   0x01460CBC, 0x0142D662, 0x013FB013, 0x013C995A,
+   0x013991C2, 0x013698DF, 0x0133AE45, 0x0130D190,
+   0x012E025C, 0x012B404A, 0x01288B01, 0x0125E227,
+   0x01234567, 0x0120B470, 0x011E2EF3, 0x011BB4A4,
+   0x01194538, 0x0116E068, 0x011485F0, 0x0112358E,
+   0x010FEF01, 0x010DB20A, 0x010B7E6E, 0x010953F3,
+   0x01073260, 0x0105197F, 0x0103091B, 0x01010101
+};
+#endif
diff --git a/third_party/opus/src/celt/entcode.h b/third_party/opus/src/celt/entcode.h
new file mode 100644
index 0000000..13d6c84e
--- /dev/null
+++ b/third_party/opus/src/celt/entcode.h
@@ -0,0 +1,152 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+   Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#if !defined(_entcode_H)
+# define _entcode_H (1)
+# include <limits.h>
+# include <stddef.h>
+# include "ecintrin.h"
+
+extern const opus_uint32 SMALL_DIV_TABLE[129];
+
+#ifdef OPUS_ARM_ASM
+#define USE_SMALL_DIV_TABLE
+#endif
+
+/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a
+   larger type, you can speed up the decoder by using it here.*/
+typedef opus_uint32           ec_window;
+typedef struct ec_ctx         ec_ctx;
+typedef struct ec_ctx         ec_enc;
+typedef struct ec_ctx         ec_dec;
+
+# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT)
+
+/*The number of bits to use for the range-coded part of unsigned integers.*/
+# define EC_UINT_BITS   (8)
+
+/*The resolution of fractional-precision bit usage measurements, i.e.,
+   3 => 1/8th bits.*/
+# define BITRES 3
+
+/*The entropy encoder/decoder context.
+  We use the same structure for both, so that common functions like ec_tell()
+   can be used on either one.*/
+struct ec_ctx{
+   /*Buffered input/output.*/
+   unsigned char *buf;
+   /*The size of the buffer.*/
+   opus_uint32    storage;
+   /*The offset at which the last byte containing raw bits was read/written.*/
+   opus_uint32    end_offs;
+   /*Bits that will be read from/written at the end.*/
+   ec_window      end_window;
+   /*Number of valid bits in end_window.*/
+   int            nend_bits;
+   /*The total number of whole bits read/written.
+     This does not include partial bits currently in the range coder.*/
+   int            nbits_total;
+   /*The offset at which the next range coder byte will be read/written.*/
+   opus_uint32    offs;
+   /*The number of values in the current range.*/
+   opus_uint32    rng;
+   /*In the decoder: the difference between the top of the current range and
+      the input value, minus one.
+     In the encoder: the low end of the current range.*/
+   opus_uint32    val;
+   /*In the decoder: the saved normalization factor from ec_decode().
+     In the encoder: the number of oustanding carry propagating symbols.*/
+   opus_uint32    ext;
+   /*A buffered input/output symbol, awaiting carry propagation.*/
+   int            rem;
+   /*Nonzero if an error occurred.*/
+   int            error;
+};
+
+static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){
+  return _this->offs;
+}
+
+static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){
+  return _this->buf;
+}
+
+static OPUS_INLINE int ec_get_error(ec_ctx *_this){
+  return _this->error;
+}
+
+/*Returns the number of bits "used" by the encoded or decoded symbols so far.
+  This same number can be computed in either the encoder or the decoder, and is
+   suitable for making coding decisions.
+  Return: The number of bits.
+          This will always be slightly larger than the exact value (e.g., all
+           rounding error is in the positive direction).*/
+static OPUS_INLINE int ec_tell(ec_ctx *_this){
+  return _this->nbits_total-EC_ILOG(_this->rng);
+}
+
+/*Returns the number of bits "used" by the encoded or decoded symbols so far.
+  This same number can be computed in either the encoder or the decoder, and is
+   suitable for making coding decisions.
+  Return: The number of bits scaled by 2**BITRES.
+          This will always be slightly larger than the exact value (e.g., all
+           rounding error is in the positive direction).*/
+opus_uint32 ec_tell_frac(ec_ctx *_this);
+
+/* Tested exhaustively for all n and for 1<=d<=256 */
+static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) {
+   celt_assert(d>0);
+#ifdef USE_SMALL_DIV_TABLE
+   if (d>256)
+      return n/d;
+   else {
+      opus_uint32 t, q;
+      t = EC_ILOG(d&-d);
+      q = (opus_uint64)SMALL_DIV_TABLE[d>>t]*(n>>(t-1))>>32;
+      return q+(n-q*d >= d);
+   }
+#else
+   return n/d;
+#endif
+}
+
+static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) {
+   celt_assert(d>0);
+#ifdef USE_SMALL_DIV_TABLE
+   if (n<0)
+      return -(opus_int32)celt_udiv(-n, d);
+   else
+      return celt_udiv(n, d);
+#else
+   return n/d;
+#endif
+}
+
+#endif
diff --git a/third_party/opus/src/celt/entdec.c b/third_party/opus/src/celt/entdec.c
new file mode 100644
index 0000000..0b3433e
--- /dev/null
+++ b/third_party/opus/src/celt/entdec.c
@@ -0,0 +1,245 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+   Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stddef.h>
+#include "os_support.h"
+#include "arch.h"
+#include "entdec.h"
+#include "mfrngcod.h"
+
+/*A range decoder.
+  This is an entropy decoder based upon \cite{Mar79}, which is itself a
+   rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}.
+  It is very similar to arithmetic encoding, except that encoding is done with
+   digits in any base, instead of with bits, and so it is faster when using
+   larger bases (i.e.: a byte).
+  The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$
+   is the base, longer than the theoretical optimum, but to my knowledge there
+   is no published justification for this claim.
+  This only seems true when using near-infinite precision arithmetic so that
+   the process is carried out with no rounding errors.
+
+  An excellent description of implementation details is available at
+   http://www.arturocampos.com/ac_range.html
+  A recent work \cite{MNW98} which proposes several changes to arithmetic
+   encoding for efficiency actually re-discovers many of the principles
+   behind range encoding, and presents a good theoretical analysis of them.
+
+  End of stream is handled by writing out the smallest number of bits that
+   ensures that the stream will be correctly decoded regardless of the value of
+   any subsequent bits.
+  ec_tell() can be used to determine how many bits were needed to decode
+   all the symbols thus far; other data can be packed in the remaining bits of
+   the input buffer.
+  @PHDTHESIS{Pas76,
+    author="Richard Clark Pasco",
+    title="Source coding algorithms for fast data compression",
+    school="Dept. of Electrical Engineering, Stanford University",
+    address="Stanford, CA",
+    month=May,
+    year=1976
+  }
+  @INPROCEEDINGS{Mar79,
+   author="Martin, G.N.N.",
+   title="Range encoding: an algorithm for removing redundancy from a digitised
+    message",
+   booktitle="Video & Data Recording Conference",
+   year=1979,
+   address="Southampton",
+   month=Jul
+  }
+  @ARTICLE{MNW98,
+   author="Alistair Moffat and Radford Neal and Ian H. Witten",
+   title="Arithmetic Coding Revisited",
+   journal="{ACM} Transactions on Information Systems",
+   year=1998,
+   volume=16,
+   number=3,
+   pages="256--294",
+   month=Jul,
+   URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf"
+  }*/
+
+static int ec_read_byte(ec_dec *_this){
+  return _this->offs<_this->storage?_this->buf[_this->offs++]:0;
+}
+
+static int ec_read_byte_from_end(ec_dec *_this){
+  return _this->end_offs<_this->storage?
+   _this->buf[_this->storage-++(_this->end_offs)]:0;
+}
+
+/*Normalizes the contents of val and rng so that rng lies entirely in the
+   high-order symbol.*/
+static void ec_dec_normalize(ec_dec *_this){
+  /*If the range is too small, rescale it and input some bits.*/
+  while(_this->rng<=EC_CODE_BOT){
+    int sym;
+    _this->nbits_total+=EC_SYM_BITS;
+    _this->rng<<=EC_SYM_BITS;
+    /*Use up the remaining bits from our last symbol.*/
+    sym=_this->rem;
+    /*Read the next value from the input.*/
+    _this->rem=ec_read_byte(_this);
+    /*Take the rest of the bits we need from this new symbol.*/
+    sym=(sym<<EC_SYM_BITS|_this->rem)>>(EC_SYM_BITS-EC_CODE_EXTRA);
+    /*And subtract them from val, capped to be less than EC_CODE_TOP.*/
+    _this->val=((_this->val<<EC_SYM_BITS)+(EC_SYM_MAX&~sym))&(EC_CODE_TOP-1);
+  }
+}
+
+void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage){
+  _this->buf=_buf;
+  _this->storage=_storage;
+  _this->end_offs=0;
+  _this->end_window=0;
+  _this->nend_bits=0;
+  /*This is the offset from which ec_tell() will subtract partial bits.
+    The final value after the ec_dec_normalize() call will be the same as in
+     the encoder, but we have to compensate for the bits that are added there.*/
+  _this->nbits_total=EC_CODE_BITS+1
+   -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS;
+  _this->offs=0;
+  _this->rng=1U<<EC_CODE_EXTRA;
+  _this->rem=ec_read_byte(_this);
+  _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA));
+  _this->error=0;
+  /*Normalize the interval.*/
+  ec_dec_normalize(_this);
+}
+
+unsigned ec_decode(ec_dec *_this,unsigned _ft){
+  unsigned s;
+  _this->ext=celt_udiv(_this->rng,_ft);
+  s=(unsigned)(_this->val/_this->ext);
+  return _ft-EC_MINI(s+1,_ft);
+}
+
+unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){
+   unsigned s;
+   _this->ext=_this->rng>>_bits;
+   s=(unsigned)(_this->val/_this->ext);
+   return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits);
+}
+
+void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){
+  opus_uint32 s;
+  s=IMUL32(_this->ext,_ft-_fh);
+  _this->val-=s;
+  _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s;
+  ec_dec_normalize(_this);
+}
+
+/*The probability of having a "one" is 1/(1<<_logp).*/
+int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){
+  opus_uint32 r;
+  opus_uint32 d;
+  opus_uint32 s;
+  int         ret;
+  r=_this->rng;
+  d=_this->val;
+  s=r>>_logp;
+  ret=d<s;
+  if(!ret)_this->val=d-s;
+  _this->rng=ret?s:r-s;
+  ec_dec_normalize(_this);
+  return ret;
+}
+
+int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){
+  opus_uint32 r;
+  opus_uint32 d;
+  opus_uint32 s;
+  opus_uint32 t;
+  int         ret;
+  s=_this->rng;
+  d=_this->val;
+  r=s>>_ftb;
+  ret=-1;
+  do{
+    t=s;
+    s=IMUL32(r,_icdf[++ret]);
+  }
+  while(d<s);
+  _this->val=d-s;
+  _this->rng=t-s;
+  ec_dec_normalize(_this);
+  return ret;
+}
+
+opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){
+  unsigned ft;
+  unsigned s;
+  int      ftb;
+  /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
+  celt_assert(_ft>1);
+  _ft--;
+  ftb=EC_ILOG(_ft);
+  if(ftb>EC_UINT_BITS){
+    opus_uint32 t;
+    ftb-=EC_UINT_BITS;
+    ft=(unsigned)(_ft>>ftb)+1;
+    s=ec_decode(_this,ft);
+    ec_dec_update(_this,s,s+1,ft);
+    t=(opus_uint32)s<<ftb|ec_dec_bits(_this,ftb);
+    if(t<=_ft)return t;
+    _this->error=1;
+    return _ft;
+  }
+  else{
+    _ft++;
+    s=ec_decode(_this,(unsigned)_ft);
+    ec_dec_update(_this,s,s+1,(unsigned)_ft);
+    return s;
+  }
+}
+
+opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){
+  ec_window   window;
+  int         available;
+  opus_uint32 ret;
+  window=_this->end_window;
+  available=_this->nend_bits;
+  if((unsigned)available<_bits){
+    do{
+      window|=(ec_window)ec_read_byte_from_end(_this)<<available;
+      available+=EC_SYM_BITS;
+    }
+    while(available<=EC_WINDOW_SIZE-EC_SYM_BITS);
+  }
+  ret=(opus_uint32)window&(((opus_uint32)1<<_bits)-1U);
+  window>>=_bits;
+  available-=_bits;
+  _this->end_window=window;
+  _this->nend_bits=available;
+  _this->nbits_total+=_bits;
+  return ret;
+}
diff --git a/third_party/opus/src/celt/entdec.h b/third_party/opus/src/celt/entdec.h
new file mode 100644
index 0000000..d8ab318
--- /dev/null
+++ b/third_party/opus/src/celt/entdec.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+   Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(_entdec_H)
+# define _entdec_H (1)
+# include <limits.h>
+# include "entcode.h"
+
+/*Initializes the decoder.
+  _buf: The input buffer to use.
+  Return: 0 on success, or a negative value on error.*/
+void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage);
+
+/*Calculates the cumulative frequency for the next symbol.
+  This can then be fed into the probability model to determine what that
+   symbol is, and the additional frequency information required to advance to
+   the next symbol.
+  This function cannot be called more than once without a corresponding call to
+   ec_dec_update(), or decoding will not proceed correctly.
+  _ft: The total frequency of the symbols in the alphabet the next symbol was
+        encoded with.
+  Return: A cumulative frequency representing the encoded symbol.
+          If the cumulative frequency of all the symbols before the one that
+           was encoded was fl, and the cumulative frequency of all the symbols
+           up to and including the one encoded is fh, then the returned value
+           will fall in the range [fl,fh).*/
+unsigned ec_decode(ec_dec *_this,unsigned _ft);
+
+/*Equivalent to ec_decode() with _ft==1<<_bits.*/
+unsigned ec_decode_bin(ec_dec *_this,unsigned _bits);
+
+/*Advance the decoder past the next symbol using the frequency information the
+   symbol was encoded with.
+  Exactly one call to ec_decode() must have been made so that all necessary
+   intermediate calculations are performed.
+  _fl:  The cumulative frequency of all symbols that come before the symbol
+         decoded.
+  _fh:  The cumulative frequency of all symbols up to and including the symbol
+         decoded.
+        Together with _fl, this defines the range [_fl,_fh) in which the value
+         returned above must fall.
+  _ft:  The total frequency of the symbols in the alphabet the symbol decoded
+         was encoded in.
+        This must be the same as passed to the preceding call to ec_decode().*/
+void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft);
+
+/* Decode a bit that has a 1/(1<<_logp) probability of being a one */
+int ec_dec_bit_logp(ec_dec *_this,unsigned _logp);
+
+/*Decodes a symbol given an "inverse" CDF table.
+  No call to ec_dec_update() is necessary after this call.
+  _icdf: The "inverse" CDF, such that symbol s falls in the range
+          [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb.
+         The values must be monotonically non-increasing, and the last value
+          must be 0.
+  _ftb: The number of bits of precision in the cumulative distribution.
+  Return: The decoded symbol s.*/
+int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb);
+
+/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream.
+  The bits must have been encoded with ec_enc_uint().
+  No call to ec_dec_update() is necessary after this call.
+  _ft: The number of integers that can be decoded (one more than the max).
+       This must be at least one, and no more than 2**32-1.
+  Return: The decoded bits.*/
+opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft);
+
+/*Extracts a sequence of raw bits from the stream.
+  The bits must have been encoded with ec_enc_bits().
+  No call to ec_dec_update() is necessary after this call.
+  _ftb: The number of bits to extract.
+        This must be between 0 and 25, inclusive.
+  Return: The decoded bits.*/
+opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb);
+
+#endif
diff --git a/third_party/opus/src/celt/entenc.c b/third_party/opus/src/celt/entenc.c
new file mode 100644
index 0000000..f1750d25
--- /dev/null
+++ b/third_party/opus/src/celt/entenc.c
@@ -0,0 +1,294 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+   Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(HAVE_CONFIG_H)
+# include "config.h"
+#endif
+#include "os_support.h"
+#include "arch.h"
+#include "entenc.h"
+#include "mfrngcod.h"
+
+/*A range encoder.
+  See entdec.c and the references for implementation details \cite{Mar79,MNW98}.
+
+  @INPROCEEDINGS{Mar79,
+   author="Martin, G.N.N.",
+   title="Range encoding: an algorithm for removing redundancy from a digitised
+    message",
+   booktitle="Video \& Data Recording Conference",
+   year=1979,
+   address="Southampton",
+   month=Jul
+  }
+  @ARTICLE{MNW98,
+   author="Alistair Moffat and Radford Neal and Ian H. Witten",
+   title="Arithmetic Coding Revisited",
+   journal="{ACM} Transactions on Information Systems",
+   year=1998,
+   volume=16,
+   number=3,
+   pages="256--294",
+   month=Jul,
+   URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf"
+  }*/
+
+static int ec_write_byte(ec_enc *_this,unsigned _value){
+  if(_this->offs+_this->end_offs>=_this->storage)return -1;
+  _this->buf[_this->offs++]=(unsigned char)_value;
+  return 0;
+}
+
+static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){
+  if(_this->offs+_this->end_offs>=_this->storage)return -1;
+  _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value;
+  return 0;
+}
+
+/*Outputs a symbol, with a carry bit.
+  If there is a potential to propagate a carry over several symbols, they are
+   buffered until it can be determined whether or not an actual carry will
+   occur.
+  If the counter for the buffered symbols overflows, then the stream becomes
+   undecodable.
+  This gives a theoretical limit of a few billion symbols in a single packet on
+   32-bit systems.
+  The alternative is to truncate the range in order to force a carry, but
+   requires similar carry tracking in the decoder, needlessly slowing it down.*/
+static void ec_enc_carry_out(ec_enc *_this,int _c){
+  if(_c!=EC_SYM_MAX){
+    /*No further carry propagation possible, flush buffer.*/
+    int carry;
+    carry=_c>>EC_SYM_BITS;
+    /*Don't output a byte on the first write.
+      This compare should be taken care of by branch-prediction thereafter.*/
+    if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry);
+    if(_this->ext>0){
+      unsigned sym;
+      sym=(EC_SYM_MAX+carry)&EC_SYM_MAX;
+      do _this->error|=ec_write_byte(_this,sym);
+      while(--(_this->ext)>0);
+    }
+    _this->rem=_c&EC_SYM_MAX;
+  }
+  else _this->ext++;
+}
+
+static OPUS_INLINE void ec_enc_normalize(ec_enc *_this){
+  /*If the range is too small, output some bits and rescale it.*/
+  while(_this->rng<=EC_CODE_BOT){
+    ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT));
+    /*Move the next-to-high-order symbol into the high-order position.*/
+    _this->val=(_this->val<<EC_SYM_BITS)&(EC_CODE_TOP-1);
+    _this->rng<<=EC_SYM_BITS;
+    _this->nbits_total+=EC_SYM_BITS;
+  }
+}
+
+void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){
+  _this->buf=_buf;
+  _this->end_offs=0;
+  _this->end_window=0;
+  _this->nend_bits=0;
+  /*This is the offset from which ec_tell() will subtract partial bits.*/
+  _this->nbits_total=EC_CODE_BITS+1;
+  _this->offs=0;
+  _this->rng=EC_CODE_TOP;
+  _this->rem=-1;
+  _this->val=0;
+  _this->ext=0;
+  _this->storage=_size;
+  _this->error=0;
+}
+
+void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){
+  opus_uint32 r;
+  r=celt_udiv(_this->rng,_ft);
+  if(_fl>0){
+    _this->val+=_this->rng-IMUL32(r,(_ft-_fl));
+    _this->rng=IMUL32(r,(_fh-_fl));
+  }
+  else _this->rng-=IMUL32(r,(_ft-_fh));
+  ec_enc_normalize(_this);
+}
+
+void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){
+  opus_uint32 r;
+  r=_this->rng>>_bits;
+  if(_fl>0){
+    _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl));
+    _this->rng=IMUL32(r,(_fh-_fl));
+  }
+  else _this->rng-=IMUL32(r,((1U<<_bits)-_fh));
+  ec_enc_normalize(_this);
+}
+
+/*The probability of having a "one" is 1/(1<<_logp).*/
+void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){
+  opus_uint32 r;
+  opus_uint32 s;
+  opus_uint32 l;
+  r=_this->rng;
+  l=_this->val;
+  s=r>>_logp;
+  r-=s;
+  if(_val)_this->val=l+r;
+  _this->rng=_val?s:r;
+  ec_enc_normalize(_this);
+}
+
+void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){
+  opus_uint32 r;
+  r=_this->rng>>_ftb;
+  if(_s>0){
+    _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]);
+    _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]);
+  }
+  else _this->rng-=IMUL32(r,_icdf[_s]);
+  ec_enc_normalize(_this);
+}
+
+void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){
+  unsigned  ft;
+  unsigned  fl;
+  int       ftb;
+  /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
+  celt_assert(_ft>1);
+  _ft--;
+  ftb=EC_ILOG(_ft);
+  if(ftb>EC_UINT_BITS){
+    ftb-=EC_UINT_BITS;
+    ft=(_ft>>ftb)+1;
+    fl=(unsigned)(_fl>>ftb);
+    ec_encode(_this,fl,fl+1,ft);
+    ec_enc_bits(_this,_fl&(((opus_uint32)1<<ftb)-1U),ftb);
+  }
+  else ec_encode(_this,_fl,_fl+1,_ft+1);
+}
+
+void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _bits){
+  ec_window window;
+  int       used;
+  window=_this->end_window;
+  used=_this->nend_bits;
+  celt_assert(_bits>0);
+  if(used+_bits>EC_WINDOW_SIZE){
+    do{
+      _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX);
+      window>>=EC_SYM_BITS;
+      used-=EC_SYM_BITS;
+    }
+    while(used>=EC_SYM_BITS);
+  }
+  window|=(ec_window)_fl<<used;
+  used+=_bits;
+  _this->end_window=window;
+  _this->nend_bits=used;
+  _this->nbits_total+=_bits;
+}
+
+void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){
+  int      shift;
+  unsigned mask;
+  celt_assert(_nbits<=EC_SYM_BITS);
+  shift=EC_SYM_BITS-_nbits;
+  mask=((1<<_nbits)-1)<<shift;
+  if(_this->offs>0){
+    /*The first byte has been finalized.*/
+    _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<<shift);
+  }
+  else if(_this->rem>=0){
+    /*The first byte is still awaiting carry propagation.*/
+    _this->rem=(_this->rem&~mask)|_val<<shift;
+  }
+  else if(_this->rng<=(EC_CODE_TOP>>_nbits)){
+    /*The renormalization loop has never been run.*/
+    _this->val=(_this->val&~((opus_uint32)mask<<EC_CODE_SHIFT))|
+     (opus_uint32)_val<<(EC_CODE_SHIFT+shift);
+  }
+  /*The encoder hasn't even encoded _nbits of data yet.*/
+  else _this->error=-1;
+}
+
+void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){
+  celt_assert(_this->offs+_this->end_offs<=_size);
+  OPUS_MOVE(_this->buf+_size-_this->end_offs,
+   _this->buf+_this->storage-_this->end_offs,_this->end_offs);
+  _this->storage=_size;
+}
+
+void ec_enc_done(ec_enc *_this){
+  ec_window   window;
+  int         used;
+  opus_uint32 msk;
+  opus_uint32 end;
+  int         l;
+  /*We output the minimum number of bits that ensures that the symbols encoded
+     thus far will be decoded correctly regardless of the bits that follow.*/
+  l=EC_CODE_BITS-EC_ILOG(_this->rng);
+  msk=(EC_CODE_TOP-1)>>l;
+  end=(_this->val+msk)&~msk;
+  if((end|msk)>=_this->val+_this->rng){
+    l++;
+    msk>>=1;
+    end=(_this->val+msk)&~msk;
+  }
+  while(l>0){
+    ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT));
+    end=(end<<EC_SYM_BITS)&(EC_CODE_TOP-1);
+    l-=EC_SYM_BITS;
+  }
+  /*If we have a buffered byte flush it into the output buffer.*/
+  if(_this->rem>=0||_this->ext>0)ec_enc_carry_out(_this,0);
+  /*If we have buffered extra bits, flush them as well.*/
+  window=_this->end_window;
+  used=_this->nend_bits;
+  while(used>=EC_SYM_BITS){
+    _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX);
+    window>>=EC_SYM_BITS;
+    used-=EC_SYM_BITS;
+  }
+  /*Clear any excess space and add any remaining extra bits to the last byte.*/
+  if(!_this->error){
+    OPUS_CLEAR(_this->buf+_this->offs,
+     _this->storage-_this->offs-_this->end_offs);
+    if(used>0){
+      /*If there's no range coder data at all, give up.*/
+      if(_this->end_offs>=_this->storage)_this->error=-1;
+      else{
+        l=-l;
+        /*If we've busted, don't add too many extra bits to the last byte; it
+           would corrupt the range coder data, and that's more important.*/
+        if(_this->offs+_this->end_offs>=_this->storage&&l<used){
+          window&=(1<<l)-1;
+          _this->error=-1;
+        }
+        _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window;
+      }
+    }
+  }
+}
diff --git a/third_party/opus/src/celt/entenc.h b/third_party/opus/src/celt/entenc.h
new file mode 100644
index 0000000..796bc4d
--- /dev/null
+++ b/third_party/opus/src/celt/entenc.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+   Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(_entenc_H)
+# define _entenc_H (1)
+# include <stddef.h>
+# include "entcode.h"
+
+/*Initializes the encoder.
+  _buf:  The buffer to store output bytes in.
+  _size: The size of the buffer, in chars.*/
+void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size);
+/*Encodes a symbol given its frequency information.
+  The frequency information must be discernable by the decoder, assuming it
+   has read only the previous symbols from the stream.
+  It is allowable to change the frequency information, or even the entire
+   source alphabet, so long as the decoder can tell from the context of the
+   previously encoded information that it is supposed to do so as well.
+  _fl: The cumulative frequency of all symbols that come before the one to be
+        encoded.
+  _fh: The cumulative frequency of all symbols up to and including the one to
+        be encoded.
+       Together with _fl, this defines the range [_fl,_fh) in which the
+        decoded value will fall.
+  _ft: The sum of the frequencies of all the symbols*/
+void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft);
+
+/*Equivalent to ec_encode() with _ft==1<<_bits.*/
+void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits);
+
+/* Encode a bit that has a 1/(1<<_logp) probability of being a one */
+void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp);
+
+/*Encodes a symbol given an "inverse" CDF table.
+  _s:    The index of the symbol to encode.
+  _icdf: The "inverse" CDF, such that symbol _s falls in the range
+          [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb.
+         The values must be monotonically non-increasing, and the last value
+          must be 0.
+  _ftb: The number of bits of precision in the cumulative distribution.*/
+void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb);
+
+/*Encodes a raw unsigned integer in the stream.
+  _fl: The integer to encode.
+  _ft: The number of integers that can be encoded (one more than the max).
+       This must be at least one, and no more than 2**32-1.*/
+void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft);
+
+/*Encodes a sequence of raw bits in the stream.
+  _fl:  The bits to encode.
+  _ftb: The number of bits to encode.
+        This must be between 1 and 25, inclusive.*/
+void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb);
+
+/*Overwrites a few bits at the very start of an existing stream, after they
+   have already been encoded.
+  This makes it possible to have a few flags up front, where it is easy for
+   decoders to access them without parsing the whole stream, even if their
+   values are not determined until late in the encoding process, without having
+   to buffer all the intermediate symbols in the encoder.
+  In order for this to work, at least _nbits bits must have already been
+   encoded using probabilities that are an exact power of two.
+  The encoder can verify the number of encoded bits is sufficient, but cannot
+   check this latter condition.
+  _val:   The bits to encode (in the least _nbits significant bits).
+          They will be decoded in order from most-significant to least.
+  _nbits: The number of bits to overwrite.
+          This must be no more than 8.*/
+void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits);
+
+/*Compacts the data to fit in the target size.
+  This moves up the raw bits at the end of the current buffer so they are at
+   the end of the new buffer size.
+  The caller must ensure that the amount of data that's already been written
+   will fit in the new size.
+  _size: The number of bytes in the new buffer.
+         This must be large enough to contain the bits already written, and
+          must be no larger than the existing size.*/
+void ec_enc_shrink(ec_enc *_this,opus_uint32 _size);
+
+/*Indicates that there are no more symbols to encode.
+  All reamining output bytes are flushed to the output buffer.
+  ec_enc_init() must be called before the encoder can be used again.*/
+void ec_enc_done(ec_enc *_this);
+
+#endif
diff --git a/third_party/opus/src/celt/fixed_debug.h b/third_party/opus/src/celt/fixed_debug.h
new file mode 100644
index 0000000..d28227f5
--- /dev/null
+++ b/third_party/opus/src/celt/fixed_debug.h
@@ -0,0 +1,784 @@
+/* Copyright (C) 2003-2008 Jean-Marc Valin
+   Copyright (C) 2007-2012 Xiph.Org Foundation */
+/**
+   @file fixed_debug.h
+   @brief Fixed-point operations with debugging
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_DEBUG_H
+#define FIXED_DEBUG_H
+
+#include <stdio.h>
+#include "opus_defines.h"
+
+#ifdef CELT_C
+OPUS_EXPORT opus_int64 celt_mips=0;
+#else
+extern opus_int64 celt_mips;
+#endif
+
+#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
+#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15))
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16))
+
+#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16)
+
+#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
+#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768)
+#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL)
+#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1))
+
+#define SHR(a,b) SHR32(a,b)
+#define PSHR(a,b) PSHR32(a,b)
+
+static OPUS_INLINE short NEG16(int x)
+{
+   int res;
+   if (!VERIFY_SHORT(x))
+   {
+      fprintf (stderr, "NEG16: input is not short: %d\n", (int)x);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = -x;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "NEG16: output is not short: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips++;
+   return res;
+}
+static OPUS_INLINE int NEG32(opus_int64 x)
+{
+   opus_int64 res;
+   if (!VERIFY_INT(x))
+   {
+      fprintf (stderr, "NEG16: input is not int: %d\n", (int)x);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = -x;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "NEG16: output is not int: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=2;
+   return res;
+}
+
+#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__)
+static OPUS_INLINE short EXTRACT16_(int x, char *file, int line)
+{
+   int res;
+   if (!VERIFY_SHORT(x))
+   {
+      fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = x;
+   celt_mips++;
+   return res;
+}
+
+#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__)
+static OPUS_INLINE int EXTEND32_(int x, char *file, int line)
+{
+   int res;
+   if (!VERIFY_SHORT(x))
+   {
+      fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = x;
+   celt_mips++;
+   return res;
+}
+
+#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE short SHR16_(int a, int shift, char *file, int line)
+{
+   int res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
+   {
+      fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a>>shift;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips++;
+   return res;
+}
+#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE short SHL16_(int a, int shift, char *file, int line)
+{
+   int res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
+   {
+      fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a<<shift;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips++;
+   return res;
+}
+
+static OPUS_INLINE int SHR32(opus_int64 a, int shift)
+{
+   opus_int64  res;
+   if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
+   {
+      fprintf (stderr, "SHR32: inputs are not int: %d %d\n", (int)a, shift);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a>>shift;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=2;
+   return res;
+}
+#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line)
+{
+   opus_int64  res;
+   if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
+   {
+      fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a<<shift;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "SHL32: output is not int: %lld<<%d = %lld in %s: line %d\n", a, shift, res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=2;
+   return res;
+}
+
+#define PSHR32(a,shift) (celt_mips--,SHR32(ADD32((a),(((opus_val32)(1)<<((shift))>>1))),shift))
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+
+#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a))))
+#define HALF16(x)  (SHR16(x,1))
+#define HALF32(x)  (SHR32(x,1))
+
+//#define SHR(a,shift) ((a) >> (shift))
+//#define SHL(a,shift) ((a) << (shift))
+
+#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short ADD16_(int a, int b, char *file, int line)
+{
+   int res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a+b;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips++;
+   return res;
+}
+
+#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short SUB16_(int a, int b, char *file, int line)
+{
+   int res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a-b;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips++;
+   return res;
+}
+
+#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int ADD32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+   opus_int64 res;
+   if (!VERIFY_INT(a) || !VERIFY_INT(b))
+   {
+      fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a+b;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=2;
+   return res;
+}
+
+#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int SUB32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+   opus_int64 res;
+   if (!VERIFY_INT(a) || !VERIFY_INT(b))
+   {
+      fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a-b;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=2;
+   return res;
+}
+
+#undef UADD32
+#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line)
+{
+   opus_uint64 res;
+   if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
+   {
+      fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a+b;
+   if (!VERIFY_UINT(res))
+   {
+      fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=2;
+   return res;
+}
+
+#undef USUB32
+#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line)
+{
+   opus_uint64 res;
+   if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
+   {
+      fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   if (a<b)
+   {
+      fprintf (stderr, "USUB32: inputs underflow: %llu < %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a-b;
+   if (!VERIFY_UINT(res))
+   {
+      fprintf (stderr, "USUB32: output is not uint32: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=2;
+   return res;
+}
+
+/* result fits in 16 bits */
+static OPUS_INLINE short MULT16_16_16(int a, int b)
+{
+   int res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a*b;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips++;
+   return res;
+}
+
+#define MULT16_16(a, b) MULT16_16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_16_(int a, int b, char *file, int line)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((opus_int64)a)*b;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips++;
+   return res;
+}
+
+#define MAC16_16(c,a,b)     (celt_mips-=2,ADD32((c),MULT16_16((a),(b))))
+
+#define MULT16_32_QX(a, b, Q) MULT16_32_QX_(a, b, Q, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_32_QX_(int a, opus_int64 b, int Q, char *file, int line)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
+   {
+      fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   if (ABS32(b)>=((opus_val32)(1)<<(15+Q)))
+   {
+      fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = (((opus_int64)a)*(opus_int64)b) >> Q;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   if (Q==15)
+      celt_mips+=3;
+   else
+      celt_mips+=4;
+   return res;
+}
+
+#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
+   {
+      fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   if (ABS32(b)>=((opus_int64)(1)<<(15+Q)))
+   {
+      fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<<Q)>>1))>> Q;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   if (Q==15)
+      celt_mips+=4;
+   else
+      celt_mips+=5;
+   return res;
+}
+
+#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
+#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b))))
+#define MAC16_32_Q16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q16((a),(b))))
+
+static OPUS_INLINE int SATURATE(int a, int b)
+{
+   if (a>b)
+      a=b;
+   if (a<-b)
+      a = -b;
+   celt_mips+=3;
+   return a;
+}
+
+static OPUS_INLINE opus_int16 SATURATE16(opus_int32 a)
+{
+   celt_mips+=3;
+   if (a>32767)
+      return 32767;
+   else if (a<-32768)
+      return -32768;
+   else return a;
+}
+
+static OPUS_INLINE int MULT16_16_Q11_32(int a, int b)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((opus_int64)a)*b;
+   res >>= 11;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=3;
+   return res;
+}
+static OPUS_INLINE short MULT16_16_Q13(int a, int b)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((opus_int64)a)*b;
+   res >>= 13;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=3;
+   return res;
+}
+static OPUS_INLINE short MULT16_16_Q14(int a, int b)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((opus_int64)a)*b;
+   res >>= 14;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=3;
+   return res;
+}
+
+#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short MULT16_16_Q15_(int a, int b, char *file, int line)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((opus_int64)a)*b;
+   res >>= 15;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=1;
+   return res;
+}
+
+static OPUS_INLINE short MULT16_16_P13(int a, int b)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((opus_int64)a)*b;
+   res += 4096;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res >>= 13;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=4;
+   return res;
+}
+static OPUS_INLINE short MULT16_16_P14(int a, int b)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((opus_int64)a)*b;
+   res += 8192;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res >>= 14;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=4;
+   return res;
+}
+static OPUS_INLINE short MULT16_16_P15(int a, int b)
+{
+   opus_int64 res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = ((opus_int64)a)*b;
+   res += 16384;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res >>= 15;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=2;
+   return res;
+}
+
+#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__)
+
+static OPUS_INLINE int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+   opus_int64 res;
+   if (b==0)
+   {
+      fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+      return 0;
+   }
+   if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a/b;
+   if (!VERIFY_SHORT(res))
+   {
+      fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
+      if (res>32767)
+         res = 32767;
+      if (res<-32768)
+         res = -32768;
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=35;
+   return res;
+}
+
+#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int DIV32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+   opus_int64 res;
+   if (b==0)
+   {
+      fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+      return 0;
+   }
+
+   if (!VERIFY_INT(a) || !VERIFY_INT(b))
+   {
+      fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   res = a/b;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+      celt_assert(0);
+#endif
+   }
+   celt_mips+=70;
+   return res;
+}
+
+static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x)
+{
+   x = PSHR32(x, SIG_SHIFT);
+   x = MAX32(x, -32768);
+   x = MIN32(x, 32767);
+   return EXTRACT16(x);
+}
+#define SIG2WORD16(x) (SIG2WORD16_generic(x))
+
+
+#undef PRINT_MIPS
+#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0);
+
+#endif
diff --git a/third_party/opus/src/celt/fixed_generic.h b/third_party/opus/src/celt/fixed_generic.h
new file mode 100644
index 0000000..1cfd6d69
--- /dev/null
+++ b/third_party/opus/src/celt/fixed_generic.h
@@ -0,0 +1,167 @@
+/* Copyright (C) 2007-2009 Xiph.Org Foundation
+   Copyright (C) 2003-2008 Jean-Marc Valin
+   Copyright (C) 2007-2008 CSIRO */
+/**
+   @file fixed_generic.h
+   @brief Generic fixed-point operations
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_GENERIC_H
+#define FIXED_GENERIC_H
+
+/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */
+#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#if OPUS_FAST_INT64
+#define MULT16_32_Q16(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),16))
+#else
+#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+#endif
+
+/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */
+#if OPUS_FAST_INT64
+#define MULT16_32_P16(a,b) ((opus_val32)PSHR((opus_int64)((opus_val16)(a))*(b),16))
+#else
+#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+#endif
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#if OPUS_FAST_INT64
+#define MULT16_32_Q15(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),15))
+#else
+#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15))
+#endif
+
+/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
+#if OPUS_FAST_INT64
+#define MULT32_32_Q31(a,b) ((opus_val32)SHR((opus_int64)(a)*(opus_int64)(b),31))
+#else
+#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15))
+#endif
+
+/** Compile-time conversion of float constant to 16-bit value */
+#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+/** Compile-time conversion of float constant to 32-bit value */
+#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+/** Negate a 16-bit value */
+#define NEG16(x) (-(x))
+/** Negate a 32-bit value */
+#define NEG32(x) (-(x))
+
+/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */
+#define EXTRACT16(x) ((opus_val16)(x))
+/** Change a 16-bit value into a 32-bit value */
+#define EXTEND32(x) ((opus_val32)(x))
+
+/** Arithmetic shift-right of a 16-bit value */
+#define SHR16(a,shift) ((a) >> (shift))
+/** Arithmetic shift-left of a 16-bit value */
+#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift)))
+/** Arithmetic shift-right of a 32-bit value */
+#define SHR32(a,shift) ((a) >> (shift))
+/** Arithmetic shift-left of a 32-bit value */
+#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift)))
+
+/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */
+#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+/** 32-bit arithmetic shift right where the argument can be negative */
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+
+/** "RAW" macros, should not be used outside of this header file */
+#define SHR(a,shift) ((a) >> (shift))
+#define SHL(a,shift) SHL32(a,shift)
+#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+
+#define SATURATE16(x) (EXTRACT16((x)>32767 ? 32767 : (x)<-32768 ? -32768 : (x)))
+
+/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */
+#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a))))
+/** Divide by two */
+#define HALF16(x)  (SHR16(x,1))
+#define HALF32(x)  (SHR32(x,1))
+
+/** Add two 16-bit values */
+#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b)))
+/** Subtract two 16-bit values */
+#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b))
+/** Add two 32-bit values */
+#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b))
+/** Subtract two 32-bit values */
+#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b))
+
+/** 16x16 multiplication where the result fits in 16 bits */
+#define MULT16_16_16(a,b)     ((((opus_val16)(a))*((opus_val16)(b))))
+
+/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */
+/** 16x16 multiplication where the result fits in 32 bits */
+#define MULT16_16(a,b)     (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b)))
+
+/** 16x16 multiply-add where the result fits in 32 bits */
+#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+    b must fit in 31 bits.
+    Result fits in 32 bits. */
+#define MAC16_32_Q15(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
+
+/** 16x32 multiplication, followed by a 16-bit shift right and 32-bit add.
+    Results fits in 32 bits */
+#define MAC16_32_Q16(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)))
+
+#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
+#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
+#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
+
+#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
+#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
+#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
+
+/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */
+#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b))))
+
+/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */
+#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b)))
+
+#if defined(MIPSr1_ASM)
+#include "mips/fixed_generic_mipsr1.h"
+#endif
+
+static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x)
+{
+   x = PSHR32(x, SIG_SHIFT);
+   x = MAX32(x, -32768);
+   x = MIN32(x, 32767);
+   return EXTRACT16(x);
+}
+#define SIG2WORD16(x) (SIG2WORD16_generic(x))
+
+#endif
diff --git a/third_party/opus/src/celt/float_cast.h b/third_party/opus/src/celt/float_cast.h
new file mode 100644
index 0000000..ed5a39b5
--- /dev/null
+++ b/third_party/opus/src/celt/float_cast.h
@@ -0,0 +1,140 @@
+/* Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com> */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Version 1.1 */
+
+#ifndef FLOAT_CAST_H
+#define FLOAT_CAST_H
+
+
+#include "arch.h"
+
+/*============================================================================
+**      On Intel Pentium processors (especially PIII and probably P4), converting
+**      from float to int is very slow. To meet the C specs, the code produced by
+**      most C compilers targeting Pentium needs to change the FPU rounding mode
+**      before the float to int conversion is performed.
+**
+**      Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
+**      is this flushing of the pipeline which is so slow.
+**
+**      Fortunately the ISO C99 specifications define the functions lrint, lrintf,
+**      llrint and llrintf which fix this problem as a side effect.
+**
+**      On Unix-like systems, the configure process should have detected the
+**      presence of these functions. If they weren't found we have to replace them
+**      here with a standard C cast.
+*/
+
+/*
+**      The C99 prototypes for lrint and lrintf are as follows:
+**
+**              long int lrintf (float x) ;
+**              long int lrint  (double x) ;
+*/
+
+/*      The presence of the required functions are detected during the configure
+**      process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
+**      the config.h file.
+*/
+
+#if (HAVE_LRINTF)
+
+/*      These defines enable functionality introduced with the 1999 ISO C
+**      standard. They must be defined before the inclusion of math.h to
+**      engage them. If optimisation is enabled, these functions will be
+**      inlined. With optimisation switched off, you have to link in the
+**      maths library using -lm.
+*/
+
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+
+#include <math.h>
+#define float2int(x) lrintf(x)
+
+#elif (defined(HAVE_LRINT))
+
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+
+#include <math.h>
+#define float2int(x) lrint(x)
+
+#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_X64)
+        #include <xmmintrin.h>
+
+        __inline long int float2int(float value)
+        {
+                return _mm_cvtss_si32(_mm_load_ss(&value));
+        }
+#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_IX86)
+        #include <math.h>
+
+        /*      Win32 doesn't seem to have these functions.
+        **      Therefore implement OPUS_INLINE versions of these functions here.
+        */
+
+        __inline long int
+        float2int (float flt)
+        {       int intgr;
+
+                _asm
+                {       fld flt
+                        fistp intgr
+                } ;
+
+                return intgr ;
+        }
+
+#else
+
+#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L)
+        /* supported by gcc in C99 mode, but not by all other compilers */
+        #warning "Don't have the functions lrint() and lrintf ()."
+        #warning "Replacing these functions with a standard C cast."
+#endif /* __STDC_VERSION__ >= 199901L */
+        #include <math.h>
+        #define float2int(flt) ((int)(floor(.5+flt)))
+#endif
+
+#ifndef DISABLE_FLOAT_API
+static OPUS_INLINE opus_int16 FLOAT2INT16(float x)
+{
+   x = x*CELT_SIG_SCALE;
+   x = MAX32(x, -32768);
+   x = MIN32(x, 32767);
+   return (opus_int16)float2int(x);
+}
+#endif /* DISABLE_FLOAT_API */
+
+#endif /* FLOAT_CAST_H */
diff --git a/third_party/opus/src/celt/kiss_fft.c b/third_party/opus/src/celt/kiss_fft.c
new file mode 100644
index 0000000..1f8fd05
--- /dev/null
+++ b/third_party/opus/src/celt/kiss_fft.c
@@ -0,0 +1,604 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+  Lots of modifications by Jean-Marc Valin
+  Copyright (c) 2005-2007, Xiph.Org Foundation
+  Copyright (c) 2008,      Xiph.Org Foundation, CSIRO
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+       this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.*/
+
+/* This code is originally from Mark Borgerding's KISS-FFT but has been
+   heavily modified to better suit Opus */
+
+#ifndef SKIP_CONFIG_H
+#  ifdef HAVE_CONFIG_H
+#    include "config.h"
+#  endif
+#endif
+
+#include "_kiss_fft_guts.h"
+#include "arch.h"
+#include "os_support.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+
+/* The guts header contains all the multiplication and addition macros that are defined for
+   complex numbers.  It also delares the kf_ internal functions.
+*/
+
+static void kf_bfly2(
+                     kiss_fft_cpx * Fout,
+                     int m,
+                     int N
+                    )
+{
+   kiss_fft_cpx * Fout2;
+   int i;
+   (void)m;
+#ifdef CUSTOM_MODES
+   if (m==1)
+   {
+      celt_assert(m==1);
+      for (i=0;i<N;i++)
+      {
+         kiss_fft_cpx t;
+         Fout2 = Fout + 1;
+         t = *Fout2;
+         C_SUB( *Fout2 ,  *Fout , t );
+         C_ADDTO( *Fout ,  t );
+         Fout += 2;
+      }
+   } else
+#endif
+   {
+      opus_val16 tw;
+      tw = QCONST16(0.7071067812f, 15);
+      /* We know that m==4 here because the radix-2 is just after a radix-4 */
+      celt_assert(m==4);
+      for (i=0;i<N;i++)
+      {
+         kiss_fft_cpx t;
+         Fout2 = Fout + 4;
+         t = Fout2[0];
+         C_SUB( Fout2[0] ,  Fout[0] , t );
+         C_ADDTO( Fout[0] ,  t );
+
+         t.r = S_MUL(Fout2[1].r+Fout2[1].i, tw);
+         t.i = S_MUL(Fout2[1].i-Fout2[1].r, tw);
+         C_SUB( Fout2[1] ,  Fout[1] , t );
+         C_ADDTO( Fout[1] ,  t );
+
+         t.r = Fout2[2].i;
+         t.i = -Fout2[2].r;
+         C_SUB( Fout2[2] ,  Fout[2] , t );
+         C_ADDTO( Fout[2] ,  t );
+
+         t.r = S_MUL(Fout2[3].i-Fout2[3].r, tw);
+         t.i = S_MUL(-Fout2[3].i-Fout2[3].r, tw);
+         C_SUB( Fout2[3] ,  Fout[3] , t );
+         C_ADDTO( Fout[3] ,  t );
+         Fout += 8;
+      }
+   }
+}
+
+static void kf_bfly4(
+                     kiss_fft_cpx * Fout,
+                     const size_t fstride,
+                     const kiss_fft_state *st,
+                     int m,
+                     int N,
+                     int mm
+                    )
+{
+   int i;
+
+   if (m==1)
+   {
+      /* Degenerate case where all the twiddles are 1. */
+      for (i=0;i<N;i++)
+      {
+         kiss_fft_cpx scratch0, scratch1;
+
+         C_SUB( scratch0 , *Fout, Fout[2] );
+         C_ADDTO(*Fout, Fout[2]);
+         C_ADD( scratch1 , Fout[1] , Fout[3] );
+         C_SUB( Fout[2], *Fout, scratch1 );
+         C_ADDTO( *Fout , scratch1 );
+         C_SUB( scratch1 , Fout[1] , Fout[3] );
+
+         Fout[1].r = scratch0.r + scratch1.i;
+         Fout[1].i = scratch0.i - scratch1.r;
+         Fout[3].r = scratch0.r - scratch1.i;
+         Fout[3].i = scratch0.i + scratch1.r;
+         Fout+=4;
+      }
+   } else {
+      int j;
+      kiss_fft_cpx scratch[6];
+      const kiss_twiddle_cpx *tw1,*tw2,*tw3;
+      const int m2=2*m;
+      const int m3=3*m;
+      kiss_fft_cpx * Fout_beg = Fout;
+      for (i=0;i<N;i++)
+      {
+         Fout = Fout_beg + i*mm;
+         tw3 = tw2 = tw1 = st->twiddles;
+         /* m is guaranteed to be a multiple of 4. */
+         for (j=0;j<m;j++)
+         {
+            C_MUL(scratch[0],Fout[m] , *tw1 );
+            C_MUL(scratch[1],Fout[m2] , *tw2 );
+            C_MUL(scratch[2],Fout[m3] , *tw3 );
+
+            C_SUB( scratch[5] , *Fout, scratch[1] );
+            C_ADDTO(*Fout, scratch[1]);
+            C_ADD( scratch[3] , scratch[0] , scratch[2] );
+            C_SUB( scratch[4] , scratch[0] , scratch[2] );
+            C_SUB( Fout[m2], *Fout, scratch[3] );
+            tw1 += fstride;
+            tw2 += fstride*2;
+            tw3 += fstride*3;
+            C_ADDTO( *Fout , scratch[3] );
+
+            Fout[m].r = scratch[5].r + scratch[4].i;
+            Fout[m].i = scratch[5].i - scratch[4].r;
+            Fout[m3].r = scratch[5].r - scratch[4].i;
+            Fout[m3].i = scratch[5].i + scratch[4].r;
+            ++Fout;
+         }
+      }
+   }
+}
+
+
+#ifndef RADIX_TWO_ONLY
+
+static void kf_bfly3(
+                     kiss_fft_cpx * Fout,
+                     const size_t fstride,
+                     const kiss_fft_state *st,
+                     int m,
+                     int N,
+                     int mm
+                    )
+{
+   int i;
+   size_t k;
+   const size_t m2 = 2*m;
+   const kiss_twiddle_cpx *tw1,*tw2;
+   kiss_fft_cpx scratch[5];
+   kiss_twiddle_cpx epi3;
+
+   kiss_fft_cpx * Fout_beg = Fout;
+#ifdef FIXED_POINT
+   /*epi3.r = -16384;*/ /* Unused */
+   epi3.i = -28378;
+#else
+   epi3 = st->twiddles[fstride*m];
+#endif
+   for (i=0;i<N;i++)
+   {
+      Fout = Fout_beg + i*mm;
+      tw1=tw2=st->twiddles;
+      /* For non-custom modes, m is guaranteed to be a multiple of 4. */
+      k=m;
+      do {
+
+         C_MUL(scratch[1],Fout[m] , *tw1);
+         C_MUL(scratch[2],Fout[m2] , *tw2);
+
+         C_ADD(scratch[3],scratch[1],scratch[2]);
+         C_SUB(scratch[0],scratch[1],scratch[2]);
+         tw1 += fstride;
+         tw2 += fstride*2;
+
+         Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
+         Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
+
+         C_MULBYSCALAR( scratch[0] , epi3.i );
+
+         C_ADDTO(*Fout,scratch[3]);
+
+         Fout[m2].r = Fout[m].r + scratch[0].i;
+         Fout[m2].i = Fout[m].i - scratch[0].r;
+
+         Fout[m].r -= scratch[0].i;
+         Fout[m].i += scratch[0].r;
+
+         ++Fout;
+      } while(--k);
+   }
+}
+
+
+#ifndef OVERRIDE_kf_bfly5
+static void kf_bfly5(
+                     kiss_fft_cpx * Fout,
+                     const size_t fstride,
+                     const kiss_fft_state *st,
+                     int m,
+                     int N,
+                     int mm
+                    )
+{
+   kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+   int i, u;
+   kiss_fft_cpx scratch[13];
+   const kiss_twiddle_cpx *tw;
+   kiss_twiddle_cpx ya,yb;
+   kiss_fft_cpx * Fout_beg = Fout;
+
+#ifdef FIXED_POINT
+   ya.r = 10126;
+   ya.i = -31164;
+   yb.r = -26510;
+   yb.i = -19261;
+#else
+   ya = st->twiddles[fstride*m];
+   yb = st->twiddles[fstride*2*m];
+#endif
+   tw=st->twiddles;
+
+   for (i=0;i<N;i++)
+   {
+      Fout = Fout_beg + i*mm;
+      Fout0=Fout;
+      Fout1=Fout0+m;
+      Fout2=Fout0+2*m;
+      Fout3=Fout0+3*m;
+      Fout4=Fout0+4*m;
+
+      /* For non-custom modes, m is guaranteed to be a multiple of 4. */
+      for ( u=0; u<m; ++u ) {
+         scratch[0] = *Fout0;
+
+         C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
+         C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
+         C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
+         C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+         C_ADD( scratch[7],scratch[1],scratch[4]);
+         C_SUB( scratch[10],scratch[1],scratch[4]);
+         C_ADD( scratch[8],scratch[2],scratch[3]);
+         C_SUB( scratch[9],scratch[2],scratch[3]);
+
+         Fout0->r += scratch[7].r + scratch[8].r;
+         Fout0->i += scratch[7].i + scratch[8].i;
+
+         scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
+         scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
+
+         scratch[6].r =  S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
+         scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
+
+         C_SUB(*Fout1,scratch[5],scratch[6]);
+         C_ADD(*Fout4,scratch[5],scratch[6]);
+
+         scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
+         scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
+         scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
+         scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
+
+         C_ADD(*Fout2,scratch[11],scratch[12]);
+         C_SUB(*Fout3,scratch[11],scratch[12]);
+
+         ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+      }
+   }
+}
+#endif /* OVERRIDE_kf_bfly5 */
+
+
+#endif
+
+
+#ifdef CUSTOM_MODES
+
+static
+void compute_bitrev_table(
+         int Fout,
+         opus_int16 *f,
+         const size_t fstride,
+         int in_stride,
+         opus_int16 * factors,
+         const kiss_fft_state *st
+            )
+{
+   const int p=*factors++; /* the radix  */
+   const int m=*factors++; /* stage's fft length/p */
+
+    /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
+   if (m==1)
+   {
+      int j;
+      for (j=0;j<p;j++)
+      {
+         *f = Fout+j;
+         f += fstride*in_stride;
+      }
+   } else {
+      int j;
+      for (j=0;j<p;j++)
+      {
+         compute_bitrev_table( Fout , f, fstride*p, in_stride, factors,st);
+         f += fstride*in_stride;
+         Fout += m;
+      }
+   }
+}
+
+/*  facbuf is populated by p1,m1,p2,m2, ...
+    where
+    p[i] * m[i] = m[i-1]
+    m0 = n                  */
+static
+int kf_factor(int n,opus_int16 * facbuf)
+{
+    int p=4;
+    int i;
+    int stages=0;
+    int nbak = n;
+
+    /*factor out powers of 4, powers of 2, then any remaining primes */
+    do {
+        while (n % p) {
+            switch (p) {
+                case 4: p = 2; break;
+                case 2: p = 3; break;
+                default: p += 2; break;
+            }
+            if (p>32000 || (opus_int32)p*(opus_int32)p > n)
+                p = n;          /* no more factors, skip to end */
+        }
+        n /= p;
+#ifdef RADIX_TWO_ONLY
+        if (p!=2 && p != 4)
+#else
+        if (p>5)
+#endif
+        {
+           return 0;
+        }
+        facbuf[2*stages] = p;
+        if (p==2 && stages > 1)
+        {
+           facbuf[2*stages] = 4;
+           facbuf[2] = 2;
+        }
+        stages++;
+    } while (n > 1);
+    n = nbak;
+    /* Reverse the order to get the radix 4 at the end, so we can use the
+       fast degenerate case. It turns out that reversing the order also
+       improves the noise behaviour. */
+    for (i=0;i<stages/2;i++)
+    {
+       int tmp;
+       tmp = facbuf[2*i];
+       facbuf[2*i] = facbuf[2*(stages-i-1)];
+       facbuf[2*(stages-i-1)] = tmp;
+    }
+    for (i=0;i<stages;i++)
+    {
+        n /= facbuf[2*i];
+        facbuf[2*i+1] = n;
+    }
+    return 1;
+}
+
+static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft)
+{
+   int i;
+#ifdef FIXED_POINT
+   for (i=0;i<nfft;++i) {
+      opus_val32 phase = -i;
+      kf_cexp2(twiddles+i, DIV32(SHL32(phase,17),nfft));
+   }
+#else
+   for (i=0;i<nfft;++i) {
+      const double pi=3.14159265358979323846264338327;
+      double phase = ( -2*pi /nfft ) * i;
+      kf_cexp(twiddles+i, phase );
+   }
+#endif
+}
+
+int opus_fft_alloc_arch_c(kiss_fft_state *st) {
+   (void)st;
+   return 0;
+}
+
+/*
+ *
+ * Allocates all necessary storage space for the fft and ifft.
+ * The return value is a contiguous block of memory.  As such,
+ * It can be freed with free().
+ * */
+kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem,
+                                        const kiss_fft_state *base, int arch)
+{
+    kiss_fft_state *st=NULL;
+    size_t memneeded = sizeof(struct kiss_fft_state); /* twiddle factors*/
+
+    if ( lenmem==NULL ) {
+        st = ( kiss_fft_state*)KISS_FFT_MALLOC( memneeded );
+    }else{
+        if (mem != NULL && *lenmem >= memneeded)
+            st = (kiss_fft_state*)mem;
+        *lenmem = memneeded;
+    }
+    if (st) {
+        opus_int16 *bitrev;
+        kiss_twiddle_cpx *twiddles;
+
+        st->nfft=nfft;
+#ifdef FIXED_POINT
+        st->scale_shift = celt_ilog2(st->nfft);
+        if (st->nfft == 1<<st->scale_shift)
+           st->scale = Q15ONE;
+        else
+           st->scale = (1073741824+st->nfft/2)/st->nfft>>(15-st->scale_shift);
+#else
+        st->scale = 1.f/nfft;
+#endif
+        if (base != NULL)
+        {
+           st->twiddles = base->twiddles;
+           st->shift = 0;
+           while (st->shift < 32 && nfft<<st->shift != base->nfft)
+              st->shift++;
+           if (st->shift>=32)
+              goto fail;
+        } else {
+           st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft);
+           compute_twiddles(twiddles, nfft);
+           st->shift = -1;
+        }
+        if (!kf_factor(nfft,st->factors))
+        {
+           goto fail;
+        }
+
+        /* bitrev */
+        st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft);
+        if (st->bitrev==NULL)
+            goto fail;
+        compute_bitrev_table(0, bitrev, 1,1, st->factors,st);
+
+        /* Initialize architecture specific fft parameters */
+        if (opus_fft_alloc_arch(st, arch))
+            goto fail;
+    }
+    return st;
+fail:
+    opus_fft_free(st, arch);
+    return NULL;
+}
+
+kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch)
+{
+   return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL, arch);
+}
+
+void opus_fft_free_arch_c(kiss_fft_state *st) {
+   (void)st;
+}
+
+void opus_fft_free(const kiss_fft_state *cfg, int arch)
+{
+   if (cfg)
+   {
+      opus_fft_free_arch((kiss_fft_state *)cfg, arch);
+      opus_free((opus_int16*)cfg->bitrev);
+      if (cfg->shift < 0)
+         opus_free((kiss_twiddle_cpx*)cfg->twiddles);
+      opus_free((kiss_fft_state*)cfg);
+   }
+}
+
+#endif /* CUSTOM_MODES */
+
+void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout)
+{
+    int m2, m;
+    int p;
+    int L;
+    int fstride[MAXFACTORS];
+    int i;
+    int shift;
+
+    /* st->shift can be -1 */
+    shift = st->shift>0 ? st->shift : 0;
+
+    fstride[0] = 1;
+    L=0;
+    do {
+       p = st->factors[2*L];
+       m = st->factors[2*L+1];
+       fstride[L+1] = fstride[L]*p;
+       L++;
+    } while(m!=1);
+    m = st->factors[2*L-1];
+    for (i=L-1;i>=0;i--)
+    {
+       if (i!=0)
+          m2 = st->factors[2*i-1];
+       else
+          m2 = 1;
+       switch (st->factors[2*i])
+       {
+       case 2:
+          kf_bfly2(fout, m, fstride[i]);
+          break;
+       case 4:
+          kf_bfly4(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+          break;
+ #ifndef RADIX_TWO_ONLY
+       case 3:
+          kf_bfly3(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+          break;
+       case 5:
+          kf_bfly5(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+          break;
+ #endif
+       }
+       m = m2;
+    }
+}
+
+void opus_fft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+   int i;
+   opus_val16 scale;
+#ifdef FIXED_POINT
+   /* Allows us to scale with MULT16_32_Q16(), which is faster than
+      MULT16_32_Q15() on ARM. */
+   int scale_shift = st->scale_shift-1;
+#endif
+   scale = st->scale;
+
+   celt_assert2 (fin != fout, "In-place FFT not supported");
+   /* Bit-reverse the input */
+   for (i=0;i<st->nfft;i++)
+   {
+      kiss_fft_cpx x = fin[i];
+      fout[st->bitrev[i]].r = SHR32(MULT16_32_Q16(scale, x.r), scale_shift);
+      fout[st->bitrev[i]].i = SHR32(MULT16_32_Q16(scale, x.i), scale_shift);
+   }
+   opus_fft_impl(st, fout);
+}
+
+
+void opus_ifft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+   int i;
+   celt_assert2 (fin != fout, "In-place FFT not supported");
+   /* Bit-reverse the input */
+   for (i=0;i<st->nfft;i++)
+      fout[st->bitrev[i]] = fin[i];
+   for (i=0;i<st->nfft;i++)
+      fout[i].i = -fout[i].i;
+   opus_fft_impl(st, fout);
+   for (i=0;i<st->nfft;i++)
+      fout[i].i = -fout[i].i;
+}
diff --git a/third_party/opus/src/celt/kiss_fft.h b/third_party/opus/src/celt/kiss_fft.h
new file mode 100644
index 0000000..bffa2bf
--- /dev/null
+++ b/third_party/opus/src/celt/kiss_fft.h
@@ -0,0 +1,200 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+  Lots of modifications by Jean-Marc Valin
+  Copyright (c) 2005-2007, Xiph.Org Foundation
+  Copyright (c) 2008,      Xiph.Org Foundation, CSIRO
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+       this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_H
+#define KISS_FFT_H
+
+#include <stdlib.h>
+#include <math.h>
+#include "arch.h"
+#include "cpu_support.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef USE_SIMD
+# include <xmmintrin.h>
+# define kiss_fft_scalar __m128
+#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes)
+#else
+#define KISS_FFT_MALLOC opus_alloc
+#endif
+
+#ifdef FIXED_POINT
+#include "arch.h"
+
+#  define kiss_fft_scalar opus_int32
+#  define kiss_twiddle_scalar opus_int16
+
+
+#else
+# ifndef kiss_fft_scalar
+/*  default is float */
+#   define kiss_fft_scalar float
+#   define kiss_twiddle_scalar float
+#   define KF_SUFFIX _celt_single
+# endif
+#endif
+
+typedef struct {
+    kiss_fft_scalar r;
+    kiss_fft_scalar i;
+}kiss_fft_cpx;
+
+typedef struct {
+   kiss_twiddle_scalar r;
+   kiss_twiddle_scalar i;
+}kiss_twiddle_cpx;
+
+#define MAXFACTORS 8
+/* e.g. an fft of length 128 has 4 factors
+ as far as kissfft is concerned
+ 4*4*4*2
+ */
+
+typedef struct arch_fft_state{
+   int is_supported;
+   void *priv;
+} arch_fft_state;
+
+typedef struct kiss_fft_state{
+    int nfft;
+    opus_val16 scale;
+#ifdef FIXED_POINT
+    int scale_shift;
+#endif
+    int shift;
+    opus_int16 factors[2*MAXFACTORS];
+    const opus_int16 *bitrev;
+    const kiss_twiddle_cpx *twiddles;
+    arch_fft_state *arch_fft;
+} kiss_fft_state;
+
+#if defined(HAVE_ARM_NE10)
+#include "arm/fft_arm.h"
+#endif
+
+/*typedef struct kiss_fft_state* kiss_fft_cfg;*/
+
+/**
+ *  opus_fft_alloc
+ *
+ *  Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
+ *
+ *  typical usage:      kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL);
+ *
+ *  The return value from fft_alloc is a cfg buffer used internally
+ *  by the fft routine or NULL.
+ *
+ *  If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc.
+ *  The returned value should be free()d when done to avoid memory leaks.
+ *
+ *  The state can be placed in a user supplied buffer 'mem':
+ *  If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
+ *      then the function places the cfg in mem and the size used in *lenmem
+ *      and returns mem.
+ *
+ *  If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
+ *      then the function returns NULL and places the minimum cfg
+ *      buffer size in *lenmem.
+ * */
+
+kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base, int arch);
+
+kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch);
+
+/**
+ * opus_fft(cfg,in_out_buf)
+ *
+ * Perform an FFT on a complex input buffer.
+ * for a forward FFT,
+ * fin should be  f[0] , f[1] , ... ,f[nfft-1]
+ * fout will be   F[0] , F[1] , ... ,F[nfft-1]
+ * Note that each element is complex and can be accessed like
+    f[k].r and f[k].i
+ * */
+void opus_fft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+void opus_ifft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+
+void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout);
+void opus_ifft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout);
+
+void opus_fft_free(const kiss_fft_state *cfg, int arch);
+
+
+void opus_fft_free_arch_c(kiss_fft_state *st);
+int opus_fft_alloc_arch_c(kiss_fft_state *st);
+
+#if !defined(OVERRIDE_OPUS_FFT)
+/* Is run-time CPU detection enabled on this platform? */
+#if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10))
+
+extern int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])(
+ kiss_fft_state *st);
+
+#define opus_fft_alloc_arch(_st, arch) \
+         ((*OPUS_FFT_ALLOC_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st))
+
+extern void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])(
+ kiss_fft_state *st);
+#define opus_fft_free_arch(_st, arch) \
+         ((*OPUS_FFT_FREE_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st))
+
+extern void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
+ const kiss_fft_cpx *fin, kiss_fft_cpx *fout);
+#define opus_fft(_cfg, _fin, _fout, arch) \
+   ((*OPUS_FFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout))
+
+extern void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg,
+ const kiss_fft_cpx *fin, kiss_fft_cpx *fout);
+#define opus_ifft(_cfg, _fin, _fout, arch) \
+   ((*OPUS_IFFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout))
+
+#else /* else for if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */
+
+#define opus_fft_alloc_arch(_st, arch) \
+         ((void)(arch), opus_fft_alloc_arch_c(_st))
+
+#define opus_fft_free_arch(_st, arch) \
+         ((void)(arch), opus_fft_free_arch_c(_st))
+
+#define opus_fft(_cfg, _fin, _fout, arch) \
+         ((void)(arch), opus_fft_c(_cfg, _fin, _fout))
+
+#define opus_ifft(_cfg, _fin, _fout, arch) \
+         ((void)(arch), opus_ifft_c(_cfg, _fin, _fout))
+
+#endif /* end if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */
+#endif /* end if !defined(OVERRIDE_OPUS_FFT) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/celt/laplace.c b/third_party/opus/src/celt/laplace.c
new file mode 100644
index 0000000..a7bca874
--- /dev/null
+++ b/third_party/opus/src/celt/laplace.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2007 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "laplace.h"
+#include "mathops.h"
+
+/* The minimum probability of an energy delta (out of 32768). */
+#define LAPLACE_LOG_MINP (0)
+#define LAPLACE_MINP (1<<LAPLACE_LOG_MINP)
+/* The minimum number of guaranteed representable energy deltas (in one
+    direction). */
+#define LAPLACE_NMIN (16)
+
+/* When called, decay is positive and at most 11456. */
+static unsigned ec_laplace_get_freq1(unsigned fs0, int decay)
+{
+   unsigned ft;
+   ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN) - fs0;
+   return ft*(opus_int32)(16384-decay)>>15;
+}
+
+void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay)
+{
+   unsigned fl;
+   int val = *value;
+   fl = 0;
+   if (val)
+   {
+      int s;
+      int i;
+      s = -(val<0);
+      val = (val+s)^s;
+      fl = fs;
+      fs = ec_laplace_get_freq1(fs, decay);
+      /* Search the decaying part of the PDF.*/
+      for (i=1; fs > 0 && i < val; i++)
+      {
+         fs *= 2;
+         fl += fs+2*LAPLACE_MINP;
+         fs = (fs*(opus_int32)decay)>>15;
+      }
+      /* Everything beyond that has probability LAPLACE_MINP. */
+      if (!fs)
+      {
+         int di;
+         int ndi_max;
+         ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP;
+         ndi_max = (ndi_max-s)>>1;
+         di = IMIN(val - i, ndi_max - 1);
+         fl += (2*di+1+s)*LAPLACE_MINP;
+         fs = IMIN(LAPLACE_MINP, 32768-fl);
+         *value = (i+di+s)^s;
+      }
+      else
+      {
+         fs += LAPLACE_MINP;
+         fl += fs&~s;
+      }
+      celt_assert(fl+fs<=32768);
+      celt_assert(fs>0);
+   }
+   ec_encode_bin(enc, fl, fl+fs, 15);
+}
+
+int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay)
+{
+   int val=0;
+   unsigned fl;
+   unsigned fm;
+   fm = ec_decode_bin(dec, 15);
+   fl = 0;
+   if (fm >= fs)
+   {
+      val++;
+      fl = fs;
+      fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP;
+      /* Search the decaying part of the PDF.*/
+      while(fs > LAPLACE_MINP && fm >= fl+2*fs)
+      {
+         fs *= 2;
+         fl += fs;
+         fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15;
+         fs += LAPLACE_MINP;
+         val++;
+      }
+      /* Everything beyond that has probability LAPLACE_MINP. */
+      if (fs <= LAPLACE_MINP)
+      {
+         int di;
+         di = (fm-fl)>>(LAPLACE_LOG_MINP+1);
+         val += di;
+         fl += 2*di*LAPLACE_MINP;
+      }
+      if (fm < fl+fs)
+         val = -val;
+      else
+         fl += fs;
+   }
+   celt_assert(fl<32768);
+   celt_assert(fs>0);
+   celt_assert(fl<=fm);
+   celt_assert(fm<IMIN(fl+fs,32768));
+   ec_dec_update(dec, fl, IMIN(fl+fs,32768), 32768);
+   return val;
+}
diff --git a/third_party/opus/src/celt/laplace.h b/third_party/opus/src/celt/laplace.h
new file mode 100644
index 0000000..46c14b5
--- /dev/null
+++ b/third_party/opus/src/celt/laplace.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2007 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "entenc.h"
+#include "entdec.h"
+
+/** Encode a value that is assumed to be the realisation of a
+    Laplace-distributed random process
+ @param enc Entropy encoder state
+ @param value Value to encode
+ @param fs Probability of 0, multiplied by 32768
+ @param decay Probability of the value +/- 1, multiplied by 16384
+*/
+void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay);
+
+/** Decode a value that is assumed to be the realisation of a
+    Laplace-distributed random process
+ @param dec Entropy decoder state
+ @param fs Probability of 0, multiplied by 32768
+ @param decay Probability of the value +/- 1, multiplied by 16384
+ @return Value decoded
+ */
+int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay);
diff --git a/third_party/opus/src/celt/mathops.c b/third_party/opus/src/celt/mathops.c
new file mode 100644
index 0000000..21a01f5
--- /dev/null
+++ b/third_party/opus/src/celt/mathops.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2002-2008 Jean-Marc Valin
+   Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/**
+   @file mathops.h
+   @brief Various math functions
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mathops.h"
+
+/*Compute floor(sqrt(_val)) with exact arithmetic.
+  This has been tested on all possible 32-bit inputs.*/
+unsigned isqrt32(opus_uint32 _val){
+  unsigned b;
+  unsigned g;
+  int      bshift;
+  /*Uses the second method from
+     http://www.azillionmonkeys.com/qed/sqroot.html
+    The main idea is to search for the largest binary digit b such that
+     (g+b)*(g+b) <= _val, and add it to the solution g.*/
+  g=0;
+  bshift=(EC_ILOG(_val)-1)>>1;
+  b=1U<<bshift;
+  do{
+    opus_uint32 t;
+    t=(((opus_uint32)g<<1)+b)<<bshift;
+    if(t<=_val){
+      g+=b;
+      _val-=t;
+    }
+    b>>=1;
+    bshift--;
+  }
+  while(bshift>=0);
+  return g;
+}
+
+#ifdef FIXED_POINT
+
+opus_val32 frac_div32(opus_val32 a, opus_val32 b)
+{
+   opus_val16 rcp;
+   opus_val32 result, rem;
+   int shift = celt_ilog2(b)-29;
+   a = VSHR32(a,shift);
+   b = VSHR32(b,shift);
+   /* 16-bit reciprocal */
+   rcp = ROUND16(celt_rcp(ROUND16(b,16)),3);
+   result = MULT16_32_Q15(rcp, a);
+   rem = PSHR32(a,2)-MULT32_32_Q31(result, b);
+   result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2));
+   if (result >= 536870912)       /*  2^29 */
+      return 2147483647;          /*  2^31 - 1 */
+   else if (result <= -536870912) /* -2^29 */
+      return -2147483647;         /* -2^31 */
+   else
+      return SHL32(result, 2);
+}
+
+/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */
+opus_val16 celt_rsqrt_norm(opus_val32 x)
+{
+   opus_val16 n;
+   opus_val16 r;
+   opus_val16 r2;
+   opus_val16 y;
+   /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */
+   n = x-32768;
+   /* Get a rough initial guess for the root.
+      The optimal minimax quadratic approximation (using relative error) is
+       r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485).
+      Coefficients here, and the final result r, are Q14.*/
+   r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713))));
+   /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14.
+      We can compute the result from n and r using Q15 multiplies with some
+       adjustment, carefully done to avoid overflow.
+      Range of y is [-1564,1594]. */
+   r2 = MULT16_16_Q15(r, r);
+   y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1);
+   /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5).
+      This yields the Q14 reciprocal square root of the Q16 x, with a maximum
+       relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a
+       peak absolute error of 2.26591/16384. */
+   return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y,
+              SUB16(MULT16_16_Q15(y, 12288), 16384))));
+}
+
+/** Sqrt approximation (QX input, QX/2 output) */
+opus_val32 celt_sqrt(opus_val32 x)
+{
+   int k;
+   opus_val16 n;
+   opus_val32 rt;
+   static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664};
+   if (x==0)
+      return 0;
+   else if (x>=1073741824)
+      return 32767;
+   k = (celt_ilog2(x)>>1)-7;
+   x = VSHR32(x, 2*k);
+   n = x-32768;
+   rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2],
+              MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4])))))))));
+   rt = VSHR32(rt,7-k);
+   return rt;
+}
+
+#define L1 32767
+#define L2 -7651
+#define L3 8277
+#define L4 -626
+
+static OPUS_INLINE opus_val16 _celt_cos_pi_2(opus_val16 x)
+{
+   opus_val16 x2;
+
+   x2 = MULT16_16_P15(x,x);
+   return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2
+                                                                                ))))))));
+}
+
+#undef L1
+#undef L2
+#undef L3
+#undef L4
+
+opus_val16 celt_cos_norm(opus_val32 x)
+{
+   x = x&0x0001ffff;
+   if (x>SHL32(EXTEND32(1), 16))
+      x = SUB32(SHL32(EXTEND32(1), 17),x);
+   if (x&0x00007fff)
+   {
+      if (x<SHL32(EXTEND32(1), 15))
+      {
+         return _celt_cos_pi_2(EXTRACT16(x));
+      } else {
+         return NEG16(_celt_cos_pi_2(EXTRACT16(65536-x)));
+      }
+   } else {
+      if (x&0x0000ffff)
+         return 0;
+      else if (x&0x0001ffff)
+         return -32767;
+      else
+         return 32767;
+   }
+}
+
+/** Reciprocal approximation (Q15 input, Q16 output) */
+opus_val32 celt_rcp(opus_val32 x)
+{
+   int i;
+   opus_val16 n;
+   opus_val16 r;
+   celt_assert2(x>0, "celt_rcp() only defined for positive values");
+   i = celt_ilog2(x);
+   /* n is Q15 with range [0,1). */
+   n = VSHR32(x,i-15)-32768;
+   /* Start with a linear approximation:
+      r = 1.8823529411764706-0.9411764705882353*n.
+      The coefficients and the result are Q14 in the range [15420,30840].*/
+   r = ADD16(30840, MULT16_16_Q15(-15420, n));
+   /* Perform two Newton iterations:
+      r -= r*((r*n)-1.Q15)
+         = r*((r*n)+(r-1.Q15)). */
+   r = SUB16(r, MULT16_16_Q15(r,
+             ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))));
+   /* We subtract an extra 1 in the second iteration to avoid overflow; it also
+       neatly compensates for truncation error in the rest of the process. */
+   r = SUB16(r, ADD16(1, MULT16_16_Q15(r,
+             ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))));
+   /* r is now the Q15 solution to 2/(n+1), with a maximum relative error
+       of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute
+       error of 1.24665/32768. */
+   return VSHR32(EXTEND32(r),i-16);
+}
+
+#endif
diff --git a/third_party/opus/src/celt/mathops.h b/third_party/opus/src/celt/mathops.h
new file mode 100644
index 0000000..a0525a9
--- /dev/null
+++ b/third_party/opus/src/celt/mathops.h
@@ -0,0 +1,258 @@
+/* Copyright (c) 2002-2008 Jean-Marc Valin
+   Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/**
+   @file mathops.h
+   @brief Various math functions
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MATHOPS_H
+#define MATHOPS_H
+
+#include "arch.h"
+#include "entcode.h"
+#include "os_support.h"
+
+/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */
+#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15)
+
+unsigned isqrt32(opus_uint32 _val);
+
+#ifndef OVERRIDE_CELT_MAXABS16
+static OPUS_INLINE opus_val32 celt_maxabs16(const opus_val16 *x, int len)
+{
+   int i;
+   opus_val16 maxval = 0;
+   opus_val16 minval = 0;
+   for (i=0;i<len;i++)
+   {
+      maxval = MAX16(maxval, x[i]);
+      minval = MIN16(minval, x[i]);
+   }
+   return MAX32(EXTEND32(maxval),-EXTEND32(minval));
+}
+#endif
+
+#ifndef OVERRIDE_CELT_MAXABS32
+#ifdef FIXED_POINT
+static OPUS_INLINE opus_val32 celt_maxabs32(const opus_val32 *x, int len)
+{
+   int i;
+   opus_val32 maxval = 0;
+   opus_val32 minval = 0;
+   for (i=0;i<len;i++)
+   {
+      maxval = MAX32(maxval, x[i]);
+      minval = MIN32(minval, x[i]);
+   }
+   return MAX32(maxval, -minval);
+}
+#else
+#define celt_maxabs32(x,len) celt_maxabs16(x,len)
+#endif
+#endif
+
+
+#ifndef FIXED_POINT
+
+#define PI 3.141592653f
+#define celt_sqrt(x) ((float)sqrt(x))
+#define celt_rsqrt(x) (1.f/celt_sqrt(x))
+#define celt_rsqrt_norm(x) (celt_rsqrt(x))
+#define celt_cos_norm(x) ((float)cos((.5f*PI)*(x)))
+#define celt_rcp(x) (1.f/(x))
+#define celt_div(a,b) ((a)/(b))
+#define frac_div32(a,b) ((float)(a)/(b))
+
+#ifdef FLOAT_APPROX
+
+/* Note: This assumes radix-2 floating point with the exponent at bits 23..30 and an offset of 127
+         denorm, +/- inf and NaN are *not* handled */
+
+/** Base-2 log approximation (log2(x)). */
+static OPUS_INLINE float celt_log2(float x)
+{
+   int integer;
+   float frac;
+   union {
+      float f;
+      opus_uint32 i;
+   } in;
+   in.f = x;
+   integer = (in.i>>23)-127;
+   in.i -= integer<<23;
+   frac = in.f - 1.5f;
+   frac = -0.41445418f + frac*(0.95909232f
+          + frac*(-0.33951290f + frac*0.16541097f));
+   return 1+integer+frac;
+}
+
+/** Base-2 exponential approximation (2^x). */
+static OPUS_INLINE float celt_exp2(float x)
+{
+   int integer;
+   float frac;
+   union {
+      float f;
+      opus_uint32 i;
+   } res;
+   integer = floor(x);
+   if (integer < -50)
+      return 0;
+   frac = x-integer;
+   /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */
+   res.f = 0.99992522f + frac * (0.69583354f
+           + frac * (0.22606716f + 0.078024523f*frac));
+   res.i = (res.i + (integer<<23)) & 0x7fffffff;
+   return res.f;
+}
+
+#else
+#define celt_log2(x) ((float)(1.442695040888963387*log(x)))
+#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x)))
+#endif
+
+#endif
+
+#ifdef FIXED_POINT
+
+#include "os_support.h"
+
+#ifndef OVERRIDE_CELT_ILOG2
+/** Integer log in base2. Undefined for zero and negative numbers */
+static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x)
+{
+   celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers");
+   return EC_ILOG(x)-1;
+}
+#endif
+
+
+/** Integer log in base2. Defined for zero, but not for negative numbers */
+static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x)
+{
+   return x <= 0 ? 0 : celt_ilog2(x);
+}
+
+opus_val16 celt_rsqrt_norm(opus_val32 x);
+
+opus_val32 celt_sqrt(opus_val32 x);
+
+opus_val16 celt_cos_norm(opus_val32 x);
+
+/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */
+static OPUS_INLINE opus_val16 celt_log2(opus_val32 x)
+{
+   int i;
+   opus_val16 n, frac;
+   /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605,
+       0.15530808010959576, -0.08556153059057618 */
+   static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401};
+   if (x==0)
+      return -32767;
+   i = celt_ilog2(x);
+   n = VSHR32(x,i-15)-32768-16384;
+   frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4]))))))));
+   return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT);
+}
+
+/*
+ K0 = 1
+ K1 = log(2)
+ K2 = 3-4*log(2)
+ K3 = 3*log(2) - 2
+*/
+#define D0 16383
+#define D1 22804
+#define D2 14819
+#define D3 10204
+
+static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x)
+{
+   opus_val16 frac;
+   frac = SHL16(x, 4);
+   return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac))))));
+}
+/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */
+static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x)
+{
+   int integer;
+   opus_val16 frac;
+   integer = SHR16(x,10);
+   if (integer>14)
+      return 0x7f000000;
+   else if (integer < -15)
+      return 0;
+   frac = celt_exp2_frac(x-SHL16(integer,10));
+   return VSHR32(EXTEND32(frac), -integer-2);
+}
+
+opus_val32 celt_rcp(opus_val32 x);
+
+#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b))
+
+opus_val32 frac_div32(opus_val32 a, opus_val32 b);
+
+#define M1 32767
+#define M2 -21
+#define M3 -11943
+#define M4 4936
+
+/* Atan approximation using a 4th order polynomial. Input is in Q15 format
+   and normalized by pi/4. Output is in Q15 format */
+static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x)
+{
+   return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x)))))));
+}
+
+#undef M1
+#undef M2
+#undef M3
+#undef M4
+
+/* atan2() approximation valid for positive input values */
+static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x)
+{
+   if (y < x)
+   {
+      opus_val32 arg;
+      arg = celt_div(SHL32(EXTEND32(y),15),x);
+      if (arg >= 32767)
+         arg = 32767;
+      return SHR16(celt_atan01(EXTRACT16(arg)),1);
+   } else {
+      opus_val32 arg;
+      arg = celt_div(SHL32(EXTEND32(x),15),y);
+      if (arg >= 32767)
+         arg = 32767;
+      return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1);
+   }
+}
+
+#endif /* FIXED_POINT */
+#endif /* MATHOPS_H */
diff --git a/third_party/opus/src/celt/mdct.c b/third_party/opus/src/celt/mdct.c
new file mode 100644
index 0000000..5315ad11
--- /dev/null
+++ b/third_party/opus/src/celt/mdct.c
@@ -0,0 +1,343 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2008 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+   to do most of the work. It should be relatively straightforward to
+   plug in pretty much and FFT here.
+
+   This replaces the Vorbis FFT (and uses the exact same API), which
+   was a bit too messy and that was ending up duplicating code
+   (might as well use the same FFT everywhere).
+
+   The algorithm is similar to (and inspired from) Fabrice Bellard's
+   MDCT implementation in FFMPEG, but has differences in signs, ordering
+   and scaling in many places.
+*/
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+#include "mdct.h"
+#include "kiss_fft.h"
+#include "_kiss_fft_guts.h"
+#include <math.h>
+#include "os_support.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+
+#if defined(MIPSr1_ASM)
+#include "mips/mdct_mipsr1.h"
+#endif
+
+
+#ifdef CUSTOM_MODES
+
+int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch)
+{
+   int i;
+   kiss_twiddle_scalar *trig;
+   int shift;
+   int N2=N>>1;
+   l->n = N;
+   l->maxshift = maxshift;
+   for (i=0;i<=maxshift;i++)
+   {
+      if (i==0)
+         l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0, arch);
+      else
+         l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0], arch);
+#ifndef ENABLE_TI_DSPLIB55
+      if (l->kfft[i]==NULL)
+         return 0;
+#endif
+   }
+   l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N-(N2>>maxshift))*sizeof(kiss_twiddle_scalar));
+   if (l->trig==NULL)
+     return 0;
+   for (shift=0;shift<=maxshift;shift++)
+   {
+      /* We have enough points that sine isn't necessary */
+#if defined(FIXED_POINT)
+#if 1
+      for (i=0;i<N2;i++)
+         trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2+16384),N));
+#else
+      for (i=0;i<N2;i++)
+         trig[i] = (kiss_twiddle_scalar)MAX32(-32767,MIN32(32767,floor(.5+32768*cos(2*M_PI*(i+.125)/N))));
+#endif
+#else
+      for (i=0;i<N2;i++)
+         trig[i] = (kiss_twiddle_scalar)cos(2*PI*(i+.125)/N);
+#endif
+      trig += N2;
+      N2 >>= 1;
+      N >>= 1;
+   }
+   return 1;
+}
+
+void clt_mdct_clear(mdct_lookup *l, int arch)
+{
+   int i;
+   for (i=0;i<=l->maxshift;i++)
+      opus_fft_free(l->kfft[i], arch);
+   opus_free((kiss_twiddle_scalar*)l->trig);
+}
+
+#endif /* CUSTOM_MODES */
+
+/* Forward MDCT trashes the input array */
+#ifndef OVERRIDE_clt_mdct_forward
+void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+      const opus_val16 *window, int overlap, int shift, int stride, int arch)
+{
+   int i;
+   int N, N2, N4;
+   VARDECL(kiss_fft_scalar, f);
+   VARDECL(kiss_fft_cpx, f2);
+   const kiss_fft_state *st = l->kfft[shift];
+   const kiss_twiddle_scalar *trig;
+   opus_val16 scale;
+#ifdef FIXED_POINT
+   /* Allows us to scale with MULT16_32_Q16(), which is faster than
+      MULT16_32_Q15() on ARM. */
+   int scale_shift = st->scale_shift-1;
+#endif
+   SAVE_STACK;
+   (void)arch;
+   scale = st->scale;
+
+   N = l->n;
+   trig = l->trig;
+   for (i=0;i<shift;i++)
+   {
+      N >>= 1;
+      trig += N;
+   }
+   N2 = N>>1;
+   N4 = N>>2;
+
+   ALLOC(f, N2, kiss_fft_scalar);
+   ALLOC(f2, N4, kiss_fft_cpx);
+
+   /* Consider the input to be composed of four blocks: [a, b, c, d] */
+   /* Window, shuffle, fold */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
+      const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
+      kiss_fft_scalar * OPUS_RESTRICT yp = f;
+      const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1);
+      const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
+      for(i=0;i<((overlap+3)>>2);i++)
+      {
+         /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+         *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2);
+         *yp++ = MULT16_32_Q15(*wp1, *xp1)    - MULT16_32_Q15(*wp2, xp2[-N2]);
+         xp1+=2;
+         xp2-=2;
+         wp1+=2;
+         wp2-=2;
+      }
+      wp1 = window;
+      wp2 = window+overlap-1;
+      for(;i<N4-((overlap+3)>>2);i++)
+      {
+         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+         *yp++ = *xp2;
+         *yp++ = *xp1;
+         xp1+=2;
+         xp2-=2;
+      }
+      for(;i<N4;i++)
+      {
+         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+         *yp++ =  -MULT16_32_Q15(*wp1, xp1[-N2]) + MULT16_32_Q15(*wp2, *xp2);
+         *yp++ = MULT16_32_Q15(*wp2, *xp1)     + MULT16_32_Q15(*wp1, xp2[N2]);
+         xp1+=2;
+         xp2-=2;
+         wp1+=2;
+         wp2-=2;
+      }
+   }
+   /* Pre-rotation */
+   {
+      kiss_fft_scalar * OPUS_RESTRICT yp = f;
+      const kiss_twiddle_scalar *t = &trig[0];
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_cpx yc;
+         kiss_twiddle_scalar t0, t1;
+         kiss_fft_scalar re, im, yr, yi;
+         t0 = t[i];
+         t1 = t[N4+i];
+         re = *yp++;
+         im = *yp++;
+         yr = S_MUL(re,t0)  -  S_MUL(im,t1);
+         yi = S_MUL(im,t0)  +  S_MUL(re,t1);
+         yc.r = yr;
+         yc.i = yi;
+         yc.r = PSHR32(MULT16_32_Q16(scale, yc.r), scale_shift);
+         yc.i = PSHR32(MULT16_32_Q16(scale, yc.i), scale_shift);
+         f2[st->bitrev[i]] = yc;
+      }
+   }
+
+   /* N/4 complex FFT, does not downscale anymore */
+   opus_fft_impl(st, f2);
+
+   /* Post-rotate */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_cpx * OPUS_RESTRICT fp = f2;
+      kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+      kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
+      const kiss_twiddle_scalar *t = &trig[0];
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_scalar yr, yi;
+         yr = S_MUL(fp->i,t[N4+i]) - S_MUL(fp->r,t[i]);
+         yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]);
+         *yp1 = yr;
+         *yp2 = yi;
+         fp++;
+         yp1 += 2*stride;
+         yp2 -= 2*stride;
+      }
+   }
+   RESTORE_STACK;
+}
+#endif /* OVERRIDE_clt_mdct_forward */
+
+#ifndef OVERRIDE_clt_mdct_backward
+void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+      const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch)
+{
+   int i;
+   int N, N2, N4;
+   const kiss_twiddle_scalar *trig;
+   (void) arch;
+
+   N = l->n;
+   trig = l->trig;
+   for (i=0;i<shift;i++)
+   {
+      N >>= 1;
+      trig += N;
+   }
+   N2 = N>>1;
+   N4 = N>>2;
+
+   /* Pre-rotate */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
+      const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
+      kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1);
+      const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0];
+      const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev;
+      for(i=0;i<N4;i++)
+      {
+         int rev;
+         kiss_fft_scalar yr, yi;
+         rev = *bitrev++;
+         yr = S_MUL(*xp2, t[i]) + S_MUL(*xp1, t[N4+i]);
+         yi = S_MUL(*xp1, t[i]) - S_MUL(*xp2, t[N4+i]);
+         /* We swap real and imag because we use an FFT instead of an IFFT. */
+         yp[2*rev+1] = yr;
+         yp[2*rev] = yi;
+         /* Storing the pre-rotation directly in the bitrev order. */
+         xp1+=2*stride;
+         xp2-=2*stride;
+      }
+   }
+
+   opus_fft_impl(l->kfft[shift], (kiss_fft_cpx*)(out+(overlap>>1)));
+
+   /* Post-rotate and de-shuffle from both ends of the buffer at once to make
+      it in-place. */
+   {
+      kiss_fft_scalar * yp0 = out+(overlap>>1);
+      kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2;
+      const kiss_twiddle_scalar *t = &trig[0];
+      /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
+         middle pair will be computed twice. */
+      for(i=0;i<(N4+1)>>1;i++)
+      {
+         kiss_fft_scalar re, im, yr, yi;
+         kiss_twiddle_scalar t0, t1;
+         /* We swap real and imag because we're using an FFT instead of an IFFT. */
+         re = yp0[1];
+         im = yp0[0];
+         t0 = t[i];
+         t1 = t[N4+i];
+         /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+         yr = S_MUL(re,t0) + S_MUL(im,t1);
+         yi = S_MUL(re,t1) - S_MUL(im,t0);
+         /* We swap real and imag because we're using an FFT instead of an IFFT. */
+         re = yp1[1];
+         im = yp1[0];
+         yp0[0] = yr;
+         yp1[1] = yi;
+
+         t0 = t[(N4-i-1)];
+         t1 = t[(N2-i-1)];
+         /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+         yr = S_MUL(re,t0) + S_MUL(im,t1);
+         yi = S_MUL(re,t1) - S_MUL(im,t0);
+         yp1[0] = yr;
+         yp0[1] = yi;
+         yp0 += 2;
+         yp1 -= 2;
+      }
+   }
+
+   /* Mirror on both sides for TDAC */
+   {
+      kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
+      kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+      const opus_val16 * OPUS_RESTRICT wp1 = window;
+      const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1;
+
+      for(i = 0; i < overlap/2; i++)
+      {
+         kiss_fft_scalar x1, x2;
+         x1 = *xp1;
+         x2 = *yp1;
+         *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
+         *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
+         wp1++;
+         wp2--;
+      }
+   }
+}
+#endif /* OVERRIDE_clt_mdct_backward */
diff --git a/third_party/opus/src/celt/mdct.h b/third_party/opus/src/celt/mdct.h
new file mode 100644
index 0000000..160ae4e0
--- /dev/null
+++ b/third_party/opus/src/celt/mdct.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2008 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+   to do most of the work. It should be relatively straightforward to
+   plug in pretty much and FFT here.
+
+   This replaces the Vorbis FFT (and uses the exact same API), which
+   was a bit too messy and that was ending up duplicating code
+   (might as well use the same FFT everywhere).
+
+   The algorithm is similar to (and inspired from) Fabrice Bellard's
+   MDCT implementation in FFMPEG, but has differences in signs, ordering
+   and scaling in many places.
+*/
+
+#ifndef MDCT_H
+#define MDCT_H
+
+#include "opus_defines.h"
+#include "kiss_fft.h"
+#include "arch.h"
+
+typedef struct {
+   int n;
+   int maxshift;
+   const kiss_fft_state *kfft[4];
+   const kiss_twiddle_scalar * OPUS_RESTRICT trig;
+} mdct_lookup;
+
+#if defined(HAVE_ARM_NE10)
+#include "arm/mdct_arm.h"
+#endif
+
+
+int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch);
+void clt_mdct_clear(mdct_lookup *l, int arch);
+
+/** Compute a forward MDCT and scale by 4/N, trashes the input array */
+void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in,
+                        kiss_fft_scalar * OPUS_RESTRICT out,
+                        const opus_val16 *window, int overlap,
+                        int shift, int stride, int arch);
+
+/** Compute a backward MDCT (no scaling) and performs weighted overlap-add
+    (scales implicitly by 1/2) */
+void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in,
+      kiss_fft_scalar * OPUS_RESTRICT out,
+      const opus_val16 * OPUS_RESTRICT window,
+      int overlap, int shift, int stride, int arch);
+
+#if !defined(OVERRIDE_OPUS_MDCT)
+/* Is run-time CPU detection enabled on this platform? */
+#if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10)
+
+extern void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])(
+      const mdct_lookup *l, kiss_fft_scalar *in,
+      kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window,
+      int overlap, int shift, int stride, int arch);
+
+#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \
+   ((*CLT_MDCT_FORWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \
+                                                   _window, _overlap, _shift, \
+                                                   _stride, _arch))
+
+extern void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])(
+      const mdct_lookup *l, kiss_fft_scalar *in,
+      kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window,
+      int overlap, int shift, int stride, int arch);
+
+#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \
+   (*CLT_MDCT_BACKWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \
+                                                   _window, _overlap, _shift, \
+                                                   _stride, _arch)
+
+#else /* if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) */
+
+#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \
+   clt_mdct_forward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch)
+
+#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \
+   clt_mdct_backward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch)
+
+#endif /* end if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) && !defined(FIXED_POINT) */
+#endif /* end if !defined(OVERRIDE_OPUS_MDCT) */
+
+#endif
diff --git a/third_party/opus/src/celt/mfrngcod.h b/third_party/opus/src/celt/mfrngcod.h
new file mode 100644
index 0000000..809152a
--- /dev/null
+++ b/third_party/opus/src/celt/mfrngcod.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2001-2008 Timothy B. Terriberry
+   Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(_mfrngcode_H)
+# define _mfrngcode_H (1)
+# include "entcode.h"
+
+/*Constants used by the entropy encoder/decoder.*/
+
+/*The number of bits to output at a time.*/
+# define EC_SYM_BITS   (8)
+/*The total number of bits in each of the state registers.*/
+# define EC_CODE_BITS  (32)
+/*The maximum symbol value.*/
+# define EC_SYM_MAX    ((1U<<EC_SYM_BITS)-1)
+/*Bits to shift by to move a symbol into the high-order position.*/
+# define EC_CODE_SHIFT (EC_CODE_BITS-EC_SYM_BITS-1)
+/*Carry bit of the high-order range symbol.*/
+# define EC_CODE_TOP   (((opus_uint32)1U)<<(EC_CODE_BITS-1))
+/*Low-order bit of the high-order range symbol.*/
+# define EC_CODE_BOT   (EC_CODE_TOP>>EC_SYM_BITS)
+/*The number of bits available for the last, partial symbol in the code field.*/
+# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1)
+#endif
diff --git a/third_party/opus/src/celt/mips/celt_mipsr1.h b/third_party/opus/src/celt/mips/celt_mipsr1.h
new file mode 100644
index 0000000..e85661a
--- /dev/null
+++ b/third_party/opus/src/celt/mips/celt_mipsr1.h
@@ -0,0 +1,151 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2010 Xiph.Org Foundation
+   Copyright (c) 2008 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __CELT_MIPSR1_H__
+#define __CELT_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_C
+
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+#define OVERRIDE_comb_filter
+void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
+      opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
+      const opus_val16 *window, int overlap, int arch)
+{
+   int i;
+   opus_val32 x0, x1, x2, x3, x4;
+
+   (void)arch;
+
+   /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */
+   opus_val16 g00, g01, g02, g10, g11, g12;
+   static const opus_val16 gains[3][3] = {
+         {QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)},
+         {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)},
+         {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}};
+
+   if (g0==0 && g1==0)
+   {
+      /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+      if (x!=y)
+         OPUS_MOVE(y, x, N);
+      return;
+   }
+
+   g00 = MULT16_16_P15(g0, gains[tapset0][0]);
+   g01 = MULT16_16_P15(g0, gains[tapset0][1]);
+   g02 = MULT16_16_P15(g0, gains[tapset0][2]);
+   g10 = MULT16_16_P15(g1, gains[tapset1][0]);
+   g11 = MULT16_16_P15(g1, gains[tapset1][1]);
+   g12 = MULT16_16_P15(g1, gains[tapset1][2]);
+   x1 = x[-T1+1];
+   x2 = x[-T1  ];
+   x3 = x[-T1-1];
+   x4 = x[-T1-2];
+   /* If the filter didn't change, we don't need the overlap */
+   if (g0==g1 && T0==T1 && tapset0==tapset1)
+      overlap=0;
+
+   for (i=0;i<overlap;i++)
+   {
+      opus_val16 f;
+      opus_val32 res;
+      f = MULT16_16_Q15(window[i],window[i]);
+      x0= x[i-T1+2];
+
+      asm volatile("MULT $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15((Q15ONE-f),g00)), "r" ((int)x[i-T0]));
+
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15((Q15ONE-f),g01)), "r" ((int)ADD32(x[i-T0-1],x[i-T0+1])));
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15((Q15ONE-f),g02)), "r" ((int)ADD32(x[i-T0-2],x[i-T0+2])));
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15(f,g10)), "r" ((int)x2));
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15(f,g11)), "r" ((int)ADD32(x3,x1)));
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)MULT16_16_Q15(f,g12)), "r" ((int)ADD32(x4,x0)));
+
+      asm volatile("EXTR.W %0,$ac1, %1" : "=r" (res): "i" (15));
+
+      y[i] = x[i] + res;
+
+      x4=x3;
+      x3=x2;
+      x2=x1;
+      x1=x0;
+   }
+
+   x4 = x[i-T1-2];
+   x3 = x[i-T1-1];
+   x2 = x[i-T1];
+   x1 = x[i-T1+1];
+
+   if (g1==0)
+   {
+      /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+      if (x!=y)
+         OPUS_MOVE(y+overlap, x+overlap, N-overlap);
+      return;
+   }
+
+   for (i=overlap;i<N;i++)
+   {
+      opus_val32 res;
+      x0=x[i-T1+2];
+
+      asm volatile("MULT $ac1, %0, %1" : : "r" ((int)g10), "r" ((int)x2));
+
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)g11), "r" ((int)ADD32(x3,x1)));
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)g12), "r" ((int)ADD32(x4,x0)));
+      asm volatile("EXTR.W %0,$ac1, %1" : "=r" (res): "i" (15));
+      y[i] = x[i] + res;
+      x4=x3;
+      x3=x2;
+      x2=x1;
+      x1=x0;
+   }
+}
+
+#endif /* __CELT_MIPSR1_H__ */
diff --git a/third_party/opus/src/celt/mips/fixed_generic_mipsr1.h b/third_party/opus/src/celt/mips/fixed_generic_mipsr1.h
new file mode 100644
index 0000000..4a05efb
--- /dev/null
+++ b/third_party/opus/src/celt/mips/fixed_generic_mipsr1.h
@@ -0,0 +1,126 @@
+/* Copyright (C) 2007-2009 Xiph.Org Foundation
+   Copyright (C) 2003-2008 Jean-Marc Valin
+   Copyright (C) 2007-2008 CSIRO */
+/**
+   @file fixed_generic.h
+   @brief Generic fixed-point operations
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CELT_FIXED_GENERIC_MIPSR1_H
+#define CELT_FIXED_GENERIC_MIPSR1_H
+
+#undef MULT16_32_Q15_ADD
+static inline int MULT16_32_Q15_ADD(int a, int b, int c, int d) {
+    int m;
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+    asm volatile("madd $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+    return m;
+}
+
+#undef MULT16_32_Q15_SUB
+static inline int MULT16_32_Q15_SUB(int a, int b, int c, int d) {
+    int m;
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+    asm volatile("msub $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+    return m;
+}
+
+#undef MULT16_16_Q15_ADD
+static inline int MULT16_16_Q15_ADD(int a, int b, int c, int d) {
+    int m;
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+    asm volatile("madd $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+    return m;
+}
+
+#undef MULT16_16_Q15_SUB
+static inline int MULT16_16_Q15_SUB(int a, int b, int c, int d) {
+    int m;
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+    asm volatile("msub $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+    return m;
+}
+
+
+#undef MULT16_32_Q16
+static inline int MULT16_32_Q16(int a, int b)
+{
+    int c;
+    asm volatile("MULT $ac1,%0, %1" : : "r" (a), "r" (b));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (c): "i" (16));
+    return c;
+}
+
+#undef MULT16_32_P16
+static inline int MULT16_32_P16(int a, int b)
+{
+    int c;
+    asm volatile("MULT $ac1, %0, %1" : : "r" (a), "r" (b));
+    asm volatile("EXTR_R.W %0,$ac1, %1" : "=r" (c): "i" (16));
+    return c;
+}
+
+#undef MULT16_32_Q15
+static inline int MULT16_32_Q15(int a, int b)
+{
+    int c;
+    asm volatile("MULT $ac1, %0, %1" : : "r" (a), "r" (b));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (c): "i" (15));
+    return c;
+}
+
+#undef MULT32_32_Q31
+static inline int MULT32_32_Q31(int a, int b)
+{
+    int r;
+    asm volatile("MULT $ac1, %0, %1" : : "r" (a), "r" (b));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (r): "i" (31));
+    return r;
+}
+
+#undef PSHR32
+static inline int PSHR32(int a, int shift)
+{
+    int r;
+    asm volatile ("SHRAV_R.W %0, %1, %2" :"=r" (r): "r" (a), "r" (shift));
+    return r;
+}
+
+#undef MULT16_16_P15
+static inline int MULT16_16_P15(int a, int b)
+{
+    int r;
+    asm volatile ("mul %0, %1, %2" :"=r" (r): "r" (a), "r" (b));
+    asm volatile ("SHRA_R.W %0, %1, %2" : "+r" (r):  "0" (r), "i"(15));
+    return r;
+}
+
+#endif /* CELT_FIXED_GENERIC_MIPSR1_H */
diff --git a/third_party/opus/src/celt/mips/kiss_fft_mipsr1.h b/third_party/opus/src/celt/mips/kiss_fft_mipsr1.h
new file mode 100644
index 0000000..400ca4d
--- /dev/null
+++ b/third_party/opus/src/celt/mips/kiss_fft_mipsr1.h
@@ -0,0 +1,167 @@
+/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+       this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_MIPSR1_H
+#define KISS_FFT_MIPSR1_H
+
+#if !defined(KISS_FFT_GUTS_H)
+#error "This file should only be included from _kiss_fft_guts.h"
+#endif
+
+#ifdef FIXED_POINT
+
+#define S_MUL_ADD(a, b, c, d) (S_MUL(a,b)+S_MUL(c,d))
+#define S_MUL_SUB(a, b, c, d) (S_MUL(a,b)-S_MUL(c,d))
+
+#undef S_MUL_ADD
+static inline int S_MUL_ADD(int a, int b, int c, int d) {
+    int m;
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+    asm volatile("madd $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+    return m;
+}
+
+#undef S_MUL_SUB
+static inline int S_MUL_SUB(int a, int b, int c, int d) {
+    int m;
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a), "r" ((int)b));
+    asm volatile("msub $ac1, %0, %1" : : "r" ((int)c), "r" ((int)d));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m): "i" (15));
+    return m;
+}
+
+#undef C_MUL
+#   define C_MUL(m,a,b) (m=C_MUL_fun(a,b))
+static inline kiss_fft_cpx C_MUL_fun(kiss_fft_cpx a, kiss_twiddle_cpx b) {
+    kiss_fft_cpx m;
+
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a.r), "r" ((int)b.r));
+    asm volatile("msub $ac1, %0, %1" : : "r" ((int)a.i), "r" ((int)b.i));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m.r): "i" (15));
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a.r), "r" ((int)b.i));
+    asm volatile("madd $ac1, %0, %1" : : "r" ((int)a.i), "r" ((int)b.r));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m.i): "i" (15));
+
+    return m;
+}
+#undef C_MULC
+#   define C_MULC(m,a,b) (m=C_MULC_fun(a,b))
+static inline kiss_fft_cpx C_MULC_fun(kiss_fft_cpx a, kiss_twiddle_cpx b) {
+    kiss_fft_cpx m;
+
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a.r), "r" ((int)b.r));
+    asm volatile("madd $ac1, %0, %1" : : "r" ((int)a.i), "r" ((int)b.i));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m.r): "i" (15));
+    asm volatile("MULT $ac1, %0, %1" : : "r" ((int)a.i), "r" ((int)b.r));
+    asm volatile("msub $ac1, %0, %1" : : "r" ((int)a.r), "r" ((int)b.i));
+    asm volatile("EXTR.W %0,$ac1, %1" : "=r" (m.i): "i" (15));
+
+    return m;
+}
+
+#endif /* FIXED_POINT */
+
+#define OVERRIDE_kf_bfly5
+static void kf_bfly5(
+                     kiss_fft_cpx * Fout,
+                     const size_t fstride,
+                     const kiss_fft_state *st,
+                     int m,
+                     int N,
+                     int mm
+                    )
+{
+   kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+   int i, u;
+   kiss_fft_cpx scratch[13];
+
+   const kiss_twiddle_cpx *tw;
+   kiss_twiddle_cpx ya,yb;
+   kiss_fft_cpx * Fout_beg = Fout;
+
+#ifdef FIXED_POINT
+   ya.r = 10126;
+   ya.i = -31164;
+   yb.r = -26510;
+   yb.i = -19261;
+#else
+   ya = st->twiddles[fstride*m];
+   yb = st->twiddles[fstride*2*m];
+#endif
+
+   tw=st->twiddles;
+
+   for (i=0;i<N;i++)
+   {
+      Fout = Fout_beg + i*mm;
+      Fout0=Fout;
+      Fout1=Fout0+m;
+      Fout2=Fout0+2*m;
+      Fout3=Fout0+3*m;
+      Fout4=Fout0+4*m;
+
+      /* For non-custom modes, m is guaranteed to be a multiple of 4. */
+      for ( u=0; u<m; ++u ) {
+         scratch[0] = *Fout0;
+
+
+         C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
+         C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
+         C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
+         C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+         C_ADD( scratch[7],scratch[1],scratch[4]);
+         C_SUB( scratch[10],scratch[1],scratch[4]);
+         C_ADD( scratch[8],scratch[2],scratch[3]);
+         C_SUB( scratch[9],scratch[2],scratch[3]);
+
+         Fout0->r += scratch[7].r + scratch[8].r;
+         Fout0->i += scratch[7].i + scratch[8].i;
+         scratch[5].r = scratch[0].r + S_MUL_ADD(scratch[7].r,ya.r,scratch[8].r,yb.r);
+         scratch[5].i = scratch[0].i + S_MUL_ADD(scratch[7].i,ya.r,scratch[8].i,yb.r);
+
+         scratch[6].r =  S_MUL_ADD(scratch[10].i,ya.i,scratch[9].i,yb.i);
+         scratch[6].i =  -S_MUL_ADD(scratch[10].r,ya.i,scratch[9].r,yb.i);
+
+         C_SUB(*Fout1,scratch[5],scratch[6]);
+         C_ADD(*Fout4,scratch[5],scratch[6]);
+
+         scratch[11].r = scratch[0].r + S_MUL_ADD(scratch[7].r,yb.r,scratch[8].r,ya.r);
+         scratch[11].i = scratch[0].i + S_MUL_ADD(scratch[7].i,yb.r,scratch[8].i,ya.r);
+
+         scratch[12].r =  S_MUL_SUB(scratch[9].i,ya.i,scratch[10].i,yb.i);
+         scratch[12].i =  S_MUL_SUB(scratch[10].r,yb.i,scratch[9].r,ya.i);
+
+         C_ADD(*Fout2,scratch[11],scratch[12]);
+         C_SUB(*Fout3,scratch[11],scratch[12]);
+
+         ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+      }
+   }
+}
+
+
+#endif /* KISS_FFT_MIPSR1_H */
diff --git a/third_party/opus/src/celt/mips/mdct_mipsr1.h b/third_party/opus/src/celt/mips/mdct_mipsr1.h
new file mode 100644
index 0000000..2934dab7
--- /dev/null
+++ b/third_party/opus/src/celt/mips/mdct_mipsr1.h
@@ -0,0 +1,288 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2008 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+   to do most of the work. It should be relatively straightforward to
+   plug in pretty much and FFT here.
+
+   This replaces the Vorbis FFT (and uses the exact same API), which
+   was a bit too messy and that was ending up duplicating code
+   (might as well use the same FFT everywhere).
+
+   The algorithm is similar to (and inspired from) Fabrice Bellard's
+   MDCT implementation in FFMPEG, but has differences in signs, ordering
+   and scaling in many places.
+*/
+#ifndef __MDCT_MIPSR1_H__
+#define __MDCT_MIPSR1_H__
+
+#ifndef SKIP_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+#include "mdct.h"
+#include "kiss_fft.h"
+#include "_kiss_fft_guts.h"
+#include <math.h>
+#include "os_support.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+
+/* Forward MDCT trashes the input array */
+#define OVERRIDE_clt_mdct_forward
+void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+      const opus_val16 *window, int overlap, int shift, int stride, int arch)
+{
+   int i;
+   int N, N2, N4;
+   VARDECL(kiss_fft_scalar, f);
+   VARDECL(kiss_fft_cpx, f2);
+   const kiss_fft_state *st = l->kfft[shift];
+   const kiss_twiddle_scalar *trig;
+   opus_val16 scale;
+#ifdef FIXED_POINT
+   /* Allows us to scale with MULT16_32_Q16(), which is faster than
+      MULT16_32_Q15() on ARM. */
+   int scale_shift = st->scale_shift-1;
+#endif
+
+    (void)arch;
+
+   SAVE_STACK;
+   scale = st->scale;
+
+   N = l->n;
+   trig = l->trig;
+   for (i=0;i<shift;i++)
+   {
+      N >>= 1;
+      trig += N;
+   }
+   N2 = N>>1;
+   N4 = N>>2;
+
+   ALLOC(f, N2, kiss_fft_scalar);
+   ALLOC(f2, N4, kiss_fft_cpx);
+
+   /* Consider the input to be composed of four blocks: [a, b, c, d] */
+   /* Window, shuffle, fold */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
+      const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
+      kiss_fft_scalar * OPUS_RESTRICT yp = f;
+      const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1);
+      const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
+      for(i=0;i<((overlap+3)>>2);i++)
+      {
+         /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+          *yp++ = S_MUL_ADD(*wp2, xp1[N2],*wp1,*xp2);
+          *yp++ = S_MUL_SUB(*wp1, *xp1,*wp2, xp2[-N2]);
+         xp1+=2;
+         xp2-=2;
+         wp1+=2;
+         wp2-=2;
+      }
+      wp1 = window;
+      wp2 = window+overlap-1;
+      for(;i<N4-((overlap+3)>>2);i++)
+      {
+         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+         *yp++ = *xp2;
+         *yp++ = *xp1;
+         xp1+=2;
+         xp2-=2;
+      }
+      for(;i<N4;i++)
+      {
+         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+          *yp++ =  S_MUL_SUB(*wp2, *xp2, *wp1, xp1[-N2]);
+          *yp++ = S_MUL_ADD(*wp2, *xp1, *wp1, xp2[N2]);
+         xp1+=2;
+         xp2-=2;
+         wp1+=2;
+         wp2-=2;
+      }
+   }
+   /* Pre-rotation */
+   {
+      kiss_fft_scalar * OPUS_RESTRICT yp = f;
+      const kiss_twiddle_scalar *t = &trig[0];
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_cpx yc;
+         kiss_twiddle_scalar t0, t1;
+         kiss_fft_scalar re, im, yr, yi;
+         t0 = t[i];
+         t1 = t[N4+i];
+         re = *yp++;
+         im = *yp++;
+
+         yr = S_MUL_SUB(re,t0,im,t1);
+         yi = S_MUL_ADD(im,t0,re,t1);
+
+         yc.r = yr;
+         yc.i = yi;
+         yc.r = PSHR32(MULT16_32_Q16(scale, yc.r), scale_shift);
+         yc.i = PSHR32(MULT16_32_Q16(scale, yc.i), scale_shift);
+         f2[st->bitrev[i]] = yc;
+      }
+   }
+
+   /* N/4 complex FFT, does not downscale anymore */
+   opus_fft_impl(st, f2);
+
+   /* Post-rotate */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_cpx * OPUS_RESTRICT fp = f2;
+      kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+      kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
+      const kiss_twiddle_scalar *t = &trig[0];
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      for(i=0;i<N4;i++)
+      {
+         kiss_fft_scalar yr, yi;
+         yr = S_MUL_SUB(fp->i,t[N4+i] , fp->r,t[i]);
+         yi = S_MUL_ADD(fp->r,t[N4+i] ,fp->i,t[i]);
+         *yp1 = yr;
+         *yp2 = yi;
+         fp++;
+         yp1 += 2*stride;
+         yp2 -= 2*stride;
+      }
+   }
+   RESTORE_STACK;
+}
+
+#define OVERRIDE_clt_mdct_backward
+void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+      const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch)
+{
+   int i;
+   int N, N2, N4;
+   const kiss_twiddle_scalar *trig;
+
+    (void)arch;
+
+   N = l->n;
+   trig = l->trig;
+   for (i=0;i<shift;i++)
+   {
+      N >>= 1;
+      trig += N;
+   }
+   N2 = N>>1;
+   N4 = N>>2;
+
+   /* Pre-rotate */
+   {
+      /* Temp pointers to make it really clear to the compiler what we're doing */
+      const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
+      const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
+      kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1);
+      const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0];
+      const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev;
+      for(i=0;i<N4;i++)
+      {
+         int rev;
+         kiss_fft_scalar yr, yi;
+         rev = *bitrev++;
+         yr = S_MUL_ADD(*xp2, t[i] , *xp1, t[N4+i]);
+         yi = S_MUL_SUB(*xp1, t[i] , *xp2, t[N4+i]);
+         /* We swap real and imag because we use an FFT instead of an IFFT. */
+         yp[2*rev+1] = yr;
+         yp[2*rev] = yi;
+         /* Storing the pre-rotation directly in the bitrev order. */
+         xp1+=2*stride;
+         xp2-=2*stride;
+      }
+   }
+
+   opus_fft_impl(l->kfft[shift], (kiss_fft_cpx*)(out+(overlap>>1)));
+
+   /* Post-rotate and de-shuffle from both ends of the buffer at once to make
+      it in-place. */
+   {
+      kiss_fft_scalar * OPUS_RESTRICT yp0 = out+(overlap>>1);
+      kiss_fft_scalar * OPUS_RESTRICT yp1 = out+(overlap>>1)+N2-2;
+      const kiss_twiddle_scalar *t = &trig[0];
+      /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
+         middle pair will be computed twice. */
+      for(i=0;i<(N4+1)>>1;i++)
+      {
+         kiss_fft_scalar re, im, yr, yi;
+         kiss_twiddle_scalar t0, t1;
+         /* We swap real and imag because we're using an FFT instead of an IFFT. */
+         re = yp0[1];
+         im = yp0[0];
+         t0 = t[i];
+         t1 = t[N4+i];
+         /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+         yr = S_MUL_ADD(re,t0 , im,t1);
+         yi = S_MUL_SUB(re,t1 , im,t0);
+         /* We swap real and imag because we're using an FFT instead of an IFFT. */
+         re = yp1[1];
+         im = yp1[0];
+         yp0[0] = yr;
+         yp1[1] = yi;
+
+         t0 = t[(N4-i-1)];
+         t1 = t[(N2-i-1)];
+         /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+         yr = S_MUL_ADD(re,t0,im,t1);
+         yi = S_MUL_SUB(re,t1,im,t0);
+         yp1[0] = yr;
+         yp0[1] = yi;
+         yp0 += 2;
+         yp1 -= 2;
+      }
+   }
+
+   /* Mirror on both sides for TDAC */
+   {
+      kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
+      kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+      const opus_val16 * OPUS_RESTRICT wp1 = window;
+      const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1;
+
+      for(i = 0; i < overlap/2; i++)
+      {
+         kiss_fft_scalar x1, x2;
+         x1 = *xp1;
+         x2 = *yp1;
+         *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
+         *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
+         wp1++;
+         wp2--;
+      }
+   }
+}
+#endif /* __MDCT_MIPSR1_H__ */
diff --git a/third_party/opus/src/celt/mips/pitch_mipsr1.h b/third_party/opus/src/celt/mips/pitch_mipsr1.h
new file mode 100644
index 0000000..a9500af
--- /dev/null
+++ b/third_party/opus/src/celt/mips/pitch_mipsr1.h
@@ -0,0 +1,161 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/**
+   @file pitch.h
+   @brief Pitch analysis
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PITCH_MIPSR1_H
+#define PITCH_MIPSR1_H
+
+#define OVERRIDE_DUAL_INNER_PROD
+static inline void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
+      int N, opus_val32 *xy1, opus_val32 *xy2, int arch)
+{
+   int j;
+   opus_val32 xy01=0;
+   opus_val32 xy02=0;
+
+   (void)arch;
+
+   asm volatile("MULT $ac1, $0, $0");
+   asm volatile("MULT $ac2, $0, $0");
+   /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */
+   for (j=0;j<N;j++)
+   {
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)x[j]), "r" ((int)y01[j]));
+      asm volatile("MADD $ac2, %0, %1" : : "r" ((int)x[j]), "r" ((int)y02[j]));
+      ++j;
+      asm volatile("MADD $ac1, %0, %1" : : "r" ((int)x[j]), "r" ((int)y01[j]));
+      asm volatile("MADD $ac2, %0, %1" : : "r" ((int)x[j]), "r" ((int)y02[j]));
+   }
+   asm volatile ("mflo %0, $ac1": "=r"(xy01));
+   asm volatile ("mflo %0, $ac2": "=r"(xy02));
+   *xy1 = xy01;
+   *xy2 = xy02;
+}
+
+static inline void xcorr_kernel_mips(const opus_val16 * x,
+      const opus_val16 * y, opus_val32 sum[4], int len)
+{
+   int j;
+   opus_val16 y_0, y_1, y_2, y_3;
+
+    opus_int64 sum_0, sum_1, sum_2, sum_3;
+    sum_0 =  (opus_int64)sum[0];
+    sum_1 =  (opus_int64)sum[1];
+    sum_2 =  (opus_int64)sum[2];
+    sum_3 =  (opus_int64)sum[3];
+
+    y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */
+    y_0=*y++;
+    y_1=*y++;
+    y_2=*y++;
+    for (j=0;j<len-3;j+=4)
+    {
+        opus_val16 tmp;
+        tmp = *x++;
+        y_3=*y++;
+
+        sum_0 = __builtin_mips_madd( sum_0, tmp, y_0);
+        sum_1 = __builtin_mips_madd( sum_1, tmp, y_1);
+        sum_2 = __builtin_mips_madd( sum_2, tmp, y_2);
+        sum_3 = __builtin_mips_madd( sum_3, tmp, y_3);
+
+        tmp=*x++;
+        y_0=*y++;
+
+        sum_0 = __builtin_mips_madd( sum_0, tmp, y_1 );
+        sum_1 = __builtin_mips_madd( sum_1, tmp, y_2 );
+        sum_2 = __builtin_mips_madd( sum_2, tmp, y_3);
+        sum_3 = __builtin_mips_madd( sum_3, tmp, y_0);
+
+       tmp=*x++;
+       y_1=*y++;
+
+       sum_0 = __builtin_mips_madd( sum_0, tmp, y_2 );
+       sum_1 = __builtin_mips_madd( sum_1, tmp, y_3 );
+       sum_2 = __builtin_mips_madd( sum_2, tmp, y_0);
+       sum_3 = __builtin_mips_madd( sum_3, tmp, y_1);
+
+
+      tmp=*x++;
+      y_2=*y++;
+
+       sum_0 = __builtin_mips_madd( sum_0, tmp, y_3 );
+       sum_1 = __builtin_mips_madd( sum_1, tmp, y_0 );
+       sum_2 = __builtin_mips_madd( sum_2, tmp, y_1);
+       sum_3 = __builtin_mips_madd( sum_3, tmp, y_2);
+
+   }
+   if (j++<len)
+   {
+      opus_val16 tmp = *x++;
+      y_3=*y++;
+
+       sum_0 = __builtin_mips_madd( sum_0, tmp, y_0 );
+       sum_1 = __builtin_mips_madd( sum_1, tmp, y_1 );
+       sum_2 = __builtin_mips_madd( sum_2, tmp, y_2);
+       sum_3 = __builtin_mips_madd( sum_3, tmp, y_3);
+   }
+
+   if (j++<len)
+   {
+      opus_val16 tmp=*x++;
+      y_0=*y++;
+
+      sum_0 = __builtin_mips_madd( sum_0, tmp, y_1 );
+      sum_1 = __builtin_mips_madd( sum_1, tmp, y_2 );
+      sum_2 = __builtin_mips_madd( sum_2, tmp, y_3);
+      sum_3 = __builtin_mips_madd( sum_3, tmp, y_0);
+   }
+
+   if (j<len)
+   {
+      opus_val16 tmp=*x++;
+      y_1=*y++;
+
+       sum_0 = __builtin_mips_madd( sum_0, tmp, y_2 );
+       sum_1 = __builtin_mips_madd( sum_1, tmp, y_3 );
+       sum_2 = __builtin_mips_madd( sum_2, tmp, y_0);
+       sum_3 = __builtin_mips_madd( sum_3, tmp, y_1);
+
+   }
+
+   sum[0] = (opus_val32)sum_0;
+   sum[1] = (opus_val32)sum_1;
+   sum[2] = (opus_val32)sum_2;
+   sum[3] = (opus_val32)sum_3;
+}
+
+#define OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+    ((void)(arch), xcorr_kernel_mips(x, y, sum, len))
+
+#endif /* PITCH_MIPSR1_H */
diff --git a/third_party/opus/src/celt/mips/vq_mipsr1.h b/third_party/opus/src/celt/mips/vq_mipsr1.h
new file mode 100644
index 0000000..54cef861
--- /dev/null
+++ b/third_party/opus/src/celt/mips/vq_mipsr1.h
@@ -0,0 +1,125 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __VQ_MIPSR1_H__
+#define __VQ_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mathops.h"
+#include "arch.h"
+
+static unsigned extract_collapse_mask(int *iy, int N, int B);
+static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X, int N, opus_val32 Ryy, opus_val16 gain);
+static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread);
+static void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch);
+
+#define OVERRIDE_vq_exp_rotation1
+static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
+{
+   int i;
+   opus_val16 ms;
+   celt_norm *Xptr;
+   Xptr = X;
+   ms = NEG16(s);
+   for (i=0;i<len-stride;i++)
+   {
+      celt_norm x1, x2;
+      x1 = Xptr[0];
+      x2 = Xptr[stride];
+      Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2),  s, x1), 15));
+      *Xptr++      = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
+   }
+   Xptr = &X[len-2*stride-1];
+   for (i=len-2*stride-1;i>=0;i--)
+   {
+      celt_norm x1, x2;
+      x1 = Xptr[0];
+      x2 = Xptr[stride];
+      Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2),  s, x1), 15));
+      *Xptr--      = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
+   }
+}
+
+#define OVERRIDE_renormalise_vector
+
+#define renormalise_vector(X, N, gain, arch) \
+ (renormalise_vector_mips(X, N, gain, arch))
+
+void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch)
+{
+   int i;
+#ifdef FIXED_POINT
+   int k;
+#endif
+   opus_val32 E = EPSILON;
+   opus_val16 g;
+   opus_val32 t;
+   celt_norm *xptr = X;
+   int X0, X1;
+
+   (void)arch;
+
+   asm volatile("mult $ac1, $0, $0");
+   asm volatile("MTLO %0, $ac1" : :"r" (E));
+   /*if(N %4)
+       printf("error");*/
+   for (i=0;i<N-2;i+=2)
+   {
+      X0 = (int)*xptr++;
+      asm volatile("MADD $ac1, %0, %1" : : "r" (X0), "r" (X0));
+
+      X1 = (int)*xptr++;
+      asm volatile("MADD $ac1, %0, %1" : : "r" (X1), "r" (X1));
+   }
+
+   for (;i<N;i++)
+   {
+      X0 = (int)*xptr++;
+      asm volatile("MADD $ac1, %0, %1" : : "r" (X0), "r" (X0));
+   }
+
+   asm volatile("MFLO %0, $ac1" : "=r" (E));
+#ifdef FIXED_POINT
+   k = celt_ilog2(E)>>1;
+#endif
+   t = VSHR32(E, 2*(k-7));
+   g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
+
+   xptr = X;
+   for (i=0;i<N;i++)
+   {
+      *xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k+1));
+      xptr++;
+   }
+   /*return celt_sqrt(E);*/
+}
+
+#endif /* __VQ_MIPSR1_H__ */
diff --git a/third_party/opus/src/celt/modes.c b/third_party/opus/src/celt/modes.c
new file mode 100644
index 0000000..911686e
--- /dev/null
+++ b/third_party/opus/src/celt/modes.c
@@ -0,0 +1,442 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Copyright (c) 2008 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "celt.h"
+#include "modes.h"
+#include "rate.h"
+#include "os_support.h"
+#include "stack_alloc.h"
+#include "quant_bands.h"
+#include "cpu_support.h"
+
+static const opus_int16 eband5ms[] = {
+/*0  200 400 600 800  1k 1.2 1.4 1.6  2k 2.4 2.8 3.2  4k 4.8 5.6 6.8  8k 9.6 12k 15.6 */
+  0,  1,  2,  3,  4,  5,  6,  7,  8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100
+};
+
+/* Alternate tuning (partially derived from Vorbis) */
+#define BITALLOC_SIZE 11
+/* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */
+static const unsigned char band_allocation[] = {
+/*0  200 400 600 800  1k 1.2 1.4 1.6  2k 2.4 2.8 3.2  4k 4.8 5.6 6.8  8k 9.6 12k 15.6 */
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+ 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10,  0,  0,  0,  0,  0,  0,  0,  0,
+110,100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12,  0,  0,  0,  0,  0,  0,
+118,110,103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15,  4,  0,  0,  0,  0,
+126,119,112,104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12,  1,  0,  0,
+134,127,120,114,103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10,  1,
+144,137,130,124,113,107,101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15,  1,
+152,145,138,132,123,117,111,105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20,  1,
+162,155,148,142,133,127,121,115,108,102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30,  1,
+172,165,158,152,143,137,131,125,118,112,106,100, 94, 87, 81, 75, 69, 63, 56, 45, 20,
+200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104,
+};
+
+#ifndef CUSTOM_MODES_ONLY
+ #ifdef FIXED_POINT
+  #include "static_modes_fixed.h"
+ #else
+  #include "static_modes_float.h"
+ #endif
+#endif /* CUSTOM_MODES_ONLY */
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+#ifdef CUSTOM_MODES
+
+/* Defining 25 critical bands for the full 0-20 kHz audio bandwidth
+   Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */
+#define BARK_BANDS 25
+static const opus_int16 bark_freq[BARK_BANDS+1] = {
+      0,   100,   200,   300,   400,
+    510,   630,   770,   920,  1080,
+   1270,  1480,  1720,  2000,  2320,
+   2700,  3150,  3700,  4400,  5300,
+   6400,  7700,  9500, 12000, 15500,
+  20000};
+
+static opus_int16 *compute_ebands(opus_int32 Fs, int frame_size, int res, int *nbEBands)
+{
+   opus_int16 *eBands;
+   int i, j, lin, low, high, nBark, offset=0;
+
+   /* All modes that have 2.5 ms short blocks use the same definition */
+   if (Fs == 400*(opus_int32)frame_size)
+   {
+      *nbEBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
+      eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+1));
+      for (i=0;i<*nbEBands+1;i++)
+         eBands[i] = eband5ms[i];
+      return eBands;
+   }
+   /* Find the number of critical bands supported by our sampling rate */
+   for (nBark=1;nBark<BARK_BANDS;nBark++)
+    if (bark_freq[nBark+1]*2 >= Fs)
+       break;
+
+   /* Find where the linear part ends (i.e. where the spacing is more than min_width */
+   for (lin=0;lin<nBark;lin++)
+      if (bark_freq[lin+1]-bark_freq[lin] >= res)
+         break;
+
+   low = (bark_freq[lin]+res/2)/res;
+   high = nBark-lin;
+   *nbEBands = low+high;
+   eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2));
+
+   if (eBands==NULL)
+      return NULL;
+
+   /* Linear spacing (min_width) */
+   for (i=0;i<low;i++)
+      eBands[i] = i;
+   if (low>0)
+      offset = eBands[low-1]*res - bark_freq[lin-1];
+   /* Spacing follows critical bands */
+   for (i=0;i<high;i++)
+   {
+      int target = bark_freq[lin+i];
+      /* Round to an even value */
+      eBands[i+low] = (target+offset/2+res)/(2*res)*2;
+      offset = eBands[i+low]*res - target;
+   }
+   /* Enforce the minimum spacing at the boundary */
+   for (i=0;i<*nbEBands;i++)
+      if (eBands[i] < i)
+         eBands[i] = i;
+   /* Round to an even value */
+   eBands[*nbEBands] = (bark_freq[nBark]+res)/(2*res)*2;
+   if (eBands[*nbEBands] > frame_size)
+      eBands[*nbEBands] = frame_size;
+   for (i=1;i<*nbEBands-1;i++)
+   {
+      if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1])
+      {
+         eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2;
+      }
+   }
+   /* Remove any empty bands. */
+   for (i=j=0;i<*nbEBands;i++)
+      if(eBands[i+1]>eBands[j])
+         eBands[++j]=eBands[i+1];
+   *nbEBands=j;
+
+   for (i=1;i<*nbEBands;i++)
+   {
+      /* Every band must be smaller than the last band. */
+      celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]);
+      /* Each band must be no larger than twice the size of the previous one. */
+      celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1]));
+   }
+
+   return eBands;
+}
+
+static void compute_allocation_table(CELTMode *mode)
+{
+   int i, j;
+   unsigned char *allocVectors;
+   int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
+
+   mode->nbAllocVectors = BITALLOC_SIZE;
+   allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands));
+   if (allocVectors==NULL)
+      return;
+
+   /* Check for standard mode */
+   if (mode->Fs == 400*(opus_int32)mode->shortMdctSize)
+   {
+      for (i=0;i<BITALLOC_SIZE*mode->nbEBands;i++)
+         allocVectors[i] = band_allocation[i];
+      mode->allocVectors = allocVectors;
+      return;
+   }
+   /* If not the standard mode, interpolate */
+   /* Compute per-codec-band allocation from per-critical-band matrix */
+   for (i=0;i<BITALLOC_SIZE;i++)
+   {
+      for (j=0;j<mode->nbEBands;j++)
+      {
+         int k;
+         for (k=0;k<maxBands;k++)
+         {
+            if (400*(opus_int32)eband5ms[k] > mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize)
+               break;
+         }
+         if (k>maxBands-1)
+            allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1];
+         else {
+            opus_int32 a0, a1;
+            a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1];
+            a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize;
+            allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1]
+                                             + a1*band_allocation[i*maxBands+k])/(a0+a1);
+         }
+      }
+   }
+
+   /*printf ("\n");
+   for (i=0;i<BITALLOC_SIZE;i++)
+   {
+      for (j=0;j<mode->nbEBands;j++)
+         printf ("%d ", allocVectors[i*mode->nbEBands+j]);
+      printf ("\n");
+   }
+   exit(0);*/
+
+   mode->allocVectors = allocVectors;
+}
+
+#endif /* CUSTOM_MODES */
+
+CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error)
+{
+   int i;
+#ifdef CUSTOM_MODES
+   CELTMode *mode=NULL;
+   int res;
+   opus_val16 *window;
+   opus_int16 *logN;
+   int LM;
+   int arch = opus_select_arch();
+   ALLOC_STACK;
+#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA)
+   if (global_stack==NULL)
+      goto failure;
+#endif
+#endif
+
+#ifndef CUSTOM_MODES_ONLY
+   for (i=0;i<TOTAL_MODES;i++)
+   {
+      int j;
+      for (j=0;j<4;j++)
+      {
+         if (Fs == static_mode_list[i]->Fs &&
+               (frame_size<<j) == static_mode_list[i]->shortMdctSize*static_mode_list[i]->nbShortMdcts)
+         {
+            if (error)
+               *error = OPUS_OK;
+            return (CELTMode*)static_mode_list[i];
+         }
+      }
+   }
+#endif /* CUSTOM_MODES_ONLY */
+
+#ifndef CUSTOM_MODES
+   if (error)
+      *error = OPUS_BAD_ARG;
+   return NULL;
+#else
+
+   /* The good thing here is that permutation of the arguments will automatically be invalid */
+
+   if (Fs < 8000 || Fs > 96000)
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+   if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0)
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+   /* Frames of less than 1ms are not supported. */
+   if ((opus_int32)frame_size*1000 < Fs)
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+
+   if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0)
+   {
+     LM = 3;
+   } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0)
+   {
+     LM = 2;
+   } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0)
+   {
+     LM = 1;
+   } else
+   {
+     LM = 0;
+   }
+
+   /* Shorts longer than 3.3ms are not supported. */
+   if ((opus_int32)(frame_size>>LM)*300 > Fs)
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+
+   mode = opus_alloc(sizeof(CELTMode));
+   if (mode==NULL)
+      goto failure;
+   mode->Fs = Fs;
+
+   /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis
+      is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should
+      approximate that. */
+   if(Fs < 12000) /* 8 kHz */
+   {
+      mode->preemph[0] =  QCONST16(0.3500061035f, 15);
+      mode->preemph[1] = -QCONST16(0.1799926758f, 15);
+      mode->preemph[2] =  QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */
+      mode->preemph[3] =  QCONST16(3.6765136719f, 13);
+   } else if(Fs < 24000) /* 16 kHz */
+   {
+      mode->preemph[0] =  QCONST16(0.6000061035f, 15);
+      mode->preemph[1] = -QCONST16(0.1799926758f, 15);
+      mode->preemph[2] =  QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */
+      mode->preemph[3] =  QCONST16(2.2598876953f, 13);
+   } else if(Fs < 40000) /* 32 kHz */
+   {
+      mode->preemph[0] =  QCONST16(0.7799987793f, 15);
+      mode->preemph[1] = -QCONST16(0.1000061035f, 15);
+      mode->preemph[2] =  QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */
+      mode->preemph[3] =  QCONST16(1.3333740234f, 13);
+   } else /* 48 kHz */
+   {
+      mode->preemph[0] =  QCONST16(0.8500061035f, 15);
+      mode->preemph[1] =  QCONST16(0.0f, 15);
+      mode->preemph[2] =  QCONST16(1.f, SIG_SHIFT);
+      mode->preemph[3] =  QCONST16(1.f, 13);
+   }
+
+   mode->maxLM = LM;
+   mode->nbShortMdcts = 1<<LM;
+   mode->shortMdctSize = frame_size/mode->nbShortMdcts;
+   res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize);
+
+   mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands);
+   if (mode->eBands==NULL)
+      goto failure;
+#if !defined(SMALL_FOOTPRINT)
+   /* Make sure we don't allocate a band larger than our PVQ table.
+      208 should be enough, but let's be paranoid. */
+   if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])<<LM >
+    208) {
+       goto failure;
+   }
+#endif
+
+   mode->effEBands = mode->nbEBands;
+   while (mode->eBands[mode->effEBands] > mode->shortMdctSize)
+      mode->effEBands--;
+
+   /* Overlap must be divisible by 4 */
+   mode->overlap = ((mode->shortMdctSize>>2)<<2);
+
+   compute_allocation_table(mode);
+   if (mode->allocVectors==NULL)
+      goto failure;
+
+   window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16));
+   if (window==NULL)
+      goto failure;
+
+#ifndef FIXED_POINT
+   for (i=0;i<mode->overlap;i++)
+      window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap));
+#else
+   for (i=0;i<mode->overlap;i++)
+      window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap))));
+#endif
+   mode->window = window;
+
+   logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16));
+   if (logN==NULL)
+      goto failure;
+
+   for (i=0;i<mode->nbEBands;i++)
+      logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES);
+   mode->logN = logN;
+
+   compute_pulse_cache(mode, mode->maxLM);
+
+   if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts,
+           mode->maxLM, arch) == 0)
+      goto failure;
+
+   if (error)
+      *error = OPUS_OK;
+
+   return mode;
+failure:
+   if (error)
+      *error = OPUS_ALLOC_FAIL;
+   if (mode!=NULL)
+      opus_custom_mode_destroy(mode);
+   return NULL;
+#endif /* !CUSTOM_MODES */
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_mode_destroy(CELTMode *mode)
+{
+   int arch = opus_select_arch();
+
+   if (mode == NULL)
+      return;
+#ifndef CUSTOM_MODES_ONLY
+   {
+     int i;
+     for (i=0;i<TOTAL_MODES;i++)
+     {
+        if (mode == static_mode_list[i])
+        {
+           return;
+        }
+     }
+   }
+#endif /* CUSTOM_MODES_ONLY */
+   opus_free((opus_int16*)mode->eBands);
+   opus_free((opus_int16*)mode->allocVectors);
+
+   opus_free((opus_val16*)mode->window);
+   opus_free((opus_int16*)mode->logN);
+
+   opus_free((opus_int16*)mode->cache.index);
+   opus_free((unsigned char*)mode->cache.bits);
+   opus_free((unsigned char*)mode->cache.caps);
+   clt_mdct_clear(&mode->mdct, arch);
+
+   opus_free((CELTMode *)mode);
+}
+#endif
diff --git a/third_party/opus/src/celt/modes.h b/third_party/opus/src/celt/modes.h
new file mode 100644
index 0000000..be813ccc
--- /dev/null
+++ b/third_party/opus/src/celt/modes.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Copyright (c) 2008 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MODES_H
+#define MODES_H
+
+#include "opus_types.h"
+#include "celt.h"
+#include "arch.h"
+#include "mdct.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#define MAX_PERIOD 1024
+
+typedef struct {
+   int size;
+   const opus_int16 *index;
+   const unsigned char *bits;
+   const unsigned char *caps;
+} PulseCache;
+
+/** Mode definition (opaque)
+ @brief Mode definition
+ */
+struct OpusCustomMode {
+   opus_int32 Fs;
+   int          overlap;
+
+   int          nbEBands;
+   int          effEBands;
+   opus_val16    preemph[4];
+   const opus_int16   *eBands;   /**< Definition for each "pseudo-critical band" */
+
+   int         maxLM;
+   int         nbShortMdcts;
+   int         shortMdctSize;
+
+   int          nbAllocVectors; /**< Number of lines in the matrix below */
+   const unsigned char   *allocVectors;   /**< Number of bits in each band for several rates */
+   const opus_int16 *logN;
+
+   const opus_val16 *window;
+   mdct_lookup mdct;
+   PulseCache cache;
+};
+
+
+#endif
diff --git a/third_party/opus/src/celt/opus_custom_demo.c b/third_party/opus/src/celt/opus_custom_demo.c
new file mode 100644
index 0000000..ae41c0de
--- /dev/null
+++ b/third_party/opus/src/celt/opus_custom_demo.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_custom.h"
+#include "arch.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#define MAX_PACKET 1275
+
+int main(int argc, char *argv[])
+{
+   int err;
+   char *inFile, *outFile;
+   FILE *fin, *fout;
+   OpusCustomMode *mode=NULL;
+   OpusCustomEncoder *enc;
+   OpusCustomDecoder *dec;
+   int len;
+   opus_int32 frame_size, channels, rate;
+   int bytes_per_packet;
+   unsigned char data[MAX_PACKET];
+   int complexity;
+#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+   int i;
+   double rmsd = 0;
+#endif
+   int count = 0;
+   opus_int32 skip;
+   opus_int16 *in, *out;
+   if (argc != 9 && argc != 8 && argc != 7)
+   {
+      fprintf (stderr, "Usage: test_opus_custom <rate> <channels> <frame size> "
+               " <bytes per packet> [<complexity> [packet loss rate]] "
+               "<input> <output>\n");
+      return 1;
+   }
+
+   rate = (opus_int32)atol(argv[1]);
+   channels = atoi(argv[2]);
+   frame_size = atoi(argv[3]);
+   mode = opus_custom_mode_create(rate, frame_size, NULL);
+   if (mode == NULL)
+   {
+      fprintf(stderr, "failed to create a mode\n");
+      return 1;
+   }
+
+   bytes_per_packet = atoi(argv[4]);
+   if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET)
+   {
+      fprintf (stderr, "bytes per packet must be between 0 and %d\n",
+                        MAX_PACKET);
+      return 1;
+   }
+
+   inFile = argv[argc-2];
+   fin = fopen(inFile, "rb");
+   if (!fin)
+   {
+      fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
+      return 1;
+   }
+   outFile = argv[argc-1];
+   fout = fopen(outFile, "wb+");
+   if (!fout)
+   {
+      fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
+      fclose(fin);
+      return 1;
+   }
+
+   enc = opus_custom_encoder_create(mode, channels, &err);
+   if (err != 0)
+   {
+      fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err));
+      fclose(fin);
+      fclose(fout);
+      return 1;
+   }
+   dec = opus_custom_decoder_create(mode, channels, &err);
+   if (err != 0)
+   {
+      fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err));
+      fclose(fin);
+      fclose(fout);
+      return 1;
+   }
+   opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip));
+
+   if (argc>7)
+   {
+      complexity=atoi(argv[5]);
+      opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity));
+   }
+
+   in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
+   out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
+
+   while (!feof(fin))
+   {
+      int ret;
+      err = fread(in, sizeof(short), frame_size*channels, fin);
+      if (feof(fin))
+         break;
+      len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet);
+      if (len <= 0)
+         fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len));
+
+      /* This is for simulating bit errors */
+#if 0
+      int errors = 0;
+      int eid = 0;
+      /* This simulates random bit error */
+      for (i=0;i<len*8;i++)
+      {
+         if (rand()%atoi(argv[8])==0)
+         {
+            if (i<64)
+            {
+               errors++;
+               eid = i;
+            }
+            data[i/8] ^= 1<<(7-(i%8));
+         }
+      }
+      if (errors == 1)
+         data[eid/8] ^= 1<<(7-(eid%8));
+      else if (errors%2 == 1)
+         data[rand()%8] ^= 1<<rand()%8;
+#endif
+
+#if 1 /* Set to zero to use the encoder's output instead */
+      /* This is to simulate packet loss */
+      if (argc==9 && rand()%1000<atoi(argv[argc-3]))
+      /*if (errors && (errors%2==0))*/
+         ret = opus_custom_decode(dec, NULL, len, out, frame_size);
+      else
+         ret = opus_custom_decode(dec, data, len, out, frame_size);
+      if (ret < 0)
+         fprintf(stderr, "opus_custom_decode() failed: %s\n", opus_strerror(ret));
+#else
+      for (i=0;i<ret*channels;i++)
+         out[i] = in[i];
+#endif
+#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+      for (i=0;i<ret*channels;i++)
+      {
+         rmsd += (in[i]-out[i])*1.0*(in[i]-out[i]);
+         /*out[i] -= in[i];*/
+      }
+#endif
+      count++;
+      fwrite(out+skip*channels, sizeof(short), (ret-skip)*channels, fout);
+      skip = 0;
+   }
+   PRINT_MIPS(stderr);
+
+   opus_custom_encoder_destroy(enc);
+   opus_custom_decoder_destroy(dec);
+   fclose(fin);
+   fclose(fout);
+   opus_custom_mode_destroy(mode);
+   free(in);
+   free(out);
+#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+   if (rmsd > 0)
+   {
+      rmsd = sqrt(rmsd/(1.0*frame_size*channels*count));
+      fprintf (stderr, "Error: encoder doesn't match decoder\n");
+      fprintf (stderr, "RMS mismatch is %f\n", rmsd);
+      return 1;
+   } else {
+      fprintf (stderr, "Encoder matches decoder!!\n");
+   }
+#endif
+   return 0;
+}
+
diff --git a/third_party/opus/src/celt/os_support.h b/third_party/opus/src/celt/os_support.h
new file mode 100644
index 0000000..a2171971
--- /dev/null
+++ b/third_party/opus/src/celt/os_support.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+   File: os_support.h
+   This is the (tiny) OS abstraction layer. Aside from math.h, this is the
+   only place where system headers are allowed.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef OS_SUPPORT_H
+#define OS_SUPPORT_H
+
+#ifdef CUSTOM_SUPPORT
+#  include "custom_support.h"
+#endif
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */
+#ifndef OVERRIDE_OPUS_ALLOC
+static OPUS_INLINE void *opus_alloc (size_t size)
+{
+   return malloc(size);
+}
+#endif
+
+/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */
+#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH
+static OPUS_INLINE void *opus_alloc_scratch (size_t size)
+{
+   /* Scratch space doesn't need to be cleared */
+   return opus_alloc(size);
+}
+#endif
+
+/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */
+#ifndef OVERRIDE_OPUS_FREE
+static OPUS_INLINE void opus_free (void *ptr)
+{
+   free(ptr);
+}
+#endif
+
+/** Copy n elements from src to dst. The 0* term provides compile-time type checking  */
+#ifndef OVERRIDE_OPUS_COPY
+#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Copy n elements from src to dst, allowing overlapping regions. The 0* term
+    provides compile-time type checking */
+#ifndef OVERRIDE_OPUS_MOVE
+#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Set n elements of dst to zero */
+#ifndef OVERRIDE_OPUS_CLEAR
+#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst))))
+#endif
+
+/*#ifdef __GNUC__
+#pragma GCC poison printf sprintf
+#pragma GCC poison malloc free realloc calloc
+#endif*/
+
+#endif /* OS_SUPPORT_H */
+
diff --git a/third_party/opus/src/celt/pitch.c b/third_party/opus/src/celt/pitch.c
new file mode 100644
index 0000000..bf46e7d5
--- /dev/null
+++ b/third_party/opus/src/celt/pitch.c
@@ -0,0 +1,557 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/**
+   @file pitch.c
+   @brief Pitch analysis
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pitch.h"
+#include "os_support.h"
+#include "modes.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "celt_lpc.h"
+
+static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len,
+                            int max_pitch, int *best_pitch
+#ifdef FIXED_POINT
+                            , int yshift, opus_val32 maxcorr
+#endif
+                            )
+{
+   int i, j;
+   opus_val32 Syy=1;
+   opus_val16 best_num[2];
+   opus_val32 best_den[2];
+#ifdef FIXED_POINT
+   int xshift;
+
+   xshift = celt_ilog2(maxcorr)-14;
+#endif
+
+   best_num[0] = -1;
+   best_num[1] = -1;
+   best_den[0] = 0;
+   best_den[1] = 0;
+   best_pitch[0] = 0;
+   best_pitch[1] = 1;
+   for (j=0;j<len;j++)
+      Syy = ADD32(Syy, SHR32(MULT16_16(y[j],y[j]), yshift));
+   for (i=0;i<max_pitch;i++)
+   {
+      if (xcorr[i]>0)
+      {
+         opus_val16 num;
+         opus_val32 xcorr16;
+         xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift));
+#ifndef FIXED_POINT
+         /* Considering the range of xcorr16, this should avoid both underflows
+            and overflows (inf) when squaring xcorr16 */
+         xcorr16 *= 1e-12f;
+#endif
+         num = MULT16_16_Q15(xcorr16,xcorr16);
+         if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy))
+         {
+            if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy))
+            {
+               best_num[1] = best_num[0];
+               best_den[1] = best_den[0];
+               best_pitch[1] = best_pitch[0];
+               best_num[0] = num;
+               best_den[0] = Syy;
+               best_pitch[0] = i;
+            } else {
+               best_num[1] = num;
+               best_den[1] = Syy;
+               best_pitch[1] = i;
+            }
+         }
+      }
+      Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift);
+      Syy = MAX32(1, Syy);
+   }
+}
+
+static void celt_fir5(const opus_val16 *x,
+         const opus_val16 *num,
+         opus_val16 *y,
+         int N,
+         opus_val16 *mem)
+{
+   int i;
+   opus_val16 num0, num1, num2, num3, num4;
+   opus_val32 mem0, mem1, mem2, mem3, mem4;
+   num0=num[0];
+   num1=num[1];
+   num2=num[2];
+   num3=num[3];
+   num4=num[4];
+   mem0=mem[0];
+   mem1=mem[1];
+   mem2=mem[2];
+   mem3=mem[3];
+   mem4=mem[4];
+   for (i=0;i<N;i++)
+   {
+      opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
+      sum = MAC16_16(sum,num0,mem0);
+      sum = MAC16_16(sum,num1,mem1);
+      sum = MAC16_16(sum,num2,mem2);
+      sum = MAC16_16(sum,num3,mem3);
+      sum = MAC16_16(sum,num4,mem4);
+      mem4 = mem3;
+      mem3 = mem2;
+      mem2 = mem1;
+      mem1 = mem0;
+      mem0 = x[i];
+      y[i] = ROUND16(sum, SIG_SHIFT);
+   }
+   mem[0]=mem0;
+   mem[1]=mem1;
+   mem[2]=mem2;
+   mem[3]=mem3;
+   mem[4]=mem4;
+}
+
+
+void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
+      int len, int C, int arch)
+{
+   int i;
+   opus_val32 ac[5];
+   opus_val16 tmp=Q15ONE;
+   opus_val16 lpc[4], mem[5]={0,0,0,0,0};
+   opus_val16 lpc2[5];
+   opus_val16 c1 = QCONST16(.8f,15);
+#ifdef FIXED_POINT
+   int shift;
+   opus_val32 maxabs = celt_maxabs32(x[0], len);
+   if (C==2)
+   {
+      opus_val32 maxabs_1 = celt_maxabs32(x[1], len);
+      maxabs = MAX32(maxabs, maxabs_1);
+   }
+   if (maxabs<1)
+      maxabs=1;
+   shift = celt_ilog2(maxabs)-10;
+   if (shift<0)
+      shift=0;
+   if (C==2)
+      shift++;
+#endif
+   for (i=1;i<len>>1;i++)
+      x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift);
+   x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift);
+   if (C==2)
+   {
+      for (i=1;i<len>>1;i++)
+         x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift);
+      x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift);
+   }
+
+   _celt_autocorr(x_lp, ac, NULL, 0,
+                  4, len>>1, arch);
+
+   /* Noise floor -40 dB */
+#ifdef FIXED_POINT
+   ac[0] += SHR32(ac[0],13);
+#else
+   ac[0] *= 1.0001f;
+#endif
+   /* Lag windowing */
+   for (i=1;i<=4;i++)
+   {
+      /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+#ifdef FIXED_POINT
+      ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
+#else
+      ac[i] -= ac[i]*(.008f*i)*(.008f*i);
+#endif
+   }
+
+   _celt_lpc(lpc, ac, 4);
+   for (i=0;i<4;i++)
+   {
+      tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp);
+      lpc[i] = MULT16_16_Q15(lpc[i], tmp);
+   }
+   /* Add a zero */
+   lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT);
+   lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]);
+   lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]);
+   lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]);
+   lpc2[4] = MULT16_16_Q15(c1,lpc[3]);
+   celt_fir5(x_lp, lpc2, x_lp, len>>1, mem);
+}
+
+/* Pure C implementation. */
+#ifdef FIXED_POINT
+opus_val32
+#else
+void
+#endif
+#if defined(OVERRIDE_PITCH_XCORR)
+celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
+      opus_val32 *xcorr, int len, int max_pitch)
+#else
+celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
+      opus_val32 *xcorr, int len, int max_pitch, int arch)
+#endif
+{
+
+#if 0 /* This is a simple version of the pitch correlation that should work
+         well on DSPs like Blackfin and TI C5x/C6x */
+   int i, j;
+#ifdef FIXED_POINT
+   opus_val32 maxcorr=1;
+#endif
+#if !defined(OVERRIDE_PITCH_XCORR)
+   (void)arch;
+#endif
+   for (i=0;i<max_pitch;i++)
+   {
+      opus_val32 sum = 0;
+      for (j=0;j<len;j++)
+         sum = MAC16_16(sum, _x[j], _y[i+j]);
+      xcorr[i] = sum;
+#ifdef FIXED_POINT
+      maxcorr = MAX32(maxcorr, sum);
+#endif
+   }
+#ifdef FIXED_POINT
+   return maxcorr;
+#endif
+
+#else /* Unrolled version of the pitch correlation -- runs faster on x86 and ARM */
+   int i;
+   /*The EDSP version requires that max_pitch is at least 1, and that _x is
+      32-bit aligned.
+     Since it's hard to put asserts in assembly, put them here.*/
+#ifdef FIXED_POINT
+   opus_val32 maxcorr=1;
+#endif
+   celt_assert(max_pitch>0);
+   celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
+   for (i=0;i<max_pitch-3;i+=4)
+   {
+      opus_val32 sum[4]={0,0,0,0};
+#if defined(OVERRIDE_PITCH_XCORR)
+      xcorr_kernel_c(_x, _y+i, sum, len);
+#else
+      xcorr_kernel(_x, _y+i, sum, len, arch);
+#endif
+      xcorr[i]=sum[0];
+      xcorr[i+1]=sum[1];
+      xcorr[i+2]=sum[2];
+      xcorr[i+3]=sum[3];
+#ifdef FIXED_POINT
+      sum[0] = MAX32(sum[0], sum[1]);
+      sum[2] = MAX32(sum[2], sum[3]);
+      sum[0] = MAX32(sum[0], sum[2]);
+      maxcorr = MAX32(maxcorr, sum[0]);
+#endif
+   }
+   /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
+   for (;i<max_pitch;i++)
+   {
+      opus_val32 sum;
+#if defined(OVERRIDE_PITCH_XCORR)
+      sum = celt_inner_prod_c(_x, _y+i, len);
+#else
+      sum = celt_inner_prod(_x, _y+i, len, arch);
+#endif
+      xcorr[i] = sum;
+#ifdef FIXED_POINT
+      maxcorr = MAX32(maxcorr, sum);
+#endif
+   }
+#ifdef FIXED_POINT
+   return maxcorr;
+#endif
+#endif
+}
+
+void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
+                  int len, int max_pitch, int *pitch, int arch)
+{
+   int i, j;
+   int lag;
+   int best_pitch[2]={0,0};
+   VARDECL(opus_val16, x_lp4);
+   VARDECL(opus_val16, y_lp4);
+   VARDECL(opus_val32, xcorr);
+#ifdef FIXED_POINT
+   opus_val32 maxcorr;
+   opus_val32 xmax, ymax;
+   int shift=0;
+#endif
+   int offset;
+
+   SAVE_STACK;
+
+   celt_assert(len>0);
+   celt_assert(max_pitch>0);
+   lag = len+max_pitch;
+
+   ALLOC(x_lp4, len>>2, opus_val16);
+   ALLOC(y_lp4, lag>>2, opus_val16);
+   ALLOC(xcorr, max_pitch>>1, opus_val32);
+
+   /* Downsample by 2 again */
+   for (j=0;j<len>>2;j++)
+      x_lp4[j] = x_lp[2*j];
+   for (j=0;j<lag>>2;j++)
+      y_lp4[j] = y[2*j];
+
+#ifdef FIXED_POINT
+   xmax = celt_maxabs16(x_lp4, len>>2);
+   ymax = celt_maxabs16(y_lp4, lag>>2);
+   shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11;
+   if (shift>0)
+   {
+      for (j=0;j<len>>2;j++)
+         x_lp4[j] = SHR16(x_lp4[j], shift);
+      for (j=0;j<lag>>2;j++)
+         y_lp4[j] = SHR16(y_lp4[j], shift);
+      /* Use double the shift for a MAC */
+      shift *= 2;
+   } else {
+      shift = 0;
+   }
+#endif
+
+   /* Coarse search with 4x decimation */
+
+#ifdef FIXED_POINT
+   maxcorr =
+#endif
+   celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch);
+
+   find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch
+#ifdef FIXED_POINT
+                   , 0, maxcorr
+#endif
+                   );
+
+   /* Finer search with 2x decimation */
+#ifdef FIXED_POINT
+   maxcorr=1;
+#endif
+   for (i=0;i<max_pitch>>1;i++)
+   {
+      opus_val32 sum;
+      xcorr[i] = 0;
+      if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2)
+         continue;
+#ifdef FIXED_POINT
+      sum = 0;
+      for (j=0;j<len>>1;j++)
+         sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift);
+#else
+      sum = celt_inner_prod_c(x_lp, y+i, len>>1);
+#endif
+      xcorr[i] = MAX32(-1, sum);
+#ifdef FIXED_POINT
+      maxcorr = MAX32(maxcorr, sum);
+#endif
+   }
+   find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch
+#ifdef FIXED_POINT
+                   , shift+1, maxcorr
+#endif
+                   );
+
+   /* Refine by pseudo-interpolation */
+   if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1)
+   {
+      opus_val32 a, b, c;
+      a = xcorr[best_pitch[0]-1];
+      b = xcorr[best_pitch[0]];
+      c = xcorr[best_pitch[0]+1];
+      if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a))
+         offset = 1;
+      else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c))
+         offset = -1;
+      else
+         offset = 0;
+   } else {
+      offset = 0;
+   }
+   *pitch = 2*best_pitch[0]-offset;
+
+   RESTORE_STACK;
+}
+
+#ifdef FIXED_POINT
+static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
+{
+   opus_val32 x2y2;
+   int sx, sy, shift;
+   opus_val32 g;
+   opus_val16 den;
+   if (xy == 0 || xx == 0 || yy == 0)
+      return 0;
+   sx = celt_ilog2(xx)-14;
+   sy = celt_ilog2(yy)-14;
+   shift = sx + sy;
+   x2y2 = MULT16_16_Q14(VSHR32(xx, sx), VSHR32(yy, sy));
+   if (shift & 1) {
+      if (x2y2 < 32768)
+      {
+         x2y2 <<= 1;
+         shift--;
+      } else {
+         x2y2 >>= 1;
+         shift++;
+      }
+   }
+   den = celt_rsqrt_norm(x2y2);
+   g = MULT16_32_Q15(den, xy);
+   g = VSHR32(g, (shift>>1)-1);
+   return EXTRACT16(MIN32(g, Q15ONE));
+}
+#else
+static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy)
+{
+   return xy/celt_sqrt(1+xx*yy);
+}
+#endif
+
+static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
+opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
+      int N, int *T0_, int prev_period, opus_val16 prev_gain, int arch)
+{
+   int k, i, T, T0;
+   opus_val16 g, g0;
+   opus_val16 pg;
+   opus_val32 xy,xx,yy,xy2;
+   opus_val32 xcorr[3];
+   opus_val32 best_xy, best_yy;
+   int offset;
+   int minperiod0;
+   VARDECL(opus_val32, yy_lookup);
+   SAVE_STACK;
+
+   minperiod0 = minperiod;
+   maxperiod /= 2;
+   minperiod /= 2;
+   *T0_ /= 2;
+   prev_period /= 2;
+   N /= 2;
+   x += maxperiod;
+   if (*T0_>=maxperiod)
+      *T0_=maxperiod-1;
+
+   T = T0 = *T0_;
+   ALLOC(yy_lookup, maxperiod+1, opus_val32);
+   dual_inner_prod(x, x, x-T0, N, &xx, &xy, arch);
+   yy_lookup[0] = xx;
+   yy=xx;
+   for (i=1;i<=maxperiod;i++)
+   {
+      yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]);
+      yy_lookup[i] = MAX32(0, yy);
+   }
+   yy = yy_lookup[T0];
+   best_xy = xy;
+   best_yy = yy;
+   g = g0 = compute_pitch_gain(xy, xx, yy);
+   /* Look for any pitch at T/k */
+   for (k=2;k<=15;k++)
+   {
+      int T1, T1b;
+      opus_val16 g1;
+      opus_val16 cont=0;
+      opus_val16 thresh;
+      T1 = celt_udiv(2*T0+k, 2*k);
+      if (T1 < minperiod)
+         break;
+      /* Look for another strong correlation at T1b */
+      if (k==2)
+      {
+         if (T1+T0>maxperiod)
+            T1b = T0;
+         else
+            T1b = T0+T1;
+      } else
+      {
+         T1b = celt_udiv(2*second_check[k]*T0+k, 2*k);
+      }
+      dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2, arch);
+      xy = HALF32(xy + xy2);
+      yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]);
+      g1 = compute_pitch_gain(xy, xx, yy);
+      if (abs(T1-prev_period)<=1)
+         cont = prev_gain;
+      else if (abs(T1-prev_period)<=2 && 5*k*k < T0)
+         cont = HALF16(prev_gain);
+      else
+         cont = 0;
+      thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont);
+      /* Bias against very high pitch (very short period) to avoid false-positives
+         due to short-term correlation */
+      if (T1<3*minperiod)
+         thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont);
+      else if (T1<2*minperiod)
+         thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont);
+      if (g1 > thresh)
+      {
+         best_xy = xy;
+         best_yy = yy;
+         T = T1;
+         g = g1;
+      }
+   }
+   best_xy = MAX32(0, best_xy);
+   if (best_yy <= best_xy)
+      pg = Q15ONE;
+   else
+      pg = SHR32(frac_div32(best_xy,best_yy+1),16);
+
+   for (k=0;k<3;k++)
+      xcorr[k] = celt_inner_prod(x, x-(T+k-1), N, arch);
+   if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0]))
+      offset = 1;
+   else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2]))
+      offset = -1;
+   else
+      offset = 0;
+   if (pg > g)
+      pg = g;
+   *T0_ = 2*T+offset;
+
+   if (*T0_<minperiod0)
+      *T0_=minperiod0;
+   RESTORE_STACK;
+   return pg;
+}
diff --git a/third_party/opus/src/celt/pitch.h b/third_party/opus/src/celt/pitch.h
new file mode 100644
index 0000000..d350353
--- /dev/null
+++ b/third_party/opus/src/celt/pitch.h
@@ -0,0 +1,200 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/**
+   @file pitch.h
+   @brief Pitch analysis
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PITCH_H
+#define PITCH_H
+
+#include "modes.h"
+#include "cpu_support.h"
+
+#if (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT)) \
+  || ((defined(OPUS_X86_MAY_HAVE_SSE4_1) || defined(OPUS_X86_MAY_HAVE_SSE2)) && defined(FIXED_POINT))
+#include "x86/pitch_sse.h"
+#endif
+
+#if defined(MIPSr1_ASM)
+#include "mips/pitch_mipsr1.h"
+#endif
+
+#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \
+  || defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
+# include "arm/pitch_arm.h"
+#endif
+
+void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
+      int len, int C, int arch);
+
+void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
+                  int len, int max_pitch, int *pitch, int arch);
+
+opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
+      int N, int *T0, int prev_period, opus_val16 prev_gain, int arch);
+
+
+/* OPT: This is the kernel you really want to optimize. It gets used a lot
+   by the prefilter and by the PLC. */
+static OPUS_INLINE void xcorr_kernel_c(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len)
+{
+   int j;
+   opus_val16 y_0, y_1, y_2, y_3;
+   celt_assert(len>=3);
+   y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */
+   y_0=*y++;
+   y_1=*y++;
+   y_2=*y++;
+   for (j=0;j<len-3;j+=4)
+   {
+      opus_val16 tmp;
+      tmp = *x++;
+      y_3=*y++;
+      sum[0] = MAC16_16(sum[0],tmp,y_0);
+      sum[1] = MAC16_16(sum[1],tmp,y_1);
+      sum[2] = MAC16_16(sum[2],tmp,y_2);
+      sum[3] = MAC16_16(sum[3],tmp,y_3);
+      tmp=*x++;
+      y_0=*y++;
+      sum[0] = MAC16_16(sum[0],tmp,y_1);
+      sum[1] = MAC16_16(sum[1],tmp,y_2);
+      sum[2] = MAC16_16(sum[2],tmp,y_3);
+      sum[3] = MAC16_16(sum[3],tmp,y_0);
+      tmp=*x++;
+      y_1=*y++;
+      sum[0] = MAC16_16(sum[0],tmp,y_2);
+      sum[1] = MAC16_16(sum[1],tmp,y_3);
+      sum[2] = MAC16_16(sum[2],tmp,y_0);
+      sum[3] = MAC16_16(sum[3],tmp,y_1);
+      tmp=*x++;
+      y_2=*y++;
+      sum[0] = MAC16_16(sum[0],tmp,y_3);
+      sum[1] = MAC16_16(sum[1],tmp,y_0);
+      sum[2] = MAC16_16(sum[2],tmp,y_1);
+      sum[3] = MAC16_16(sum[3],tmp,y_2);
+   }
+   if (j++<len)
+   {
+      opus_val16 tmp = *x++;
+      y_3=*y++;
+      sum[0] = MAC16_16(sum[0],tmp,y_0);
+      sum[1] = MAC16_16(sum[1],tmp,y_1);
+      sum[2] = MAC16_16(sum[2],tmp,y_2);
+      sum[3] = MAC16_16(sum[3],tmp,y_3);
+   }
+   if (j++<len)
+   {
+      opus_val16 tmp=*x++;
+      y_0=*y++;
+      sum[0] = MAC16_16(sum[0],tmp,y_1);
+      sum[1] = MAC16_16(sum[1],tmp,y_2);
+      sum[2] = MAC16_16(sum[2],tmp,y_3);
+      sum[3] = MAC16_16(sum[3],tmp,y_0);
+   }
+   if (j<len)
+   {
+      opus_val16 tmp=*x++;
+      y_1=*y++;
+      sum[0] = MAC16_16(sum[0],tmp,y_2);
+      sum[1] = MAC16_16(sum[1],tmp,y_3);
+      sum[2] = MAC16_16(sum[2],tmp,y_0);
+      sum[3] = MAC16_16(sum[3],tmp,y_1);
+   }
+}
+
+#ifndef OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+    ((void)(arch),xcorr_kernel_c(x, y, sum, len))
+#endif /* OVERRIDE_XCORR_KERNEL */
+
+
+static OPUS_INLINE void dual_inner_prod_c(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
+      int N, opus_val32 *xy1, opus_val32 *xy2)
+{
+   int i;
+   opus_val32 xy01=0;
+   opus_val32 xy02=0;
+   for (i=0;i<N;i++)
+   {
+      xy01 = MAC16_16(xy01, x[i], y01[i]);
+      xy02 = MAC16_16(xy02, x[i], y02[i]);
+   }
+   *xy1 = xy01;
+   *xy2 = xy02;
+}
+
+#ifndef OVERRIDE_DUAL_INNER_PROD
+# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) \
+    ((void)(arch),dual_inner_prod_c(x, y01, y02, N, xy1, xy2))
+#endif
+
+/*We make sure a C version is always available for cases where the overhead of
+  vectorization and passing around an arch flag aren't worth it.*/
+static OPUS_INLINE opus_val32 celt_inner_prod_c(const opus_val16 *x,
+      const opus_val16 *y, int N)
+{
+   int i;
+   opus_val32 xy=0;
+   for (i=0;i<N;i++)
+      xy = MAC16_16(xy, x[i], y[i]);
+   return xy;
+}
+
+#if !defined(OVERRIDE_CELT_INNER_PROD)
+# define celt_inner_prod(x, y, N, arch) \
+    ((void)(arch),celt_inner_prod_c(x, y, N))
+#endif
+
+#ifdef NON_STATIC_COMB_FILTER_CONST_C
+void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
+     opus_val16 g10, opus_val16 g11, opus_val16 g12);
+#endif
+
+
+#ifdef FIXED_POINT
+opus_val32
+#else
+void
+#endif
+celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
+      opus_val32 *xcorr, int len, int max_pitch);
+
+#if !defined(OVERRIDE_PITCH_XCORR)
+#ifdef FIXED_POINT
+opus_val32
+#else
+void
+#endif
+celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
+      opus_val32 *xcorr, int len, int max_pitch, int arch);
+
+#endif
+
+#endif
diff --git a/third_party/opus/src/celt/quant_bands.c b/third_party/opus/src/celt/quant_bands.c
new file mode 100644
index 0000000..95076e0
--- /dev/null
+++ b/third_party/opus/src/celt/quant_bands.c
@@ -0,0 +1,556 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "quant_bands.h"
+#include "laplace.h"
+#include <math.h>
+#include "os_support.h"
+#include "arch.h"
+#include "mathops.h"
+#include "stack_alloc.h"
+#include "rate.h"
+
+#ifdef FIXED_POINT
+/* Mean energy in each band quantized in Q4 */
+const signed char eMeans[25] = {
+      103,100, 92, 85, 81,
+       77, 72, 70, 78, 75,
+       73, 71, 78, 74, 69,
+       72, 70, 74, 76, 71,
+       60, 60, 60, 60, 60
+};
+#else
+/* Mean energy in each band quantized in Q4 and converted back to float */
+const opus_val16 eMeans[25] = {
+      6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f,
+      4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f,
+      4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f,
+      4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f,
+      3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f
+};
+#endif
+/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */
+#ifdef FIXED_POINT
+static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384};
+static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554};
+static const opus_val16 beta_intra = 4915;
+#else
+static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.};
+static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.};
+static const opus_val16 beta_intra = 4915/32768.;
+#endif
+
+/*Parameters of the Laplace-like probability models used for the coarse energy.
+  There is one pair of parameters for each frame size, prediction type
+   (inter/intra), and band number.
+  The first number of each pair is the probability of 0, and the second is the
+   decay rate, both in Q8 precision.*/
+static const unsigned char e_prob_model[4][2][42] = {
+   /*120 sample frames.*/
+   {
+      /*Inter*/
+      {
+          72, 127,  65, 129,  66, 128,  65, 128,  64, 128,  62, 128,  64, 128,
+          64, 128,  92,  78,  92,  79,  92,  78,  90,  79, 116,  41, 115,  40,
+         114,  40, 132,  26, 132,  26, 145,  17, 161,  12, 176,  10, 177,  11
+      },
+      /*Intra*/
+      {
+          24, 179,  48, 138,  54, 135,  54, 132,  53, 134,  56, 133,  55, 132,
+          55, 132,  61, 114,  70,  96,  74,  88,  75,  88,  87,  74,  89,  66,
+          91,  67, 100,  59, 108,  50, 120,  40, 122,  37,  97,  43,  78,  50
+      }
+   },
+   /*240 sample frames.*/
+   {
+      /*Inter*/
+      {
+          83,  78,  84,  81,  88,  75,  86,  74,  87,  71,  90,  73,  93,  74,
+          93,  74, 109,  40, 114,  36, 117,  34, 117,  34, 143,  17, 145,  18,
+         146,  19, 162,  12, 165,  10, 178,   7, 189,   6, 190,   8, 177,   9
+      },
+      /*Intra*/
+      {
+          23, 178,  54, 115,  63, 102,  66,  98,  69,  99,  74,  89,  71,  91,
+          73,  91,  78,  89,  86,  80,  92,  66,  93,  64, 102,  59, 103,  60,
+         104,  60, 117,  52, 123,  44, 138,  35, 133,  31,  97,  38,  77,  45
+      }
+   },
+   /*480 sample frames.*/
+   {
+      /*Inter*/
+      {
+          61,  90,  93,  60, 105,  42, 107,  41, 110,  45, 116,  38, 113,  38,
+         112,  38, 124,  26, 132,  27, 136,  19, 140,  20, 155,  14, 159,  16,
+         158,  18, 170,  13, 177,  10, 187,   8, 192,   6, 175,   9, 159,  10
+      },
+      /*Intra*/
+      {
+          21, 178,  59, 110,  71,  86,  75,  85,  84,  83,  91,  66,  88,  73,
+          87,  72,  92,  75,  98,  72, 105,  58, 107,  54, 115,  52, 114,  55,
+         112,  56, 129,  51, 132,  40, 150,  33, 140,  29,  98,  35,  77,  42
+      }
+   },
+   /*960 sample frames.*/
+   {
+      /*Inter*/
+      {
+          42, 121,  96,  66, 108,  43, 111,  40, 117,  44, 123,  32, 120,  36,
+         119,  33, 127,  33, 134,  34, 139,  21, 147,  23, 152,  20, 158,  25,
+         154,  26, 166,  21, 173,  16, 184,  13, 184,  10, 150,  13, 139,  15
+      },
+      /*Intra*/
+      {
+          22, 178,  63, 114,  74,  82,  84,  83,  92,  82, 103,  62,  96,  72,
+          96,  67, 101,  73, 107,  72, 113,  55, 118,  52, 125,  52, 118,  52,
+         117,  55, 135,  49, 137,  39, 157,  32, 145,  29,  97,  33,  77,  40
+      }
+   }
+};
+
+static const unsigned char small_energy_icdf[3]={2,1,0};
+
+static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C)
+{
+   int c, i;
+   opus_val32 dist = 0;
+   c=0; do {
+      for (i=start;i<end;i++)
+      {
+         opus_val16 d = SUB16(SHR16(eBands[i+c*len], 3), SHR16(oldEBands[i+c*len], 3));
+         dist = MAC16_16(dist, d,d);
+      }
+   } while (++c<C);
+   return MIN32(200,SHR32(dist,2*DB_SHIFT-6));
+}
+
+static int quant_coarse_energy_impl(const CELTMode *m, int start, int end,
+      const opus_val16 *eBands, opus_val16 *oldEBands,
+      opus_int32 budget, opus_int32 tell,
+      const unsigned char *prob_model, opus_val16 *error, ec_enc *enc,
+      int C, int LM, int intra, opus_val16 max_decay, int lfe)
+{
+   int i, c;
+   int badness = 0;
+   opus_val32 prev[2] = {0,0};
+   opus_val16 coef;
+   opus_val16 beta;
+
+   if (tell+3 <= budget)
+      ec_enc_bit_logp(enc, intra, 3);
+   if (intra)
+   {
+      coef = 0;
+      beta = beta_intra;
+   } else {
+      beta = beta_coef[LM];
+      coef = pred_coef[LM];
+   }
+
+   /* Encode at a fixed coarse resolution */
+   for (i=start;i<end;i++)
+   {
+      c=0;
+      do {
+         int bits_left;
+         int qi, qi0;
+         opus_val32 q;
+         opus_val16 x;
+         opus_val32 f, tmp;
+         opus_val16 oldE;
+         opus_val16 decay_bound;
+         x = eBands[i+c*m->nbEBands];
+         oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
+#ifdef FIXED_POINT
+         f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c];
+         /* Rounding to nearest integer here is really important! */
+         qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7);
+         decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT),
+               SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay)));
+#else
+         f = x-coef*oldE-prev[c];
+         /* Rounding to nearest integer here is really important! */
+         qi = (int)floor(.5f+f);
+         decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay;
+#endif
+         /* Prevent the energy from going down too quickly (e.g. for bands
+            that have just one bin) */
+         if (qi < 0 && x < decay_bound)
+         {
+            qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT);
+            if (qi > 0)
+               qi = 0;
+         }
+         qi0 = qi;
+         /* If we don't have enough bits to encode all the energy, just assume
+             something safe. */
+         tell = ec_tell(enc);
+         bits_left = budget-tell-3*C*(end-i);
+         if (i!=start && bits_left < 30)
+         {
+            if (bits_left < 24)
+               qi = IMIN(1, qi);
+            if (bits_left < 16)
+               qi = IMAX(-1, qi);
+         }
+         if (lfe && i>=2)
+            qi = IMIN(qi, 0);
+         if (budget-tell >= 15)
+         {
+            int pi;
+            pi = 2*IMIN(i,20);
+            ec_laplace_encode(enc, &qi,
+                  prob_model[pi]<<7, prob_model[pi+1]<<6);
+         }
+         else if(budget-tell >= 2)
+         {
+            qi = IMAX(-1, IMIN(qi, 1));
+            ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2);
+         }
+         else if(budget-tell >= 1)
+         {
+            qi = IMIN(0, qi);
+            ec_enc_bit_logp(enc, -qi, 1);
+         }
+         else
+            qi = -1;
+         error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT);
+         badness += abs(qi0-qi);
+         q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT);
+
+         tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7);
+#ifdef FIXED_POINT
+         tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
+#endif
+         oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
+         prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
+      } while (++c < C);
+   }
+   return lfe ? 0 : badness;
+}
+
+void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
+      const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget,
+      opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes,
+      int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate, int lfe)
+{
+   int intra;
+   opus_val16 max_decay;
+   VARDECL(opus_val16, oldEBands_intra);
+   VARDECL(opus_val16, error_intra);
+   ec_enc enc_start_state;
+   opus_uint32 tell;
+   int badness1=0;
+   opus_int32 intra_bias;
+   opus_val32 new_distortion;
+   SAVE_STACK;
+
+   intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C);
+   intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512));
+   new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C);
+
+   tell = ec_tell(enc);
+   if (tell+3 > budget)
+      two_pass = intra = 0;
+
+   max_decay = QCONST16(16.f,DB_SHIFT);
+   if (end-start>10)
+   {
+#ifdef FIXED_POINT
+      max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3));
+#else
+      max_decay = MIN32(max_decay, .125f*nbAvailableBytes);
+#endif
+   }
+   if (lfe)
+      max_decay = QCONST16(3.f,DB_SHIFT);
+   enc_start_state = *enc;
+
+   ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16);
+   ALLOC(error_intra, C*m->nbEBands, opus_val16);
+   OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands);
+
+   if (two_pass || intra)
+   {
+      badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget,
+            tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe);
+   }
+
+   if (!intra)
+   {
+      unsigned char *intra_buf;
+      ec_enc enc_intra_state;
+      opus_int32 tell_intra;
+      opus_uint32 nstart_bytes;
+      opus_uint32 nintra_bytes;
+      opus_uint32 save_bytes;
+      int badness2;
+      VARDECL(unsigned char, intra_bits);
+
+      tell_intra = ec_tell_frac(enc);
+
+      enc_intra_state = *enc;
+
+      nstart_bytes = ec_range_bytes(&enc_start_state);
+      nintra_bytes = ec_range_bytes(&enc_intra_state);
+      intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes;
+      save_bytes = nintra_bytes-nstart_bytes;
+      if (save_bytes == 0)
+         save_bytes = ALLOC_NONE;
+      ALLOC(intra_bits, save_bytes, unsigned char);
+      /* Copy bits from intra bit-stream */
+      OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes);
+
+      *enc = enc_start_state;
+
+      badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget,
+            tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe);
+
+      if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra)))
+      {
+         *enc = enc_intra_state;
+         /* Copy intra bits to bit-stream */
+         OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes);
+         OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands);
+         OPUS_COPY(error, error_intra, C*m->nbEBands);
+         intra = 1;
+      }
+   } else {
+      OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands);
+      OPUS_COPY(error, error_intra, C*m->nbEBands);
+   }
+
+   if (intra)
+      *delayedIntra = new_distortion;
+   else
+      *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra),
+            new_distortion);
+
+   RESTORE_STACK;
+}
+
+void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C)
+{
+   int i, c;
+
+   /* Encode finer resolution */
+   for (i=start;i<end;i++)
+   {
+      opus_int16 frac = 1<<fine_quant[i];
+      if (fine_quant[i] <= 0)
+         continue;
+      c=0;
+      do {
+         int q2;
+         opus_val16 offset;
+#ifdef FIXED_POINT
+         /* Has to be without rounding */
+         q2 = (error[i+c*m->nbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]);
+#else
+         q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac);
+#endif
+         if (q2 > frac-1)
+            q2 = frac-1;
+         if (q2<0)
+            q2 = 0;
+         ec_enc_bits(enc, q2, fine_quant[i]);
+#ifdef FIXED_POINT
+         offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT));
+#else
+         offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f;
+#endif
+         oldEBands[i+c*m->nbEBands] += offset;
+         error[i+c*m->nbEBands] -= offset;
+         /*printf ("%f ", error[i] - offset);*/
+      } while (++c < C);
+   }
+}
+
+void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C)
+{
+   int i, prio, c;
+
+   /* Use up the remaining bits */
+   for (prio=0;prio<2;prio++)
+   {
+      for (i=start;i<end && bits_left>=C ;i++)
+      {
+         if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
+            continue;
+         c=0;
+         do {
+            int q2;
+            opus_val16 offset;
+            q2 = error[i+c*m->nbEBands]<0 ? 0 : 1;
+            ec_enc_bits(enc, q2, 1);
+#ifdef FIXED_POINT
+            offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1);
+#else
+            offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
+#endif
+            oldEBands[i+c*m->nbEBands] += offset;
+            bits_left--;
+         } while (++c < C);
+      }
+   }
+}
+
+void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM)
+{
+   const unsigned char *prob_model = e_prob_model[LM][intra];
+   int i, c;
+   opus_val32 prev[2] = {0, 0};
+   opus_val16 coef;
+   opus_val16 beta;
+   opus_int32 budget;
+   opus_int32 tell;
+
+   if (intra)
+   {
+      coef = 0;
+      beta = beta_intra;
+   } else {
+      beta = beta_coef[LM];
+      coef = pred_coef[LM];
+   }
+
+   budget = dec->storage*8;
+
+   /* Decode at a fixed coarse resolution */
+   for (i=start;i<end;i++)
+   {
+      c=0;
+      do {
+         int qi;
+         opus_val32 q;
+         opus_val32 tmp;
+         /* It would be better to express this invariant as a
+            test on C at function entry, but that isn't enough
+            to make the static analyzer happy. */
+         celt_assert(c<2);
+         tell = ec_tell(dec);
+         if(budget-tell>=15)
+         {
+            int pi;
+            pi = 2*IMIN(i,20);
+            qi = ec_laplace_decode(dec,
+                  prob_model[pi]<<7, prob_model[pi+1]<<6);
+         }
+         else if(budget-tell>=2)
+         {
+            qi = ec_dec_icdf(dec, small_energy_icdf, 2);
+            qi = (qi>>1)^-(qi&1);
+         }
+         else if(budget-tell>=1)
+         {
+            qi = -ec_dec_bit_logp(dec, 1);
+         }
+         else
+            qi = -1;
+         q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT);
+
+         oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
+         tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7);
+#ifdef FIXED_POINT
+         tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
+#endif
+         oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
+         prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
+      } while (++c < C);
+   }
+}
+
+void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C)
+{
+   int i, c;
+   /* Decode finer resolution */
+   for (i=start;i<end;i++)
+   {
+      if (fine_quant[i] <= 0)
+         continue;
+      c=0;
+      do {
+         int q2;
+         opus_val16 offset;
+         q2 = ec_dec_bits(dec, fine_quant[i]);
+#ifdef FIXED_POINT
+         offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT));
+#else
+         offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f;
+#endif
+         oldEBands[i+c*m->nbEBands] += offset;
+      } while (++c < C);
+   }
+}
+
+void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant,  int *fine_priority, int bits_left, ec_dec *dec, int C)
+{
+   int i, prio, c;
+
+   /* Use up the remaining bits */
+   for (prio=0;prio<2;prio++)
+   {
+      for (i=start;i<end && bits_left>=C ;i++)
+      {
+         if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
+            continue;
+         c=0;
+         do {
+            int q2;
+            opus_val16 offset;
+            q2 = ec_dec_bits(dec, 1);
+#ifdef FIXED_POINT
+            offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1);
+#else
+            offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
+#endif
+            oldEBands[i+c*m->nbEBands] += offset;
+            bits_left--;
+         } while (++c < C);
+      }
+   }
+}
+
+void amp2Log2(const CELTMode *m, int effEnd, int end,
+      celt_ener *bandE, opus_val16 *bandLogE, int C)
+{
+   int c, i;
+   c=0;
+   do {
+      for (i=0;i<effEnd;i++)
+         bandLogE[i+c*m->nbEBands] =
+               celt_log2(SHL32(bandE[i+c*m->nbEBands],2))
+               - SHL16((opus_val16)eMeans[i],6);
+      for (i=effEnd;i<end;i++)
+         bandLogE[c*m->nbEBands+i] = -QCONST16(14.f,DB_SHIFT);
+   } while (++c < C);
+}
diff --git a/third_party/opus/src/celt/quant_bands.h b/third_party/opus/src/celt/quant_bands.h
new file mode 100644
index 0000000..0490bca
--- /dev/null
+++ b/third_party/opus/src/celt/quant_bands.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef QUANT_BANDS
+#define QUANT_BANDS
+
+#include "arch.h"
+#include "modes.h"
+#include "entenc.h"
+#include "entdec.h"
+#include "mathops.h"
+
+#ifdef FIXED_POINT
+extern const signed char eMeans[25];
+#else
+extern const opus_val16 eMeans[25];
+#endif
+
+void amp2Log2(const CELTMode *m, int effEnd, int end,
+      celt_ener *bandE, opus_val16 *bandLogE, int C);
+
+void log2Amp(const CELTMode *m, int start, int end,
+      celt_ener *eBands, const opus_val16 *oldEBands, int C);
+
+void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
+      const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget,
+      opus_val16 *error, ec_enc *enc, int C, int LM,
+      int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra,
+      int two_pass, int loss_rate, int lfe);
+
+void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C);
+
+void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C);
+
+void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM);
+
+void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C);
+
+void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C);
+
+#endif /* QUANT_BANDS */
diff --git a/third_party/opus/src/celt/rate.c b/third_party/opus/src/celt/rate.c
new file mode 100644
index 0000000..7dfa5be
--- /dev/null
+++ b/third_party/opus/src/celt/rate.c
@@ -0,0 +1,639 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "modes.h"
+#include "cwrs.h"
+#include "arch.h"
+#include "os_support.h"
+
+#include "entcode.h"
+#include "rate.h"
+
+static const unsigned char LOG2_FRAC_TABLE[24]={
+   0,
+   8,13,
+  16,19,21,23,
+  24,26,27,28,29,30,31,32,
+  32,33,34,34,35,36,36,37,37
+};
+
+#ifdef CUSTOM_MODES
+
+/*Determines if V(N,K) fits in a 32-bit unsigned integer.
+  N and K are themselves limited to 15 bits.*/
+static int fits_in32(int _n, int _k)
+{
+   static const opus_int16 maxN[15] = {
+      32767, 32767, 32767, 1476, 283, 109,  60,  40,
+       29,  24,  20,  18,  16,  14,  13};
+   static const opus_int16 maxK[15] = {
+      32767, 32767, 32767, 32767, 1172, 238,  95,  53,
+       36,  27,  22,  18,  16,  15,  13};
+   if (_n>=14)
+   {
+      if (_k>=14)
+         return 0;
+      else
+         return _n <= maxN[_k];
+   } else {
+      return _k <= maxK[_n];
+   }
+}
+
+void compute_pulse_cache(CELTMode *m, int LM)
+{
+   int C;
+   int i;
+   int j;
+   int curr=0;
+   int nbEntries=0;
+   int entryN[100], entryK[100], entryI[100];
+   const opus_int16 *eBands = m->eBands;
+   PulseCache *cache = &m->cache;
+   opus_int16 *cindex;
+   unsigned char *bits;
+   unsigned char *cap;
+
+   cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2));
+   cache->index = cindex;
+
+   /* Scan for all unique band sizes */
+   for (i=0;i<=LM+1;i++)
+   {
+      for (j=0;j<m->nbEBands;j++)
+      {
+         int k;
+         int N = (eBands[j+1]-eBands[j])<<i>>1;
+         cindex[i*m->nbEBands+j] = -1;
+         /* Find other bands that have the same size */
+         for (k=0;k<=i;k++)
+         {
+            int n;
+            for (n=0;n<m->nbEBands && (k!=i || n<j);n++)
+            {
+               if (N == (eBands[n+1]-eBands[n])<<k>>1)
+               {
+                  cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n];
+                  break;
+               }
+            }
+         }
+         if (cache->index[i*m->nbEBands+j] == -1 && N!=0)
+         {
+            int K;
+            entryN[nbEntries] = N;
+            K = 0;
+            while (fits_in32(N,get_pulses(K+1)) && K<MAX_PSEUDO)
+               K++;
+            entryK[nbEntries] = K;
+            cindex[i*m->nbEBands+j] = curr;
+            entryI[nbEntries] = curr;
+
+            curr += K+1;
+            nbEntries++;
+         }
+      }
+   }
+   bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr);
+   cache->bits = bits;
+   cache->size = curr;
+   /* Compute the cache for all unique sizes */
+   for (i=0;i<nbEntries;i++)
+   {
+      unsigned char *ptr = bits+entryI[i];
+      opus_int16 tmp[CELT_MAX_PULSES+1];
+      get_required_bits(tmp, entryN[i], get_pulses(entryK[i]), BITRES);
+      for (j=1;j<=entryK[i];j++)
+         ptr[j] = tmp[get_pulses(j)]-1;
+      ptr[0] = entryK[i];
+   }
+
+   /* Compute the maximum rate for each band at which we'll reliably use as
+       many bits as we ask for. */
+   cache->caps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands);
+   for (i=0;i<=LM;i++)
+   {
+      for (C=1;C<=2;C++)
+      {
+         for (j=0;j<m->nbEBands;j++)
+         {
+            int N0;
+            int max_bits;
+            N0 = m->eBands[j+1]-m->eBands[j];
+            /* N=1 bands only have a sign bit and fine bits. */
+            if (N0<<i == 1)
+               max_bits = C*(1+MAX_FINE_BITS)<<BITRES;
+            else
+            {
+               const unsigned char *pcache;
+               opus_int32           num;
+               opus_int32           den;
+               int                  LM0;
+               int                  N;
+               int                  offset;
+               int                  ndof;
+               int                  qb;
+               int                  k;
+               LM0 = 0;
+               /* Even-sized bands bigger than N=2 can be split one more time.
+                  As of commit 44203907 all bands >1 are even, including custom modes.*/
+               if (N0 > 2)
+               {
+                  N0>>=1;
+                  LM0--;
+               }
+               /* N0=1 bands can't be split down to N<2. */
+               else if (N0 <= 1)
+               {
+                  LM0=IMIN(i,1);
+                  N0<<=LM0;
+               }
+               /* Compute the cost for the lowest-level PVQ of a fully split
+                   band. */
+               pcache = bits + cindex[(LM0+1)*m->nbEBands+j];
+               max_bits = pcache[pcache[0]]+1;
+               /* Add in the cost of coding regular splits. */
+               N = N0;
+               for(k=0;k<i-LM0;k++){
+                  max_bits <<= 1;
+                  /* Offset the number of qtheta bits by log2(N)/2
+                      + QTHETA_OFFSET compared to their "fair share" of
+                      total/N */
+                  offset = ((m->logN[j]+((LM0+k)<<BITRES))>>1)-QTHETA_OFFSET;
+                  /* The number of qtheta bits we'll allocate if the remainder
+                      is to be max_bits.
+                     The average measured cost for theta is 0.89701 times qb,
+                      approximated here as 459/512. */
+                  num=459*(opus_int32)((2*N-1)*offset+max_bits);
+                  den=((opus_int32)(2*N-1)<<9)-459;
+                  qb = IMIN((num+(den>>1))/den, 57);
+                  celt_assert(qb >= 0);
+                  max_bits += qb;
+                  N <<= 1;
+               }
+               /* Add in the cost of a stereo split, if necessary. */
+               if (C==2)
+               {
+                  max_bits <<= 1;
+                  offset = ((m->logN[j]+(i<<BITRES))>>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET);
+                  ndof = 2*N-1-(N==2);
+                  /* The average measured cost for theta with the step PDF is
+                      0.95164 times qb, approximated here as 487/512. */
+                  num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset);
+                  den = ((opus_int32)ndof<<9)-(N==2?512:487);
+                  qb = IMIN((num+(den>>1))/den, (N==2?64:61));
+                  celt_assert(qb >= 0);
+                  max_bits += qb;
+               }
+               /* Add the fine bits we'll use. */
+               /* Compensate for the extra DoF in stereo */
+               ndof = C*N + ((C==2 && N>2) ? 1 : 0);
+               /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET
+                   compared to their "fair share" of total/N */
+               offset = ((m->logN[j] + (i<<BITRES))>>1)-FINE_OFFSET;
+               /* N=2 is the only point that doesn't match the curve */
+               if (N==2)
+                  offset += 1<<BITRES>>2;
+               /* The number of fine bits we'll allocate if the remainder is
+                   to be max_bits. */
+               num = max_bits+ndof*offset;
+               den = (ndof-1)<<BITRES;
+               qb = IMIN((num+(den>>1))/den, MAX_FINE_BITS);
+               celt_assert(qb >= 0);
+               max_bits += C*qb<<BITRES;
+            }
+            max_bits = (4*max_bits/(C*((m->eBands[j+1]-m->eBands[j])<<i)))-64;
+            celt_assert(max_bits >= 0);
+            celt_assert(max_bits < 256);
+            *cap++ = (unsigned char)max_bits;
+         }
+      }
+   }
+}
+
+#endif /* CUSTOM_MODES */
+
+#define ALLOC_STEPS 6
+
+static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start,
+      const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance,
+      int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits,
+      int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
+{
+   opus_int32 psum;
+   int lo, hi;
+   int i, j;
+   int logM;
+   int stereo;
+   int codedBands=-1;
+   int alloc_floor;
+   opus_int32 left, percoeff;
+   int done;
+   opus_int32 balance;
+   SAVE_STACK;
+
+   alloc_floor = C<<BITRES;
+   stereo = C>1;
+
+   logM = LM<<BITRES;
+   lo = 0;
+   hi = 1<<ALLOC_STEPS;
+   for (i=0;i<ALLOC_STEPS;i++)
+   {
+      int mid = (lo+hi)>>1;
+      psum = 0;
+      done = 0;
+      for (j=end;j-->start;)
+      {
+         int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS);
+         if (tmp >= thresh[j] || done)
+         {
+            done = 1;
+            /* Don't allocate more than we can actually use */
+            psum += IMIN(tmp, cap[j]);
+         } else {
+            if (tmp >= alloc_floor)
+               psum += alloc_floor;
+         }
+      }
+      if (psum > total)
+         hi = mid;
+      else
+         lo = mid;
+   }
+   psum = 0;
+   /*printf ("interp bisection gave %d\n", lo);*/
+   done = 0;
+   for (j=end;j-->start;)
+   {
+      int tmp = bits1[j] + ((opus_int32)lo*bits2[j]>>ALLOC_STEPS);
+      if (tmp < thresh[j] && !done)
+      {
+         if (tmp >= alloc_floor)
+            tmp = alloc_floor;
+         else
+            tmp = 0;
+      } else
+         done = 1;
+      /* Don't allocate more than we can actually use */
+      tmp = IMIN(tmp, cap[j]);
+      bits[j] = tmp;
+      psum += tmp;
+   }
+
+   /* Decide which bands to skip, working backwards from the end. */
+   for (codedBands=end;;codedBands--)
+   {
+      int band_width;
+      int band_bits;
+      int rem;
+      j = codedBands-1;
+      /* Never skip the first band, nor a band that has been boosted by
+          dynalloc.
+         In the first case, we'd be coding a bit to signal we're going to waste
+          all the other bits.
+         In the second case, we'd be coding a bit to redistribute all the bits
+          we just signaled should be cocentrated in this band. */
+      if (j<=skip_start)
+      {
+         /* Give the bit we reserved to end skipping back. */
+         total += skip_rsv;
+         break;
+      }
+      /*Figure out how many left-over bits we would be adding to this band.
+        This can include bits we've stolen back from higher, skipped bands.*/
+      left = total-psum;
+      percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]);
+      left -= (m->eBands[codedBands]-m->eBands[start])*percoeff;
+      rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0);
+      band_width = m->eBands[codedBands]-m->eBands[j];
+      band_bits = (int)(bits[j] + percoeff*band_width + rem);
+      /*Only code a skip decision if we're above the threshold for this band.
+        Otherwise it is force-skipped.
+        This ensures that we have enough bits to code the skip flag.*/
+      if (band_bits >= IMAX(thresh[j], alloc_floor+(1<<BITRES)))
+      {
+         if (encode)
+         {
+            /*This if() block is the only part of the allocation function that
+               is not a mandatory part of the bitstream: any bands we choose to
+               skip here must be explicitly signaled.*/
+            /*Choose a threshold with some hysteresis to keep bands from
+               fluctuating in and out.*/
+#ifdef FUZZING
+            if ((rand()&0x1) == 0)
+#else
+            if (codedBands<=start+2 || (band_bits > ((j<prev?7:9)*band_width<<LM<<BITRES)>>4 && j<=signalBandwidth))
+#endif
+            {
+               ec_enc_bit_logp(ec, 1, 1);
+               break;
+            }
+            ec_enc_bit_logp(ec, 0, 1);
+         } else if (ec_dec_bit_logp(ec, 1)) {
+            break;
+         }
+         /*We used a bit to skip this band.*/
+         psum += 1<<BITRES;
+         band_bits -= 1<<BITRES;
+      }
+      /*Reclaim the bits originally allocated to this band.*/
+      psum -= bits[j]+intensity_rsv;
+      if (intensity_rsv > 0)
+         intensity_rsv = LOG2_FRAC_TABLE[j-start];
+      psum += intensity_rsv;
+      if (band_bits >= alloc_floor)
+      {
+         /*If we have enough for a fine energy bit per channel, use it.*/
+         psum += alloc_floor;
+         bits[j] = alloc_floor;
+      } else {
+         /*Otherwise this band gets nothing at all.*/
+         bits[j] = 0;
+      }
+   }
+
+   celt_assert(codedBands > start);
+   /* Code the intensity and dual stereo parameters. */
+   if (intensity_rsv > 0)
+   {
+      if (encode)
+      {
+         *intensity = IMIN(*intensity, codedBands);
+         ec_enc_uint(ec, *intensity-start, codedBands+1-start);
+      }
+      else
+         *intensity = start+ec_dec_uint(ec, codedBands+1-start);
+   }
+   else
+      *intensity = 0;
+   if (*intensity <= start)
+   {
+      total += dual_stereo_rsv;
+      dual_stereo_rsv = 0;
+   }
+   if (dual_stereo_rsv > 0)
+   {
+      if (encode)
+         ec_enc_bit_logp(ec, *dual_stereo, 1);
+      else
+         *dual_stereo = ec_dec_bit_logp(ec, 1);
+   }
+   else
+      *dual_stereo = 0;
+
+   /* Allocate the remaining bits */
+   left = total-psum;
+   percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]);
+   left -= (m->eBands[codedBands]-m->eBands[start])*percoeff;
+   for (j=start;j<codedBands;j++)
+      bits[j] += ((int)percoeff*(m->eBands[j+1]-m->eBands[j]));
+   for (j=start;j<codedBands;j++)
+   {
+      int tmp = (int)IMIN(left, m->eBands[j+1]-m->eBands[j]);
+      bits[j] += tmp;
+      left -= tmp;
+   }
+   /*for (j=0;j<end;j++)printf("%d ", bits[j]);printf("\n");*/
+
+   balance = 0;
+   for (j=start;j<codedBands;j++)
+   {
+      int N0, N, den;
+      int offset;
+      int NClogN;
+      opus_int32 excess, bit;
+
+      celt_assert(bits[j] >= 0);
+      N0 = m->eBands[j+1]-m->eBands[j];
+      N=N0<<LM;
+      bit = (opus_int32)bits[j]+balance;
+
+      if (N>1)
+      {
+         excess = MAX32(bit-cap[j],0);
+         bits[j] = bit-excess;
+
+         /* Compensate for the extra DoF in stereo */
+         den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0));
+
+         NClogN = den*(m->logN[j] + logM);
+
+         /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET
+            compared to their "fair share" of total/N */
+         offset = (NClogN>>1)-den*FINE_OFFSET;
+
+         /* N=2 is the only point that doesn't match the curve */
+         if (N==2)
+            offset += den<<BITRES>>2;
+
+         /* Changing the offset for allocating the second and third
+             fine energy bit */
+         if (bits[j] + offset < den*2<<BITRES)
+            offset += NClogN>>2;
+         else if (bits[j] + offset < den*3<<BITRES)
+            offset += NClogN>>3;
+
+         /* Divide with rounding */
+         ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1))));
+         ebits[j] = celt_udiv(ebits[j], den)>>BITRES;
+
+         /* Make sure not to bust */
+         if (C*ebits[j] > (bits[j]>>BITRES))
+            ebits[j] = bits[j] >> stereo >> BITRES;
+
+         /* More than that is useless because that's about as far as PVQ can go */
+         ebits[j] = IMIN(ebits[j], MAX_FINE_BITS);
+
+         /* If we rounded down or capped this band, make it a candidate for the
+             final fine energy pass */
+         fine_priority[j] = ebits[j]*(den<<BITRES) >= bits[j]+offset;
+
+         /* Remove the allocated fine bits; the rest are assigned to PVQ */
+         bits[j] -= C*ebits[j]<<BITRES;
+
+      } else {
+         /* For N=1, all bits go to fine energy except for a single sign bit */
+         excess = MAX32(0,bit-(C<<BITRES));
+         bits[j] = bit-excess;
+         ebits[j] = 0;
+         fine_priority[j] = 1;
+      }
+
+      /* Fine energy can't take advantage of the re-balancing in
+          quant_all_bands().
+         Instead, do the re-balancing here.*/
+      if(excess > 0)
+      {
+         int extra_fine;
+         int extra_bits;
+         extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]);
+         ebits[j] += extra_fine;
+         extra_bits = extra_fine*C<<BITRES;
+         fine_priority[j] = extra_bits >= excess-balance;
+         excess -= extra_bits;
+      }
+      balance = excess;
+
+      celt_assert(bits[j] >= 0);
+      celt_assert(ebits[j] >= 0);
+   }
+   /* Save any remaining bits over the cap for the rebalancing in
+       quant_all_bands(). */
+   *_balance = balance;
+
+   /* The skipped bands use all their bits for fine energy. */
+   for (;j<end;j++)
+   {
+      ebits[j] = bits[j] >> stereo >> BITRES;
+      celt_assert(C*ebits[j]<<BITRES == bits[j]);
+      bits[j] = 0;
+      fine_priority[j] = ebits[j]<1;
+   }
+   RESTORE_STACK;
+   return codedBands;
+}
+
+int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
+      opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
+{
+   int lo, hi, len, j;
+   int codedBands;
+   int skip_start;
+   int skip_rsv;
+   int intensity_rsv;
+   int dual_stereo_rsv;
+   VARDECL(int, bits1);
+   VARDECL(int, bits2);
+   VARDECL(int, thresh);
+   VARDECL(int, trim_offset);
+   SAVE_STACK;
+
+   total = IMAX(total, 0);
+   len = m->nbEBands;
+   skip_start = start;
+   /* Reserve a bit to signal the end of manually skipped bands. */
+   skip_rsv = total >= 1<<BITRES ? 1<<BITRES : 0;
+   total -= skip_rsv;
+   /* Reserve bits for the intensity and dual stereo parameters. */
+   intensity_rsv = dual_stereo_rsv = 0;
+   if (C==2)
+   {
+      intensity_rsv = LOG2_FRAC_TABLE[end-start];
+      if (intensity_rsv>total)
+         intensity_rsv = 0;
+      else
+      {
+         total -= intensity_rsv;
+         dual_stereo_rsv = total>=1<<BITRES ? 1<<BITRES : 0;
+         total -= dual_stereo_rsv;
+      }
+   }
+   ALLOC(bits1, len, int);
+   ALLOC(bits2, len, int);
+   ALLOC(thresh, len, int);
+   ALLOC(trim_offset, len, int);
+
+   for (j=start;j<end;j++)
+   {
+      /* Below this threshold, we're sure not to allocate any PVQ bits */
+      thresh[j] = IMAX((C)<<BITRES, (3*(m->eBands[j+1]-m->eBands[j])<<LM<<BITRES)>>4);
+      /* Tilt of the allocation curve */
+      trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1)
+            *(1<<(LM+BITRES))>>6;
+      /* Giving less resolution to single-coefficient bands because they get
+         more benefit from having one coarse value per coefficient*/
+      if ((m->eBands[j+1]-m->eBands[j])<<LM==1)
+         trim_offset[j] -= C<<BITRES;
+   }
+   lo = 1;
+   hi = m->nbAllocVectors - 1;
+   do
+   {
+      int done = 0;
+      int psum = 0;
+      int mid = (lo+hi) >> 1;
+      for (j=end;j-->start;)
+      {
+         int bitsj;
+         int N = m->eBands[j+1]-m->eBands[j];
+         bitsj = C*N*m->allocVectors[mid*len+j]<<LM>>2;
+         if (bitsj > 0)
+            bitsj = IMAX(0, bitsj + trim_offset[j]);
+         bitsj += offsets[j];
+         if (bitsj >= thresh[j] || done)
+         {
+            done = 1;
+            /* Don't allocate more than we can actually use */
+            psum += IMIN(bitsj, cap[j]);
+         } else {
+            if (bitsj >= C<<BITRES)
+               psum += C<<BITRES;
+         }
+      }
+      if (psum > total)
+         hi = mid - 1;
+      else
+         lo = mid + 1;
+      /*printf ("lo = %d, hi = %d\n", lo, hi);*/
+   }
+   while (lo <= hi);
+   hi = lo--;
+   /*printf ("interp between %d and %d\n", lo, hi);*/
+   for (j=start;j<end;j++)
+   {
+      int bits1j, bits2j;
+      int N = m->eBands[j+1]-m->eBands[j];
+      bits1j = C*N*m->allocVectors[lo*len+j]<<LM>>2;
+      bits2j = hi>=m->nbAllocVectors ?
+            cap[j] : C*N*m->allocVectors[hi*len+j]<<LM>>2;
+      if (bits1j > 0)
+         bits1j = IMAX(0, bits1j + trim_offset[j]);
+      if (bits2j > 0)
+         bits2j = IMAX(0, bits2j + trim_offset[j]);
+      if (lo > 0)
+         bits1j += offsets[j];
+      bits2j += offsets[j];
+      if (offsets[j]>0)
+         skip_start = j;
+      bits2j = IMAX(0,bits2j-bits1j);
+      bits1[j] = bits1j;
+      bits2[j] = bits2j;
+   }
+   codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap,
+         total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv,
+         pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth);
+   RESTORE_STACK;
+   return codedBands;
+}
+
diff --git a/third_party/opus/src/celt/rate.h b/third_party/opus/src/celt/rate.h
new file mode 100644
index 0000000..515f7687
--- /dev/null
+++ b/third_party/opus/src/celt/rate.h
@@ -0,0 +1,101 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef RATE_H
+#define RATE_H
+
+#define MAX_PSEUDO 40
+#define LOG_MAX_PSEUDO 6
+
+#define CELT_MAX_PULSES 128
+
+#define MAX_FINE_BITS 8
+
+#define FINE_OFFSET 21
+#define QTHETA_OFFSET 4
+#define QTHETA_OFFSET_TWOPHASE 16
+
+#include "cwrs.h"
+#include "modes.h"
+
+void compute_pulse_cache(CELTMode *m, int LM);
+
+static OPUS_INLINE int get_pulses(int i)
+{
+   return i<8 ? i : (8 + (i&7)) << ((i>>3)-1);
+}
+
+static OPUS_INLINE int bits2pulses(const CELTMode *m, int band, int LM, int bits)
+{
+   int i;
+   int lo, hi;
+   const unsigned char *cache;
+
+   LM++;
+   cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band];
+
+   lo = 0;
+   hi = cache[0];
+   bits--;
+   for (i=0;i<LOG_MAX_PSEUDO;i++)
+   {
+      int mid = (lo+hi+1)>>1;
+      /* OPT: Make sure this is implemented with a conditional move */
+      if ((int)cache[mid] >= bits)
+         hi = mid;
+      else
+         lo = mid;
+   }
+   if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits)
+      return lo;
+   else
+      return hi;
+}
+
+static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int pulses)
+{
+   const unsigned char *cache;
+
+   LM++;
+   cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band];
+   return pulses == 0 ? 0 : cache[pulses]+1;
+}
+
+/** Compute the pulse allocation, i.e. how many pulses will go in each
+  * band.
+ @param m mode
+ @param offsets Requested increase or decrease in the number of bits for
+                each band
+ @param total Number of bands
+ @param pulses Number of pulses per band (returned)
+ @return Total number of bits allocated
+*/
+int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero,
+      opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth);
+
+#endif
diff --git a/third_party/opus/src/celt/stack_alloc.h b/third_party/opus/src/celt/stack_alloc.h
new file mode 100644
index 0000000..2b51c8d
--- /dev/null
+++ b/third_party/opus/src/celt/stack_alloc.h
@@ -0,0 +1,184 @@
+/* Copyright (C) 2002-2003 Jean-Marc Valin
+   Copyright (C) 2007-2009 Xiph.Org Foundation */
+/**
+   @file stack_alloc.h
+   @brief Temporary memory allocation on stack
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef STACK_ALLOC_H
+#define STACK_ALLOC_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK))
+#error "Opus requires one of VAR_ARRAYS, USE_ALLOCA, or NONTHREADSAFE_PSEUDOSTACK be defined to select the temporary allocation mode."
+#endif
+
+#ifdef USE_ALLOCA
+# ifdef WIN32
+#  include <malloc.h>
+# else
+#  ifdef HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   include <stdlib.h>
+#  endif
+# endif
+#endif
+
+/**
+ * @def ALIGN(stack, size)
+ *
+ * Aligns the stack to a 'size' boundary
+ *
+ * @param stack Stack
+ * @param size  New size boundary
+ */
+
+/**
+ * @def PUSH(stack, size, type)
+ *
+ * Allocates 'size' elements of type 'type' on the stack
+ *
+ * @param stack Stack
+ * @param size  Number of elements
+ * @param type  Type of element
+ */
+
+/**
+ * @def VARDECL(var)
+ *
+ * Declare variable on stack
+ *
+ * @param var Variable to declare
+ */
+
+/**
+ * @def ALLOC(var, size, type)
+ *
+ * Allocate 'size' elements of 'type' on stack
+ *
+ * @param var  Name of variable to allocate
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+#if defined(VAR_ARRAYS)
+
+#define VARDECL(type, var)
+#define ALLOC(var, size, type) type var[size]
+#define SAVE_STACK
+#define RESTORE_STACK
+#define ALLOC_STACK
+/* C99 does not allow VLAs of size zero */
+#define ALLOC_NONE 1
+
+#elif defined(USE_ALLOCA)
+
+#define VARDECL(type, var) type *var
+
+# ifdef WIN32
+#  define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size)))
+# else
+#  define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size)))
+# endif
+
+#define SAVE_STACK
+#define RESTORE_STACK
+#define ALLOC_STACK
+#define ALLOC_NONE 0
+
+#else
+
+#ifdef CELT_C
+char *scratch_ptr=0;
+char *global_stack=0;
+#else
+extern char *global_stack;
+extern char *scratch_ptr;
+#endif /* CELT_C */
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+
+#ifdef CELT_C
+char *global_stack_top=0;
+#else
+extern char *global_stack_top;
+#endif /* CELT_C */
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char))))
+#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack))
+#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack;
+
+#else
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char))))
+#if 0 /* Set this to 1 to instrument pseudostack usage */
+#define RESTORE_STACK (printf("%ld %s:%d\n", global_stack-scratch_ptr, __FILE__, __LINE__),global_stack = _saved_stack)
+#else
+#define RESTORE_STACK (global_stack = _saved_stack)
+#endif
+#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? (scratch_ptr=opus_alloc_scratch(GLOBAL_STACK_SIZE)) : global_stack); _saved_stack = global_stack;
+
+#endif /* ENABLE_VALGRIND */
+
+#include "os_support.h"
+#define VARDECL(type, var) type *var
+#define ALLOC(var, size, type) var = PUSH(global_stack, size, type)
+#define SAVE_STACK char *_saved_stack = global_stack;
+#define ALLOC_NONE 0
+
+#endif /* VAR_ARRAYS */
+
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
+#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
+#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
+#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
+#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0)
+#define OPUS_FPRINTF fprintf
+
+#else
+
+static OPUS_INLINE int _opus_false(void) {return 0;}
+#define OPUS_CHECK_ARRAY(ptr, len) _opus_false()
+#define OPUS_CHECK_VALUE(value) _opus_false()
+#define OPUS_PRINT_INT(value) do{}while(0)
+#define OPUS_FPRINTF (void)
+
+#endif
+
+
+#endif /* STACK_ALLOC_H */
diff --git a/third_party/opus/src/celt/static_modes_fixed.h b/third_party/opus/src/celt/static_modes_fixed.h
new file mode 100644
index 0000000..8717d626
--- /dev/null
+++ b/third_party/opus/src/celt/static_modes_fixed.h
@@ -0,0 +1,892 @@
+/* The contents of this file was automatically generated by dump_modes.c
+   with arguments: 48000 960
+   It contains static definitions for some pre-defined modes. */
+#include "modes.h"
+#include "rate.h"
+
+#ifdef HAVE_ARM_NE10
+#define OVERRIDE_FFT 1
+#include "static_modes_fixed_arm_ne10.h"
+#endif
+
+#ifndef DEF_WINDOW120
+#define DEF_WINDOW120
+static const opus_val16 window120[120] = {
+2, 20, 55, 108, 178,
+266, 372, 494, 635, 792,
+966, 1157, 1365, 1590, 1831,
+2089, 2362, 2651, 2956, 3276,
+3611, 3961, 4325, 4703, 5094,
+5499, 5916, 6346, 6788, 7241,
+7705, 8179, 8663, 9156, 9657,
+10167, 10684, 11207, 11736, 12271,
+12810, 13353, 13899, 14447, 14997,
+15547, 16098, 16648, 17197, 17744,
+18287, 18827, 19363, 19893, 20418,
+20936, 21447, 21950, 22445, 22931,
+23407, 23874, 24330, 24774, 25208,
+25629, 26039, 26435, 26819, 27190,
+27548, 27893, 28224, 28541, 28845,
+29135, 29411, 29674, 29924, 30160,
+30384, 30594, 30792, 30977, 31151,
+31313, 31463, 31602, 31731, 31849,
+31958, 32057, 32148, 32229, 32303,
+32370, 32429, 32481, 32528, 32568,
+32604, 32634, 32661, 32683, 32701,
+32717, 32729, 32740, 32748, 32754,
+32758, 32762, 32764, 32766, 32767,
+32767, 32767, 32767, 32767, 32767,
+};
+#endif
+
+#ifndef DEF_LOGN400
+#define DEF_LOGN400
+static const opus_int16 logN400[21] = {
+0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, };
+#endif
+
+#ifndef DEF_PULSE_CACHE50
+#define DEF_PULSE_CACHE50
+static const opus_int16 cache_index50[105] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
+82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
+41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
+41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
+318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
+305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
+240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,
+};
+static const unsigned char cache_bits50[392] = {
+40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
+31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
+51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
+66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
+64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
+94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
+124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
+97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
+142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
+28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
+153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
+229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
+166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
+86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
+25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
+185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
+110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
+74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
+163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
+228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
+90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
+87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
+106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
+224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
+182, 234, };
+static const unsigned char cache_caps50[168] = {
+224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
+178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
+240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
+160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
+138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
+204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
+185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
+207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
+188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
+204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
+140, 66, 40, };
+#endif
+
+#ifndef FFT_TWIDDLES48000_960
+#define FFT_TWIDDLES48000_960
+static const kiss_twiddle_cpx fft_twiddles48000_960[480] = {
+{32767, 0}, {32766, -429},
+{32757, -858}, {32743, -1287},
+{32724, -1715}, {32698, -2143},
+{32667, -2570}, {32631, -2998},
+{32588, -3425}, {32541, -3851},
+{32488, -4277}, {32429, -4701},
+{32364, -5125}, {32295, -5548},
+{32219, -5971}, {32138, -6393},
+{32051, -6813}, {31960, -7231},
+{31863, -7650}, {31760, -8067},
+{31652, -8481}, {31539, -8895},
+{31419, -9306}, {31294, -9716},
+{31165, -10126}, {31030, -10532},
+{30889, -10937}, {30743, -11340},
+{30592, -11741}, {30436, -12141},
+{30274, -12540}, {30107, -12935},
+{29936, -13328}, {29758, -13718},
+{29577, -14107}, {29390, -14493},
+{29197, -14875}, {29000, -15257},
+{28797, -15635}, {28590, -16010},
+{28379, -16384}, {28162, -16753},
+{27940, -17119}, {27714, -17484},
+{27482, -17845}, {27246, -18205},
+{27006, -18560}, {26760, -18911},
+{26510, -19260}, {26257, -19606},
+{25997, -19947}, {25734, -20286},
+{25466, -20621}, {25194, -20952},
+{24918, -21281}, {24637, -21605},
+{24353, -21926}, {24063, -22242},
+{23770, -22555}, {23473, -22865},
+{23171, -23171}, {22866, -23472},
+{22557, -23769}, {22244, -24063},
+{21927, -24352}, {21606, -24636},
+{21282, -24917}, {20954, -25194},
+{20622, -25465}, {20288, -25733},
+{19949, -25997}, {19607, -26255},
+{19261, -26509}, {18914, -26760},
+{18561, -27004}, {18205, -27246},
+{17846, -27481}, {17485, -27713},
+{17122, -27940}, {16755, -28162},
+{16385, -28378}, {16012, -28590},
+{15636, -28797}, {15258, -28999},
+{14878, -29197}, {14494, -29389},
+{14108, -29576}, {13720, -29757},
+{13329, -29934}, {12937, -30107},
+{12540, -30274}, {12142, -30435},
+{11744, -30592}, {11342, -30743},
+{10939, -30889}, {10534, -31030},
+{10127, -31164}, {9718, -31294},
+{9307, -31418}, {8895, -31537},
+{8482, -31652}, {8067, -31759},
+{7650, -31862}, {7233, -31960},
+{6815, -32051}, {6393, -32138},
+{5973, -32219}, {5549, -32294},
+{5127, -32364}, {4703, -32429},
+{4278, -32487}, {3852, -32541},
+{3426, -32588}, {2999, -32630},
+{2572, -32667}, {2144, -32698},
+{1716, -32724}, {1287, -32742},
+{860, -32757}, {430, -32766},
+{0, -32767}, {-429, -32766},
+{-858, -32757}, {-1287, -32743},
+{-1715, -32724}, {-2143, -32698},
+{-2570, -32667}, {-2998, -32631},
+{-3425, -32588}, {-3851, -32541},
+{-4277, -32488}, {-4701, -32429},
+{-5125, -32364}, {-5548, -32295},
+{-5971, -32219}, {-6393, -32138},
+{-6813, -32051}, {-7231, -31960},
+{-7650, -31863}, {-8067, -31760},
+{-8481, -31652}, {-8895, -31539},
+{-9306, -31419}, {-9716, -31294},
+{-10126, -31165}, {-10532, -31030},
+{-10937, -30889}, {-11340, -30743},
+{-11741, -30592}, {-12141, -30436},
+{-12540, -30274}, {-12935, -30107},
+{-13328, -29936}, {-13718, -29758},
+{-14107, -29577}, {-14493, -29390},
+{-14875, -29197}, {-15257, -29000},
+{-15635, -28797}, {-16010, -28590},
+{-16384, -28379}, {-16753, -28162},
+{-17119, -27940}, {-17484, -27714},
+{-17845, -27482}, {-18205, -27246},
+{-18560, -27006}, {-18911, -26760},
+{-19260, -26510}, {-19606, -26257},
+{-19947, -25997}, {-20286, -25734},
+{-20621, -25466}, {-20952, -25194},
+{-21281, -24918}, {-21605, -24637},
+{-21926, -24353}, {-22242, -24063},
+{-22555, -23770}, {-22865, -23473},
+{-23171, -23171}, {-23472, -22866},
+{-23769, -22557}, {-24063, -22244},
+{-24352, -21927}, {-24636, -21606},
+{-24917, -21282}, {-25194, -20954},
+{-25465, -20622}, {-25733, -20288},
+{-25997, -19949}, {-26255, -19607},
+{-26509, -19261}, {-26760, -18914},
+{-27004, -18561}, {-27246, -18205},
+{-27481, -17846}, {-27713, -17485},
+{-27940, -17122}, {-28162, -16755},
+{-28378, -16385}, {-28590, -16012},
+{-28797, -15636}, {-28999, -15258},
+{-29197, -14878}, {-29389, -14494},
+{-29576, -14108}, {-29757, -13720},
+{-29934, -13329}, {-30107, -12937},
+{-30274, -12540}, {-30435, -12142},
+{-30592, -11744}, {-30743, -11342},
+{-30889, -10939}, {-31030, -10534},
+{-31164, -10127}, {-31294, -9718},
+{-31418, -9307}, {-31537, -8895},
+{-31652, -8482}, {-31759, -8067},
+{-31862, -7650}, {-31960, -7233},
+{-32051, -6815}, {-32138, -6393},
+{-32219, -5973}, {-32294, -5549},
+{-32364, -5127}, {-32429, -4703},
+{-32487, -4278}, {-32541, -3852},
+{-32588, -3426}, {-32630, -2999},
+{-32667, -2572}, {-32698, -2144},
+{-32724, -1716}, {-32742, -1287},
+{-32757, -860}, {-32766, -430},
+{-32767, 0}, {-32766, 429},
+{-32757, 858}, {-32743, 1287},
+{-32724, 1715}, {-32698, 2143},
+{-32667, 2570}, {-32631, 2998},
+{-32588, 3425}, {-32541, 3851},
+{-32488, 4277}, {-32429, 4701},
+{-32364, 5125}, {-32295, 5548},
+{-32219, 5971}, {-32138, 6393},
+{-32051, 6813}, {-31960, 7231},
+{-31863, 7650}, {-31760, 8067},
+{-31652, 8481}, {-31539, 8895},
+{-31419, 9306}, {-31294, 9716},
+{-31165, 10126}, {-31030, 10532},
+{-30889, 10937}, {-30743, 11340},
+{-30592, 11741}, {-30436, 12141},
+{-30274, 12540}, {-30107, 12935},
+{-29936, 13328}, {-29758, 13718},
+{-29577, 14107}, {-29390, 14493},
+{-29197, 14875}, {-29000, 15257},
+{-28797, 15635}, {-28590, 16010},
+{-28379, 16384}, {-28162, 16753},
+{-27940, 17119}, {-27714, 17484},
+{-27482, 17845}, {-27246, 18205},
+{-27006, 18560}, {-26760, 18911},
+{-26510, 19260}, {-26257, 19606},
+{-25997, 19947}, {-25734, 20286},
+{-25466, 20621}, {-25194, 20952},
+{-24918, 21281}, {-24637, 21605},
+{-24353, 21926}, {-24063, 22242},
+{-23770, 22555}, {-23473, 22865},
+{-23171, 23171}, {-22866, 23472},
+{-22557, 23769}, {-22244, 24063},
+{-21927, 24352}, {-21606, 24636},
+{-21282, 24917}, {-20954, 25194},
+{-20622, 25465}, {-20288, 25733},
+{-19949, 25997}, {-19607, 26255},
+{-19261, 26509}, {-18914, 26760},
+{-18561, 27004}, {-18205, 27246},
+{-17846, 27481}, {-17485, 27713},
+{-17122, 27940}, {-16755, 28162},
+{-16385, 28378}, {-16012, 28590},
+{-15636, 28797}, {-15258, 28999},
+{-14878, 29197}, {-14494, 29389},
+{-14108, 29576}, {-13720, 29757},
+{-13329, 29934}, {-12937, 30107},
+{-12540, 30274}, {-12142, 30435},
+{-11744, 30592}, {-11342, 30743},
+{-10939, 30889}, {-10534, 31030},
+{-10127, 31164}, {-9718, 31294},
+{-9307, 31418}, {-8895, 31537},
+{-8482, 31652}, {-8067, 31759},
+{-7650, 31862}, {-7233, 31960},
+{-6815, 32051}, {-6393, 32138},
+{-5973, 32219}, {-5549, 32294},
+{-5127, 32364}, {-4703, 32429},
+{-4278, 32487}, {-3852, 32541},
+{-3426, 32588}, {-2999, 32630},
+{-2572, 32667}, {-2144, 32698},
+{-1716, 32724}, {-1287, 32742},
+{-860, 32757}, {-430, 32766},
+{0, 32767}, {429, 32766},
+{858, 32757}, {1287, 32743},
+{1715, 32724}, {2143, 32698},
+{2570, 32667}, {2998, 32631},
+{3425, 32588}, {3851, 32541},
+{4277, 32488}, {4701, 32429},
+{5125, 32364}, {5548, 32295},
+{5971, 32219}, {6393, 32138},
+{6813, 32051}, {7231, 31960},
+{7650, 31863}, {8067, 31760},
+{8481, 31652}, {8895, 31539},
+{9306, 31419}, {9716, 31294},
+{10126, 31165}, {10532, 31030},
+{10937, 30889}, {11340, 30743},
+{11741, 30592}, {12141, 30436},
+{12540, 30274}, {12935, 30107},
+{13328, 29936}, {13718, 29758},
+{14107, 29577}, {14493, 29390},
+{14875, 29197}, {15257, 29000},
+{15635, 28797}, {16010, 28590},
+{16384, 28379}, {16753, 28162},
+{17119, 27940}, {17484, 27714},
+{17845, 27482}, {18205, 27246},
+{18560, 27006}, {18911, 26760},
+{19260, 26510}, {19606, 26257},
+{19947, 25997}, {20286, 25734},
+{20621, 25466}, {20952, 25194},
+{21281, 24918}, {21605, 24637},
+{21926, 24353}, {22242, 24063},
+{22555, 23770}, {22865, 23473},
+{23171, 23171}, {23472, 22866},
+{23769, 22557}, {24063, 22244},
+{24352, 21927}, {24636, 21606},
+{24917, 21282}, {25194, 20954},
+{25465, 20622}, {25733, 20288},
+{25997, 19949}, {26255, 19607},
+{26509, 19261}, {26760, 18914},
+{27004, 18561}, {27246, 18205},
+{27481, 17846}, {27713, 17485},
+{27940, 17122}, {28162, 16755},
+{28378, 16385}, {28590, 16012},
+{28797, 15636}, {28999, 15258},
+{29197, 14878}, {29389, 14494},
+{29576, 14108}, {29757, 13720},
+{29934, 13329}, {30107, 12937},
+{30274, 12540}, {30435, 12142},
+{30592, 11744}, {30743, 11342},
+{30889, 10939}, {31030, 10534},
+{31164, 10127}, {31294, 9718},
+{31418, 9307}, {31537, 8895},
+{31652, 8482}, {31759, 8067},
+{31862, 7650}, {31960, 7233},
+{32051, 6815}, {32138, 6393},
+{32219, 5973}, {32294, 5549},
+{32364, 5127}, {32429, 4703},
+{32487, 4278}, {32541, 3852},
+{32588, 3426}, {32630, 2999},
+{32667, 2572}, {32698, 2144},
+{32724, 1716}, {32742, 1287},
+{32757, 860}, {32766, 430},
+};
+#ifndef FFT_BITREV480
+#define FFT_BITREV480
+static const opus_int16 fft_bitrev480[480] = {
+0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448,
+8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456,
+16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464,
+24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472,
+4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452,
+12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460,
+20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468,
+28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476,
+1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449,
+9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457,
+17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465,
+25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473,
+5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453,
+13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461,
+21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469,
+29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477,
+2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450,
+10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458,
+18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466,
+26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474,
+6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454,
+14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462,
+22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470,
+30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478,
+3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451,
+11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459,
+19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467,
+27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475,
+7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455,
+15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463,
+23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471,
+31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479,
+};
+#endif
+
+#ifndef FFT_BITREV240
+#define FFT_BITREV240
+static const opus_int16 fft_bitrev240[240] = {
+0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224,
+4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228,
+8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232,
+12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236,
+1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225,
+5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229,
+9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233,
+13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237,
+2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226,
+6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230,
+10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234,
+14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238,
+3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227,
+7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231,
+11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235,
+15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239,
+};
+#endif
+
+#ifndef FFT_BITREV120
+#define FFT_BITREV120
+static const opus_int16 fft_bitrev120[120] = {
+0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112,
+4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116,
+1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113,
+5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117,
+2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114,
+6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118,
+3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115,
+7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119,
+};
+#endif
+
+#ifndef FFT_BITREV60
+#define FFT_BITREV60
+static const opus_int16 fft_bitrev60[60] = {
+0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56,
+1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57,
+2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58,
+3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59,
+};
+#endif
+
+#ifndef FFT_STATE48000_960_0
+#define FFT_STATE48000_960_0
+static const kiss_fft_state fft_state48000_960_0 = {
+480,    /* nfft */
+17476,    /* scale */
+8,      /* scale_shift */
+-1,     /* shift */
+{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, },    /* factors */
+fft_bitrev480,  /* bitrev */
+fft_twiddles48000_960,  /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_480,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_1
+#define FFT_STATE48000_960_1
+static const kiss_fft_state fft_state48000_960_1 = {
+240,    /* nfft */
+17476,    /* scale */
+7,      /* scale_shift */
+1,      /* shift */
+{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, },    /* factors */
+fft_bitrev240,  /* bitrev */
+fft_twiddles48000_960,  /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_240,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_2
+#define FFT_STATE48000_960_2
+static const kiss_fft_state fft_state48000_960_2 = {
+120,    /* nfft */
+17476,    /* scale */
+6,      /* scale_shift */
+2,      /* shift */
+{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, },    /* factors */
+fft_bitrev120,  /* bitrev */
+fft_twiddles48000_960,  /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_120,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_3
+#define FFT_STATE48000_960_3
+static const kiss_fft_state fft_state48000_960_3 = {
+60,     /* nfft */
+17476,    /* scale */
+5,      /* scale_shift */
+3,      /* shift */
+{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },    /* factors */
+fft_bitrev60,   /* bitrev */
+fft_twiddles48000_960,  /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_60,
+#else
+NULL,
+#endif
+};
+#endif
+
+#endif
+
+#ifndef MDCT_TWIDDLES960
+#define MDCT_TWIDDLES960
+static const opus_val16 mdct_twiddles960[1800] = {
+32767, 32767, 32767, 32766, 32765,
+32763, 32761, 32759, 32756, 32753,
+32750, 32746, 32742, 32738, 32733,
+32728, 32722, 32717, 32710, 32704,
+32697, 32690, 32682, 32674, 32666,
+32657, 32648, 32639, 32629, 32619,
+32609, 32598, 32587, 32576, 32564,
+32552, 32539, 32526, 32513, 32500,
+32486, 32472, 32457, 32442, 32427,
+32411, 32395, 32379, 32362, 32345,
+32328, 32310, 32292, 32274, 32255,
+32236, 32217, 32197, 32177, 32157,
+32136, 32115, 32093, 32071, 32049,
+32027, 32004, 31981, 31957, 31933,
+31909, 31884, 31859, 31834, 31809,
+31783, 31756, 31730, 31703, 31676,
+31648, 31620, 31592, 31563, 31534,
+31505, 31475, 31445, 31415, 31384,
+31353, 31322, 31290, 31258, 31226,
+31193, 31160, 31127, 31093, 31059,
+31025, 30990, 30955, 30920, 30884,
+30848, 30812, 30775, 30738, 30701,
+30663, 30625, 30587, 30548, 30509,
+30470, 30430, 30390, 30350, 30309,
+30269, 30227, 30186, 30144, 30102,
+30059, 30016, 29973, 29930, 29886,
+29842, 29797, 29752, 29707, 29662,
+29616, 29570, 29524, 29477, 29430,
+29383, 29335, 29287, 29239, 29190,
+29142, 29092, 29043, 28993, 28943,
+28892, 28842, 28791, 28739, 28688,
+28636, 28583, 28531, 28478, 28425,
+28371, 28317, 28263, 28209, 28154,
+28099, 28044, 27988, 27932, 27876,
+27820, 27763, 27706, 27648, 27591,
+27533, 27474, 27416, 27357, 27298,
+27238, 27178, 27118, 27058, 26997,
+26936, 26875, 26814, 26752, 26690,
+26628, 26565, 26502, 26439, 26375,
+26312, 26247, 26183, 26119, 26054,
+25988, 25923, 25857, 25791, 25725,
+25658, 25592, 25524, 25457, 25389,
+25322, 25253, 25185, 25116, 25047,
+24978, 24908, 24838, 24768, 24698,
+24627, 24557, 24485, 24414, 24342,
+24270, 24198, 24126, 24053, 23980,
+23907, 23834, 23760, 23686, 23612,
+23537, 23462, 23387, 23312, 23237,
+23161, 23085, 23009, 22932, 22856,
+22779, 22701, 22624, 22546, 22468,
+22390, 22312, 22233, 22154, 22075,
+21996, 21916, 21836, 21756, 21676,
+21595, 21515, 21434, 21352, 21271,
+21189, 21107, 21025, 20943, 20860,
+20777, 20694, 20611, 20528, 20444,
+20360, 20276, 20192, 20107, 20022,
+19937, 19852, 19767, 19681, 19595,
+19509, 19423, 19336, 19250, 19163,
+19076, 18988, 18901, 18813, 18725,
+18637, 18549, 18460, 18372, 18283,
+18194, 18104, 18015, 17925, 17835,
+17745, 17655, 17565, 17474, 17383,
+17292, 17201, 17110, 17018, 16927,
+16835, 16743, 16650, 16558, 16465,
+16372, 16279, 16186, 16093, 15999,
+15906, 15812, 15718, 15624, 15529,
+15435, 15340, 15245, 15150, 15055,
+14960, 14864, 14769, 14673, 14577,
+14481, 14385, 14288, 14192, 14095,
+13998, 13901, 13804, 13706, 13609,
+13511, 13414, 13316, 13218, 13119,
+13021, 12923, 12824, 12725, 12626,
+12527, 12428, 12329, 12230, 12130,
+12030, 11930, 11831, 11730, 11630,
+11530, 11430, 11329, 11228, 11128,
+11027, 10926, 10824, 10723, 10622,
+10520, 10419, 10317, 10215, 10113,
+10011, 9909, 9807, 9704, 9602,
+9499, 9397, 9294, 9191, 9088,
+8985, 8882, 8778, 8675, 8572,
+8468, 8364, 8261, 8157, 8053,
+7949, 7845, 7741, 7637, 7532,
+7428, 7323, 7219, 7114, 7009,
+6905, 6800, 6695, 6590, 6485,
+6380, 6274, 6169, 6064, 5958,
+5853, 5747, 5642, 5536, 5430,
+5325, 5219, 5113, 5007, 4901,
+4795, 4689, 4583, 4476, 4370,
+4264, 4157, 4051, 3945, 3838,
+3732, 3625, 3518, 3412, 3305,
+3198, 3092, 2985, 2878, 2771,
+2664, 2558, 2451, 2344, 2237,
+2130, 2023, 1916, 1809, 1702,
+1594, 1487, 1380, 1273, 1166,
+1059, 952, 844, 737, 630,
+523, 416, 308, 201, 94,
+-13, -121, -228, -335, -442,
+-550, -657, -764, -871, -978,
+-1086, -1193, -1300, -1407, -1514,
+-1621, -1728, -1835, -1942, -2049,
+-2157, -2263, -2370, -2477, -2584,
+-2691, -2798, -2905, -3012, -3118,
+-3225, -3332, -3439, -3545, -3652,
+-3758, -3865, -3971, -4078, -4184,
+-4290, -4397, -4503, -4609, -4715,
+-4821, -4927, -5033, -5139, -5245,
+-5351, -5457, -5562, -5668, -5774,
+-5879, -5985, -6090, -6195, -6301,
+-6406, -6511, -6616, -6721, -6826,
+-6931, -7036, -7140, -7245, -7349,
+-7454, -7558, -7663, -7767, -7871,
+-7975, -8079, -8183, -8287, -8390,
+-8494, -8597, -8701, -8804, -8907,
+-9011, -9114, -9217, -9319, -9422,
+-9525, -9627, -9730, -9832, -9934,
+-10037, -10139, -10241, -10342, -10444,
+-10546, -10647, -10748, -10850, -10951,
+-11052, -11153, -11253, -11354, -11455,
+-11555, -11655, -11756, -11856, -11955,
+-12055, -12155, -12254, -12354, -12453,
+-12552, -12651, -12750, -12849, -12947,
+-13046, -13144, -13242, -13340, -13438,
+-13536, -13633, -13731, -13828, -13925,
+-14022, -14119, -14216, -14312, -14409,
+-14505, -14601, -14697, -14793, -14888,
+-14984, -15079, -15174, -15269, -15364,
+-15459, -15553, -15647, -15741, -15835,
+-15929, -16023, -16116, -16210, -16303,
+-16396, -16488, -16581, -16673, -16766,
+-16858, -16949, -17041, -17133, -17224,
+-17315, -17406, -17497, -17587, -17678,
+-17768, -17858, -17948, -18037, -18127,
+-18216, -18305, -18394, -18483, -18571,
+-18659, -18747, -18835, -18923, -19010,
+-19098, -19185, -19271, -19358, -19444,
+-19531, -19617, -19702, -19788, -19873,
+-19959, -20043, -20128, -20213, -20297,
+-20381, -20465, -20549, -20632, -20715,
+-20798, -20881, -20963, -21046, -21128,
+-21210, -21291, -21373, -21454, -21535,
+-21616, -21696, -21776, -21856, -21936,
+-22016, -22095, -22174, -22253, -22331,
+-22410, -22488, -22566, -22643, -22721,
+-22798, -22875, -22951, -23028, -23104,
+-23180, -23256, -23331, -23406, -23481,
+-23556, -23630, -23704, -23778, -23852,
+-23925, -23998, -24071, -24144, -24216,
+-24288, -24360, -24432, -24503, -24574,
+-24645, -24716, -24786, -24856, -24926,
+-24995, -25064, -25133, -25202, -25270,
+-25339, -25406, -25474, -25541, -25608,
+-25675, -25742, -25808, -25874, -25939,
+-26005, -26070, -26135, -26199, -26264,
+-26327, -26391, -26455, -26518, -26581,
+-26643, -26705, -26767, -26829, -26891,
+-26952, -27013, -27073, -27133, -27193,
+-27253, -27312, -27372, -27430, -27489,
+-27547, -27605, -27663, -27720, -27777,
+-27834, -27890, -27946, -28002, -28058,
+-28113, -28168, -28223, -28277, -28331,
+-28385, -28438, -28491, -28544, -28596,
+-28649, -28701, -28752, -28803, -28854,
+-28905, -28955, -29006, -29055, -29105,
+-29154, -29203, -29251, -29299, -29347,
+-29395, -29442, -29489, -29535, -29582,
+-29628, -29673, -29719, -29764, -29808,
+-29853, -29897, -29941, -29984, -30027,
+-30070, -30112, -30154, -30196, -30238,
+-30279, -30320, -30360, -30400, -30440,
+-30480, -30519, -30558, -30596, -30635,
+-30672, -30710, -30747, -30784, -30821,
+-30857, -30893, -30929, -30964, -30999,
+-31033, -31068, -31102, -31135, -31168,
+-31201, -31234, -31266, -31298, -31330,
+-31361, -31392, -31422, -31453, -31483,
+-31512, -31541, -31570, -31599, -31627,
+-31655, -31682, -31710, -31737, -31763,
+-31789, -31815, -31841, -31866, -31891,
+-31915, -31939, -31963, -31986, -32010,
+-32032, -32055, -32077, -32099, -32120,
+-32141, -32162, -32182, -32202, -32222,
+-32241, -32260, -32279, -32297, -32315,
+-32333, -32350, -32367, -32383, -32399,
+-32415, -32431, -32446, -32461, -32475,
+-32489, -32503, -32517, -32530, -32542,
+-32555, -32567, -32579, -32590, -32601,
+-32612, -32622, -32632, -32641, -32651,
+-32659, -32668, -32676, -32684, -32692,
+-32699, -32706, -32712, -32718, -32724,
+-32729, -32734, -32739, -32743, -32747,
+-32751, -32754, -32757, -32760, -32762,
+-32764, -32765, -32767, -32767, -32767,
+32767, 32767, 32765, 32761, 32756,
+32750, 32742, 32732, 32722, 32710,
+32696, 32681, 32665, 32647, 32628,
+32608, 32586, 32562, 32538, 32512,
+32484, 32455, 32425, 32393, 32360,
+32326, 32290, 32253, 32214, 32174,
+32133, 32090, 32046, 32001, 31954,
+31906, 31856, 31805, 31753, 31700,
+31645, 31588, 31530, 31471, 31411,
+31349, 31286, 31222, 31156, 31089,
+31020, 30951, 30880, 30807, 30733,
+30658, 30582, 30504, 30425, 30345,
+30263, 30181, 30096, 30011, 29924,
+29836, 29747, 29656, 29564, 29471,
+29377, 29281, 29184, 29086, 28987,
+28886, 28784, 28681, 28577, 28471,
+28365, 28257, 28147, 28037, 27925,
+27812, 27698, 27583, 27467, 27349,
+27231, 27111, 26990, 26868, 26744,
+26620, 26494, 26367, 26239, 26110,
+25980, 25849, 25717, 25583, 25449,
+25313, 25176, 25038, 24900, 24760,
+24619, 24477, 24333, 24189, 24044,
+23898, 23751, 23602, 23453, 23303,
+23152, 22999, 22846, 22692, 22537,
+22380, 22223, 22065, 21906, 21746,
+21585, 21423, 21261, 21097, 20933,
+20767, 20601, 20434, 20265, 20096,
+19927, 19756, 19584, 19412, 19239,
+19065, 18890, 18714, 18538, 18361,
+18183, 18004, 17824, 17644, 17463,
+17281, 17098, 16915, 16731, 16546,
+16361, 16175, 15988, 15800, 15612,
+15423, 15234, 15043, 14852, 14661,
+14469, 14276, 14083, 13889, 13694,
+13499, 13303, 13107, 12910, 12713,
+12515, 12317, 12118, 11918, 11718,
+11517, 11316, 11115, 10913, 10710,
+10508, 10304, 10100, 9896, 9691,
+9486, 9281, 9075, 8869, 8662,
+8455, 8248, 8040, 7832, 7623,
+7415, 7206, 6996, 6787, 6577,
+6366, 6156, 5945, 5734, 5523,
+5311, 5100, 4888, 4675, 4463,
+4251, 4038, 3825, 3612, 3399,
+3185, 2972, 2758, 2544, 2330,
+2116, 1902, 1688, 1474, 1260,
+1045, 831, 617, 402, 188,
+-27, -241, -456, -670, -885,
+-1099, -1313, -1528, -1742, -1956,
+-2170, -2384, -2598, -2811, -3025,
+-3239, -3452, -3665, -3878, -4091,
+-4304, -4516, -4728, -4941, -5153,
+-5364, -5576, -5787, -5998, -6209,
+-6419, -6629, -6839, -7049, -7258,
+-7467, -7676, -7884, -8092, -8300,
+-8507, -8714, -8920, -9127, -9332,
+-9538, -9743, -9947, -10151, -10355,
+-10558, -10761, -10963, -11165, -11367,
+-11568, -11768, -11968, -12167, -12366,
+-12565, -12762, -12960, -13156, -13352,
+-13548, -13743, -13937, -14131, -14324,
+-14517, -14709, -14900, -15091, -15281,
+-15470, -15659, -15847, -16035, -16221,
+-16407, -16593, -16777, -16961, -17144,
+-17326, -17508, -17689, -17869, -18049,
+-18227, -18405, -18582, -18758, -18934,
+-19108, -19282, -19455, -19627, -19799,
+-19969, -20139, -20308, -20475, -20642,
+-20809, -20974, -21138, -21301, -21464,
+-21626, -21786, -21946, -22105, -22263,
+-22420, -22575, -22730, -22884, -23037,
+-23189, -23340, -23490, -23640, -23788,
+-23935, -24080, -24225, -24369, -24512,
+-24654, -24795, -24934, -25073, -25211,
+-25347, -25482, -25617, -25750, -25882,
+-26013, -26143, -26272, -26399, -26526,
+-26651, -26775, -26898, -27020, -27141,
+-27260, -27379, -27496, -27612, -27727,
+-27841, -27953, -28065, -28175, -28284,
+-28391, -28498, -28603, -28707, -28810,
+-28911, -29012, -29111, -29209, -29305,
+-29401, -29495, -29587, -29679, -29769,
+-29858, -29946, -30032, -30118, -30201,
+-30284, -30365, -30445, -30524, -30601,
+-30677, -30752, -30825, -30897, -30968,
+-31038, -31106, -31172, -31238, -31302,
+-31365, -31426, -31486, -31545, -31602,
+-31658, -31713, -31766, -31818, -31869,
+-31918, -31966, -32012, -32058, -32101,
+-32144, -32185, -32224, -32262, -32299,
+-32335, -32369, -32401, -32433, -32463,
+-32491, -32518, -32544, -32568, -32591,
+-32613, -32633, -32652, -32669, -32685,
+-32700, -32713, -32724, -32735, -32744,
+-32751, -32757, -32762, -32766, -32767,
+32767, 32764, 32755, 32741, 32720,
+32694, 32663, 32626, 32583, 32535,
+32481, 32421, 32356, 32286, 32209,
+32128, 32041, 31948, 31850, 31747,
+31638, 31523, 31403, 31278, 31148,
+31012, 30871, 30724, 30572, 30415,
+30253, 30086, 29913, 29736, 29553,
+29365, 29172, 28974, 28771, 28564,
+28351, 28134, 27911, 27684, 27452,
+27216, 26975, 26729, 26478, 26223,
+25964, 25700, 25432, 25159, 24882,
+24601, 24315, 24026, 23732, 23434,
+23133, 22827, 22517, 22204, 21886,
+21565, 21240, 20912, 20580, 20244,
+19905, 19563, 19217, 18868, 18516,
+18160, 17802, 17440, 17075, 16708,
+16338, 15964, 15588, 15210, 14829,
+14445, 14059, 13670, 13279, 12886,
+12490, 12093, 11693, 11291, 10888,
+10482, 10075, 9666, 9255, 8843,
+8429, 8014, 7597, 7180, 6760,
+6340, 5919, 5496, 5073, 4649,
+4224, 3798, 3372, 2945, 2517,
+2090, 1661, 1233, 804, 375,
+-54, -483, -911, -1340, -1768,
+-2197, -2624, -3052, -3479, -3905,
+-4330, -4755, -5179, -5602, -6024,
+-6445, -6865, -7284, -7702, -8118,
+-8533, -8946, -9358, -9768, -10177,
+-10584, -10989, -11392, -11793, -12192,
+-12589, -12984, -13377, -13767, -14155,
+-14541, -14924, -15305, -15683, -16058,
+-16430, -16800, -17167, -17531, -17892,
+-18249, -18604, -18956, -19304, -19649,
+-19990, -20329, -20663, -20994, -21322,
+-21646, -21966, -22282, -22595, -22904,
+-23208, -23509, -23806, -24099, -24387,
+-24672, -24952, -25228, -25499, -25766,
+-26029, -26288, -26541, -26791, -27035,
+-27275, -27511, -27741, -27967, -28188,
+-28405, -28616, -28823, -29024, -29221,
+-29412, -29599, -29780, -29957, -30128,
+-30294, -30455, -30611, -30761, -30906,
+-31046, -31181, -31310, -31434, -31552,
+-31665, -31773, -31875, -31972, -32063,
+-32149, -32229, -32304, -32373, -32437,
+-32495, -32547, -32594, -32635, -32671,
+-32701, -32726, -32745, -32758, -32766,
+32767, 32754, 32717, 32658, 32577,
+32473, 32348, 32200, 32029, 31837,
+31624, 31388, 31131, 30853, 30553,
+30232, 29891, 29530, 29148, 28746,
+28324, 27883, 27423, 26944, 26447,
+25931, 25398, 24847, 24279, 23695,
+23095, 22478, 21846, 21199, 20538,
+19863, 19174, 18472, 17757, 17030,
+16291, 15541, 14781, 14010, 13230,
+12441, 11643, 10837, 10024, 9204,
+8377, 7545, 6708, 5866, 5020,
+4171, 3319, 2464, 1608, 751,
+-107, -965, -1822, -2678, -3532,
+-4383, -5232, -6077, -6918, -7754,
+-8585, -9409, -10228, -11039, -11843,
+-12639, -13426, -14204, -14972, -15730,
+-16477, -17213, -17937, -18648, -19347,
+-20033, -20705, -21363, -22006, -22634,
+-23246, -23843, -24423, -24986, -25533,
+-26062, -26573, -27066, -27540, -27995,
+-28431, -28848, -29245, -29622, -29979,
+-30315, -30630, -30924, -31197, -31449,
+-31679, -31887, -32074, -32239, -32381,
+-32501, -32600, -32675, -32729, -32759,
+};
+#endif
+
+static const CELTMode mode48000_960_120 = {
+48000,  /* Fs */
+120,    /* overlap */
+21,     /* nbEBands */
+21,     /* effEBands */
+{27853, 0, 4096, 8192, },       /* preemph */
+eband5ms,       /* eBands */
+3,      /* maxLM */
+8,      /* nbShortMdcts */
+120,    /* shortMdctSize */
+11,     /* nbAllocVectors */
+band_allocation,        /* allocVectors */
+logN400,        /* logN */
+window120,      /* window */
+{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960},    /* mdct */
+{392, cache_index50, cache_bits50, cache_caps50},       /* cache */
+};
+
+/* List of all the available modes */
+#define TOTAL_MODES 1
+static const CELTMode * const static_mode_list[TOTAL_MODES] = {
+&mode48000_960_120,
+};
diff --git a/third_party/opus/src/celt/static_modes_fixed_arm_ne10.h b/third_party/opus/src/celt/static_modes_fixed_arm_ne10.h
new file mode 100644
index 0000000..b8ef0ce
--- /dev/null
+++ b/third_party/opus/src/celt/static_modes_fixed_arm_ne10.h
@@ -0,0 +1,388 @@
+/* The contents of this file was automatically generated by
+ * dump_mode_arm_ne10.c with arguments: 48000 960
+ * It contains static definitions for some pre-defined modes. */
+#include <NE10_init.h>
+
+#ifndef NE10_FFT_PARAMS48000_960
+#define NE10_FFT_PARAMS48000_960
+static const ne10_int32_t ne10_factors_480[64] = {
+4, 40, 4, 30, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, };
+static const ne10_int32_t ne10_factors_240[64] = {
+3, 20, 4, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, };
+static const ne10_int32_t ne10_factors_120[64] = {
+3, 10, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, };
+static const ne10_int32_t ne10_factors_60[64] = {
+2, 5, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, };
+static const ne10_fft_cpx_int32_t ne10_twiddles_480[480] = {
+{0,0}, {2147483647,0}, {2147483647,0},
+{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394},
+{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496},
+{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096},
+{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152},
+{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313},
+{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424},
+{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496},
+{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268},
+{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785},
+{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172},
+{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682},
+{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313},
+{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450},
+{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067},
+{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277},
+{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424},
+{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771},
+{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994},
+{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593},
+{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968},
+{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851},
+{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394},
+{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959},
+{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516},
+{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955},
+{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330},
+{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738},
+{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141},
+{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240},
+{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960},
+{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282},
+{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339},
+{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564},
+{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839},
+{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918},
+{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188},
+{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252},
+{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059},
+{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542},
+{2147483647,0}, {2147299667,-28109693}, {2146747758,-56214570},
+{2145828015,-84309815}, {2144540595,-112390613}, {2142885719,-140452154},
+{2140863671,-168489630}, {2138474797,-196498235}, {2135719506,-224473172},
+{2132598271,-252409646}, {2129111626,-280302871}, {2125260168,-308148068},
+{2121044558,-335940465}, {2116465518,-363675300}, {2111523833,-391347822},
+{2106220349,-418953288}, {2100555974,-446486968}, {2094531681,-473944146},
+{2088148500,-501320115}, {2081407525,-528610186}, {2074309912,-555809682},
+{2066856885,-582913912}, {2059049696,-609918325}, {2050889698,-636818231},
+{2042378310,-663608960}, {2033516972,-690285983}, {2024307180,-716844791},
+{2014750533,-743280770}, {2004848691,-769589332}, {1994603329,-795766029},
+{1984016179,-821806435}, {1973089077,-847706028}, {1961823921,-873460313},
+{1950222618,-899064934}, {1938287127,-924515564}, {1926019520,-949807783},
+{1913421927,-974937199}, {1900496481,-999899565}, {1887245364,-1024690661},
+{1873670877,-1049306180}, {1859775377,-1073741851}, {1845561215,-1097993541},
+{1831030826,-1122057097}, {1816186632,-1145928502}, {1801031311,-1169603450},
+{1785567394,-1193077993}, {1769797456,-1216348214}, {1753724345,-1239409914},
+{1737350743,-1262259248}, {1720679456,-1284892300}, {1703713340,-1307305194},
+{1686455222,-1329494189}, {1668908218,-1351455280}, {1651075255,-1373184807},
+{1632959307,-1394679144}, {1614563642,-1415934412}, {1595891331,-1436947067},
+{1576945572,-1457713510}, {1557729613,-1478230181}, {1538246655,-1498493658},
+{1518500216,-1518500282}, {1498493590,-1538246721}, {1478230113,-1557729677},
+{1457713441,-1576945636}, {1436946998,-1595891394}, {1415934341,-1614563704},
+{1394679073,-1632959368}, {1373184735,-1651075315}, {1351455207,-1668908277},
+{1329494115,-1686455280}, {1307305120,-1703713397}, {1284892225,-1720679512},
+{1262259172,-1737350799}, {1239409837,-1753724400}, {1216348136,-1769797510},
+{1193077915,-1785567446}, {1169603371,-1801031362}, {1145928423,-1816186682},
+{1122057017,-1831030875}, {1097993571,-1845561197}, {1073741769,-1859775424},
+{1049305987,-1873670985}, {1024690635,-1887245378}, {999899482,-1900496524},
+{974937230,-1913421912}, {949807699,-1926019561}, {924515422,-1938287195},
+{899064965,-1950222603}, {873460227,-1961823959}, {847705824,-1973089164},
+{821806407,-1984016190}, {795765941,-1994603364}, {769589125,-2004848771},
+{743280682,-2014750566}, {716844642,-2024307233}, {690286016,-2033516961},
+{663608871,-2042378339}, {636818019,-2050889764}, {609918296,-2059049705},
+{582913822,-2066856911}, {555809715,-2074309903}, {528610126,-2081407540},
+{501319962,-2088148536}, {473944148,-2094531680}, {446486876,-2100555994},
+{418953102,-2106220386}, {391347792,-2111523838}, {363675176,-2116465540},
+{335940246,-2121044593}, {308148006,-2125260177}, {280302715,-2129111646},
+{252409648,-2132598271}, {224473078,-2135719516}, {196498046,-2138474814},
+{168489600,-2140863674}, {140452029,-2142885728}, {112390647,-2144540593},
+{84309753,-2145828017}, {56214412,-2146747762}, {28109695,-2147299667},
+{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613},
+{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871},
+{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968},
+{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325},
+{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332},
+{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564},
+{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851},
+{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214},
+{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280},
+{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181},
+{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394},
+{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397},
+{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362},
+{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378},
+{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959},
+{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233},
+{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903},
+{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838},
+{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516},
+{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762},
+{-94,-2147483647}, {-56214600,-2146747757}, {-112390835,-2144540584},
+{-168489787,-2140863659}, {-224473265,-2135719496}, {-280302901,-2129111622},
+{-335940431,-2121044564}, {-391347977,-2111523804}, {-446487060,-2100555955},
+{-501320144,-2088148493}, {-555809896,-2074309855}, {-609918476,-2059049651},
+{-663609049,-2042378281}, {-716844819,-2024307170}, {-769589300,-2004848703},
+{-821806581,-1984016118}, {-873460398,-1961823883}, {-924515591,-1938287114},
+{-974937397,-1913421827}, {-1024690575,-1887245411}, {-1073741932,-1859775330},
+{-1122057395,-1831030643}, {-1169603421,-1801031330}, {-1216348291,-1769797403},
+{-1262259116,-1737350839}, {-1307305268,-1703713283}, {-1351455453,-1668908078},
+{-1394679021,-1632959413}, {-1436947137,-1595891268}, {-1478230435,-1557729372},
+{-1518500258,-1518500240}, {-1557729742,-1478230045}, {-1595891628,-1436946738},
+{-1632959429,-1394679001}, {-1668908417,-1351455035}, {-1703713298,-1307305248},
+{-1737350854,-1262259096}, {-1769797708,-1216347848}, {-1801031344,-1169603400},
+{-1831030924,-1122056937}, {-1859775343,-1073741910}, {-1887245423,-1024690552},
+{-1913422071,-974936918}, {-1938287125,-924515568}, {-1961823997,-873460141},
+{-1984016324,-821806084}, {-2004848713,-769589276}, {-2024307264,-716844553},
+{-2042378447,-663608538}, {-2059049731,-609918206}, {-2074309994,-555809377},
+{-2088148499,-501320119}, {-2100556013,-446486785}, {-2111523902,-391347448},
+{-2121044568,-335940406}, {-2129111659,-280302621}, {-2135719499,-224473240},
+{-2140863681,-168489506}, {-2144540612,-112390298}, {-2146747758,-56214574},
+{2147483647,0}, {2145828015,-84309815}, {2140863671,-168489630},
+{2132598271,-252409646}, {2121044558,-335940465}, {2106220349,-418953288},
+{2088148500,-501320115}, {2066856885,-582913912}, {2042378310,-663608960},
+{2014750533,-743280770}, {1984016179,-821806435}, {1950222618,-899064934},
+{1913421927,-974937199}, {1873670877,-1049306180}, {1831030826,-1122057097},
+{1785567394,-1193077993}, {1737350743,-1262259248}, {1686455222,-1329494189},
+{1632959307,-1394679144}, {1576945572,-1457713510}, {1518500216,-1518500282},
+{1457713441,-1576945636}, {1394679073,-1632959368}, {1329494115,-1686455280},
+{1262259172,-1737350799}, {1193077915,-1785567446}, {1122057017,-1831030875},
+{1049305987,-1873670985}, {974937230,-1913421912}, {899064965,-1950222603},
+{821806407,-1984016190}, {743280682,-2014750566}, {663608871,-2042378339},
+{582913822,-2066856911}, {501319962,-2088148536}, {418953102,-2106220386},
+{335940246,-2121044593}, {252409648,-2132598271}, {168489600,-2140863674},
+{84309753,-2145828017}, {-94,-2147483647}, {-84309940,-2145828010},
+{-168489787,-2140863659}, {-252409834,-2132598249}, {-335940431,-2121044564},
+{-418953286,-2106220349}, {-501320144,-2088148493}, {-582914003,-2066856860},
+{-663609049,-2042378281}, {-743280858,-2014750501}, {-821806581,-1984016118},
+{-899065136,-1950222525}, {-974937397,-1913421827}, {-1049306374,-1873670768},
+{-1122057395,-1831030643}, {-1193078284,-1785567199}, {-1262259116,-1737350839},
+{-1329494061,-1686455323}, {-1394679021,-1632959413}, {-1457713485,-1576945595},
+{-1518500258,-1518500240}, {-1576945613,-1457713466}, {-1632959429,-1394679001},
+{-1686455338,-1329494041}, {-1737350854,-1262259096}, {-1785567498,-1193077837},
+{-1831030924,-1122056937}, {-1873671031,-1049305905}, {-1913422071,-974936918},
+{-1950222750,-899064648}, {-1984016324,-821806084}, {-2014750687,-743280354},
+{-2042378447,-663608538}, {-2066856867,-582913978}, {-2088148499,-501320119},
+{-2106220354,-418953261}, {-2121044568,-335940406}, {-2132598282,-252409555},
+{-2140863681,-168489506}, {-2145828021,-84309659}, {-2147483647,188},
+{-2145828006,84310034}, {-2140863651,168489881}, {-2132598237,252409928},
+{-2121044509,335940777}, {-2106220281,418953629}, {-2088148411,501320484},
+{-2066856765,582914339}, {-2042378331,663608895}, {-2014750557,743280706},
+{-1984016181,821806431}, {-1950222593,899064989}, {-1913421900,974937252},
+{-1873670848,1049306232}, {-1831030728,1122057257}, {-1785567289,1193078149},
+{-1737350633,1262259400}, {-1686455106,1329494336}, {-1632959185,1394679287},
+{-1576945358,1457713742}, {-1518499993,1518500506}, {-1457713209,1576945850},
+{-1394678735,1632959656}, {-1329493766,1686455555}, {-1262258813,1737351059},
+{-1193077546,1785567692}, {-1122056638,1831031107}, {-1049305599,1873671202},
+{-974936606,1913422229}, {-899064330,1950222896}, {-821805761,1984016458},
+{-743280025,2014750808}, {-663609179,2042378239}, {-582914134,2066856823},
+{-501320277,2088148461}, {-418953420,2106220322}, {-335940566,2121044542},
+{-252409716,2132598263}, {-168489668,2140863668}, {-84309821,2145828015},
+};
+static const ne10_fft_cpx_int32_t ne10_twiddles_240[240] = {
+{0,0}, {2147483647,0}, {2147483647,0},
+{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394},
+{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496},
+{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096},
+{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152},
+{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968},
+{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851},
+{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394},
+{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959},
+{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516},
+{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313},
+{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424},
+{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496},
+{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268},
+{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785},
+{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248},
+{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647},
+{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096},
+{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895},
+{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239},
+{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613},
+{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871},
+{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968},
+{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325},
+{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332},
+{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564},
+{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851},
+{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214},
+{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280},
+{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181},
+{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394},
+{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397},
+{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362},
+{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378},
+{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959},
+{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233},
+{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903},
+{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838},
+{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516},
+{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762},
+{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172},
+{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682},
+{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313},
+{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450},
+{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067},
+{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277},
+{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424},
+{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771},
+{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994},
+{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593},
+{-94,-2147483647}, {-112390835,-2144540584}, {-224473265,-2135719496},
+{-335940431,-2121044564}, {-446487060,-2100555955}, {-555809896,-2074309855},
+{-663609049,-2042378281}, {-769589300,-2004848703}, {-873460398,-1961823883},
+{-974937397,-1913421827}, {-1073741932,-1859775330}, {-1169603421,-1801031330},
+{-1262259116,-1737350839}, {-1351455453,-1668908078}, {-1436947137,-1595891268},
+{-1518500258,-1518500240}, {-1595891628,-1436946738}, {-1668908417,-1351455035},
+{-1737350854,-1262259096}, {-1801031344,-1169603400}, {-1859775343,-1073741910},
+{-1913422071,-974936918}, {-1961823997,-873460141}, {-2004848713,-769589276},
+{-2042378447,-663608538}, {-2074309994,-555809377}, {-2100556013,-446486785},
+{-2121044568,-335940406}, {-2135719499,-224473240}, {-2144540612,-112390298},
+{2147483647,0}, {2140863671,-168489630}, {2121044558,-335940465},
+{2088148500,-501320115}, {2042378310,-663608960}, {1984016179,-821806435},
+{1913421927,-974937199}, {1831030826,-1122057097}, {1737350743,-1262259248},
+{1632959307,-1394679144}, {1518500216,-1518500282}, {1394679073,-1632959368},
+{1262259172,-1737350799}, {1122057017,-1831030875}, {974937230,-1913421912},
+{821806407,-1984016190}, {663608871,-2042378339}, {501319962,-2088148536},
+{335940246,-2121044593}, {168489600,-2140863674}, {-94,-2147483647},
+{-168489787,-2140863659}, {-335940431,-2121044564}, {-501320144,-2088148493},
+{-663609049,-2042378281}, {-821806581,-1984016118}, {-974937397,-1913421827},
+{-1122057395,-1831030643}, {-1262259116,-1737350839}, {-1394679021,-1632959413},
+{-1518500258,-1518500240}, {-1632959429,-1394679001}, {-1737350854,-1262259096},
+{-1831030924,-1122056937}, {-1913422071,-974936918}, {-1984016324,-821806084},
+{-2042378447,-663608538}, {-2088148499,-501320119}, {-2121044568,-335940406},
+{-2140863681,-168489506}, {-2147483647,188}, {-2140863651,168489881},
+{-2121044509,335940777}, {-2088148411,501320484}, {-2042378331,663608895},
+{-1984016181,821806431}, {-1913421900,974937252}, {-1831030728,1122057257},
+{-1737350633,1262259400}, {-1632959185,1394679287}, {-1518499993,1518500506},
+{-1394678735,1632959656}, {-1262258813,1737351059}, {-1122056638,1831031107},
+{-974936606,1913422229}, {-821805761,1984016458}, {-663609179,2042378239},
+{-501320277,2088148461}, {-335940566,2121044542}, {-168489668,2140863668},
+};
+static const ne10_fft_cpx_int32_t ne10_twiddles_120[120] = {
+{0,0}, {2147483647,0}, {2147483647,0},
+{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394},
+{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496},
+{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096},
+{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152},
+{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313},
+{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424},
+{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496},
+{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268},
+{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785},
+{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172},
+{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682},
+{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313},
+{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450},
+{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067},
+{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277},
+{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424},
+{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771},
+{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994},
+{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593},
+{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968},
+{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851},
+{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394},
+{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959},
+{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516},
+{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955},
+{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330},
+{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738},
+{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141},
+{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240},
+{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960},
+{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282},
+{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339},
+{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564},
+{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839},
+{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918},
+{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188},
+{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252},
+{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059},
+{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542},
+};
+static const ne10_fft_cpx_int32_t ne10_twiddles_60[60] = {
+{0,0}, {2147483647,0}, {2147483647,0},
+{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394},
+{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496},
+{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096},
+{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152},
+{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968},
+{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851},
+{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394},
+{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959},
+{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516},
+{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313},
+{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424},
+{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496},
+{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268},
+{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785},
+{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248},
+{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647},
+{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096},
+{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895},
+{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239},
+};
+static const ne10_fft_state_int32_t ne10_fft_state_int32_t_480 = {
+120,
+(ne10_int32_t *)ne10_factors_480,
+(ne10_fft_cpx_int32_t *)ne10_twiddles_480,
+NULL,
+(ne10_fft_cpx_int32_t *)&ne10_twiddles_480[120],
+};
+static const arch_fft_state cfg_arch_480 = {
+1,
+(void *)&ne10_fft_state_int32_t_480,
+};
+
+static const ne10_fft_state_int32_t ne10_fft_state_int32_t_240 = {
+60,
+(ne10_int32_t *)ne10_factors_240,
+(ne10_fft_cpx_int32_t *)ne10_twiddles_240,
+NULL,
+(ne10_fft_cpx_int32_t *)&ne10_twiddles_240[60],
+};
+static const arch_fft_state cfg_arch_240 = {
+1,
+(void *)&ne10_fft_state_int32_t_240,
+};
+
+static const ne10_fft_state_int32_t ne10_fft_state_int32_t_120 = {
+30,
+(ne10_int32_t *)ne10_factors_120,
+(ne10_fft_cpx_int32_t *)ne10_twiddles_120,
+NULL,
+(ne10_fft_cpx_int32_t *)&ne10_twiddles_120[30],
+};
+static const arch_fft_state cfg_arch_120 = {
+1,
+(void *)&ne10_fft_state_int32_t_120,
+};
+
+static const ne10_fft_state_int32_t ne10_fft_state_int32_t_60 = {
+15,
+(ne10_int32_t *)ne10_factors_60,
+(ne10_fft_cpx_int32_t *)ne10_twiddles_60,
+NULL,
+(ne10_fft_cpx_int32_t *)&ne10_twiddles_60[15],
+};
+static const arch_fft_state cfg_arch_60 = {
+1,
+(void *)&ne10_fft_state_int32_t_60,
+};
+
+#endif  /* end NE10_FFT_PARAMS48000_960 */
diff --git a/third_party/opus/src/celt/static_modes_float.h b/third_party/opus/src/celt/static_modes_float.h
new file mode 100644
index 0000000..e102a38
--- /dev/null
+++ b/third_party/opus/src/celt/static_modes_float.h
@@ -0,0 +1,888 @@
+/* The contents of this file was automatically generated by dump_modes.c
+   with arguments: 48000 960
+   It contains static definitions for some pre-defined modes. */
+#include "modes.h"
+#include "rate.h"
+
+#ifdef HAVE_ARM_NE10
+#define OVERRIDE_FFT 1
+#include "static_modes_float_arm_ne10.h"
+#endif
+
+#ifndef DEF_WINDOW120
+#define DEF_WINDOW120
+static const opus_val16 window120[120] = {
+6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f,
+0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f,
+0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f,
+0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f,
+0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f,
+0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f,
+0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f,
+0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f,
+0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f,
+0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f,
+0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f,
+0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f,
+0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f,
+0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f,
+0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f,
+0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f,
+0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f,
+0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f,
+0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f,
+0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f,
+0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f,
+0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f,
+0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f,
+0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f,
+};
+#endif
+
+#ifndef DEF_LOGN400
+#define DEF_LOGN400
+static const opus_int16 logN400[21] = {
+0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, };
+#endif
+
+#ifndef DEF_PULSE_CACHE50
+#define DEF_PULSE_CACHE50
+static const opus_int16 cache_index50[105] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
+82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
+41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
+41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
+318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
+305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
+240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,
+};
+static const unsigned char cache_bits50[392] = {
+40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
+31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
+51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
+66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
+64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
+94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
+124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
+97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
+142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
+28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
+153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
+229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
+166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
+86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
+25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
+185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
+110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
+74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
+163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
+228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
+90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
+87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
+106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
+224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
+182, 234, };
+static const unsigned char cache_caps50[168] = {
+224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
+178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
+240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
+160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
+138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
+204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
+185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
+207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
+188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
+204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
+140, 66, 40, };
+#endif
+
+#ifndef FFT_TWIDDLES48000_960
+#define FFT_TWIDDLES48000_960
+static const kiss_twiddle_cpx fft_twiddles48000_960[480] = {
+{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f},
+{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f},
+{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f},
+{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f},
+{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f},
+{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f},
+{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f},
+{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f},
+{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f},
+{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f},
+{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f},
+{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f},
+{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f},
+{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f},
+{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f},
+{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f},
+{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f},
+{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f},
+{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f},
+{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f},
+{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f},
+{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f},
+{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f},
+{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f},
+{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f},
+{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f},
+{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f},
+{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f},
+{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f},
+{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f},
+{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f},
+{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f},
+{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f},
+{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f},
+{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f},
+{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f},
+{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f},
+{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f},
+{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f},
+{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f},
+{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f},
+{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f},
+{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f},
+{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f},
+{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f},
+{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f},
+{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f},
+{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f},
+{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f},
+{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f},
+{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f},
+{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f},
+{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f},
+{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f},
+{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f},
+{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f},
+{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f},
+{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f},
+{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f},
+{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f},
+{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f},
+{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f},
+{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f},
+{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f},
+{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f},
+{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f},
+{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f},
+{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f},
+{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f},
+{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f},
+{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f},
+{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f},
+{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f},
+{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f},
+{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f},
+{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f},
+{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f},
+{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f},
+{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f},
+{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f},
+{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f},
+{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f},
+{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f},
+{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f},
+{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f},
+{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f},
+{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f},
+{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f},
+{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f},
+{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f},
+{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f},
+{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f},
+{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f},
+{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f},
+{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f},
+{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f},
+{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f},
+{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f},
+{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f},
+{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f},
+{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f},
+{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f},
+{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f},
+{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f},
+{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f},
+{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f},
+{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f},
+{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f},
+{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f},
+{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f},
+{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f},
+{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f},
+{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f},
+{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f},
+{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f},
+{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f},
+{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f},
+{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f},
+{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f},
+{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f},
+{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f},
+{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f},
+{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f},
+{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f},
+{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f},
+{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f},
+{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f},
+{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f},
+{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f},
+{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f},
+{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f},
+{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f},
+{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f},
+{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f},
+{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f},
+{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f},
+{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f},
+{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f},
+{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f},
+{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f},
+{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f},
+{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f},
+{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f},
+{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f},
+{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f},
+{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f},
+{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f},
+{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f},
+{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f},
+{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f},
+{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f},
+{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f},
+{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f},
+{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f},
+{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f},
+{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f},
+{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f},
+{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f},
+{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f},
+{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f},
+{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f},
+{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f},
+{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f},
+{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f},
+{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f},
+{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f},
+{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f},
+{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f},
+{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f},
+{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f},
+{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f},
+{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f},
+{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f},
+{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f},
+{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f},
+{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f},
+{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f},
+{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f},
+{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f},
+{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f},
+{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f},
+{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f},
+{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f},
+{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f},
+{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f},
+{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f},
+{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f},
+{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f},
+{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f},
+{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f},
+{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f},
+{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f},
+{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f},
+{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f},
+{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f},
+{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f},
+{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f},
+{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f},
+{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f},
+{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f},
+{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f},
+{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f},
+{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f},
+{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f},
+{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f},
+{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f},
+{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f},
+{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f},
+{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f},
+{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f},
+{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f},
+{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f},
+{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f},
+{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f},
+{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f},
+{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f},
+{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f},
+{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f},
+{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f},
+{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f},
+{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f},
+{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f},
+{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f},
+{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f},
+{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f},
+{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f},
+{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f},
+{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f},
+{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f},
+{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f},
+{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f},
+{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f},
+{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f},
+{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f},
+{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f},
+{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f},
+{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f},
+{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f},
+{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f},
+{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f},
+};
+#ifndef FFT_BITREV480
+#define FFT_BITREV480
+static const opus_int16 fft_bitrev480[480] = {
+0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448,
+8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456,
+16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464,
+24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472,
+4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452,
+12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460,
+20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468,
+28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476,
+1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449,
+9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457,
+17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465,
+25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473,
+5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453,
+13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461,
+21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469,
+29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477,
+2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450,
+10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458,
+18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466,
+26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474,
+6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454,
+14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462,
+22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470,
+30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478,
+3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451,
+11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459,
+19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467,
+27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475,
+7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455,
+15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463,
+23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471,
+31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479,
+};
+#endif
+
+#ifndef FFT_BITREV240
+#define FFT_BITREV240
+static const opus_int16 fft_bitrev240[240] = {
+0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224,
+4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228,
+8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232,
+12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236,
+1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225,
+5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229,
+9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233,
+13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237,
+2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226,
+6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230,
+10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234,
+14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238,
+3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227,
+7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231,
+11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235,
+15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239,
+};
+#endif
+
+#ifndef FFT_BITREV120
+#define FFT_BITREV120
+static const opus_int16 fft_bitrev120[120] = {
+0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112,
+4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116,
+1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113,
+5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117,
+2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114,
+6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118,
+3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115,
+7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119,
+};
+#endif
+
+#ifndef FFT_BITREV60
+#define FFT_BITREV60
+static const opus_int16 fft_bitrev60[60] = {
+0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56,
+1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57,
+2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58,
+3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59,
+};
+#endif
+
+#ifndef FFT_STATE48000_960_0
+#define FFT_STATE48000_960_0
+static const kiss_fft_state fft_state48000_960_0 = {
+480,    /* nfft */
+0.002083333f,   /* scale */
+-1,     /* shift */
+{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, },   /* factors */
+fft_bitrev480,  /* bitrev */
+fft_twiddles48000_960,  /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_480,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_1
+#define FFT_STATE48000_960_1
+static const kiss_fft_state fft_state48000_960_1 = {
+240,    /* nfft */
+0.004166667f,   /* scale */
+1,      /* shift */
+{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, },    /* factors */
+fft_bitrev240,  /* bitrev */
+fft_twiddles48000_960,  /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_240,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_2
+#define FFT_STATE48000_960_2
+static const kiss_fft_state fft_state48000_960_2 = {
+120,    /* nfft */
+0.008333333f,   /* scale */
+2,      /* shift */
+{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, },    /* factors */
+fft_bitrev120,  /* bitrev */
+fft_twiddles48000_960,  /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_120,
+#else
+NULL,
+#endif
+};
+#endif
+
+#ifndef FFT_STATE48000_960_3
+#define FFT_STATE48000_960_3
+static const kiss_fft_state fft_state48000_960_3 = {
+60,     /* nfft */
+0.016666667f,   /* scale */
+3,      /* shift */
+{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },    /* factors */
+fft_bitrev60,   /* bitrev */
+fft_twiddles48000_960,  /* bitrev */
+#ifdef OVERRIDE_FFT
+(arch_fft_state *)&cfg_arch_60,
+#else
+NULL,
+#endif
+};
+#endif
+
+#endif
+
+#ifndef MDCT_TWIDDLES960
+#define MDCT_TWIDDLES960
+static const opus_val16 mdct_twiddles960[1800] = {
+0.99999994f, 0.99999321f, 0.99997580f, 0.99994773f, 0.99990886f,
+0.99985933f, 0.99979913f, 0.99972820f, 0.99964654f, 0.99955416f,
+0.99945110f, 0.99933738f, 0.99921292f, 0.99907774f, 0.99893188f,
+0.99877530f, 0.99860805f, 0.99843007f, 0.99824142f, 0.99804211f,
+0.99783206f, 0.99761140f, 0.99737996f, 0.99713790f, 0.99688518f,
+0.99662173f, 0.99634761f, 0.99606287f, 0.99576741f, 0.99546129f,
+0.99514455f, 0.99481714f, 0.99447906f, 0.99413031f, 0.99377096f,
+0.99340093f, 0.99302030f, 0.99262899f, 0.99222708f, 0.99181455f,
+0.99139136f, 0.99095762f, 0.99051321f, 0.99005818f, 0.98959261f,
+0.98911643f, 0.98862964f, 0.98813224f, 0.98762429f, 0.98710573f,
+0.98657662f, 0.98603696f, 0.98548669f, 0.98492593f, 0.98435456f,
+0.98377270f, 0.98318028f, 0.98257732f, 0.98196387f, 0.98133987f,
+0.98070538f, 0.98006040f, 0.97940493f, 0.97873890f, 0.97806245f,
+0.97737551f, 0.97667813f, 0.97597027f, 0.97525197f, 0.97452319f,
+0.97378403f, 0.97303438f, 0.97227436f, 0.97150391f, 0.97072303f,
+0.96993178f, 0.96913016f, 0.96831810f, 0.96749574f, 0.96666300f,
+0.96581990f, 0.96496642f, 0.96410263f, 0.96322852f, 0.96234411f,
+0.96144938f, 0.96054435f, 0.95962906f, 0.95870346f, 0.95776761f,
+0.95682150f, 0.95586514f, 0.95489854f, 0.95392174f, 0.95293468f,
+0.95193744f, 0.95093000f, 0.94991243f, 0.94888461f, 0.94784665f,
+0.94679856f, 0.94574034f, 0.94467193f, 0.94359344f, 0.94250488f,
+0.94140619f, 0.94029742f, 0.93917859f, 0.93804967f, 0.93691075f,
+0.93576175f, 0.93460274f, 0.93343377f, 0.93225473f, 0.93106574f,
+0.92986679f, 0.92865789f, 0.92743903f, 0.92621022f, 0.92497152f,
+0.92372292f, 0.92246443f, 0.92119598f, 0.91991776f, 0.91862965f,
+0.91733170f, 0.91602397f, 0.91470635f, 0.91337901f, 0.91204184f,
+0.91069490f, 0.90933824f, 0.90797186f, 0.90659571f, 0.90520984f,
+0.90381432f, 0.90240908f, 0.90099424f, 0.89956969f, 0.89813554f,
+0.89669174f, 0.89523834f, 0.89377540f, 0.89230281f, 0.89082074f,
+0.88932908f, 0.88782793f, 0.88631725f, 0.88479710f, 0.88326746f,
+0.88172835f, 0.88017982f, 0.87862182f, 0.87705445f, 0.87547767f,
+0.87389153f, 0.87229604f, 0.87069118f, 0.86907703f, 0.86745358f,
+0.86582077f, 0.86417878f, 0.86252749f, 0.86086690f, 0.85919720f,
+0.85751826f, 0.85583007f, 0.85413277f, 0.85242635f, 0.85071075f,
+0.84898609f, 0.84725231f, 0.84550947f, 0.84375757f, 0.84199661f,
+0.84022665f, 0.83844769f, 0.83665979f, 0.83486289f, 0.83305705f,
+0.83124226f, 0.82941860f, 0.82758605f, 0.82574469f, 0.82389444f,
+0.82203537f, 0.82016748f, 0.81829083f, 0.81640542f, 0.81451124f,
+0.81260836f, 0.81069672f, 0.80877650f, 0.80684757f, 0.80490994f,
+0.80296379f, 0.80100900f, 0.79904562f, 0.79707366f, 0.79509324f,
+0.79310423f, 0.79110676f, 0.78910083f, 0.78708643f, 0.78506362f,
+0.78303236f, 0.78099275f, 0.77894479f, 0.77688843f, 0.77482378f,
+0.77275085f, 0.77066964f, 0.76858020f, 0.76648247f, 0.76437658f,
+0.76226246f, 0.76014024f, 0.75800985f, 0.75587130f, 0.75372469f,
+0.75157005f, 0.74940729f, 0.74723655f, 0.74505776f, 0.74287105f,
+0.74067634f, 0.73847371f, 0.73626316f, 0.73404479f, 0.73181850f,
+0.72958434f, 0.72734243f, 0.72509271f, 0.72283524f, 0.72057003f,
+0.71829706f, 0.71601641f, 0.71372813f, 0.71143216f, 0.70912862f,
+0.70681745f, 0.70449871f, 0.70217246f, 0.69983864f, 0.69749737f,
+0.69514859f, 0.69279242f, 0.69042879f, 0.68805778f, 0.68567938f,
+0.68329364f, 0.68090063f, 0.67850029f, 0.67609268f, 0.67367786f,
+0.67125577f, 0.66882652f, 0.66639012f, 0.66394657f, 0.66149592f,
+0.65903819f, 0.65657341f, 0.65410155f, 0.65162271f, 0.64913690f,
+0.64664418f, 0.64414448f, 0.64163786f, 0.63912445f, 0.63660413f,
+0.63407701f, 0.63154310f, 0.62900239f, 0.62645501f, 0.62390089f,
+0.62134010f, 0.61877263f, 0.61619854f, 0.61361790f, 0.61103064f,
+0.60843682f, 0.60583651f, 0.60322970f, 0.60061646f, 0.59799677f,
+0.59537065f, 0.59273821f, 0.59009939f, 0.58745426f, 0.58480281f,
+0.58214509f, 0.57948118f, 0.57681108f, 0.57413477f, 0.57145232f,
+0.56876373f, 0.56606907f, 0.56336832f, 0.56066155f, 0.55794877f,
+0.55523002f, 0.55250537f, 0.54977477f, 0.54703826f, 0.54429591f,
+0.54154772f, 0.53879374f, 0.53603399f, 0.53326851f, 0.53049731f,
+0.52772039f, 0.52493787f, 0.52214974f, 0.51935595f, 0.51655668f,
+0.51375180f, 0.51094145f, 0.50812566f, 0.50530440f, 0.50247771f,
+0.49964568f, 0.49680826f, 0.49396557f, 0.49111754f, 0.48826426f,
+0.48540577f, 0.48254207f, 0.47967321f, 0.47679919f, 0.47392011f,
+0.47103590f, 0.46814668f, 0.46525243f, 0.46235323f, 0.45944905f,
+0.45653993f, 0.45362595f, 0.45070711f, 0.44778344f, 0.44485497f,
+0.44192174f, 0.43898380f, 0.43604112f, 0.43309379f, 0.43014181f,
+0.42718524f, 0.42422408f, 0.42125839f, 0.41828820f, 0.41531351f,
+0.41233435f, 0.40935081f, 0.40636289f, 0.40337059f, 0.40037400f,
+0.39737311f, 0.39436796f, 0.39135858f, 0.38834500f, 0.38532731f,
+0.38230544f, 0.37927949f, 0.37624949f, 0.37321547f, 0.37017745f,
+0.36713544f, 0.36408952f, 0.36103970f, 0.35798600f, 0.35492846f,
+0.35186714f, 0.34880206f, 0.34573323f, 0.34266070f, 0.33958447f,
+0.33650464f, 0.33342120f, 0.33033419f, 0.32724363f, 0.32414958f,
+0.32105204f, 0.31795108f, 0.31484672f, 0.31173897f, 0.30862790f,
+0.30551350f, 0.30239585f, 0.29927495f, 0.29615086f, 0.29302359f,
+0.28989318f, 0.28675964f, 0.28362307f, 0.28048345f, 0.27734083f,
+0.27419522f, 0.27104670f, 0.26789525f, 0.26474094f, 0.26158381f,
+0.25842386f, 0.25526115f, 0.25209570f, 0.24892756f, 0.24575676f,
+0.24258332f, 0.23940729f, 0.23622867f, 0.23304754f, 0.22986393f,
+0.22667783f, 0.22348931f, 0.22029841f, 0.21710514f, 0.21390954f,
+0.21071166f, 0.20751151f, 0.20430915f, 0.20110460f, 0.19789790f,
+0.19468907f, 0.19147816f, 0.18826519f, 0.18505022f, 0.18183327f,
+0.17861435f, 0.17539354f, 0.17217083f, 0.16894630f, 0.16571994f,
+0.16249183f, 0.15926196f, 0.15603039f, 0.15279715f, 0.14956227f,
+0.14632578f, 0.14308774f, 0.13984816f, 0.13660708f, 0.13336454f,
+0.13012058f, 0.12687522f, 0.12362850f, 0.12038045f, 0.11713112f,
+0.11388054f, 0.11062872f, 0.10737573f, 0.10412160f, 0.10086634f,
+0.097609997f, 0.094352618f, 0.091094226f, 0.087834857f, 0.084574550f,
+0.081313334f, 0.078051247f, 0.074788325f, 0.071524605f, 0.068260118f,
+0.064994894f, 0.061728980f, 0.058462404f, 0.055195201f, 0.051927410f,
+0.048659060f, 0.045390189f, 0.042120833f, 0.038851023f, 0.035580799f,
+0.032310195f, 0.029039243f, 0.025767982f, 0.022496443f, 0.019224664f,
+0.015952680f, 0.012680525f, 0.0094082337f, 0.0061358409f, 0.0028633832f,
+-0.00040910527f, -0.0036815894f, -0.0069540343f, -0.010226404f, -0.013498665f,
+-0.016770782f, -0.020042717f, -0.023314439f, -0.026585912f, -0.029857099f,
+-0.033127967f, -0.036398482f, -0.039668605f, -0.042938303f, -0.046207540f,
+-0.049476285f, -0.052744497f, -0.056012146f, -0.059279196f, -0.062545612f,
+-0.065811358f, -0.069076397f, -0.072340697f, -0.075604223f, -0.078866936f,
+-0.082128808f, -0.085389800f, -0.088649876f, -0.091909006f, -0.095167145f,
+-0.098424271f, -0.10168034f, -0.10493532f, -0.10818918f, -0.11144188f,
+-0.11469338f, -0.11794366f, -0.12119267f, -0.12444039f, -0.12768677f,
+-0.13093179f, -0.13417540f, -0.13741758f, -0.14065829f, -0.14389749f,
+-0.14713514f, -0.15037122f, -0.15360570f, -0.15683852f, -0.16006967f,
+-0.16329910f, -0.16652679f, -0.16975269f, -0.17297678f, -0.17619900f,
+-0.17941935f, -0.18263777f, -0.18585424f, -0.18906870f, -0.19228116f,
+-0.19549155f, -0.19869985f, -0.20190603f, -0.20511003f, -0.20831184f,
+-0.21151142f, -0.21470875f, -0.21790376f, -0.22109644f, -0.22428675f,
+-0.22747467f, -0.23066014f, -0.23384315f, -0.23702365f, -0.24020162f,
+-0.24337701f, -0.24654980f, -0.24971995f, -0.25288740f, -0.25605217f,
+-0.25921419f, -0.26237345f, -0.26552987f, -0.26868346f, -0.27183419f,
+-0.27498198f, -0.27812684f, -0.28126872f, -0.28440759f, -0.28754342f,
+-0.29067615f, -0.29380578f, -0.29693225f, -0.30005556f, -0.30317566f,
+-0.30629250f, -0.30940607f, -0.31251630f, -0.31562322f, -0.31872672f,
+-0.32182685f, -0.32492352f, -0.32801670f, -0.33110636f, -0.33419248f,
+-0.33727503f, -0.34035397f, -0.34342924f, -0.34650084f, -0.34956875f,
+-0.35263291f, -0.35569328f, -0.35874987f, -0.36180258f, -0.36485144f,
+-0.36789638f, -0.37093741f, -0.37397444f, -0.37700745f, -0.38003644f,
+-0.38306138f, -0.38608220f, -0.38909888f, -0.39211139f, -0.39511973f,
+-0.39812380f, -0.40112361f, -0.40411916f, -0.40711036f, -0.41009718f,
+-0.41307965f, -0.41605768f, -0.41903123f, -0.42200032f, -0.42496487f,
+-0.42792490f, -0.43088034f, -0.43383113f, -0.43677729f, -0.43971881f,
+-0.44265559f, -0.44558764f, -0.44851488f, -0.45143735f, -0.45435500f,
+-0.45726776f, -0.46017563f, -0.46307856f, -0.46597654f, -0.46886954f,
+-0.47175750f, -0.47464043f, -0.47751826f, -0.48039100f, -0.48325855f,
+-0.48612097f, -0.48897815f, -0.49183011f, -0.49467680f, -0.49751821f,
+-0.50035429f, -0.50318497f, -0.50601029f, -0.50883019f, -0.51164466f,
+-0.51445359f, -0.51725709f, -0.52005500f, -0.52284735f, -0.52563411f,
+-0.52841520f, -0.53119069f, -0.53396046f, -0.53672451f, -0.53948283f,
+-0.54223537f, -0.54498214f, -0.54772300f, -0.55045801f, -0.55318713f,
+-0.55591035f, -0.55862761f, -0.56133890f, -0.56404412f, -0.56674337f,
+-0.56943649f, -0.57212353f, -0.57480448f, -0.57747924f, -0.58014780f,
+-0.58281022f, -0.58546633f, -0.58811617f, -0.59075975f, -0.59339696f,
+-0.59602785f, -0.59865236f, -0.60127044f, -0.60388207f, -0.60648727f,
+-0.60908598f, -0.61167812f, -0.61426371f, -0.61684275f, -0.61941516f,
+-0.62198097f, -0.62454009f, -0.62709254f, -0.62963831f, -0.63217729f,
+-0.63470948f, -0.63723493f, -0.63975352f, -0.64226526f, -0.64477009f,
+-0.64726806f, -0.64975911f, -0.65224314f, -0.65472025f, -0.65719032f,
+-0.65965337f, -0.66210932f, -0.66455823f, -0.66700000f, -0.66943461f,
+-0.67186207f, -0.67428231f, -0.67669535f, -0.67910111f, -0.68149966f,
+-0.68389088f, -0.68627477f, -0.68865126f, -0.69102043f, -0.69338220f,
+-0.69573659f, -0.69808346f, -0.70042288f, -0.70275480f, -0.70507920f,
+-0.70739603f, -0.70970529f, -0.71200693f, -0.71430099f, -0.71658736f,
+-0.71886611f, -0.72113711f, -0.72340041f, -0.72565591f, -0.72790372f,
+-0.73014367f, -0.73237586f, -0.73460019f, -0.73681659f, -0.73902518f,
+-0.74122584f, -0.74341851f, -0.74560326f, -0.74778003f, -0.74994880f,
+-0.75210953f, -0.75426215f, -0.75640678f, -0.75854325f, -0.76067162f,
+-0.76279181f, -0.76490390f, -0.76700771f, -0.76910341f, -0.77119076f,
+-0.77326995f, -0.77534080f, -0.77740335f, -0.77945763f, -0.78150350f,
+-0.78354102f, -0.78557014f, -0.78759086f, -0.78960317f, -0.79160696f,
+-0.79360235f, -0.79558921f, -0.79756755f, -0.79953730f, -0.80149853f,
+-0.80345118f, -0.80539525f, -0.80733067f, -0.80925739f, -0.81117553f,
+-0.81308490f, -0.81498563f, -0.81687760f, -0.81876087f, -0.82063532f,
+-0.82250100f, -0.82435787f, -0.82620591f, -0.82804507f, -0.82987541f,
+-0.83169687f, -0.83350939f, -0.83531296f, -0.83710766f, -0.83889335f,
+-0.84067005f, -0.84243774f, -0.84419644f, -0.84594607f, -0.84768665f,
+-0.84941816f, -0.85114056f, -0.85285389f, -0.85455805f, -0.85625303f,
+-0.85793889f, -0.85961550f, -0.86128294f, -0.86294121f, -0.86459017f,
+-0.86622989f, -0.86786032f, -0.86948150f, -0.87109333f, -0.87269586f,
+-0.87428904f, -0.87587279f, -0.87744725f, -0.87901229f, -0.88056785f,
+-0.88211405f, -0.88365078f, -0.88517809f, -0.88669586f, -0.88820416f,
+-0.88970292f, -0.89119220f, -0.89267188f, -0.89414203f, -0.89560264f,
+-0.89705360f, -0.89849502f, -0.89992678f, -0.90134889f, -0.90276134f,
+-0.90416414f, -0.90555727f, -0.90694070f, -0.90831441f, -0.90967834f,
+-0.91103262f, -0.91237706f, -0.91371179f, -0.91503674f, -0.91635185f,
+-0.91765714f, -0.91895264f, -0.92023826f, -0.92151409f, -0.92277998f,
+-0.92403603f, -0.92528218f, -0.92651838f, -0.92774469f, -0.92896110f,
+-0.93016750f, -0.93136400f, -0.93255049f, -0.93372697f, -0.93489349f,
+-0.93604994f, -0.93719643f, -0.93833286f, -0.93945926f, -0.94057560f,
+-0.94168180f, -0.94277799f, -0.94386405f, -0.94494003f, -0.94600588f,
+-0.94706154f, -0.94810712f, -0.94914252f, -0.95016778f, -0.95118284f,
+-0.95218778f, -0.95318246f, -0.95416695f, -0.95514119f, -0.95610523f,
+-0.95705903f, -0.95800257f, -0.95893586f, -0.95985889f, -0.96077162f,
+-0.96167403f, -0.96256620f, -0.96344805f, -0.96431959f, -0.96518075f,
+-0.96603161f, -0.96687216f, -0.96770233f, -0.96852213f, -0.96933156f,
+-0.97013056f, -0.97091925f, -0.97169751f, -0.97246534f, -0.97322279f,
+-0.97396982f, -0.97470641f, -0.97543252f, -0.97614825f, -0.97685349f,
+-0.97754824f, -0.97823256f, -0.97890645f, -0.97956979f, -0.98022264f,
+-0.98086500f, -0.98149687f, -0.98211825f, -0.98272908f, -0.98332942f,
+-0.98391914f, -0.98449844f, -0.98506713f, -0.98562527f, -0.98617285f,
+-0.98670989f, -0.98723638f, -0.98775226f, -0.98825759f, -0.98875231f,
+-0.98923647f, -0.98971003f, -0.99017298f, -0.99062532f, -0.99106705f,
+-0.99149817f, -0.99191868f, -0.99232858f, -0.99272782f, -0.99311644f,
+-0.99349445f, -0.99386179f, -0.99421853f, -0.99456459f, -0.99489999f,
+-0.99522477f, -0.99553883f, -0.99584228f, -0.99613506f, -0.99641716f,
+-0.99668860f, -0.99694937f, -0.99719942f, -0.99743885f, -0.99766755f,
+-0.99788558f, -0.99809295f, -0.99828959f, -0.99847561f, -0.99865085f,
+-0.99881548f, -0.99896932f, -0.99911255f, -0.99924499f, -0.99936682f,
+-0.99947786f, -0.99957830f, -0.99966794f, -0.99974692f, -0.99981517f,
+-0.99987274f, -0.99991959f, -0.99995571f, -0.99998116f, -0.99999589f,
+0.99999964f, 0.99997288f, 0.99990326f, 0.99979085f, 0.99963558f,
+0.99943751f, 0.99919659f, 0.99891287f, 0.99858636f, 0.99821711f,
+0.99780506f, 0.99735034f, 0.99685282f, 0.99631262f, 0.99572974f,
+0.99510419f, 0.99443603f, 0.99372530f, 0.99297196f, 0.99217612f,
+0.99133772f, 0.99045694f, 0.98953366f, 0.98856801f, 0.98756003f,
+0.98650974f, 0.98541719f, 0.98428243f, 0.98310548f, 0.98188645f,
+0.98062533f, 0.97932225f, 0.97797716f, 0.97659022f, 0.97516143f,
+0.97369087f, 0.97217858f, 0.97062469f, 0.96902919f, 0.96739221f,
+0.96571374f, 0.96399397f, 0.96223283f, 0.96043050f, 0.95858705f,
+0.95670253f, 0.95477700f, 0.95281059f, 0.95080340f, 0.94875544f,
+0.94666684f, 0.94453770f, 0.94236809f, 0.94015813f, 0.93790787f,
+0.93561745f, 0.93328691f, 0.93091643f, 0.92850608f, 0.92605597f,
+0.92356616f, 0.92103678f, 0.91846794f, 0.91585976f, 0.91321236f,
+0.91052586f, 0.90780038f, 0.90503591f, 0.90223277f, 0.89939094f,
+0.89651060f, 0.89359182f, 0.89063478f, 0.88763964f, 0.88460642f,
+0.88153529f, 0.87842643f, 0.87527996f, 0.87209594f, 0.86887461f,
+0.86561602f, 0.86232042f, 0.85898781f, 0.85561842f, 0.85221243f,
+0.84876984f, 0.84529096f, 0.84177583f, 0.83822471f, 0.83463764f,
+0.83101481f, 0.82735640f, 0.82366252f, 0.81993335f, 0.81616908f,
+0.81236988f, 0.80853581f, 0.80466717f, 0.80076402f, 0.79682660f,
+0.79285502f, 0.78884947f, 0.78481019f, 0.78073722f, 0.77663082f,
+0.77249116f, 0.76831841f, 0.76411277f, 0.75987434f, 0.75560343f,
+0.75130010f, 0.74696463f, 0.74259710f, 0.73819780f, 0.73376691f,
+0.72930455f, 0.72481096f, 0.72028631f, 0.71573079f, 0.71114463f,
+0.70652801f, 0.70188117f, 0.69720417f, 0.69249737f, 0.68776089f,
+0.68299496f, 0.67819971f, 0.67337549f, 0.66852236f, 0.66364062f,
+0.65873051f, 0.65379208f, 0.64882571f, 0.64383155f, 0.63880974f,
+0.63376063f, 0.62868434f, 0.62358117f, 0.61845124f, 0.61329484f,
+0.60811216f, 0.60290343f, 0.59766883f, 0.59240872f, 0.58712316f,
+0.58181250f, 0.57647687f, 0.57111657f, 0.56573176f, 0.56032276f,
+0.55488980f, 0.54943299f, 0.54395270f, 0.53844911f, 0.53292239f,
+0.52737290f, 0.52180082f, 0.51620632f, 0.51058978f, 0.50495136f,
+0.49929130f, 0.49360985f, 0.48790723f, 0.48218375f, 0.47643960f,
+0.47067502f, 0.46489030f, 0.45908567f, 0.45326138f, 0.44741765f,
+0.44155475f, 0.43567297f, 0.42977250f, 0.42385364f, 0.41791660f,
+0.41196167f, 0.40598908f, 0.39999911f, 0.39399201f, 0.38796803f,
+0.38192743f, 0.37587047f, 0.36979741f, 0.36370850f, 0.35760403f,
+0.35148421f, 0.34534934f, 0.33919969f, 0.33303553f, 0.32685706f,
+0.32066461f, 0.31445843f, 0.30823877f, 0.30200592f, 0.29576012f,
+0.28950164f, 0.28323078f, 0.27694780f, 0.27065292f, 0.26434645f,
+0.25802869f, 0.25169984f, 0.24536023f, 0.23901010f, 0.23264973f,
+0.22627939f, 0.21989937f, 0.21350993f, 0.20711134f, 0.20070387f,
+0.19428782f, 0.18786344f, 0.18143101f, 0.17499080f, 0.16854310f,
+0.16208819f, 0.15562633f, 0.14915779f, 0.14268288f, 0.13620184f,
+0.12971498f, 0.12322257f, 0.11672486f, 0.11022217f, 0.10371475f,
+0.097202882f, 0.090686858f, 0.084166944f, 0.077643424f, 0.071116582f,
+0.064586692f, 0.058054037f, 0.051518895f, 0.044981543f, 0.038442269f,
+0.031901345f, 0.025359053f, 0.018815678f, 0.012271495f, 0.0057267868f,
+-0.00081816671f, -0.0073630852f, -0.013907688f, -0.020451695f, -0.026994826f,
+-0.033536803f, -0.040077340f, -0.046616159f, -0.053152986f, -0.059687532f,
+-0.066219524f, -0.072748676f, -0.079274714f, -0.085797355f, -0.092316322f,
+-0.098831341f, -0.10534211f, -0.11184838f, -0.11834986f, -0.12484626f,
+-0.13133731f, -0.13782275f, -0.14430228f, -0.15077563f, -0.15724251f,
+-0.16370267f, -0.17015581f, -0.17660165f, -0.18303993f, -0.18947038f,
+-0.19589271f, -0.20230664f, -0.20871192f, -0.21510825f, -0.22149536f,
+-0.22787298f, -0.23424086f, -0.24059868f, -0.24694622f, -0.25328314f,
+-0.25960925f, -0.26592422f, -0.27222782f, -0.27851975f, -0.28479972f,
+-0.29106751f, -0.29732284f, -0.30356544f, -0.30979502f, -0.31601134f,
+-0.32221413f, -0.32840309f, -0.33457801f, -0.34073856f, -0.34688455f,
+-0.35301566f, -0.35913166f, -0.36523229f, -0.37131724f, -0.37738630f,
+-0.38343921f, -0.38947567f, -0.39549544f, -0.40149832f, -0.40748394f,
+-0.41345215f, -0.41940263f, -0.42533514f, -0.43124944f, -0.43714526f,
+-0.44302234f, -0.44888046f, -0.45471936f, -0.46053877f, -0.46633846f,
+-0.47211814f, -0.47787762f, -0.48361665f, -0.48933494f, -0.49503228f,
+-0.50070840f, -0.50636309f, -0.51199609f, -0.51760709f, -0.52319598f,
+-0.52876246f, -0.53430629f, -0.53982723f, -0.54532504f, -0.55079949f,
+-0.55625033f, -0.56167740f, -0.56708032f, -0.57245898f, -0.57781315f,
+-0.58314258f, -0.58844697f, -0.59372622f, -0.59897995f, -0.60420811f,
+-0.60941035f, -0.61458647f, -0.61973625f, -0.62485951f, -0.62995601f,
+-0.63502556f, -0.64006782f, -0.64508271f, -0.65007001f, -0.65502942f,
+-0.65996075f, -0.66486382f, -0.66973841f, -0.67458433f, -0.67940134f,
+-0.68418926f, -0.68894786f, -0.69367695f, -0.69837630f, -0.70304573f,
+-0.70768511f, -0.71229410f, -0.71687263f, -0.72142041f, -0.72593731f,
+-0.73042315f, -0.73487765f, -0.73930067f, -0.74369204f, -0.74805158f,
+-0.75237900f, -0.75667429f, -0.76093709f, -0.76516730f, -0.76936477f,
+-0.77352923f, -0.77766061f, -0.78175867f, -0.78582323f, -0.78985411f,
+-0.79385114f, -0.79781419f, -0.80174309f, -0.80563760f, -0.80949765f,
+-0.81332302f, -0.81711352f, -0.82086903f, -0.82458937f, -0.82827437f,
+-0.83192390f, -0.83553779f, -0.83911592f, -0.84265804f, -0.84616417f,
+-0.84963393f, -0.85306740f, -0.85646427f, -0.85982448f, -0.86314780f,
+-0.86643422f, -0.86968350f, -0.87289548f, -0.87607014f, -0.87920725f,
+-0.88230664f, -0.88536829f, -0.88839203f, -0.89137769f, -0.89432514f,
+-0.89723432f, -0.90010506f, -0.90293723f, -0.90573072f, -0.90848541f,
+-0.91120118f, -0.91387796f, -0.91651553f, -0.91911387f, -0.92167282f,
+-0.92419231f, -0.92667222f, -0.92911243f, -0.93151283f, -0.93387336f,
+-0.93619382f, -0.93847424f, -0.94071442f, -0.94291431f, -0.94507378f,
+-0.94719279f, -0.94927126f, -0.95130903f, -0.95330608f, -0.95526224f,
+-0.95717752f, -0.95905179f, -0.96088499f, -0.96267700f, -0.96442777f,
+-0.96613729f, -0.96780539f, -0.96943200f, -0.97101706f, -0.97256058f,
+-0.97406244f, -0.97552258f, -0.97694093f, -0.97831738f, -0.97965199f,
+-0.98094457f, -0.98219514f, -0.98340368f, -0.98457009f, -0.98569429f,
+-0.98677629f, -0.98781598f, -0.98881340f, -0.98976845f, -0.99068111f,
+-0.99155134f, -0.99237907f, -0.99316430f, -0.99390697f, -0.99460709f,
+-0.99526459f, -0.99587947f, -0.99645168f, -0.99698120f, -0.99746799f,
+-0.99791211f, -0.99831343f, -0.99867201f, -0.99898779f, -0.99926084f,
+-0.99949104f, -0.99967843f, -0.99982297f, -0.99992472f, -0.99998361f,
+0.99999869f, 0.99989158f, 0.99961317f, 0.99916345f, 0.99854255f,
+0.99775058f, 0.99678761f, 0.99565387f, 0.99434954f, 0.99287480f,
+0.99122995f, 0.98941529f, 0.98743105f, 0.98527765f, 0.98295540f,
+0.98046476f, 0.97780609f, 0.97497988f, 0.97198665f, 0.96882683f,
+0.96550101f, 0.96200979f, 0.95835376f, 0.95453346f, 0.95054960f,
+0.94640291f, 0.94209403f, 0.93762374f, 0.93299282f, 0.92820197f,
+0.92325211f, 0.91814411f, 0.91287869f, 0.90745693f, 0.90187967f,
+0.89614785f, 0.89026248f, 0.88422459f, 0.87803519f, 0.87169534f,
+0.86520612f, 0.85856867f, 0.85178405f, 0.84485358f, 0.83777827f,
+0.83055943f, 0.82319832f, 0.81569612f, 0.80805415f, 0.80027372f,
+0.79235619f, 0.78430289f, 0.77611518f, 0.76779449f, 0.75934225f,
+0.75075996f, 0.74204898f, 0.73321080f, 0.72424710f, 0.71515924f,
+0.70594883f, 0.69661748f, 0.68716675f, 0.67759830f, 0.66791373f,
+0.65811473f, 0.64820296f, 0.63818014f, 0.62804794f, 0.61780810f,
+0.60746247f, 0.59701276f, 0.58646071f, 0.57580817f, 0.56505698f,
+0.55420899f, 0.54326600f, 0.53222996f, 0.52110273f, 0.50988621f,
+0.49858227f, 0.48719296f, 0.47572014f, 0.46416581f, 0.45253196f,
+0.44082057f, 0.42903364f, 0.41717321f, 0.40524128f, 0.39323992f,
+0.38117120f, 0.36903715f, 0.35683987f, 0.34458145f, 0.33226398f,
+0.31988961f, 0.30746040f, 0.29497850f, 0.28244606f, 0.26986524f,
+0.25723818f, 0.24456702f, 0.23185398f, 0.21910121f, 0.20631088f,
+0.19348522f, 0.18062639f, 0.16773662f, 0.15481812f, 0.14187308f,
+0.12890373f, 0.11591230f, 0.10290100f, 0.089872077f, 0.076827750f,
+0.063770257f, 0.050701842f, 0.037624735f, 0.024541186f, 0.011453429f,
+-0.0016362892f, -0.014725727f, -0.027812643f, -0.040894791f, -0.053969935f,
+-0.067035832f, -0.080090240f, -0.093130924f, -0.10615565f, -0.11916219f,
+-0.13214831f, -0.14511178f, -0.15805040f, -0.17096193f, -0.18384418f,
+-0.19669491f, -0.20951195f, -0.22229309f, -0.23503613f, -0.24773891f,
+-0.26039925f, -0.27301496f, -0.28558388f, -0.29810387f, -0.31057280f,
+-0.32298848f, -0.33534884f, -0.34765175f, -0.35989508f, -0.37207675f,
+-0.38419467f, -0.39624676f, -0.40823093f, -0.42014518f, -0.43198743f,
+-0.44375566f, -0.45544785f, -0.46706200f, -0.47859612f, -0.49004826f,
+-0.50141639f, -0.51269865f, -0.52389306f, -0.53499764f, -0.54601061f,
+-0.55693001f, -0.56775403f, -0.57848072f, -0.58910829f, -0.59963489f,
+-0.61005878f, -0.62037814f, -0.63059121f, -0.64069623f, -0.65069145f,
+-0.66057515f, -0.67034572f, -0.68000144f, -0.68954057f, -0.69896162f,
+-0.70826286f, -0.71744281f, -0.72649974f, -0.73543227f, -0.74423873f,
+-0.75291771f, -0.76146764f, -0.76988715f, -0.77817470f, -0.78632891f,
+-0.79434842f, -0.80223179f, -0.80997771f, -0.81758487f, -0.82505190f,
+-0.83237761f, -0.83956063f, -0.84659988f, -0.85349399f, -0.86024189f,
+-0.86684239f, -0.87329435f, -0.87959671f, -0.88574833f, -0.89174819f,
+-0.89759529f, -0.90328854f, -0.90882701f, -0.91420978f, -0.91943592f,
+-0.92450452f, -0.92941469f, -0.93416560f, -0.93875647f, -0.94318646f,
+-0.94745487f, -0.95156091f, -0.95550388f, -0.95928317f, -0.96289814f,
+-0.96634805f, -0.96963239f, -0.97275060f, -0.97570217f, -0.97848648f,
+-0.98110318f, -0.98355180f, -0.98583186f, -0.98794299f, -0.98988485f,
+-0.99165714f, -0.99325943f, -0.99469161f, -0.99595332f, -0.99704438f,
+-0.99796462f, -0.99871385f, -0.99929196f, -0.99969882f, -0.99993443f,
+0.99999464f, 0.99956632f, 0.99845290f, 0.99665523f, 0.99417448f,
+0.99101239f, 0.98717111f, 0.98265326f, 0.97746199f, 0.97160077f,
+0.96507365f, 0.95788515f, 0.95004016f, 0.94154406f, 0.93240267f,
+0.92262226f, 0.91220951f, 0.90117162f, 0.88951606f, 0.87725091f,
+0.86438453f, 0.85092574f, 0.83688372f, 0.82226819f, 0.80708915f,
+0.79135692f, 0.77508235f, 0.75827658f, 0.74095112f, 0.72311783f,
+0.70478898f, 0.68597710f, 0.66669506f, 0.64695615f, 0.62677377f,
+0.60616189f, 0.58513457f, 0.56370622f, 0.54189157f, 0.51970547f,
+0.49716324f, 0.47428027f, 0.45107225f, 0.42755505f, 0.40374488f,
+0.37965798f, 0.35531086f, 0.33072025f, 0.30590299f, 0.28087607f,
+0.25565663f, 0.23026201f, 0.20470956f, 0.17901683f, 0.15320139f,
+0.12728097f, 0.10127331f, 0.075196236f, 0.049067631f, 0.022905400f,
+-0.0032725304f, -0.029448219f, -0.055603724f, -0.081721120f, -0.10778251f,
+-0.13377003f, -0.15966587f, -0.18545228f, -0.21111161f, -0.23662624f,
+-0.26197869f, -0.28715160f, -0.31212771f, -0.33688989f, -0.36142120f,
+-0.38570482f, -0.40972409f, -0.43346253f, -0.45690393f, -0.48003218f,
+-0.50283146f, -0.52528608f, -0.54738069f, -0.56910020f, -0.59042966f,
+-0.61135447f, -0.63186026f, -0.65193301f, -0.67155898f, -0.69072473f,
+-0.70941705f, -0.72762316f, -0.74533063f, -0.76252723f, -0.77920127f,
+-0.79534131f, -0.81093621f, -0.82597536f, -0.84044844f, -0.85434550f,
+-0.86765707f, -0.88037395f, -0.89248747f, -0.90398932f, -0.91487163f,
+-0.92512697f, -0.93474823f, -0.94372886f, -0.95206273f, -0.95974404f,
+-0.96676767f, -0.97312868f, -0.97882277f, -0.98384601f, -0.98819500f,
+-0.99186671f, -0.99485862f, -0.99716878f, -0.99879545f, -0.99973762f,
+};
+#endif
+
+static const CELTMode mode48000_960_120 = {
+48000,  /* Fs */
+120,    /* overlap */
+21,     /* nbEBands */
+21,     /* effEBands */
+{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, },    /* preemph */
+eband5ms,       /* eBands */
+3,      /* maxLM */
+8,      /* nbShortMdcts */
+120,    /* shortMdctSize */
+11,     /* nbAllocVectors */
+band_allocation,        /* allocVectors */
+logN400,        /* logN */
+window120,      /* window */
+{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960},    /* mdct */
+{392, cache_index50, cache_bits50, cache_caps50},       /* cache */
+};
+
+/* List of all the available modes */
+#define TOTAL_MODES 1
+static const CELTMode * const static_mode_list[TOTAL_MODES] = {
+&mode48000_960_120,
+};
diff --git a/third_party/opus/src/celt/static_modes_float_arm_ne10.h b/third_party/opus/src/celt/static_modes_float_arm_ne10.h
new file mode 100644
index 0000000..934a82a
--- /dev/null
+++ b/third_party/opus/src/celt/static_modes_float_arm_ne10.h
@@ -0,0 +1,404 @@
+/* The contents of this file was automatically generated by
+ * dump_mode_arm_ne10.c with arguments: 48000 960
+ * It contains static definitions for some pre-defined modes. */
+#include <NE10_init.h>
+
+#ifndef NE10_FFT_PARAMS48000_960
+#define NE10_FFT_PARAMS48000_960
+static const ne10_int32_t ne10_factors_480[64] = {
+4, 40, 4, 30, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, };
+static const ne10_int32_t ne10_factors_240[64] = {
+3, 20, 4, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, };
+static const ne10_int32_t ne10_factors_120[64] = {
+3, 10, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, };
+static const ne10_int32_t ne10_factors_60[64] = {
+2, 5, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, };
+static const ne10_fft_cpx_float32_t ne10_twiddles_480[480] = {
+{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f},
+{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f},
+{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f},
+{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f},
+{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f},
+{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f},
+{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f},
+{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f},
+{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f},
+{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f},
+{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f},
+{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f},
+{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f},
+{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f},
+{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f},
+{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f},
+{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f},
+{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f},
+{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f},
+{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f},
+{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f},
+{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f},
+{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f},
+{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f},
+{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f},
+{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f},
+{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f},
+{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f},
+{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f},
+{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f},
+{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f},
+{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f},
+{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f},
+{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f},
+{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f},
+{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f},
+{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f},
+{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f},
+{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f},
+{1.0000000f,-0.0000000f}, {0.99991435f,-0.013089596f}, {0.99965733f,-0.026176950f},
+{0.99922901f,-0.039259817f}, {0.99862951f,-0.052335959f}, {0.99785894f,-0.065403134f},
+{0.99691731f,-0.078459099f}, {0.99580491f,-0.091501623f}, {0.99452192f,-0.10452846f},
+{0.99306846f,-0.11753740f}, {0.99144489f,-0.13052620f}, {0.98965138f,-0.14349262f},
+{0.98768836f,-0.15643448f}, {0.98555607f,-0.16934951f}, {0.98325491f,-0.18223552f},
+{0.98078525f,-0.19509032f}, {0.97814763f,-0.20791170f}, {0.97534233f,-0.22069745f},
+{0.97236991f,-0.23344538f}, {0.96923089f,-0.24615330f}, {0.96592581f,-0.25881904f},
+{0.96245521f,-0.27144045f}, {0.95881975f,-0.28401536f}, {0.95501995f,-0.29654160f},
+{0.95105648f,-0.30901700f}, {0.94693011f,-0.32143945f}, {0.94264150f,-0.33380687f},
+{0.93819129f,-0.34611708f}, {0.93358040f,-0.35836795f}, {0.92880952f,-0.37055743f},
+{0.92387956f,-0.38268346f}, {0.91879117f,-0.39474389f}, {0.91354543f,-0.40673664f},
+{0.90814316f,-0.41865975f}, {0.90258527f,-0.43051112f}, {0.89687270f,-0.44228873f},
+{0.89100653f,-0.45399052f}, {0.88498765f,-0.46561453f}, {0.87881708f,-0.47715878f},
+{0.87249601f,-0.48862126f}, {0.86602545f,-0.50000000f}, {0.85940641f,-0.51129311f},
+{0.85264015f,-0.52249855f}, {0.84572786f,-0.53361452f}, {0.83867055f,-0.54463905f},
+{0.83146960f,-0.55557024f}, {0.82412618f,-0.56640625f}, {0.81664151f,-0.57714522f},
+{0.80901700f,-0.58778524f}, {0.80125380f,-0.59832460f}, {0.79335332f,-0.60876143f},
+{0.78531694f,-0.61909395f}, {0.77714598f,-0.62932038f}, {0.76884180f,-0.63943899f},
+{0.76040596f,-0.64944810f}, {0.75183982f,-0.65934587f}, {0.74314475f,-0.66913062f},
+{0.73432249f,-0.67880076f}, {0.72537434f,-0.68835455f}, {0.71630192f,-0.69779050f},
+{0.70710677f,-0.70710683f}, {0.69779044f,-0.71630198f}, {0.68835455f,-0.72537440f},
+{0.67880070f,-0.73432255f}, {0.66913056f,-0.74314487f}, {0.65934581f,-0.75183982f},
+{0.64944804f,-0.76040596f}, {0.63943899f,-0.76884186f}, {0.62932038f,-0.77714598f},
+{0.61909395f,-0.78531694f}, {0.60876137f,-0.79335338f}, {0.59832460f,-0.80125386f},
+{0.58778524f,-0.80901700f}, {0.57714516f,-0.81664151f}, {0.56640625f,-0.82412618f},
+{0.55557019f,-0.83146960f}, {0.54463899f,-0.83867055f}, {0.53361452f,-0.84572786f},
+{0.52249849f,-0.85264015f}, {0.51129311f,-0.85940641f}, {0.49999997f,-0.86602545f},
+{0.48862118f,-0.87249601f}, {0.47715876f,-0.87881708f}, {0.46561447f,-0.88498765f},
+{0.45399052f,-0.89100653f}, {0.44228867f,-0.89687276f}, {0.43051103f,-0.90258533f},
+{0.41865975f,-0.90814316f}, {0.40673661f,-0.91354549f}, {0.39474380f,-0.91879129f},
+{0.38268343f,-0.92387956f}, {0.37055740f,-0.92880958f}, {0.35836786f,-0.93358046f},
+{0.34611705f,-0.93819135f}, {0.33380681f,-0.94264150f}, {0.32143947f,-0.94693011f},
+{0.30901697f,-0.95105654f}, {0.29654151f,-0.95501995f}, {0.28401533f,-0.95881975f},
+{0.27144039f,-0.96245527f}, {0.25881907f,-0.96592581f}, {0.24615327f,-0.96923089f},
+{0.23344530f,-0.97236991f}, {0.22069745f,-0.97534233f}, {0.20791166f,-0.97814763f},
+{0.19509023f,-0.98078531f}, {0.18223552f,-0.98325491f}, {0.16934945f,-0.98555607f},
+{0.15643437f,-0.98768836f}, {0.14349259f,-0.98965138f}, {0.13052613f,-0.99144489f},
+{0.11753740f,-0.99306846f}, {0.10452842f,-0.99452192f}, {0.091501534f,-0.99580491f},
+{0.078459084f,-0.99691731f}, {0.065403074f,-0.99785894f}, {0.052335974f,-0.99862951f},
+{0.039259788f,-0.99922901f}, {0.026176875f,-0.99965733f}, {0.013089597f,-0.99991435f},
+{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f},
+{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f},
+{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f},
+{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f},
+{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f},
+{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f},
+{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f},
+{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f},
+{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f},
+{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f},
+{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f},
+{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f},
+{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f},
+{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f},
+{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f},
+{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f},
+{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f},
+{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f},
+{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f},
+{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f},
+{-4.3711388e-08f,-1.0000000f}, {-0.026176963f,-0.99965733f}, {-0.052336060f,-0.99862951f},
+{-0.078459173f,-0.99691731f}, {-0.10452851f,-0.99452192f}, {-0.13052621f,-0.99144489f},
+{-0.15643445f,-0.98768836f}, {-0.18223560f,-0.98325491f}, {-0.20791174f,-0.97814757f},
+{-0.23344538f,-0.97236991f}, {-0.25881916f,-0.96592581f}, {-0.28401542f,-0.95881969f},
+{-0.30901703f,-0.95105648f}, {-0.33380687f,-0.94264150f}, {-0.35836795f,-0.93358040f},
+{-0.38268352f,-0.92387950f}, {-0.40673670f,-0.91354543f}, {-0.43051112f,-0.90258527f},
+{-0.45399061f,-0.89100647f}, {-0.47715873f,-0.87881708f}, {-0.50000006f,-0.86602533f},
+{-0.52249867f,-0.85264009f}, {-0.54463905f,-0.83867055f}, {-0.56640631f,-0.82412612f},
+{-0.58778518f,-0.80901700f}, {-0.60876143f,-0.79335332f}, {-0.62932050f,-0.77714586f},
+{-0.64944804f,-0.76040596f}, {-0.66913068f,-0.74314475f}, {-0.68835467f,-0.72537428f},
+{-0.70710677f,-0.70710677f}, {-0.72537446f,-0.68835449f}, {-0.74314493f,-0.66913044f},
+{-0.76040596f,-0.64944804f}, {-0.77714604f,-0.62932026f}, {-0.79335332f,-0.60876143f},
+{-0.80901700f,-0.58778518f}, {-0.82412624f,-0.56640613f}, {-0.83867055f,-0.54463899f},
+{-0.85264021f,-0.52249849f}, {-0.86602539f,-0.50000006f}, {-0.87881714f,-0.47715873f},
+{-0.89100659f,-0.45399037f}, {-0.90258527f,-0.43051112f}, {-0.91354549f,-0.40673658f},
+{-0.92387956f,-0.38268328f}, {-0.93358040f,-0.35836792f}, {-0.94264150f,-0.33380675f},
+{-0.95105654f,-0.30901679f}, {-0.95881975f,-0.28401530f}, {-0.96592587f,-0.25881892f},
+{-0.97236991f,-0.23344538f}, {-0.97814763f,-0.20791161f}, {-0.98325491f,-0.18223536f},
+{-0.98768836f,-0.15643445f}, {-0.99144489f,-0.13052608f}, {-0.99452192f,-0.10452849f},
+{-0.99691737f,-0.078459039f}, {-0.99862957f,-0.052335810f}, {-0.99965733f,-0.026176952f},
+{1.0000000f,-0.0000000f}, {0.99922901f,-0.039259817f}, {0.99691731f,-0.078459099f},
+{0.99306846f,-0.11753740f}, {0.98768836f,-0.15643448f}, {0.98078525f,-0.19509032f},
+{0.97236991f,-0.23344538f}, {0.96245521f,-0.27144045f}, {0.95105648f,-0.30901700f},
+{0.93819129f,-0.34611708f}, {0.92387956f,-0.38268346f}, {0.90814316f,-0.41865975f},
+{0.89100653f,-0.45399052f}, {0.87249601f,-0.48862126f}, {0.85264015f,-0.52249855f},
+{0.83146960f,-0.55557024f}, {0.80901700f,-0.58778524f}, {0.78531694f,-0.61909395f},
+{0.76040596f,-0.64944810f}, {0.73432249f,-0.67880076f}, {0.70710677f,-0.70710683f},
+{0.67880070f,-0.73432255f}, {0.64944804f,-0.76040596f}, {0.61909395f,-0.78531694f},
+{0.58778524f,-0.80901700f}, {0.55557019f,-0.83146960f}, {0.52249849f,-0.85264015f},
+{0.48862118f,-0.87249601f}, {0.45399052f,-0.89100653f}, {0.41865975f,-0.90814316f},
+{0.38268343f,-0.92387956f}, {0.34611705f,-0.93819135f}, {0.30901697f,-0.95105654f},
+{0.27144039f,-0.96245527f}, {0.23344530f,-0.97236991f}, {0.19509023f,-0.98078531f},
+{0.15643437f,-0.98768836f}, {0.11753740f,-0.99306846f}, {0.078459084f,-0.99691731f},
+{0.039259788f,-0.99922901f}, {-4.3711388e-08f,-1.0000000f}, {-0.039259877f,-0.99922901f},
+{-0.078459173f,-0.99691731f}, {-0.11753749f,-0.99306846f}, {-0.15643445f,-0.98768836f},
+{-0.19509032f,-0.98078525f}, {-0.23344538f,-0.97236991f}, {-0.27144048f,-0.96245521f},
+{-0.30901703f,-0.95105648f}, {-0.34611711f,-0.93819129f}, {-0.38268352f,-0.92387950f},
+{-0.41865984f,-0.90814310f}, {-0.45399061f,-0.89100647f}, {-0.48862135f,-0.87249595f},
+{-0.52249867f,-0.85264009f}, {-0.55557036f,-0.83146954f}, {-0.58778518f,-0.80901700f},
+{-0.61909389f,-0.78531694f}, {-0.64944804f,-0.76040596f}, {-0.67880076f,-0.73432249f},
+{-0.70710677f,-0.70710677f}, {-0.73432249f,-0.67880070f}, {-0.76040596f,-0.64944804f},
+{-0.78531694f,-0.61909389f}, {-0.80901700f,-0.58778518f}, {-0.83146966f,-0.55557019f},
+{-0.85264021f,-0.52249849f}, {-0.87249607f,-0.48862115f}, {-0.89100659f,-0.45399037f},
+{-0.90814322f,-0.41865960f}, {-0.92387956f,-0.38268328f}, {-0.93819135f,-0.34611690f},
+{-0.95105654f,-0.30901679f}, {-0.96245521f,-0.27144048f}, {-0.97236991f,-0.23344538f},
+{-0.98078531f,-0.19509031f}, {-0.98768836f,-0.15643445f}, {-0.99306846f,-0.11753736f},
+{-0.99691737f,-0.078459039f}, {-0.99922901f,-0.039259743f}, {-1.0000000f,8.7422777e-08f},
+{-0.99922901f,0.039259918f}, {-0.99691731f,0.078459218f}, {-0.99306846f,0.11753753f},
+{-0.98768830f,0.15643461f}, {-0.98078525f,0.19509049f}, {-0.97236985f,0.23344554f},
+{-0.96245515f,0.27144065f}, {-0.95105654f,0.30901697f}, {-0.93819135f,0.34611705f},
+{-0.92387956f,0.38268346f}, {-0.90814316f,0.41865975f}, {-0.89100653f,0.45399055f},
+{-0.87249601f,0.48862129f}, {-0.85264015f,0.52249861f}, {-0.83146960f,0.55557030f},
+{-0.80901694f,0.58778536f}, {-0.78531688f,0.61909401f}, {-0.76040590f,0.64944816f},
+{-0.73432243f,0.67880082f}, {-0.70710665f,0.70710689f}, {-0.67880058f,0.73432261f},
+{-0.64944792f,0.76040608f}, {-0.61909378f,0.78531706f}, {-0.58778507f,0.80901712f},
+{-0.55557001f,0.83146977f}, {-0.52249837f,0.85264033f}, {-0.48862100f,0.87249613f},
+{-0.45399022f,0.89100665f}, {-0.41865945f,0.90814328f}, {-0.38268313f,0.92387968f},
+{-0.34611672f,0.93819147f}, {-0.30901709f,0.95105648f}, {-0.27144054f,0.96245521f},
+{-0.23344545f,0.97236991f}, {-0.19509038f,0.98078525f}, {-0.15643452f,0.98768830f},
+{-0.11753743f,0.99306846f}, {-0.078459114f,0.99691731f}, {-0.039259821f,0.99922901f},
+};
+static const ne10_fft_cpx_float32_t ne10_twiddles_240[240] = {
+{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f},
+{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f},
+{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f},
+{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f},
+{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f},
+{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f},
+{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f},
+{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f},
+{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f},
+{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f},
+{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f},
+{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f},
+{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f},
+{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f},
+{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f},
+{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f},
+{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f},
+{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f},
+{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f},
+{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f},
+{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f},
+{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f},
+{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f},
+{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f},
+{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f},
+{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f},
+{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f},
+{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f},
+{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f},
+{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f},
+{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f},
+{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f},
+{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f},
+{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f},
+{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f},
+{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f},
+{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f},
+{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f},
+{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f},
+{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f},
+{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f},
+{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f},
+{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f},
+{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f},
+{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f},
+{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f},
+{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f},
+{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f},
+{-4.3711388e-08f,-1.0000000f}, {-0.052336060f,-0.99862951f}, {-0.10452851f,-0.99452192f},
+{-0.15643445f,-0.98768836f}, {-0.20791174f,-0.97814757f}, {-0.25881916f,-0.96592581f},
+{-0.30901703f,-0.95105648f}, {-0.35836795f,-0.93358040f}, {-0.40673670f,-0.91354543f},
+{-0.45399061f,-0.89100647f}, {-0.50000006f,-0.86602533f}, {-0.54463905f,-0.83867055f},
+{-0.58778518f,-0.80901700f}, {-0.62932050f,-0.77714586f}, {-0.66913068f,-0.74314475f},
+{-0.70710677f,-0.70710677f}, {-0.74314493f,-0.66913044f}, {-0.77714604f,-0.62932026f},
+{-0.80901700f,-0.58778518f}, {-0.83867055f,-0.54463899f}, {-0.86602539f,-0.50000006f},
+{-0.89100659f,-0.45399037f}, {-0.91354549f,-0.40673658f}, {-0.93358040f,-0.35836792f},
+{-0.95105654f,-0.30901679f}, {-0.96592587f,-0.25881892f}, {-0.97814763f,-0.20791161f},
+{-0.98768836f,-0.15643445f}, {-0.99452192f,-0.10452849f}, {-0.99862957f,-0.052335810f},
+{1.0000000f,-0.0000000f}, {0.99691731f,-0.078459099f}, {0.98768836f,-0.15643448f},
+{0.97236991f,-0.23344538f}, {0.95105648f,-0.30901700f}, {0.92387956f,-0.38268346f},
+{0.89100653f,-0.45399052f}, {0.85264015f,-0.52249855f}, {0.80901700f,-0.58778524f},
+{0.76040596f,-0.64944810f}, {0.70710677f,-0.70710683f}, {0.64944804f,-0.76040596f},
+{0.58778524f,-0.80901700f}, {0.52249849f,-0.85264015f}, {0.45399052f,-0.89100653f},
+{0.38268343f,-0.92387956f}, {0.30901697f,-0.95105654f}, {0.23344530f,-0.97236991f},
+{0.15643437f,-0.98768836f}, {0.078459084f,-0.99691731f}, {-4.3711388e-08f,-1.0000000f},
+{-0.078459173f,-0.99691731f}, {-0.15643445f,-0.98768836f}, {-0.23344538f,-0.97236991f},
+{-0.30901703f,-0.95105648f}, {-0.38268352f,-0.92387950f}, {-0.45399061f,-0.89100647f},
+{-0.52249867f,-0.85264009f}, {-0.58778518f,-0.80901700f}, {-0.64944804f,-0.76040596f},
+{-0.70710677f,-0.70710677f}, {-0.76040596f,-0.64944804f}, {-0.80901700f,-0.58778518f},
+{-0.85264021f,-0.52249849f}, {-0.89100659f,-0.45399037f}, {-0.92387956f,-0.38268328f},
+{-0.95105654f,-0.30901679f}, {-0.97236991f,-0.23344538f}, {-0.98768836f,-0.15643445f},
+{-0.99691737f,-0.078459039f}, {-1.0000000f,8.7422777e-08f}, {-0.99691731f,0.078459218f},
+{-0.98768830f,0.15643461f}, {-0.97236985f,0.23344554f}, {-0.95105654f,0.30901697f},
+{-0.92387956f,0.38268346f}, {-0.89100653f,0.45399055f}, {-0.85264015f,0.52249861f},
+{-0.80901694f,0.58778536f}, {-0.76040590f,0.64944816f}, {-0.70710665f,0.70710689f},
+{-0.64944792f,0.76040608f}, {-0.58778507f,0.80901712f}, {-0.52249837f,0.85264033f},
+{-0.45399022f,0.89100665f}, {-0.38268313f,0.92387968f}, {-0.30901709f,0.95105648f},
+{-0.23344545f,0.97236991f}, {-0.15643452f,0.98768830f}, {-0.078459114f,0.99691731f},
+};
+static const ne10_fft_cpx_float32_t ne10_twiddles_120[120] = {
+{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f},
+{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f},
+{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f},
+{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f},
+{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f},
+{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f},
+{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f},
+{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f},
+{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f},
+{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f},
+{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f},
+{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f},
+{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f},
+{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f},
+{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f},
+{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f},
+{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f},
+{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f},
+{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f},
+{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f},
+{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f},
+{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f},
+{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f},
+{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f},
+{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f},
+{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f},
+{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f},
+{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f},
+{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f},
+{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f},
+{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f},
+{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f},
+{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f},
+{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f},
+{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f},
+{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f},
+{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f},
+{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f},
+{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f},
+};
+static const ne10_fft_cpx_float32_t ne10_twiddles_60[60] = {
+{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f},
+{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f},
+{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f},
+{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f},
+{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f},
+{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f},
+{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f},
+{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f},
+{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f},
+{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f},
+{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f},
+{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f},
+{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f},
+{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f},
+{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f},
+{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f},
+{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f},
+{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f},
+{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f},
+};
+static const ne10_fft_state_float32_t ne10_fft_state_float32_t_480 = {
+120,
+(ne10_int32_t *)ne10_factors_480,
+(ne10_fft_cpx_float32_t *)ne10_twiddles_480,
+NULL,
+(ne10_fft_cpx_float32_t *)&ne10_twiddles_480[120],
+/* is_forward_scaled = true */
+(ne10_int32_t) 1,
+/* is_backward_scaled = false */
+(ne10_int32_t) 0,
+};
+static const arch_fft_state cfg_arch_480 = {
+1,
+(void *)&ne10_fft_state_float32_t_480,
+};
+
+static const ne10_fft_state_float32_t ne10_fft_state_float32_t_240 = {
+60,
+(ne10_int32_t *)ne10_factors_240,
+(ne10_fft_cpx_float32_t *)ne10_twiddles_240,
+NULL,
+(ne10_fft_cpx_float32_t *)&ne10_twiddles_240[60],
+/* is_forward_scaled = true */
+(ne10_int32_t) 1,
+/* is_backward_scaled = false */
+(ne10_int32_t) 0,
+};
+static const arch_fft_state cfg_arch_240 = {
+1,
+(void *)&ne10_fft_state_float32_t_240,
+};
+
+static const ne10_fft_state_float32_t ne10_fft_state_float32_t_120 = {
+30,
+(ne10_int32_t *)ne10_factors_120,
+(ne10_fft_cpx_float32_t *)ne10_twiddles_120,
+NULL,
+(ne10_fft_cpx_float32_t *)&ne10_twiddles_120[30],
+/* is_forward_scaled = true */
+(ne10_int32_t) 1,
+/* is_backward_scaled = false */
+(ne10_int32_t) 0,
+};
+static const arch_fft_state cfg_arch_120 = {
+1,
+(void *)&ne10_fft_state_float32_t_120,
+};
+
+static const ne10_fft_state_float32_t ne10_fft_state_float32_t_60 = {
+15,
+(ne10_int32_t *)ne10_factors_60,
+(ne10_fft_cpx_float32_t *)ne10_twiddles_60,
+NULL,
+(ne10_fft_cpx_float32_t *)&ne10_twiddles_60[15],
+/* is_forward_scaled = true */
+(ne10_int32_t) 1,
+/* is_backward_scaled = false */
+(ne10_int32_t) 0,
+};
+static const arch_fft_state cfg_arch_60 = {
+1,
+(void *)&ne10_fft_state_float32_t_60,
+};
+
+#endif  /* end NE10_FFT_PARAMS48000_960 */
diff --git a/third_party/opus/src/celt/tests/test_unit_cwrs32.c b/third_party/opus/src/celt/tests/test_unit_cwrs32.c
new file mode 100644
index 0000000..36dd8af
--- /dev/null
+++ b/third_party/opus/src/celt/tests/test_unit_cwrs32.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation,
+                           Gregory Maxwell
+   Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#else
+#define TEST_CUSTOM_MODES
+#endif
+
+#define CELT_C
+#include "stack_alloc.h"
+#include "entenc.c"
+#include "entdec.c"
+#include "entcode.c"
+#include "cwrs.c"
+#include "mathops.c"
+#include "rate.h"
+
+#define NMAX (240)
+#define KMAX (128)
+
+#ifdef TEST_CUSTOM_MODES
+
+#define NDIMS (44)
+static const int pn[NDIMS]={
+   2,   3,   4,   5,   6,   7,   8,   9,  10,
+  11,  12,  13,  14,  15,  16,  18,  20,  22,
+  24,  26,  28,  30,  32,  36,  40,  44,  48,
+  52,  56,  60,  64,  72,  80,  88,  96, 104,
+ 112, 120, 128, 144, 160, 176, 192, 208
+};
+static const int pkmax[NDIMS]={
+ 128, 128, 128, 128,  88,  52,  36,  26,  22,
+  18,  16,  15,  13,  12,  12,  11,  10,   9,
+   9,   8,   8,   7,   7,   7,   7,   6,   6,
+   6,   6,   6,   5,   5,   5,   5,   5,   5,
+   4,   4,   4,   4,   4,   4,   4,   4
+};
+
+#else /* TEST_CUSTOM_MODES */
+
+#define NDIMS (22)
+static const int pn[NDIMS]={
+   2,   3,   4,   6,   8,   9,  11,  12,  16,
+  18,  22,  24,  32,  36,  44,  48,  64,  72,
+  88,  96, 144, 176
+};
+static const int pkmax[NDIMS]={
+ 128, 128, 128,  88,  36,  26,  18,  16,  12,
+  11,   9,   9,   7,   7,   6,   6,   5,   5,
+   5,   5,   4,   4
+};
+
+#endif
+
+int main(void){
+  int t;
+  int n;
+  ALLOC_STACK;
+  for(t=0;t<NDIMS;t++){
+    int pseudo;
+    n=pn[t];
+    for(pseudo=1;pseudo<41;pseudo++)
+    {
+      int k;
+#if defined(SMALL_FOOTPRINT)
+      opus_uint32 uu[KMAX+2U];
+#endif
+      opus_uint32 inc;
+      opus_uint32 nc;
+      opus_uint32 i;
+      k=get_pulses(pseudo);
+      if (k>pkmax[t])break;
+      printf("Testing CWRS with N=%i, K=%i...\n",n,k);
+#if defined(SMALL_FOOTPRINT)
+      nc=ncwrs_urow(n,k,uu);
+#else
+      nc=CELT_PVQ_V(n,k);
+#endif
+      inc=nc/20000;
+      if(inc<1)inc=1;
+      for(i=0;i<nc;i+=inc){
+#if defined(SMALL_FOOTPRINT)
+        opus_uint32 u[KMAX+2U];
+#endif
+        int         y[NMAX];
+        int         sy;
+        opus_uint32 v;
+        opus_uint32 ii;
+        int         j;
+#if defined(SMALL_FOOTPRINT)
+        memcpy(u,uu,(k+2U)*sizeof(*u));
+        cwrsi(n,k,i,y,u);
+#else
+        cwrsi(n,k,i,y);
+#endif
+        sy=0;
+        for(j=0;j<n;j++)sy+=abs(y[j]);
+        if(sy!=k){
+          fprintf(stderr,"N=%d Pulse count mismatch in cwrsi (%d!=%d).\n",
+           n,sy,k);
+          return 99;
+        }
+        /*printf("%6u of %u:",i,nc);
+        for(j=0;j<n;j++)printf(" %+3i",y[j]);
+        printf(" ->");*/
+#if defined(SMALL_FOOTPRINT)
+        ii=icwrs(n,k,&v,y,u);
+#else
+        ii=icwrs(n,y);
+        v=CELT_PVQ_V(n,k);
+#endif
+        if(ii!=i){
+          fprintf(stderr,"Combination-index mismatch (%lu!=%lu).\n",
+           (long)ii,(long)i);
+          return 1;
+        }
+        if(v!=nc){
+          fprintf(stderr,"Combination count mismatch (%lu!=%lu).\n",
+           (long)v,(long)nc);
+          return 2;
+        }
+        /*printf(" %6u\n",i);*/
+      }
+      /*printf("\n");*/
+    }
+  }
+  return 0;
+}
diff --git a/third_party/opus/src/celt/tests/test_unit_dft.c b/third_party/opus/src/celt/tests/test_unit_dft.c
new file mode 100644
index 0000000..6166eb0
--- /dev/null
+++ b/third_party/opus/src/celt/tests/test_unit_dft.c
@@ -0,0 +1,189 @@
+/* Copyright (c) 2008 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define SKIP_CONFIG_H
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#endif
+
+#include <stdio.h>
+
+#define CELT_C
+#define TEST_UNIT_DFT_C
+#include "stack_alloc.h"
+#include "kiss_fft.h"
+#include "kiss_fft.c"
+#include "mathops.c"
+#include "entcode.c"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1)
+# include "x86/x86cpu.c"
+#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+# include "arm/armcpu.c"
+# include "celt_lpc.c"
+# include "pitch.c"
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+#  include "arm/celt_neon_intr.c"
+#  if defined(HAVE_ARM_NE10)
+#   include "mdct.c"
+#   include "arm/celt_ne10_fft.c"
+#   include "arm/celt_ne10_mdct.c"
+#  endif
+# endif
+# include "arm/arm_celt_map.c"
+#endif
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+int ret = 0;
+
+void check(kiss_fft_cpx  * in,kiss_fft_cpx  * out,int nfft,int isinverse)
+{
+    int bin,k;
+    double errpow=0,sigpow=0, snr;
+
+    for (bin=0;bin<nfft;++bin) {
+        double ansr = 0;
+        double ansi = 0;
+        double difr;
+        double difi;
+
+        for (k=0;k<nfft;++k) {
+            double phase = -2*M_PI*bin*k/nfft;
+            double re = cos(phase);
+            double im = sin(phase);
+            if (isinverse)
+                im = -im;
+
+            if (!isinverse)
+            {
+               re /= nfft;
+               im /= nfft;
+            }
+
+            ansr += in[k].r * re - in[k].i * im;
+            ansi += in[k].r * im + in[k].i * re;
+        }
+        /*printf ("%d %d ", (int)ansr, (int)ansi);*/
+        difr = ansr - out[bin].r;
+        difi = ansi - out[bin].i;
+        errpow += difr*difr + difi*difi;
+        sigpow += ansr*ansr+ansi*ansi;
+    }
+    snr = 10*log10(sigpow/errpow);
+    printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
+    if (snr<60) {
+       printf( "** poor snr: %f ** \n", snr);
+       ret = 1;
+    }
+}
+
+void test1d(int nfft,int isinverse,int arch)
+{
+    size_t buflen = sizeof(kiss_fft_cpx)*nfft;
+
+    kiss_fft_cpx  * in = (kiss_fft_cpx*)malloc(buflen);
+    kiss_fft_cpx  * out= (kiss_fft_cpx*)malloc(buflen);
+    kiss_fft_state *cfg = opus_fft_alloc(nfft,0,0,arch);
+    int k;
+
+    for (k=0;k<nfft;++k) {
+        in[k].r = (rand() % 32767) - 16384;
+        in[k].i = (rand() % 32767) - 16384;
+    }
+
+    for (k=0;k<nfft;++k) {
+       in[k].r *= 32768;
+       in[k].i *= 32768;
+    }
+
+    if (isinverse)
+    {
+       for (k=0;k<nfft;++k) {
+          in[k].r /= nfft;
+          in[k].i /= nfft;
+       }
+    }
+
+    /*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/
+
+    if (isinverse)
+       opus_ifft(cfg,in,out, arch);
+    else
+       opus_fft(cfg,in,out, arch);
+
+    /*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/
+
+    check(in,out,nfft,isinverse);
+
+    free(in);
+    free(out);
+    opus_fft_free(cfg, arch);
+}
+
+int main(int argc,char ** argv)
+{
+    ALLOC_STACK;
+    int arch = opus_select_arch();
+
+    if (argc>1) {
+        int k;
+        for (k=1;k<argc;++k) {
+            test1d(atoi(argv[k]),0,arch);
+            test1d(atoi(argv[k]),1,arch);
+        }
+    }else{
+        test1d(32,0,arch);
+        test1d(32,1,arch);
+        test1d(128,0,arch);
+        test1d(128,1,arch);
+        test1d(256,0,arch);
+        test1d(256,1,arch);
+#ifndef RADIX_TWO_ONLY
+        test1d(36,0,arch);
+        test1d(36,1,arch);
+        test1d(50,0,arch);
+        test1d(50,1,arch);
+        test1d(60,0,arch);
+        test1d(60,1,arch);
+        test1d(120,0,arch);
+        test1d(120,1,arch);
+        test1d(240,0,arch);
+        test1d(240,1,arch);
+        test1d(480,0,arch);
+        test1d(480,1,arch);
+#endif
+    }
+    return ret;
+}
diff --git a/third_party/opus/src/celt/tests/test_unit_entropy.c b/third_party/opus/src/celt/tests/test_unit_entropy.c
new file mode 100644
index 0000000..ff926586
--- /dev/null
+++ b/third_party/opus/src/celt/tests/test_unit_entropy.c
@@ -0,0 +1,382 @@
+/* Copyright (c) 2007-2011 Xiph.Org Foundation, Mozilla Corporation,
+                           Gregory Maxwell
+   Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+#include "entcode.h"
+#include "entenc.h"
+#include "entdec.h"
+#include <string.h>
+
+#include "entenc.c"
+#include "entdec.c"
+#include "entcode.c"
+
+#ifndef M_LOG2E
+# define M_LOG2E    1.4426950408889634074
+#endif
+#define DATA_SIZE 10000000
+#define DATA_SIZE2 10000
+
+int main(int _argc,char **_argv){
+  ec_enc         enc;
+  ec_dec         dec;
+  long           nbits;
+  long           nbits2;
+  double         entropy;
+  int            ft;
+  int            ftb;
+  int            sz;
+  int            i;
+  int            ret;
+  unsigned int   sym;
+  unsigned int   seed;
+  unsigned char *ptr;
+  const char    *env_seed;
+  ret=0;
+  entropy=0;
+  if (_argc > 2) {
+    fprintf(stderr, "Usage: %s [<seed>]\n", _argv[0]);
+    return 1;
+  }
+  env_seed = getenv("SEED");
+  if (_argc > 1)
+    seed = atoi(_argv[1]);
+  else if (env_seed)
+    seed = atoi(env_seed);
+  else
+    seed = time(NULL);
+  /*Testing encoding of raw bit values.*/
+  ptr = (unsigned char *)malloc(DATA_SIZE);
+  ec_enc_init(&enc,ptr, DATA_SIZE);
+  for(ft=2;ft<1024;ft++){
+    for(i=0;i<ft;i++){
+      entropy+=log(ft)*M_LOG2E;
+      ec_enc_uint(&enc,i,ft);
+    }
+  }
+  /*Testing encoding of raw bit values.*/
+  for(ftb=1;ftb<16;ftb++){
+    for(i=0;i<(1<<ftb);i++){
+      entropy+=ftb;
+      nbits=ec_tell(&enc);
+      ec_enc_bits(&enc,i,ftb);
+      nbits2=ec_tell(&enc);
+      if(nbits2-nbits!=ftb){
+        fprintf(stderr,"Used %li bits to encode %i bits directly.\n",
+         nbits2-nbits,ftb);
+        ret=-1;
+      }
+    }
+  }
+  nbits=ec_tell_frac(&enc);
+  ec_enc_done(&enc);
+  fprintf(stderr,
+   "Encoded %0.2lf bits of entropy to %0.2lf bits (%0.3lf%% wasted).\n",
+   entropy,ldexp(nbits,-3),100*(nbits-ldexp(entropy,3))/nbits);
+  fprintf(stderr,"Packed to %li bytes.\n",(long)ec_range_bytes(&enc));
+  ec_dec_init(&dec,ptr,DATA_SIZE);
+  for(ft=2;ft<1024;ft++){
+    for(i=0;i<ft;i++){
+      sym=ec_dec_uint(&dec,ft);
+      if(sym!=(unsigned)i){
+        fprintf(stderr,"Decoded %i instead of %i with ft of %i.\n",sym,i,ft);
+        ret=-1;
+      }
+    }
+  }
+  for(ftb=1;ftb<16;ftb++){
+    for(i=0;i<(1<<ftb);i++){
+      sym=ec_dec_bits(&dec,ftb);
+      if(sym!=(unsigned)i){
+        fprintf(stderr,"Decoded %i instead of %i with ftb of %i.\n",sym,i,ftb);
+        ret=-1;
+      }
+    }
+  }
+  nbits2=ec_tell_frac(&dec);
+  if(nbits!=nbits2){
+    fprintf(stderr,
+     "Reported number of bits used was %0.2lf, should be %0.2lf.\n",
+     ldexp(nbits2,-3),ldexp(nbits,-3));
+    ret=-1;
+  }
+  /*Testing an encoder bust prefers range coder data over raw bits.
+    This isn't a general guarantee, will only work for data that is buffered in
+     the encoder state and not yet stored in the user buffer, and should never
+     get used in practice.
+    It's mostly here for code coverage completeness.*/
+  /*Start with a 16-bit buffer.*/
+  ec_enc_init(&enc,ptr,2);
+  /*Write 7 raw bits.*/
+  ec_enc_bits(&enc,0x55,7);
+  /*Write 12.3 bits of range coder data.*/
+  ec_enc_uint(&enc,1,2);
+  ec_enc_uint(&enc,1,3);
+  ec_enc_uint(&enc,1,4);
+  ec_enc_uint(&enc,1,5);
+  ec_enc_uint(&enc,2,6);
+  ec_enc_uint(&enc,6,7);
+  ec_enc_done(&enc);
+  ec_dec_init(&dec,ptr,2);
+  if(!enc.error
+   /*The raw bits should have been overwritten by the range coder data.*/
+   ||ec_dec_bits(&dec,7)!=0x05
+   /*And all the range coder data should have been encoded correctly.*/
+   ||ec_dec_uint(&dec,2)!=1
+   ||ec_dec_uint(&dec,3)!=1
+   ||ec_dec_uint(&dec,4)!=1
+   ||ec_dec_uint(&dec,5)!=1
+   ||ec_dec_uint(&dec,6)!=2
+   ||ec_dec_uint(&dec,7)!=6){
+    fprintf(stderr,"Encoder bust overwrote range coder data with raw bits.\n");
+    ret=-1;
+  }
+  srand(seed);
+  fprintf(stderr,"Testing random streams... Random seed: %u (%.4X)\n", seed, rand() % 65536);
+  for(i=0;i<409600;i++){
+    unsigned *data;
+    unsigned *tell;
+    unsigned tell_bits;
+    int       j;
+    int zeros;
+    ft=rand()/((RAND_MAX>>(rand()%11U))+1U)+10;
+    sz=rand()/((RAND_MAX>>(rand()%9U))+1U);
+    data=(unsigned *)malloc(sz*sizeof(*data));
+    tell=(unsigned *)malloc((sz+1)*sizeof(*tell));
+    ec_enc_init(&enc,ptr,DATA_SIZE2);
+    zeros = rand()%13==0;
+    tell[0]=ec_tell_frac(&enc);
+    for(j=0;j<sz;j++){
+      if (zeros)
+        data[j]=0;
+      else
+        data[j]=rand()%ft;
+      ec_enc_uint(&enc,data[j],ft);
+      tell[j+1]=ec_tell_frac(&enc);
+    }
+    if (rand()%2==0)
+      while(ec_tell(&enc)%8 != 0)
+        ec_enc_uint(&enc, rand()%2, 2);
+    tell_bits = ec_tell(&enc);
+    ec_enc_done(&enc);
+    if(tell_bits!=(unsigned)ec_tell(&enc)){
+      fprintf(stderr,"ec_tell() changed after ec_enc_done(): %i instead of %i (Random seed: %u)\n",
+       ec_tell(&enc),tell_bits,seed);
+      ret=-1;
+    }
+    if ((tell_bits+7)/8 < ec_range_bytes(&enc))
+    {
+      fprintf (stderr, "ec_tell() lied, there's %i bytes instead of %d (Random seed: %u)\n",
+               ec_range_bytes(&enc), (tell_bits+7)/8,seed);
+      ret=-1;
+    }
+    ec_dec_init(&dec,ptr,DATA_SIZE2);
+    if(ec_tell_frac(&dec)!=tell[0]){
+      fprintf(stderr,
+       "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
+       0,ec_tell_frac(&dec),tell[0],seed);
+    }
+    for(j=0;j<sz;j++){
+      sym=ec_dec_uint(&dec,ft);
+      if(sym!=data[j]){
+        fprintf(stderr,
+         "Decoded %i instead of %i with ft of %i at position %i of %i (Random seed: %u).\n",
+         sym,data[j],ft,j,sz,seed);
+        ret=-1;
+      }
+      if(ec_tell_frac(&dec)!=tell[j+1]){
+        fprintf(stderr,
+         "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
+         j+1,ec_tell_frac(&dec),tell[j+1],seed);
+      }
+    }
+    free(tell);
+    free(data);
+  }
+  /*Test compatibility between multiple different encode/decode routines.*/
+  for(i=0;i<409600;i++){
+    unsigned *logp1;
+    unsigned *data;
+    unsigned *tell;
+    unsigned *enc_method;
+    int       j;
+    sz=rand()/((RAND_MAX>>(rand()%9U))+1U);
+    logp1=(unsigned *)malloc(sz*sizeof(*logp1));
+    data=(unsigned *)malloc(sz*sizeof(*data));
+    tell=(unsigned *)malloc((sz+1)*sizeof(*tell));
+    enc_method=(unsigned *)malloc(sz*sizeof(*enc_method));
+    ec_enc_init(&enc,ptr,DATA_SIZE2);
+    tell[0]=ec_tell_frac(&enc);
+    for(j=0;j<sz;j++){
+      data[j]=rand()/((RAND_MAX>>1)+1);
+      logp1[j]=(rand()%15)+1;
+      enc_method[j]=rand()/((RAND_MAX>>2)+1);
+      switch(enc_method[j]){
+        case 0:{
+          ec_encode(&enc,data[j]?(1<<logp1[j])-1:0,
+           (1<<logp1[j])-(data[j]?0:1),1<<logp1[j]);
+        }break;
+        case 1:{
+          ec_encode_bin(&enc,data[j]?(1<<logp1[j])-1:0,
+           (1<<logp1[j])-(data[j]?0:1),logp1[j]);
+        }break;
+        case 2:{
+          ec_enc_bit_logp(&enc,data[j],logp1[j]);
+        }break;
+        case 3:{
+          unsigned char icdf[2];
+          icdf[0]=1;
+          icdf[1]=0;
+          ec_enc_icdf(&enc,data[j],icdf,logp1[j]);
+        }break;
+      }
+      tell[j+1]=ec_tell_frac(&enc);
+    }
+    ec_enc_done(&enc);
+    if((ec_tell(&enc)+7U)/8U<ec_range_bytes(&enc)){
+      fprintf(stderr,"tell() lied, there's %i bytes instead of %d (Random seed: %u)\n",
+       ec_range_bytes(&enc),(ec_tell(&enc)+7)/8,seed);
+      ret=-1;
+    }
+    ec_dec_init(&dec,ptr,DATA_SIZE2);
+    if(ec_tell_frac(&dec)!=tell[0]){
+      fprintf(stderr,
+       "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
+       0,ec_tell_frac(&dec),tell[0],seed);
+    }
+    for(j=0;j<sz;j++){
+      int fs;
+      int dec_method;
+      dec_method=rand()/((RAND_MAX>>2)+1);
+      switch(dec_method){
+        case 0:{
+          fs=ec_decode(&dec,1<<logp1[j]);
+          sym=fs>=(1<<logp1[j])-1;
+          ec_dec_update(&dec,sym?(1<<logp1[j])-1:0,
+           (1<<logp1[j])-(sym?0:1),1<<logp1[j]);
+        }break;
+        case 1:{
+          fs=ec_decode_bin(&dec,logp1[j]);
+          sym=fs>=(1<<logp1[j])-1;
+          ec_dec_update(&dec,sym?(1<<logp1[j])-1:0,
+           (1<<logp1[j])-(sym?0:1),1<<logp1[j]);
+        }break;
+        case 2:{
+          sym=ec_dec_bit_logp(&dec,logp1[j]);
+        }break;
+        case 3:{
+          unsigned char icdf[2];
+          icdf[0]=1;
+          icdf[1]=0;
+          sym=ec_dec_icdf(&dec,icdf,logp1[j]);
+        }break;
+      }
+      if(sym!=data[j]){
+        fprintf(stderr,
+         "Decoded %i instead of %i with logp1 of %i at position %i of %i (Random seed: %u).\n",
+         sym,data[j],logp1[j],j,sz,seed);
+        fprintf(stderr,"Encoding method: %i, decoding method: %i\n",
+         enc_method[j],dec_method);
+        ret=-1;
+      }
+      if(ec_tell_frac(&dec)!=tell[j+1]){
+        fprintf(stderr,
+         "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
+         j+1,ec_tell_frac(&dec),tell[j+1],seed);
+      }
+    }
+    free(enc_method);
+    free(tell);
+    free(data);
+    free(logp1);
+  }
+  ec_enc_init(&enc,ptr,DATA_SIZE2);
+  ec_enc_bit_logp(&enc,0,1);
+  ec_enc_bit_logp(&enc,0,1);
+  ec_enc_bit_logp(&enc,0,1);
+  ec_enc_bit_logp(&enc,0,1);
+  ec_enc_bit_logp(&enc,0,2);
+  ec_enc_patch_initial_bits(&enc,3,2);
+  if(enc.error){
+    fprintf(stderr,"patch_initial_bits failed");
+    ret=-1;
+  }
+  ec_enc_patch_initial_bits(&enc,0,5);
+  if(!enc.error){
+    fprintf(stderr,"patch_initial_bits didn't fail when it should have");
+    ret=-1;
+  }
+  ec_enc_done(&enc);
+  if(ec_range_bytes(&enc)!=1||ptr[0]!=192){
+    fprintf(stderr,"Got %d when expecting 192 for patch_initial_bits",ptr[0]);
+    ret=-1;
+  }
+  ec_enc_init(&enc,ptr,DATA_SIZE2);
+  ec_enc_bit_logp(&enc,0,1);
+  ec_enc_bit_logp(&enc,0,1);
+  ec_enc_bit_logp(&enc,1,6);
+  ec_enc_bit_logp(&enc,0,2);
+  ec_enc_patch_initial_bits(&enc,0,2);
+  if(enc.error){
+    fprintf(stderr,"patch_initial_bits failed");
+    ret=-1;
+  }
+  ec_enc_done(&enc);
+  if(ec_range_bytes(&enc)!=2||ptr[0]!=63){
+    fprintf(stderr,"Got %d when expecting 63 for patch_initial_bits",ptr[0]);
+    ret=-1;
+  }
+  ec_enc_init(&enc,ptr,2);
+  ec_enc_bit_logp(&enc,0,2);
+  for(i=0;i<48;i++){
+    ec_enc_bits(&enc,0,1);
+  }
+  ec_enc_done(&enc);
+  if(!enc.error){
+    fprintf(stderr,"Raw bits overfill didn't fail when it should have");
+    ret=-1;
+  }
+  ec_enc_init(&enc,ptr,2);
+  for(i=0;i<17;i++){
+    ec_enc_bits(&enc,0,1);
+  }
+  ec_enc_done(&enc);
+  if(!enc.error){
+    fprintf(stderr,"17 raw bits encoded in two bytes");
+    ret=-1;
+  }
+  free(ptr);
+  return ret;
+}
diff --git a/third_party/opus/src/celt/tests/test_unit_laplace.c b/third_party/opus/src/celt/tests/test_unit_laplace.c
new file mode 100644
index 0000000..22951e29
--- /dev/null
+++ b/third_party/opus/src/celt/tests/test_unit_laplace.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation
+   Written by Jean-Marc Valin and Timothy B. Terriberry */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "laplace.h"
+#define CELT_C
+#include "stack_alloc.h"
+
+#include "entenc.c"
+#include "entdec.c"
+#include "entcode.c"
+#include "laplace.c"
+
+#define DATA_SIZE 40000
+
+int ec_laplace_get_start_freq(int decay)
+{
+   opus_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1);
+   int fs = (ft*(16384-decay))/(16384+decay);
+   return fs+LAPLACE_MINP;
+}
+
+int main(void)
+{
+   int i;
+   int ret = 0;
+   ec_enc enc;
+   ec_dec dec;
+   unsigned char *ptr;
+   int val[10000], decay[10000];
+   ALLOC_STACK;
+   ptr = (unsigned char *)malloc(DATA_SIZE);
+   ec_enc_init(&enc,ptr,DATA_SIZE);
+
+   val[0] = 3; decay[0] = 6000;
+   val[1] = 0; decay[1] = 5800;
+   val[2] = -1; decay[2] = 5600;
+   for (i=3;i<10000;i++)
+   {
+      val[i] = rand()%15-7;
+      decay[i] = rand()%11000+5000;
+   }
+   for (i=0;i<10000;i++)
+      ec_laplace_encode(&enc, &val[i],
+            ec_laplace_get_start_freq(decay[i]), decay[i]);
+
+   ec_enc_done(&enc);
+
+   ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc));
+
+   for (i=0;i<10000;i++)
+   {
+      int d = ec_laplace_decode(&dec,
+            ec_laplace_get_start_freq(decay[i]), decay[i]);
+      if (d != val[i])
+      {
+         fprintf (stderr, "Got %d instead of %d\n", d, val[i]);
+         ret = 1;
+      }
+   }
+
+   free(ptr);
+   return ret;
+}
diff --git a/third_party/opus/src/celt/tests/test_unit_mathops.c b/third_party/opus/src/celt/tests/test_unit_mathops.c
new file mode 100644
index 0000000..fd3319d
--- /dev/null
+++ b/third_party/opus/src/celt/tests/test_unit_mathops.c
@@ -0,0 +1,304 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation,
+                           Gregory Maxwell
+   Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#endif
+
+#define CELT_C
+
+#include <stdio.h>
+#include <math.h>
+#include "mathops.c"
+#include "entenc.c"
+#include "entdec.c"
+#include "entcode.c"
+#include "bands.c"
+#include "quant_bands.c"
+#include "laplace.c"
+#include "vq.c"
+#include "cwrs.c"
+#include "pitch.c"
+#include "celt_lpc.c"
+#include "celt.c"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) || defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1)
+# if defined(OPUS_X86_MAY_HAVE_SSE)
+#  include "x86/pitch_sse.c"
+# endif
+# if defined(OPUS_X86_MAY_HAVE_SSE2)
+#  include "x86/pitch_sse2.c"
+# endif
+# if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#  include "x86/pitch_sse4_1.c"
+#  include "x86/celt_lpc_sse.c"
+# endif
+# include "x86/x86_celt_map.c"
+#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+# include "arm/armcpu.c"
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+#  include "arm/celt_neon_intr.c"
+#  if defined(HAVE_ARM_NE10)
+#   include "kiss_fft.c"
+#   include "mdct.c"
+#   include "arm/celt_ne10_fft.c"
+#   include "arm/celt_ne10_mdct.c"
+#  endif
+# endif
+# include "arm/arm_celt_map.c"
+#endif
+
+#ifdef FIXED_POINT
+#define WORD "%d"
+#else
+#define WORD "%f"
+#endif
+
+int ret = 0;
+
+void testdiv(void)
+{
+   opus_int32 i;
+   for (i=1;i<=327670;i++)
+   {
+      double prod;
+      opus_val32 val;
+      val = celt_rcp(i);
+#ifdef FIXED_POINT
+      prod = (1./32768./65526.)*val*i;
+#else
+      prod = val*i;
+#endif
+      if (fabs(prod-1) > .00025)
+      {
+         fprintf (stderr, "div failed: 1/%d="WORD" (product = %f)\n", i, val, prod);
+         ret = 1;
+      }
+   }
+}
+
+void testsqrt(void)
+{
+   opus_int32 i;
+   for (i=1;i<=1000000000;i++)
+   {
+      double ratio;
+      opus_val16 val;
+      val = celt_sqrt(i);
+      ratio = val/sqrt(i);
+      if (fabs(ratio - 1) > .0005 && fabs(val-sqrt(i)) > 2)
+      {
+         fprintf (stderr, "sqrt failed: sqrt(%d)="WORD" (ratio = %f)\n", i, val, ratio);
+         ret = 1;
+      }
+      i+= i>>10;
+   }
+}
+
+void testbitexactcos(void)
+{
+   int i;
+   opus_int32 min_d,max_d,last,chk;
+   chk=max_d=0;
+   last=min_d=32767;
+   for(i=64;i<=16320;i++)
+   {
+      opus_int32 d;
+      opus_int32 q=bitexact_cos(i);
+      chk ^= q*i;
+      d = last - q;
+      if (d>max_d)max_d=d;
+      if (d<min_d)min_d=d;
+      last = q;
+   }
+   if ((chk!=89408644)||(max_d!=5)||(min_d!=0)||(bitexact_cos(64)!=32767)||
+       (bitexact_cos(16320)!=200)||(bitexact_cos(8192)!=23171))
+   {
+      fprintf (stderr, "bitexact_cos failed\n");
+      ret = 1;
+   }
+}
+
+void testbitexactlog2tan(void)
+{
+   int i,fail;
+   opus_int32 min_d,max_d,last,chk;
+   fail=chk=max_d=0;
+   last=min_d=15059;
+   for(i=64;i<8193;i++)
+   {
+      opus_int32 d;
+      opus_int32 mid=bitexact_cos(i);
+      opus_int32 side=bitexact_cos(16384-i);
+      opus_int32 q=bitexact_log2tan(mid,side);
+      chk ^= q*i;
+      d = last - q;
+      if (q!=-1*bitexact_log2tan(side,mid))
+        fail = 1;
+      if (d>max_d)max_d=d;
+      if (d<min_d)min_d=d;
+      last = q;
+   }
+   if ((chk!=15821257)||(max_d!=61)||(min_d!=-2)||fail||
+       (bitexact_log2tan(32767,200)!=15059)||(bitexact_log2tan(30274,12540)!=2611)||
+       (bitexact_log2tan(23171,23171)!=0))
+   {
+      fprintf (stderr, "bitexact_log2tan failed\n");
+      ret = 1;
+   }
+}
+
+#ifndef FIXED_POINT
+void testlog2(void)
+{
+   float x;
+   for (x=0.001;x<1677700.0;x+=(x/8.0))
+   {
+      float error = fabs((1.442695040888963387*log(x))-celt_log2(x));
+      if (error>0.0009)
+      {
+         fprintf (stderr, "celt_log2 failed: fabs((1.442695040888963387*log(x))-celt_log2(x))>0.001 (x = %f, error = %f)\n", x,error);
+         ret = 1;
+      }
+   }
+}
+
+void testexp2(void)
+{
+   float x;
+   for (x=-11.0;x<24.0;x+=0.0007)
+   {
+      float error = fabs(x-(1.442695040888963387*log(celt_exp2(x))));
+      if (error>0.0002)
+      {
+         fprintf (stderr, "celt_exp2 failed: fabs(x-(1.442695040888963387*log(celt_exp2(x))))>0.0005 (x = %f, error = %f)\n", x,error);
+         ret = 1;
+      }
+   }
+}
+
+void testexp2log2(void)
+{
+   float x;
+   for (x=-11.0;x<24.0;x+=0.0007)
+   {
+      float error = fabs(x-(celt_log2(celt_exp2(x))));
+      if (error>0.001)
+      {
+         fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_log2(celt_exp2(x))))>0.001 (x = %f, error = %f)\n", x,error);
+         ret = 1;
+      }
+   }
+}
+#else
+void testlog2(void)
+{
+   opus_val32 x;
+   for (x=8;x<1073741824;x+=(x>>3))
+   {
+      float error = fabs((1.442695040888963387*log(x/16384.0))-celt_log2(x)/1024.0);
+      if (error>0.003)
+      {
+         fprintf (stderr, "celt_log2 failed: x = %ld, error = %f\n", (long)x,error);
+         ret = 1;
+      }
+   }
+}
+
+void testexp2(void)
+{
+   opus_val16 x;
+   for (x=-32768;x<15360;x++)
+   {
+      float error1 = fabs(x/1024.0-(1.442695040888963387*log(celt_exp2(x)/65536.0)));
+      float error2 = fabs(exp(0.6931471805599453094*x/1024.0)-celt_exp2(x)/65536.0);
+      if (error1>0.0002&&error2>0.00004)
+      {
+         fprintf (stderr, "celt_exp2 failed: x = "WORD", error1 = %f, error2 = %f\n", x,error1,error2);
+         ret = 1;
+      }
+   }
+}
+
+void testexp2log2(void)
+{
+   opus_val32 x;
+   for (x=8;x<65536;x+=(x>>3))
+   {
+      float error = fabs(x-0.25*celt_exp2(celt_log2(x)))/16384;
+      if (error>0.004)
+      {
+         fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_exp2(celt_log2(x))))>0.001 (x = %ld, error = %f)\n", (long)x,error);
+         ret = 1;
+      }
+   }
+}
+
+void testilog2(void)
+{
+   opus_val32 x;
+   for (x=1;x<=268435455;x+=127)
+   {
+      opus_val32 lg;
+      opus_val32 y;
+
+      lg = celt_ilog2(x);
+      if (lg<0 || lg>=31)
+      {
+         printf("celt_ilog2 failed: 0<=celt_ilog2(x)<31 (x = %d, celt_ilog2(x) = %d)\n",x,lg);
+         ret = 1;
+      }
+      y = 1<<lg;
+
+      if (x<y || (x>>1)>=y)
+      {
+         printf("celt_ilog2 failed: 2**celt_ilog2(x)<=x<2**(celt_ilog2(x)+1) (x = %d, 2**celt_ilog2(x) = %d)\n",x,y);
+         ret = 1;
+      }
+   }
+}
+#endif
+
+int main(void)
+{
+   testbitexactcos();
+   testbitexactlog2tan();
+   testdiv();
+   testsqrt();
+   testlog2();
+   testexp2();
+   testexp2log2();
+#ifdef FIXED_POINT
+   testilog2();
+#endif
+   return ret;
+}
diff --git a/third_party/opus/src/celt/tests/test_unit_mdct.c b/third_party/opus/src/celt/tests/test_unit_mdct.c
new file mode 100644
index 0000000..8dbb9ca
--- /dev/null
+++ b/third_party/opus/src/celt/tests/test_unit_mdct.c
@@ -0,0 +1,230 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define SKIP_CONFIG_H
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#endif
+
+#include <stdio.h>
+
+#define CELT_C
+#include "mdct.h"
+#include "stack_alloc.h"
+
+#include "kiss_fft.c"
+#include "mdct.c"
+#include "mathops.c"
+#include "entcode.c"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1)
+# include "x86/x86cpu.c"
+#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+# include "arm/armcpu.c"
+# include "pitch.c"
+# include "celt_lpc.c"
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+#  include "arm/celt_neon_intr.c"
+#  if defined(HAVE_ARM_NE10)
+#   include "arm/celt_ne10_fft.c"
+#   include "arm/celt_ne10_mdct.c"
+#  endif
+# endif
+# include "arm/arm_celt_map.c"
+#endif
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+int ret = 0;
+void check(kiss_fft_scalar  * in,kiss_fft_scalar  * out,int nfft,int isinverse)
+{
+    int bin,k;
+    double errpow=0,sigpow=0;
+    double snr;
+    for (bin=0;bin<nfft/2;++bin) {
+        double ansr = 0;
+        double difr;
+
+        for (k=0;k<nfft;++k) {
+           double phase = 2*M_PI*(k+.5+.25*nfft)*(bin+.5)/nfft;
+           double re = cos(phase);
+
+           re /= nfft/4;
+
+           ansr += in[k] * re;
+        }
+        /*printf ("%f %f\n", ansr, out[bin]);*/
+        difr = ansr - out[bin];
+        errpow += difr*difr;
+        sigpow += ansr*ansr;
+    }
+    snr = 10*log10(sigpow/errpow);
+    printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
+    if (snr<60) {
+       printf( "** poor snr: %f **\n", snr);
+       ret = 1;
+    }
+}
+
+void check_inv(kiss_fft_scalar  * in,kiss_fft_scalar  * out,int nfft,int isinverse)
+{
+   int bin,k;
+   double errpow=0,sigpow=0;
+   double snr;
+   for (bin=0;bin<nfft;++bin) {
+      double ansr = 0;
+      double difr;
+
+      for (k=0;k<nfft/2;++k) {
+         double phase = 2*M_PI*(bin+.5+.25*nfft)*(k+.5)/nfft;
+         double re = cos(phase);
+
+         /*re *= 2;*/
+
+         ansr += in[k] * re;
+      }
+      /*printf ("%f %f\n", ansr, out[bin]);*/
+      difr = ansr - out[bin];
+      errpow += difr*difr;
+      sigpow += ansr*ansr;
+   }
+   snr = 10*log10(sigpow/errpow);
+   printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
+   if (snr<60) {
+      printf( "** poor snr: %f **\n", snr);
+      ret = 1;
+   }
+}
+
+
+void test1d(int nfft,int isinverse,int arch)
+{
+    mdct_lookup cfg;
+    size_t buflen = sizeof(kiss_fft_scalar)*nfft;
+
+    kiss_fft_scalar  * in = (kiss_fft_scalar*)malloc(buflen);
+    kiss_fft_scalar  * in_copy = (kiss_fft_scalar*)malloc(buflen);
+    kiss_fft_scalar  * out= (kiss_fft_scalar*)malloc(buflen);
+    opus_val16  * window= (opus_val16*)malloc(sizeof(opus_val16)*nfft/2);
+    int k;
+
+    clt_mdct_init(&cfg, nfft, 0, arch);
+    for (k=0;k<nfft;++k) {
+        in[k] = (rand() % 32768) - 16384;
+    }
+
+    for (k=0;k<nfft/2;++k) {
+       window[k] = Q15ONE;
+    }
+    for (k=0;k<nfft;++k) {
+       in[k] *= 32768;
+    }
+
+    if (isinverse)
+    {
+       for (k=0;k<nfft;++k) {
+          in[k] /= nfft;
+       }
+    }
+
+    for (k=0;k<nfft;++k)
+       in_copy[k] = in[k];
+    /*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/
+
+    if (isinverse)
+    {
+       for (k=0;k<nfft;++k)
+          out[k] = 0;
+       clt_mdct_backward(&cfg,in,out, window, nfft/2, 0, 1, arch);
+       /* apply TDAC because clt_mdct_backward() no longer does that */
+       for (k=0;k<nfft/4;++k)
+          out[nfft-k-1] = out[nfft/2+k];
+       check_inv(in,out,nfft,isinverse);
+    } else {
+       clt_mdct_forward(&cfg,in,out,window, nfft/2, 0, 1, arch);
+       check(in_copy,out,nfft,isinverse);
+    }
+    /*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/
+
+
+    free(in);
+    free(in_copy);
+    free(out);
+    free(window);
+    clt_mdct_clear(&cfg, arch);
+}
+
+int main(int argc,char ** argv)
+{
+    ALLOC_STACK;
+    int arch = opus_select_arch();
+
+    if (argc>1) {
+        int k;
+        for (k=1;k<argc;++k) {
+            test1d(atoi(argv[k]),0,arch);
+            test1d(atoi(argv[k]),1,arch);
+        }
+    }else{
+        test1d(32,0,arch);
+        test1d(32,1,arch);
+        test1d(256,0,arch);
+        test1d(256,1,arch);
+        test1d(512,0,arch);
+        test1d(512,1,arch);
+        test1d(1024,0,arch);
+        test1d(1024,1,arch);
+        test1d(2048,0,arch);
+        test1d(2048,1,arch);
+#ifndef RADIX_TWO_ONLY
+        test1d(36,0,arch);
+        test1d(36,1,arch);
+        test1d(40,0,arch);
+        test1d(40,1,arch);
+        test1d(60,0,arch);
+        test1d(60,1,arch);
+        test1d(120,0,arch);
+        test1d(120,1,arch);
+        test1d(240,0,arch);
+        test1d(240,1,arch);
+        test1d(480,0,arch);
+        test1d(480,1,arch);
+        test1d(960,0,arch);
+        test1d(960,1,arch);
+        test1d(1920,0,arch);
+        test1d(1920,1,arch);
+#endif
+    }
+    return ret;
+}
diff --git a/third_party/opus/src/celt/tests/test_unit_rotation.c b/third_party/opus/src/celt/tests/test_unit_rotation.c
new file mode 100644
index 0000000..1080c208
--- /dev/null
+++ b/third_party/opus/src/celt/tests/test_unit_rotation.c
@@ -0,0 +1,120 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#endif
+
+#define CELT_C
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "vq.c"
+#include "cwrs.c"
+#include "entcode.c"
+#include "entenc.c"
+#include "entdec.c"
+#include "mathops.c"
+#include "bands.h"
+#include "pitch.c"
+#include "celt_lpc.c"
+#include "celt.c"
+#include <math.h>
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) || defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1)
+# if defined(OPUS_X86_MAY_HAVE_SSE)
+#  include "x86/pitch_sse.c"
+# endif
+# if defined(OPUS_X86_MAY_HAVE_SSE2)
+#  include "x86/pitch_sse2.c"
+# endif
+# if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#  include "x86/pitch_sse4_1.c"
+#  include "x86/celt_lpc_sse.c"
+# endif
+# include "x86/x86_celt_map.c"
+#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+# include "arm/armcpu.c"
+# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+#  include "arm/celt_neon_intr.c"
+#  if defined(HAVE_ARM_NE10)
+#   include "kiss_fft.c"
+#   include "mdct.c"
+#   include "arm/celt_ne10_fft.c"
+#   include "arm/celt_ne10_mdct.c"
+#  endif
+# endif
+# include "arm/arm_celt_map.c"
+#endif
+
+#define MAX_SIZE 100
+
+int ret=0;
+void test_rotation(int N, int K)
+{
+   int i;
+   double err = 0, ener = 0, snr, snr0;
+   opus_val16 x0[MAX_SIZE];
+   opus_val16 x1[MAX_SIZE];
+   for (i=0;i<N;i++)
+      x1[i] = x0[i] = rand()%32767-16384;
+   exp_rotation(x1, N, 1, 1, K, SPREAD_NORMAL);
+   for (i=0;i<N;i++)
+   {
+      err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
+      ener += x0[i]*(double)x0[i];
+   }
+   snr0 = 20*log10(ener/err);
+   err = ener = 0;
+   exp_rotation(x1, N, -1, 1, K, SPREAD_NORMAL);
+   for (i=0;i<N;i++)
+   {
+      err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
+      ener += x0[i]*(double)x0[i];
+   }
+   snr = 20*log10(ener/err);
+   printf ("SNR for size %d (%d pulses) is %f (was %f without inverse)\n", N, K, snr, snr0);
+   if (snr < 60 || snr0 > 20)
+   {
+      fprintf(stderr, "FAIL!\n");
+      ret = 1;
+   }
+}
+
+int main(void)
+{
+   ALLOC_STACK;
+   test_rotation(15, 3);
+   test_rotation(23, 5);
+   test_rotation(50, 3);
+   test_rotation(80, 1);
+   return ret;
+}
diff --git a/third_party/opus/src/celt/tests/test_unit_types.c b/third_party/opus/src/celt/tests/test_unit_types.c
new file mode 100644
index 0000000..67a0fb8e
--- /dev/null
+++ b/third_party/opus/src/celt/tests/test_unit_types.c
@@ -0,0 +1,50 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_types.h"
+#include <stdio.h>
+
+int main(void)
+{
+   opus_int16 i = 1;
+   i <<= 14;
+   if (i>>14 != 1)
+   {
+      fprintf(stderr, "opus_int16 isn't 16 bits\n");
+      return 1;
+   }
+   if (sizeof(opus_int16)*2 != sizeof(opus_int32))
+   {
+      fprintf(stderr, "16*2 != 32\n");
+      return 1;
+   }
+   return 0;
+}
diff --git a/third_party/opus/src/celt/vq.c b/third_party/opus/src/celt/vq.c
new file mode 100644
index 0000000..d29f38f
--- /dev/null
+++ b/third_party/opus/src/celt/vq.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mathops.h"
+#include "cwrs.h"
+#include "vq.h"
+#include "arch.h"
+#include "os_support.h"
+#include "bands.h"
+#include "rate.h"
+#include "pitch.h"
+
+#ifndef OVERRIDE_vq_exp_rotation1
+static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
+{
+   int i;
+   opus_val16 ms;
+   celt_norm *Xptr;
+   Xptr = X;
+   ms = NEG16(s);
+   for (i=0;i<len-stride;i++)
+   {
+      celt_norm x1, x2;
+      x1 = Xptr[0];
+      x2 = Xptr[stride];
+      Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2),  s, x1), 15));
+      *Xptr++      = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
+   }
+   Xptr = &X[len-2*stride-1];
+   for (i=len-2*stride-1;i>=0;i--)
+   {
+      celt_norm x1, x2;
+      x1 = Xptr[0];
+      x2 = Xptr[stride];
+      Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2),  s, x1), 15));
+      *Xptr--      = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15));
+   }
+}
+#endif /* OVERRIDE_vq_exp_rotation1 */
+
+static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread)
+{
+   static const int SPREAD_FACTOR[3]={15,10,5};
+   int i;
+   opus_val16 c, s;
+   opus_val16 gain, theta;
+   int stride2=0;
+   int factor;
+
+   if (2*K>=len || spread==SPREAD_NONE)
+      return;
+   factor = SPREAD_FACTOR[spread-1];
+
+   gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K));
+   theta = HALF16(MULT16_16_Q15(gain,gain));
+
+   c = celt_cos_norm(EXTEND32(theta));
+   s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /*  sin(theta) */
+
+   if (len>=8*stride)
+   {
+      stride2 = 1;
+      /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding.
+         It's basically incrementing long as (stride2+0.5)^2 < len/stride. */
+      while ((stride2*stride2+stride2)*stride + (stride>>2) < len)
+         stride2++;
+   }
+   /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
+      extract_collapse_mask().*/
+   len = celt_udiv(len, stride);
+   for (i=0;i<stride;i++)
+   {
+      if (dir < 0)
+      {
+         if (stride2)
+            exp_rotation1(X+i*len, len, stride2, s, c);
+         exp_rotation1(X+i*len, len, 1, c, s);
+      } else {
+         exp_rotation1(X+i*len, len, 1, c, -s);
+         if (stride2)
+            exp_rotation1(X+i*len, len, stride2, s, -c);
+      }
+   }
+}
+
+/** Takes the pitch vector and the decoded residual vector, computes the gain
+    that will give ||p+g*y||=1 and mixes the residual with the pitch. */
+static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X,
+      int N, opus_val32 Ryy, opus_val16 gain)
+{
+   int i;
+#ifdef FIXED_POINT
+   int k;
+#endif
+   opus_val32 t;
+   opus_val16 g;
+
+#ifdef FIXED_POINT
+   k = celt_ilog2(Ryy)>>1;
+#endif
+   t = VSHR32(Ryy, 2*(k-7));
+   g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
+
+   i=0;
+   do
+      X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1));
+   while (++i < N);
+}
+
+static unsigned extract_collapse_mask(int *iy, int N, int B)
+{
+   unsigned collapse_mask;
+   int N0;
+   int i;
+   if (B<=1)
+      return 1;
+   /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
+      exp_rotation().*/
+   N0 = celt_udiv(N, B);
+   collapse_mask = 0;
+   i=0; do {
+      int j;
+      unsigned tmp=0;
+      j=0; do {
+         tmp |= iy[i*N0+j];
+      } while (++j<N0);
+      collapse_mask |= (tmp!=0)<<i;
+   } while (++i<B);
+   return collapse_mask;
+}
+
+unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
+#ifdef RESYNTH
+   , opus_val16 gain
+#endif
+   )
+{
+   VARDECL(celt_norm, y);
+   VARDECL(int, iy);
+   VARDECL(opus_val16, signx);
+   int i, j;
+   opus_val16 s;
+   int pulsesLeft;
+   opus_val32 sum;
+   opus_val32 xy;
+   opus_val16 yy;
+   unsigned collapse_mask;
+   SAVE_STACK;
+
+   celt_assert2(K>0, "alg_quant() needs at least one pulse");
+   celt_assert2(N>1, "alg_quant() needs at least two dimensions");
+
+   ALLOC(y, N, celt_norm);
+   ALLOC(iy, N, int);
+   ALLOC(signx, N, opus_val16);
+
+   exp_rotation(X, N, 1, B, K, spread);
+
+   /* Get rid of the sign */
+   sum = 0;
+   j=0; do {
+      if (X[j]>0)
+         signx[j]=1;
+      else {
+         signx[j]=-1;
+         X[j]=-X[j];
+      }
+      iy[j] = 0;
+      y[j] = 0;
+   } while (++j<N);
+
+   xy = yy = 0;
+
+   pulsesLeft = K;
+
+   /* Do a pre-search by projecting on the pyramid */
+   if (K > (N>>1))
+   {
+      opus_val16 rcp;
+      j=0; do {
+         sum += X[j];
+      }  while (++j<N);
+
+      /* If X is too small, just replace it with a pulse at 0 */
+#ifdef FIXED_POINT
+      if (sum <= K)
+#else
+      /* Prevents infinities and NaNs from causing too many pulses
+         to be allocated. 64 is an approximation of infinity here. */
+      if (!(sum > EPSILON && sum < 64))
+#endif
+      {
+         X[0] = QCONST16(1.f,14);
+         j=1; do
+            X[j]=0;
+         while (++j<N);
+         sum = QCONST16(1.f,14);
+      }
+      rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
+      j=0; do {
+#ifdef FIXED_POINT
+         /* It's really important to round *towards zero* here */
+         iy[j] = MULT16_16_Q15(X[j],rcp);
+#else
+         iy[j] = (int)floor(rcp*X[j]);
+#endif
+         y[j] = (celt_norm)iy[j];
+         yy = MAC16_16(yy, y[j],y[j]);
+         xy = MAC16_16(xy, X[j],y[j]);
+         y[j] *= 2;
+         pulsesLeft -= iy[j];
+      }  while (++j<N);
+   }
+   celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
+
+   /* This should never happen, but just in case it does (e.g. on silence)
+      we fill the first bin with pulses. */
+#ifdef FIXED_POINT_DEBUG
+   celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass");
+#endif
+   if (pulsesLeft > N+3)
+   {
+      opus_val16 tmp = (opus_val16)pulsesLeft;
+      yy = MAC16_16(yy, tmp, tmp);
+      yy = MAC16_16(yy, tmp, y[0]);
+      iy[0] += pulsesLeft;
+      pulsesLeft=0;
+   }
+
+   s = 1;
+   for (i=0;i<pulsesLeft;i++)
+   {
+      int best_id;
+      opus_val32 best_num = -VERY_LARGE16;
+      opus_val16 best_den = 0;
+#ifdef FIXED_POINT
+      int rshift;
+#endif
+#ifdef FIXED_POINT
+      rshift = 1+celt_ilog2(K-pulsesLeft+i+1);
+#endif
+      best_id = 0;
+      /* The squared magnitude term gets added anyway, so we might as well
+         add it outside the loop */
+      yy = ADD16(yy, 1);
+      j=0;
+      do {
+         opus_val16 Rxy, Ryy;
+         /* Temporary sums of the new pulse(s) */
+         Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[j])),rshift));
+         /* We're multiplying y[j] by two so we don't have to do it here */
+         Ryy = ADD16(yy, y[j]);
+
+         /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
+            Rxy is positive because the sign is pre-computed) */
+         Rxy = MULT16_16_Q15(Rxy,Rxy);
+         /* The idea is to check for num/den >= best_num/best_den, but that way
+            we can do it without any division */
+         /* OPT: Make sure to use conditional moves here */
+         if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
+         {
+            best_den = Ryy;
+            best_num = Rxy;
+            best_id = j;
+         }
+      } while (++j<N);
+
+      /* Updating the sums of the new pulse(s) */
+      xy = ADD32(xy, EXTEND32(X[best_id]));
+      /* We're multiplying y[j] by two so we don't have to do it here */
+      yy = ADD16(yy, y[best_id]);
+
+      /* Only now that we've made the final choice, update y/iy */
+      /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
+      y[best_id] += 2*s;
+      iy[best_id]++;
+   }
+
+   /* Put the original sign back */
+   j=0;
+   do {
+      X[j] = MULT16_16(signx[j],X[j]);
+      if (signx[j] < 0)
+         iy[j] = -iy[j];
+   } while (++j<N);
+   encode_pulses(iy, N, K, enc);
+
+#ifdef RESYNTH
+   normalise_residual(iy, X, N, yy, gain);
+   exp_rotation(X, N, -1, B, K, spread);
+#endif
+
+   collapse_mask = extract_collapse_mask(iy, N, B);
+   RESTORE_STACK;
+   return collapse_mask;
+}
+
+/** Decode pulse vector and combine the result with the pitch vector to produce
+    the final normalised signal in the current band. */
+unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
+      ec_dec *dec, opus_val16 gain)
+{
+   opus_val32 Ryy;
+   unsigned collapse_mask;
+   VARDECL(int, iy);
+   SAVE_STACK;
+
+   celt_assert2(K>0, "alg_unquant() needs at least one pulse");
+   celt_assert2(N>1, "alg_unquant() needs at least two dimensions");
+   ALLOC(iy, N, int);
+   Ryy = decode_pulses(iy, N, K, dec);
+   normalise_residual(iy, X, N, Ryy, gain);
+   exp_rotation(X, N, -1, B, K, spread);
+   collapse_mask = extract_collapse_mask(iy, N, B);
+   RESTORE_STACK;
+   return collapse_mask;
+}
+
+#ifndef OVERRIDE_renormalise_vector
+void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch)
+{
+   int i;
+#ifdef FIXED_POINT
+   int k;
+#endif
+   opus_val32 E;
+   opus_val16 g;
+   opus_val32 t;
+   celt_norm *xptr;
+   E = EPSILON + celt_inner_prod(X, X, N, arch);
+#ifdef FIXED_POINT
+   k = celt_ilog2(E)>>1;
+#endif
+   t = VSHR32(E, 2*(k-7));
+   g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
+
+   xptr = X;
+   for (i=0;i<N;i++)
+   {
+      *xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k+1));
+      xptr++;
+   }
+   /*return celt_sqrt(E);*/
+}
+#endif /* OVERRIDE_renormalise_vector */
+
+int stereo_itheta(const celt_norm *X, const celt_norm *Y, int stereo, int N, int arch)
+{
+   int i;
+   int itheta;
+   opus_val16 mid, side;
+   opus_val32 Emid, Eside;
+
+   Emid = Eside = EPSILON;
+   if (stereo)
+   {
+      for (i=0;i<N;i++)
+      {
+         celt_norm m, s;
+         m = ADD16(SHR16(X[i],1),SHR16(Y[i],1));
+         s = SUB16(SHR16(X[i],1),SHR16(Y[i],1));
+         Emid = MAC16_16(Emid, m, m);
+         Eside = MAC16_16(Eside, s, s);
+      }
+   } else {
+      Emid += celt_inner_prod(X, X, N, arch);
+      Eside += celt_inner_prod(Y, Y, N, arch);
+   }
+   mid = celt_sqrt(Emid);
+   side = celt_sqrt(Eside);
+#ifdef FIXED_POINT
+   /* 0.63662 = 2/pi */
+   itheta = MULT16_16_Q15(QCONST16(0.63662f,15),celt_atan2p(side, mid));
+#else
+   itheta = (int)floor(.5f+16384*0.63662f*atan2(side,mid));
+#endif
+
+   return itheta;
+}
diff --git a/third_party/opus/src/celt/vq.h b/third_party/opus/src/celt/vq.h
new file mode 100644
index 0000000..5cfcbe50e
--- /dev/null
+++ b/third_party/opus/src/celt/vq.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/**
+   @file vq.h
+   @brief Vector quantisation of the residual
+ */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VQ_H
+#define VQ_H
+
+#include "entenc.h"
+#include "entdec.h"
+#include "modes.h"
+
+#if defined(MIPSr1_ASM)
+#include "mips/vq_mipsr1.h"
+#endif
+
+
+/** Algebraic pulse-vector quantiser. The signal x is replaced by the sum of
+  * the pitch and a combination of pulses such that its norm is still equal
+  * to 1. This is the function that will typically require the most CPU.
+ * @param X Residual signal to quantise/encode (returns quantised version)
+ * @param N Number of samples to encode
+ * @param K Number of pulses to use
+ * @param enc Entropy encoder state
+ * @ret A mask indicating which blocks in the band received pulses
+*/
+unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B,
+      ec_enc *enc
+#ifdef RESYNTH
+      , opus_val16 gain
+#endif
+      );
+
+/** Algebraic pulse decoder
+ * @param X Decoded normalised spectrum (returned)
+ * @param N Number of samples to decode
+ * @param K Number of pulses to use
+ * @param dec Entropy decoder state
+ * @ret A mask indicating which blocks in the band received pulses
+ */
+unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
+      ec_dec *dec, opus_val16 gain);
+
+void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch);
+
+int stereo_itheta(const celt_norm *X, const celt_norm *Y, int stereo, int N, int arch);
+
+#endif /* VQ_H */
diff --git a/third_party/opus/src/celt/x86/celt_lpc_sse.c b/third_party/opus/src/celt/x86/celt_lpc_sse.c
new file mode 100644
index 0000000..67e5592a
--- /dev/null
+++ b/third_party/opus/src/celt/x86/celt_lpc_sse.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+#include "x86cpu.h"
+
+#if defined(FIXED_POINT)
+
+void celt_fir_sse4_1(const opus_val16 *_x,
+         const opus_val16 *num,
+         opus_val16 *_y,
+         int N,
+         int ord,
+         opus_val16 *mem,
+         int arch)
+{
+    int i,j;
+    VARDECL(opus_val16, rnum);
+    VARDECL(opus_val16, x);
+
+    __m128i vecNoA;
+    opus_int32 noA ;
+    SAVE_STACK;
+
+   ALLOC(rnum, ord, opus_val16);
+   ALLOC(x, N+ord, opus_val16);
+   for(i=0;i<ord;i++)
+      rnum[i] = num[ord-i-1];
+   for(i=0;i<ord;i++)
+      x[i] = mem[ord-i-1];
+
+   for (i=0;i<N-7;i+=8)
+   {
+       x[i+ord  ]=_x[i  ];
+       x[i+ord+1]=_x[i+1];
+       x[i+ord+2]=_x[i+2];
+       x[i+ord+3]=_x[i+3];
+       x[i+ord+4]=_x[i+4];
+       x[i+ord+5]=_x[i+5];
+       x[i+ord+6]=_x[i+6];
+       x[i+ord+7]=_x[i+7];
+   }
+
+   for (;i<N-3;i+=4)
+   {
+       x[i+ord  ]=_x[i  ];
+       x[i+ord+1]=_x[i+1];
+       x[i+ord+2]=_x[i+2];
+       x[i+ord+3]=_x[i+3];
+   }
+
+   for (;i<N;i++)
+         x[i+ord]=_x[i];
+
+   for(i=0;i<ord;i++)
+      mem[i] = _x[N-i-1];
+#ifdef SMALL_FOOTPRINT
+   for (i=0;i<N;i++)
+   {
+      opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT);
+      for (j=0;j<ord;j++)
+      {
+         sum = MAC16_16(sum,rnum[j],x[i+j]);
+      }
+      _y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT));
+   }
+#else
+   noA = EXTEND32(1) << SIG_SHIFT >> 1;
+   vecNoA = _mm_set_epi32(noA, noA, noA, noA);
+
+   for (i=0;i<N-3;i+=4)
+   {
+      opus_val32 sums[4] = {0};
+      __m128i vecSum, vecX;
+
+      xcorr_kernel(rnum, x+i, sums, ord, arch);
+
+      vecSum = _mm_loadu_si128((__m128i *)sums);
+      vecSum = _mm_add_epi32(vecSum, vecNoA);
+      vecSum = _mm_srai_epi32(vecSum, SIG_SHIFT);
+      vecX = OP_CVTEPI16_EPI32_M64(_x + i);
+      vecSum = _mm_add_epi32(vecSum, vecX);
+      vecSum = _mm_packs_epi32(vecSum, vecSum);
+      _mm_storel_epi64((__m128i *)(_y + i), vecSum);
+   }
+   for (;i<N;i++)
+   {
+      opus_val32 sum = 0;
+      for (j=0;j<ord;j++)
+         sum = MAC16_16(sum, rnum[j], x[i + j]);
+      _y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT)));
+   }
+
+#endif
+   RESTORE_STACK;
+}
+
+#endif
diff --git a/third_party/opus/src/celt/x86/celt_lpc_sse.h b/third_party/opus/src/celt/x86/celt_lpc_sse.h
new file mode 100644
index 0000000..c5ec796
--- /dev/null
+++ b/third_party/opus/src/celt/x86/celt_lpc_sse.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CELT_LPC_SSE_H
+#define CELT_LPC_SSE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)
+#define OVERRIDE_CELT_FIR
+
+void celt_fir_sse4_1(
+         const opus_val16 *x,
+         const opus_val16 *num,
+         opus_val16 *y,
+         int N,
+         int ord,
+         opus_val16 *mem,
+         int arch);
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+#define celt_fir(x, num, y, N, ord, mem, arch) \
+    ((void)arch, celt_fir_sse4_1(x, num, y, N, ord, mem, arch))
+
+#else
+
+extern void (*const CELT_FIR_IMPL[OPUS_ARCHMASK + 1])(
+         const opus_val16 *x,
+         const opus_val16 *num,
+         opus_val16 *y,
+         int N,
+         int ord,
+         opus_val16 *mem,
+         int arch);
+
+#  define celt_fir(x, num, y, N, ord, mem, arch) \
+    ((*CELT_FIR_IMPL[(arch) & OPUS_ARCHMASK])(x, num, y, N, ord, mem, arch))
+
+#endif
+#endif
+
+#endif
diff --git a/third_party/opus/src/celt/x86/pitch_sse.c b/third_party/opus/src/celt/x86/pitch_sse.c
new file mode 100644
index 0000000..20e7312
--- /dev/null
+++ b/third_party/opus/src/celt/x86/pitch_sse.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "macros.h"
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT)
+
+#include <xmmintrin.h>
+#include "arch.h"
+
+void xcorr_kernel_sse(const opus_val16 *x, const opus_val16 *y, opus_val32 sum[4], int len)
+{
+   int j;
+   __m128 xsum1, xsum2;
+   xsum1 = _mm_loadu_ps(sum);
+   xsum2 = _mm_setzero_ps();
+
+   for (j = 0; j < len-3; j += 4)
+   {
+      __m128 x0 = _mm_loadu_ps(x+j);
+      __m128 yj = _mm_loadu_ps(y+j);
+      __m128 y3 = _mm_loadu_ps(y+j+3);
+
+      xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x00),yj));
+      xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x55),
+                                          _mm_shuffle_ps(yj,y3,0x49)));
+      xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xaa),
+                                          _mm_shuffle_ps(yj,y3,0x9e)));
+      xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xff),y3));
+   }
+   if (j < len)
+   {
+      xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+      if (++j < len)
+      {
+         xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+         if (++j < len)
+         {
+            xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+         }
+      }
+   }
+   _mm_storeu_ps(sum,_mm_add_ps(xsum1,xsum2));
+}
+
+
+void dual_inner_prod_sse(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
+      int N, opus_val32 *xy1, opus_val32 *xy2)
+{
+   int i;
+   __m128 xsum1, xsum2;
+   xsum1 = _mm_setzero_ps();
+   xsum2 = _mm_setzero_ps();
+   for (i=0;i<N-3;i+=4)
+   {
+      __m128 xi = _mm_loadu_ps(x+i);
+      __m128 y1i = _mm_loadu_ps(y01+i);
+      __m128 y2i = _mm_loadu_ps(y02+i);
+      xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(xi, y1i));
+      xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(xi, y2i));
+   }
+   /* Horizontal sum */
+   xsum1 = _mm_add_ps(xsum1, _mm_movehl_ps(xsum1, xsum1));
+   xsum1 = _mm_add_ss(xsum1, _mm_shuffle_ps(xsum1, xsum1, 0x55));
+   _mm_store_ss(xy1, xsum1);
+   xsum2 = _mm_add_ps(xsum2, _mm_movehl_ps(xsum2, xsum2));
+   xsum2 = _mm_add_ss(xsum2, _mm_shuffle_ps(xsum2, xsum2, 0x55));
+   _mm_store_ss(xy2, xsum2);
+   for (;i<N;i++)
+   {
+      *xy1 = MAC16_16(*xy1, x[i], y01[i]);
+      *xy2 = MAC16_16(*xy2, x[i], y02[i]);
+   }
+}
+
+opus_val32 celt_inner_prod_sse(const opus_val16 *x, const opus_val16 *y,
+      int N)
+{
+   int i;
+   float xy;
+   __m128 sum;
+   sum = _mm_setzero_ps();
+   /* FIXME: We should probably go 8-way and use 2 sums. */
+   for (i=0;i<N-3;i+=4)
+   {
+      __m128 xi = _mm_loadu_ps(x+i);
+      __m128 yi = _mm_loadu_ps(y+i);
+      sum = _mm_add_ps(sum,_mm_mul_ps(xi, yi));
+   }
+   /* Horizontal sum */
+   sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
+   sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
+   _mm_store_ss(&xy, sum);
+   for (;i<N;i++)
+   {
+      xy = MAC16_16(xy, x[i], y[i]);
+   }
+   return xy;
+}
+
+void comb_filter_const_sse(opus_val32 *y, opus_val32 *x, int T, int N,
+      opus_val16 g10, opus_val16 g11, opus_val16 g12)
+{
+   int i;
+   __m128 x0v;
+   __m128 g10v, g11v, g12v;
+   g10v = _mm_load1_ps(&g10);
+   g11v = _mm_load1_ps(&g11);
+   g12v = _mm_load1_ps(&g12);
+   x0v = _mm_loadu_ps(&x[-T-2]);
+   for (i=0;i<N-3;i+=4)
+   {
+      __m128 yi, yi2, x1v, x2v, x3v, x4v;
+      const opus_val32 *xp = &x[i-T-2];
+      yi = _mm_loadu_ps(x+i);
+      x4v = _mm_loadu_ps(xp+4);
+#if 0
+      /* Slower version with all loads */
+      x1v = _mm_loadu_ps(xp+1);
+      x2v = _mm_loadu_ps(xp+2);
+      x3v = _mm_loadu_ps(xp+3);
+#else
+      x2v = _mm_shuffle_ps(x0v, x4v, 0x4e);
+      x1v = _mm_shuffle_ps(x0v, x2v, 0x99);
+      x3v = _mm_shuffle_ps(x2v, x4v, 0x99);
+#endif
+
+      yi = _mm_add_ps(yi, _mm_mul_ps(g10v,x2v));
+#if 0 /* Set to 1 to make it bit-exact with the non-SSE version */
+      yi = _mm_add_ps(yi, _mm_mul_ps(g11v,_mm_add_ps(x3v,x1v)));
+      yi = _mm_add_ps(yi, _mm_mul_ps(g12v,_mm_add_ps(x4v,x0v)));
+#else
+      /* Use partial sums */
+      yi2 = _mm_add_ps(_mm_mul_ps(g11v,_mm_add_ps(x3v,x1v)),
+                       _mm_mul_ps(g12v,_mm_add_ps(x4v,x0v)));
+      yi = _mm_add_ps(yi, yi2);
+#endif
+      x0v=x4v;
+      _mm_storeu_ps(y+i, yi);
+   }
+#ifdef CUSTOM_MODES
+   for (;i<N;i++)
+   {
+      y[i] = x[i]
+               + MULT16_32_Q15(g10,x[i-T])
+               + MULT16_32_Q15(g11,ADD32(x[i-T+1],x[i-T-1]))
+               + MULT16_32_Q15(g12,ADD32(x[i-T+2],x[i-T-2]));
+   }
+#endif
+}
+
+
+#endif
diff --git a/third_party/opus/src/celt/x86/pitch_sse.h b/third_party/opus/src/celt/x86/pitch_sse.h
new file mode 100644
index 0000000..e5f87ab5
--- /dev/null
+++ b/third_party/opus/src/celt/x86/pitch_sse.h
@@ -0,0 +1,192 @@
+/* Copyright (c) 2013 Jean-Marc Valin and John Ridges
+   Copyright (c) 2014, Cisco Systems, INC MingXiang WeiZhou MinPeng YanWang*/
+/**
+   @file pitch_sse.h
+   @brief Pitch analysis
+ */
+
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PITCH_SSE_H
+#define PITCH_SSE_H
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)
+void xcorr_kernel_sse4_1(
+                    const opus_int16 *x,
+                    const opus_int16 *y,
+                    opus_val32       sum[4],
+                    int              len);
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT)
+void xcorr_kernel_sse(
+                    const opus_val16 *x,
+                    const opus_val16 *y,
+                    opus_val32       sum[4],
+                    int              len);
+#endif
+
+#if defined(OPUS_X86_PRESUME_SSE4_1) && defined(FIXED_POINT)
+#define OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+    ((void)arch, xcorr_kernel_sse4_1(x, y, sum, len))
+
+#elif defined(OPUS_X86_PRESUME_SSE) && !defined(FIXED_POINT)
+#define OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+    ((void)arch, xcorr_kernel_sse(x, y, sum, len))
+
+#elif (defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)) || (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT))
+
+extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+                    const opus_val16 *x,
+                    const opus_val16 *y,
+                    opus_val32       sum[4],
+                    int              len);
+
+#define OVERRIDE_XCORR_KERNEL
+#define xcorr_kernel(x, y, sum, len, arch) \
+    ((*XCORR_KERNEL_IMPL[(arch) & OPUS_ARCHMASK])(x, y, sum, len))
+
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)
+opus_val32 celt_inner_prod_sse4_1(
+    const opus_int16 *x,
+    const opus_int16 *y,
+    int               N);
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE2) && defined(FIXED_POINT)
+opus_val32 celt_inner_prod_sse2(
+    const opus_int16 *x,
+    const opus_int16 *y,
+    int               N);
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(FIXED_POINT)
+opus_val32 celt_inner_prod_sse(
+    const opus_val16 *x,
+    const opus_val16 *y,
+    int               N);
+#endif
+
+
+#if defined(OPUS_X86_PRESUME_SSE4_1) && defined(FIXED_POINT)
+#define OVERRIDE_CELT_INNER_PROD
+#define celt_inner_prod(x, y, N, arch) \
+    ((void)arch, celt_inner_prod_sse4_1(x, y, N))
+
+#elif defined(OPUS_X86_PRESUME_SSE2) && defined(FIXED_POINT) && !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#define OVERRIDE_CELT_INNER_PROD
+#define celt_inner_prod(x, y, N, arch) \
+    ((void)arch, celt_inner_prod_sse2(x, y, N))
+
+#elif defined(OPUS_X86_PRESUME_SSE) && !defined(FIXED_POINT)
+#define OVERRIDE_CELT_INNER_PROD
+#define celt_inner_prod(x, y, N, arch) \
+    ((void)arch, celt_inner_prod_sse(x, y, N))
+
+
+#elif ((defined(OPUS_X86_MAY_HAVE_SSE4_1) || defined(OPUS_X86_MAY_HAVE_SSE2)) && defined(FIXED_POINT)) || \
+    (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT))
+
+extern opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+                    const opus_val16 *x,
+                    const opus_val16 *y,
+                    int               N);
+
+#define OVERRIDE_CELT_INNER_PROD
+#define celt_inner_prod(x, y, N, arch) \
+    ((*CELT_INNER_PROD_IMPL[(arch) & OPUS_ARCHMASK])(x, y, N))
+
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) && !defined(FIXED_POINT)
+
+#define OVERRIDE_DUAL_INNER_PROD
+#define OVERRIDE_COMB_FILTER_CONST
+
+#undef dual_inner_prod
+#undef comb_filter_const
+
+void dual_inner_prod_sse(const opus_val16 *x,
+    const opus_val16 *y01,
+    const opus_val16 *y02,
+    int               N,
+    opus_val32       *xy1,
+    opus_val32       *xy2);
+
+void comb_filter_const_sse(opus_val32 *y,
+    opus_val32 *x,
+    int         T,
+    int         N,
+    opus_val16  g10,
+    opus_val16  g11,
+    opus_val16  g12);
+
+
+#if defined(OPUS_X86_PRESUME_SSE)
+# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) \
+    ((void)(arch),dual_inner_prod_sse(x, y01, y02, N, xy1, xy2))
+
+# define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \
+    ((void)(arch),comb_filter_const_sse(y, x, T, N, g10, g11, g12))
+#else
+
+extern void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+              const opus_val16 *x,
+              const opus_val16 *y01,
+              const opus_val16 *y02,
+              int               N,
+              opus_val32       *xy1,
+              opus_val32       *xy2);
+
+#define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) \
+    ((*DUAL_INNER_PROD_IMPL[(arch) & OPUS_ARCHMASK])(x, y01, y02, N, xy1, xy2))
+
+extern void (*const COMB_FILTER_CONST_IMPL[OPUS_ARCHMASK + 1])(
+              opus_val32 *y,
+              opus_val32 *x,
+              int         T,
+              int         N,
+              opus_val16  g10,
+              opus_val16  g11,
+              opus_val16  g12);
+
+#define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \
+    ((*COMB_FILTER_CONST_IMPL[(arch) & OPUS_ARCHMASK])(y, x, T, N, g10, g11, g12))
+
+#define NON_STATIC_COMB_FILTER_CONST_C
+
+#endif
+#endif
+
+#endif
diff --git a/third_party/opus/src/celt/x86/pitch_sse2.c b/third_party/opus/src/celt/x86/pitch_sse2.c
new file mode 100644
index 0000000..a0e7d1b
--- /dev/null
+++ b/third_party/opus/src/celt/x86/pitch_sse2.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+
+#include "macros.h"
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE2) && defined(FIXED_POINT)
+opus_val32 celt_inner_prod_sse2(const opus_val16 *x, const opus_val16 *y,
+      int N)
+{
+    opus_int  i, dataSize16;
+    opus_int32 sum;
+
+    __m128i inVec1_76543210, inVec1_FEDCBA98, acc1;
+    __m128i inVec2_76543210, inVec2_FEDCBA98, acc2;
+
+    sum = 0;
+    dataSize16 = N & ~15;
+
+    acc1 = _mm_setzero_si128();
+    acc2 = _mm_setzero_si128();
+
+    for (i=0;i<dataSize16;i+=16)
+    {
+        inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0]));
+        inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0]));
+
+        inVec1_FEDCBA98 = _mm_loadu_si128((__m128i *)(&x[i + 8]));
+        inVec2_FEDCBA98 = _mm_loadu_si128((__m128i *)(&y[i + 8]));
+
+        inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210);
+        inVec1_FEDCBA98 = _mm_madd_epi16(inVec1_FEDCBA98, inVec2_FEDCBA98);
+
+        acc1 = _mm_add_epi32(acc1, inVec1_76543210);
+        acc2 = _mm_add_epi32(acc2, inVec1_FEDCBA98);
+    }
+
+    acc1 = _mm_add_epi32( acc1, acc2 );
+
+    if (N - i >= 8)
+    {
+        inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0]));
+        inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0]));
+
+        inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210);
+
+        acc1 = _mm_add_epi32(acc1, inVec1_76543210);
+        i += 8;
+    }
+
+    acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64( acc1, acc1));
+    acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16( acc1, 0x0E));
+    sum += _mm_cvtsi128_si32(acc1);
+
+    for (;i<N;i++) {
+        sum = silk_SMLABB(sum, x[i], y[i]);
+    }
+
+    return sum;
+}
+#endif
diff --git a/third_party/opus/src/celt/x86/pitch_sse4_1.c b/third_party/opus/src/celt/x86/pitch_sse4_1.c
new file mode 100644
index 0000000..a092c68
--- /dev/null
+++ b/third_party/opus/src/celt/x86/pitch_sse4_1.c
@@ -0,0 +1,195 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+
+#include "macros.h"
+#include "celt_lpc.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "pitch.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT)
+#include <smmintrin.h>
+#include "x86cpu.h"
+
+opus_val32 celt_inner_prod_sse4_1(const opus_val16 *x, const opus_val16 *y,
+      int N)
+{
+    opus_int  i, dataSize16;
+    opus_int32 sum;
+    __m128i inVec1_76543210, inVec1_FEDCBA98, acc1;
+    __m128i inVec2_76543210, inVec2_FEDCBA98, acc2;
+    __m128i inVec1_3210, inVec2_3210;
+
+    sum = 0;
+    dataSize16 = N & ~15;
+
+    acc1 = _mm_setzero_si128();
+    acc2 = _mm_setzero_si128();
+
+    for (i=0;i<dataSize16;i+=16) {
+        inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0]));
+        inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0]));
+
+        inVec1_FEDCBA98 = _mm_loadu_si128((__m128i *)(&x[i + 8]));
+        inVec2_FEDCBA98 = _mm_loadu_si128((__m128i *)(&y[i + 8]));
+
+        inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210);
+        inVec1_FEDCBA98 = _mm_madd_epi16(inVec1_FEDCBA98, inVec2_FEDCBA98);
+
+        acc1 = _mm_add_epi32(acc1, inVec1_76543210);
+        acc2 = _mm_add_epi32(acc2, inVec1_FEDCBA98);
+    }
+
+    acc1 = _mm_add_epi32(acc1, acc2);
+
+    if (N - i >= 8)
+    {
+        inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0]));
+        inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0]));
+
+        inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210);
+
+        acc1 = _mm_add_epi32(acc1, inVec1_76543210);
+        i += 8;
+    }
+
+    if (N - i >= 4)
+    {
+        inVec1_3210 = OP_CVTEPI16_EPI32_M64(&x[i + 0]);
+        inVec2_3210 = OP_CVTEPI16_EPI32_M64(&y[i + 0]);
+
+        inVec1_3210 = _mm_mullo_epi32(inVec1_3210, inVec2_3210);
+
+        acc1 = _mm_add_epi32(acc1, inVec1_3210);
+        i += 4;
+    }
+
+    acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64(acc1, acc1));
+    acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16(acc1, 0x0E));
+
+    sum += _mm_cvtsi128_si32(acc1);
+
+    for (;i<N;i++)
+    {
+        sum = silk_SMLABB(sum, x[i], y[i]);
+    }
+
+    return sum;
+}
+
+void xcorr_kernel_sse4_1(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[ 4 ], int len)
+{
+    int j;
+
+    __m128i vecX, vecX0, vecX1, vecX2, vecX3;
+    __m128i vecY0, vecY1, vecY2, vecY3;
+    __m128i sum0, sum1, sum2, sum3, vecSum;
+    __m128i initSum;
+
+    celt_assert(len >= 3);
+
+    sum0 = _mm_setzero_si128();
+    sum1 = _mm_setzero_si128();
+    sum2 = _mm_setzero_si128();
+    sum3 = _mm_setzero_si128();
+
+    for (j=0;j<(len-7);j+=8)
+    {
+        vecX = _mm_loadu_si128((__m128i *)(&x[j + 0]));
+        vecY0 = _mm_loadu_si128((__m128i *)(&y[j + 0]));
+        vecY1 = _mm_loadu_si128((__m128i *)(&y[j + 1]));
+        vecY2 = _mm_loadu_si128((__m128i *)(&y[j + 2]));
+        vecY3 = _mm_loadu_si128((__m128i *)(&y[j + 3]));
+
+        sum0 = _mm_add_epi32(sum0, _mm_madd_epi16(vecX, vecY0));
+        sum1 = _mm_add_epi32(sum1, _mm_madd_epi16(vecX, vecY1));
+        sum2 = _mm_add_epi32(sum2, _mm_madd_epi16(vecX, vecY2));
+        sum3 = _mm_add_epi32(sum3, _mm_madd_epi16(vecX, vecY3));
+    }
+
+    sum0 = _mm_add_epi32(sum0, _mm_unpackhi_epi64( sum0, sum0));
+    sum0 = _mm_add_epi32(sum0, _mm_shufflelo_epi16( sum0, 0x0E));
+
+    sum1 = _mm_add_epi32(sum1, _mm_unpackhi_epi64( sum1, sum1));
+    sum1 = _mm_add_epi32(sum1, _mm_shufflelo_epi16( sum1, 0x0E));
+
+    sum2 = _mm_add_epi32(sum2, _mm_unpackhi_epi64( sum2, sum2));
+    sum2 = _mm_add_epi32(sum2, _mm_shufflelo_epi16( sum2, 0x0E));
+
+    sum3 = _mm_add_epi32(sum3, _mm_unpackhi_epi64( sum3, sum3));
+    sum3 = _mm_add_epi32(sum3, _mm_shufflelo_epi16( sum3, 0x0E));
+
+    vecSum = _mm_unpacklo_epi64(_mm_unpacklo_epi32(sum0, sum1),
+          _mm_unpacklo_epi32(sum2, sum3));
+
+    for (;j<(len-3);j+=4)
+    {
+        vecX = OP_CVTEPI16_EPI32_M64(&x[j + 0]);
+        vecX0 = _mm_shuffle_epi32(vecX, 0x00);
+        vecX1 = _mm_shuffle_epi32(vecX, 0x55);
+        vecX2 = _mm_shuffle_epi32(vecX, 0xaa);
+        vecX3 = _mm_shuffle_epi32(vecX, 0xff);
+
+        vecY0 = OP_CVTEPI16_EPI32_M64(&y[j + 0]);
+        vecY1 = OP_CVTEPI16_EPI32_M64(&y[j + 1]);
+        vecY2 = OP_CVTEPI16_EPI32_M64(&y[j + 2]);
+        vecY3 = OP_CVTEPI16_EPI32_M64(&y[j + 3]);
+
+        sum0 = _mm_mullo_epi32(vecX0, vecY0);
+        sum1 = _mm_mullo_epi32(vecX1, vecY1);
+        sum2 = _mm_mullo_epi32(vecX2, vecY2);
+        sum3 = _mm_mullo_epi32(vecX3, vecY3);
+
+        sum0 = _mm_add_epi32(sum0, sum1);
+        sum2 = _mm_add_epi32(sum2, sum3);
+        vecSum = _mm_add_epi32(vecSum, sum0);
+        vecSum = _mm_add_epi32(vecSum, sum2);
+    }
+
+    for (;j<len;j++)
+    {
+        vecX = OP_CVTEPI16_EPI32_M64(&x[j + 0]);
+        vecX0 = _mm_shuffle_epi32(vecX, 0x00);
+
+        vecY0 = OP_CVTEPI16_EPI32_M64(&y[j + 0]);
+
+        sum0 = _mm_mullo_epi32(vecX0, vecY0);
+        vecSum = _mm_add_epi32(vecSum, sum0);
+    }
+
+    initSum = _mm_loadu_si128((__m128i *)(&sum[0]));
+    initSum = _mm_add_epi32(initSum, vecSum);
+    _mm_storeu_si128((__m128i *)sum, initSum);
+}
+#endif
diff --git a/third_party/opus/src/celt/x86/x86_celt_map.c b/third_party/opus/src/celt/x86/x86_celt_map.c
new file mode 100644
index 0000000..47ba41b
--- /dev/null
+++ b/third_party/opus/src/celt/x86/x86_celt_map.c
@@ -0,0 +1,155 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include "x86/x86cpu.h"
+#include "celt_lpc.h"
+#include "pitch.h"
+#include "pitch_sse.h"
+
+#if defined(OPUS_HAVE_RTCD)
+
+# if defined(FIXED_POINT)
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)
+
+void (*const CELT_FIR_IMPL[OPUS_ARCHMASK + 1])(
+         const opus_val16 *x,
+         const opus_val16 *num,
+         opus_val16       *y,
+         int              N,
+         int              ord,
+         opus_val16       *mem,
+         int              arch
+) = {
+  celt_fir_c,                /* non-sse */
+  celt_fir_c,
+  celt_fir_c,
+  MAY_HAVE_SSE4_1(celt_fir), /* sse4.1  */
+  MAY_HAVE_SSE4_1(celt_fir)  /* avx  */
+};
+
+void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+         const opus_val16 *x,
+         const opus_val16 *y,
+         opus_val32       sum[4],
+         int              len
+) = {
+  xcorr_kernel_c,                /* non-sse */
+  xcorr_kernel_c,
+  xcorr_kernel_c,
+  MAY_HAVE_SSE4_1(xcorr_kernel), /* sse4.1  */
+  MAY_HAVE_SSE4_1(xcorr_kernel)  /* avx  */
+};
+
+#endif
+
+#if (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) ||  \
+ (!defined(OPUS_X86_MAY_HAVE_SSE_4_1) && defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2))
+
+opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+         const opus_val16 *x,
+         const opus_val16 *y,
+         int              N
+) = {
+  celt_inner_prod_c,                /* non-sse */
+  celt_inner_prod_c,
+  MAY_HAVE_SSE2(celt_inner_prod),
+  MAY_HAVE_SSE4_1(celt_inner_prod), /* sse4.1  */
+  MAY_HAVE_SSE4_1(celt_inner_prod)  /* avx  */
+};
+
+#endif
+
+# else
+
+#if defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)
+
+void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
+         const opus_val16 *x,
+         const opus_val16 *y,
+         opus_val32       sum[4],
+         int              len
+) = {
+  xcorr_kernel_c,                /* non-sse */
+  MAY_HAVE_SSE(xcorr_kernel),
+  MAY_HAVE_SSE(xcorr_kernel),
+  MAY_HAVE_SSE(xcorr_kernel),
+  MAY_HAVE_SSE(xcorr_kernel)
+};
+
+opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+         const opus_val16 *x,
+         const opus_val16 *y,
+         int              N
+) = {
+  celt_inner_prod_c,                /* non-sse */
+  MAY_HAVE_SSE(celt_inner_prod),
+  MAY_HAVE_SSE(celt_inner_prod),
+  MAY_HAVE_SSE(celt_inner_prod),
+  MAY_HAVE_SSE(celt_inner_prod)
+};
+
+void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK + 1])(
+                    const opus_val16 *x,
+                    const opus_val16 *y01,
+                    const opus_val16 *y02,
+                    int               N,
+                    opus_val32       *xy1,
+                    opus_val32       *xy2
+) = {
+  dual_inner_prod_c,                /* non-sse */
+  MAY_HAVE_SSE(dual_inner_prod),
+  MAY_HAVE_SSE(dual_inner_prod),
+  MAY_HAVE_SSE(dual_inner_prod),
+  MAY_HAVE_SSE(dual_inner_prod)
+};
+
+void (*const COMB_FILTER_CONST_IMPL[OPUS_ARCHMASK + 1])(
+              opus_val32 *y,
+              opus_val32 *x,
+              int         T,
+              int         N,
+              opus_val16  g10,
+              opus_val16  g11,
+              opus_val16  g12
+) = {
+  comb_filter_const_c,                /* non-sse */
+  MAY_HAVE_SSE(comb_filter_const),
+  MAY_HAVE_SSE(comb_filter_const),
+  MAY_HAVE_SSE(comb_filter_const),
+  MAY_HAVE_SSE(comb_filter_const)
+};
+
+
+#endif
+
+#endif
+#endif
diff --git a/third_party/opus/src/celt/x86/x86cpu.c b/third_party/opus/src/celt/x86/x86cpu.c
new file mode 100644
index 0000000..080eb25
--- /dev/null
+++ b/third_party/opus/src/celt/x86/x86cpu.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cpu_support.h"
+#include "macros.h"
+#include "main.h"
+#include "pitch.h"
+#include "x86cpu.h"
+
+#if (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)) || \
+  (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)) || \
+  (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \
+  (defined(OPUS_X86_MAY_HAVE_AVX) && !defined(OPUS_X86_PRESUME_AVX))
+
+
+#if defined(_MSC_VER)
+
+#include <intrin.h>
+static _inline void cpuid(unsigned int CPUInfo[4], unsigned int InfoType)
+{
+    __cpuid((int*)CPUInfo, InfoType);
+}
+
+#else
+
+#if defined(CPU_INFO_BY_C)
+#include <cpuid.h>
+#endif
+
+static void cpuid(unsigned int CPUInfo[4], unsigned int InfoType)
+{
+#if defined(CPU_INFO_BY_ASM)
+#if defined(__i386__) && defined(__PIC__)
+/* %ebx is PIC register in 32-bit, so mustn't clobber it. */
+    __asm__ __volatile__ (
+        "xchg %%ebx, %1\n"
+        "cpuid\n"
+        "xchg %%ebx, %1\n":
+        "=a" (CPUInfo[0]),
+        "=r" (CPUInfo[1]),
+        "=c" (CPUInfo[2]),
+        "=d" (CPUInfo[3]) :
+        "0" (InfoType)
+    );
+#else
+    __asm__ __volatile__ (
+        "cpuid":
+        "=a" (CPUInfo[0]),
+        "=b" (CPUInfo[1]),
+        "=c" (CPUInfo[2]),
+        "=d" (CPUInfo[3]) :
+        "0" (InfoType)
+    );
+#endif
+#elif defined(CPU_INFO_BY_C)
+    __get_cpuid(InfoType, &(CPUInfo[0]), &(CPUInfo[1]), &(CPUInfo[2]), &(CPUInfo[3]));
+#endif
+}
+
+#endif
+
+typedef struct CPU_Feature{
+    /*  SIMD: 128-bit */
+    int HW_SSE;
+    int HW_SSE2;
+    int HW_SSE41;
+    /*  SIMD: 256-bit */
+    int HW_AVX;
+} CPU_Feature;
+
+static void opus_cpu_feature_check(CPU_Feature *cpu_feature)
+{
+    unsigned int info[4] = {0};
+    unsigned int nIds = 0;
+
+    cpuid(info, 0);
+    nIds = info[0];
+
+    if (nIds >= 1){
+        cpuid(info, 1);
+        cpu_feature->HW_SSE = (info[3] & (1 << 25)) != 0;
+        cpu_feature->HW_SSE2 = (info[3] & (1 << 26)) != 0;
+        cpu_feature->HW_SSE41 = (info[2] & (1 << 19)) != 0;
+        cpu_feature->HW_AVX = (info[2] & (1 << 28)) != 0;
+    }
+    else {
+        cpu_feature->HW_SSE = 0;
+        cpu_feature->HW_SSE2 = 0;
+        cpu_feature->HW_SSE41 = 0;
+        cpu_feature->HW_AVX = 0;
+    }
+}
+
+int opus_select_arch(void)
+{
+    CPU_Feature cpu_feature;
+    int arch;
+
+    opus_cpu_feature_check(&cpu_feature);
+
+    arch = 0;
+    if (!cpu_feature.HW_SSE)
+    {
+       return arch;
+    }
+    arch++;
+
+    if (!cpu_feature.HW_SSE2)
+    {
+       return arch;
+    }
+    arch++;
+
+    if (!cpu_feature.HW_SSE41)
+    {
+        return arch;
+    }
+    arch++;
+
+    if (!cpu_feature.HW_AVX)
+    {
+        return arch;
+    }
+    arch++;
+
+    return arch;
+}
+
+#endif
diff --git a/third_party/opus/src/celt/x86/x86cpu.h b/third_party/opus/src/celt/x86/x86cpu.h
new file mode 100644
index 0000000..04fd48aa
--- /dev/null
+++ b/third_party/opus/src/celt/x86/x86cpu.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(X86CPU_H)
+# define X86CPU_H
+
+# if defined(OPUS_X86_MAY_HAVE_SSE)
+#  define MAY_HAVE_SSE(name) name ## _sse
+# else
+#  define MAY_HAVE_SSE(name) name ## _c
+# endif
+
+# if defined(OPUS_X86_MAY_HAVE_SSE2)
+#  define MAY_HAVE_SSE2(name) name ## _sse2
+# else
+#  define MAY_HAVE_SSE2(name) name ## _c
+# endif
+
+# if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#  define MAY_HAVE_SSE4_1(name) name ## _sse4_1
+# else
+#  define MAY_HAVE_SSE4_1(name) name ## _c
+# endif
+
+# if defined(OPUS_X86_MAY_HAVE_AVX)
+#  define MAY_HAVE_AVX(name) name ## _avx
+# else
+#  define MAY_HAVE_AVX(name) name ## _c
+# endif
+
+# if defined(OPUS_HAVE_RTCD)
+int opus_select_arch(void);
+# endif
+
+/*gcc appears to emit MOVDQA's to load the argument of an _mm_cvtepi8_epi32()
+  or _mm_cvtepi16_epi32() when optimizations are disabled, even though the
+  actual PMOVSXWD instruction takes an m32 or m64. Unlike a normal memory
+  reference, these require 16-byte alignment and load a full 16 bytes (instead
+  of 4 or 8), possibly reading out of bounds.
+
+  We can insert an explicit MOVD or MOVQ using _mm_cvtsi32_si128() or
+  _mm_loadl_epi64(), which should have the same semantics as an m32 or m64
+  reference in the PMOVSXWD instruction itself, but gcc is not smart enough to
+  optimize this out when optimizations ARE enabled.
+
+  Clang, in contrast, requires us to do this always for _mm_cvtepi8_epi32
+  (which is fair, since technically the compiler is always allowed to do the
+  dereference before invoking the function implementing the intrinsic).
+  However, it is smart enough to eliminate the extra MOVD instruction.
+  For _mm_cvtepi16_epi32, it does the right thing, though does *not* optimize out
+  the extra MOVQ if it's specified explicitly */
+
+# if defined(__clang__) || !defined(__OPTIMIZE__)
+#  define OP_CVTEPI8_EPI32_M32(x) \
+ (_mm_cvtepi8_epi32(_mm_cvtsi32_si128(*(int *)(x))))
+# else
+#  define OP_CVTEPI8_EPI32_M32(x) \
+ (_mm_cvtepi8_epi32(*(__m128i *)(x)))
+#endif
+
+# if !defined(__OPTIMIZE__)
+#  define OP_CVTEPI16_EPI32_M64(x) \
+ (_mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i *)(x))))
+# else
+#  define OP_CVTEPI16_EPI32_M64(x) \
+ (_mm_cvtepi16_epi32(*(__m128i *)(x)))
+# endif
+
+#endif
diff --git a/third_party/opus/src/configure.ac b/third_party/opus/src/configure.ac
new file mode 100644
index 0000000..c527e36
--- /dev/null
+++ b/third_party/opus/src/configure.ac
@@ -0,0 +1,871 @@
+dnl Process this file with autoconf to produce a configure script. -*-m4-*-
+
+dnl The package_version file will be automatically synced to the git revision
+dnl by the update_version script when configured in the repository, but will
+dnl remain constant in tarball releases unless it is manually edited.
+m4_define([CURRENT_VERSION],
+          m4_esyscmd([ ./update_version 2>/dev/null || true
+                       if test -e package_version; then
+                           . ./package_version
+                           printf "$PACKAGE_VERSION"
+                       else
+                           printf "unknown"
+                       fi ]))
+
+AC_INIT([opus],[CURRENT_VERSION],[opus@xiph.org])
+
+AC_CONFIG_SRCDIR(src/opus_encoder.c)
+AC_CONFIG_MACRO_DIR([m4])
+
+dnl enable silent rules on automake 1.11 and later
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+# For libtool.
+dnl Please update these for releases.
+OPUS_LT_CURRENT=5
+OPUS_LT_REVISION=3
+OPUS_LT_AGE=5
+
+AC_SUBST(OPUS_LT_CURRENT)
+AC_SUBST(OPUS_LT_REVISION)
+AC_SUBST(OPUS_LT_AGE)
+
+AM_INIT_AUTOMAKE([no-define])
+AM_MAINTAINER_MODE([enable])
+
+AC_CANONICAL_HOST
+AC_MINGW32
+AM_PROG_LIBTOOL
+AM_PROG_CC_C_O
+
+AC_PROG_CC_C99
+AC_C_CONST
+AC_C_INLINE
+
+AM_PROG_AS
+
+AC_DEFINE([OPUS_BUILD], [], [This is a build of OPUS])
+
+#Use a hacked up version of autoconf's AC_C_RESTRICT because it's not
+#strong enough a test to detect old buggy versions of GCC (e.g. 2.95.3)
+#Note: Both this and the test for variable-size arrays below are also
+#      done by AC_PROG_CC_C99, but not thoroughly enough apparently.
+AC_CACHE_CHECK([for C/C++ restrict keyword], ac_cv_c_restrict,
+  [ac_cv_c_restrict=no
+   # The order here caters to the fact that C++ does not require restrict.
+   for ac_kw in __restrict __restrict__ _Restrict restrict; do
+     AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+      [[typedef int * int_ptr;
+        int foo (int_ptr $ac_kw ip, int * $ac_kw baz[]) {
+        return ip[0];
+       }]],
+      [[int s[1];
+        int * $ac_kw t = s;
+        t[0] = 0;
+        return foo(t, (void *)0)]])],
+      [ac_cv_c_restrict=$ac_kw])
+     test "$ac_cv_c_restrict" != no && break
+   done
+  ])
+
+AH_VERBATIM([restrict],
+[/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#undef restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif])
+
+case $ac_cv_c_restrict in
+   restrict) ;;
+   no) AC_DEFINE([restrict], []) ;;
+   *)  AC_DEFINE_UNQUOTED([restrict], [$ac_cv_c_restrict]) ;;
+esac
+
+AC_MSG_CHECKING(for C99 variable-size arrays)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+                   [[static int x; char a[++x]; a[sizeof a - 1] = 0; int N; return a[0];]])],
+    [ has_var_arrays=yes
+      use_alloca="no (using var arrays)"
+      AC_DEFINE([VAR_ARRAYS], [1], [Use C99 variable-size arrays])
+    ],[
+      has_var_arrays=no
+    ])
+AC_MSG_RESULT([$has_var_arrays])
+
+AS_IF([test "$has_var_arrays" = "no"],
+  [
+   AC_CHECK_HEADERS([alloca.h])
+   AC_MSG_CHECKING(for alloca)
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <alloca.h>]],
+                                      [[int foo=10; int *array = alloca(foo);]])],
+     [ use_alloca=yes;
+       AC_DEFINE([USE_ALLOCA], [], [Make use of alloca])
+     ],[
+       use_alloca=no
+     ])
+   AC_MSG_RESULT([$use_alloca])
+  ])
+
+LT_LIB_M
+
+AC_ARG_ENABLE([fixed-point],
+    [AS_HELP_STRING([--enable-fixed-point],
+                    [compile without floating point (for machines without a fast enough FPU)])],,
+    [enable_fixed_point=no])
+
+AS_IF([test "$enable_fixed_point" = "yes"],[
+  enable_float="no"
+  AC_DEFINE([FIXED_POINT], [1], [Compile as fixed-point (for machines without a fast enough FPU)])
+  PC_BUILD="fixed-point"
+],[
+  enable_float="yes";
+  PC_BUILD="floating-point"
+])
+
+AM_CONDITIONAL([FIXED_POINT], [test "$enable_fixed_point" = "yes"])
+
+AC_ARG_ENABLE([fixed-point-debug],
+    [AS_HELP_STRING([--enable-fixed-point-debug], [debug fixed-point implementation])],,
+    [enable_fixed_point_debug=no])
+
+AS_IF([test "$enable_fixed_point_debug" = "yes"],[
+  AC_DEFINE([FIXED_DEBUG], [1], [Debug fixed-point implementation])
+])
+
+AC_ARG_ENABLE([float_api],
+    [AS_HELP_STRING([--disable-float-api],
+                    [compile without the floating point API (for machines with no float library)])],,
+    [enable_float_api=yes])
+
+AM_CONDITIONAL([DISABLE_FLOAT_API], [test "$enable_float_api" = "no"])
+
+AS_IF([test "$enable_float_api" = "no"],[
+  AC_DEFINE([DISABLE_FLOAT_API], [1], [Do not build the float API])
+])
+
+AC_ARG_ENABLE([custom-modes],
+    [AS_HELP_STRING([--enable-custom-modes], [enable non-Opus modes, e.g. 44.1 kHz & 2^n frames])],,
+    [enable_custom_modes=no])
+
+AS_IF([test "$enable_custom_modes" = "yes"],[
+  AC_DEFINE([CUSTOM_MODES], [1], [Custom modes])
+  PC_BUILD="$PC_BUILD, custom modes"
+])
+
+AM_CONDITIONAL([CUSTOM_MODES], [test "$enable_custom_modes" = "yes"])
+
+has_float_approx=no
+#case "$host_cpu" in
+#i[[3456]]86 | x86_64 | powerpc64 | powerpc32 | ia64)
+#  has_float_approx=yes
+#  ;;
+#esac
+
+AC_ARG_ENABLE([float-approx],
+    [AS_HELP_STRING([--enable-float-approx], [enable fast approximations for floating point])],
+    [if test "$enable_float_approx" = "yes"; then
+       AC_WARN([Floating point approximations are not supported on all platforms.])
+     fi
+    ],
+    [enable_float_approx=$has_float_approx])
+
+AS_IF([test "$enable_float_approx" = "yes"],[
+  AC_DEFINE([FLOAT_APPROX], [1], [Float approximations])
+])
+
+AC_ARG_ENABLE([asm],
+    [AS_HELP_STRING([--disable-asm], [Disable assembly optimizations])],,
+    [enable_asm=yes])
+
+AC_ARG_ENABLE([rtcd],
+    [AS_HELP_STRING([--disable-rtcd], [Disable run-time CPU capabilities detection])],,
+    [enable_rtcd=yes])
+
+AC_ARG_ENABLE([intrinsics],
+    [AS_HELP_STRING([--disable-intrinsics], [Disable intrinsics optimizations])],,
+    [enable_intrinsics=yes])
+
+rtcd_support=no
+cpu_arm=no
+
+AS_IF([test x"${enable_asm}" = x"yes"],[
+    inline_optimization="No inline ASM for your platform, please send patches"
+    case $host_cpu in
+      arm*)
+        dnl Currently we only have asm for fixed-point
+        AS_IF([test "$enable_float" != "yes"],[
+            cpu_arm=yes
+            AC_DEFINE([OPUS_ARM_ASM], [],  [Make use of ARM asm optimization])
+            AS_GCC_INLINE_ASSEMBLY(
+                [inline_optimization="ARM"],
+                [inline_optimization="disabled"]
+            )
+            AS_ASM_ARM_EDSP([OPUS_ARM_INLINE_EDSP=1],[OPUS_ARM_INLINE_EDSP=0])
+            AS_ASM_ARM_MEDIA([OPUS_ARM_INLINE_MEDIA=1],
+                [OPUS_ARM_INLINE_MEDIA=0])
+            AS_ASM_ARM_NEON([OPUS_ARM_INLINE_NEON=1],[OPUS_ARM_INLINE_NEON=0])
+            AS_IF([test x"$inline_optimization" = x"ARM"],[
+                AM_CONDITIONAL([OPUS_ARM_INLINE_ASM],[true])
+                AC_DEFINE([OPUS_ARM_INLINE_ASM], 1,
+                    [Use generic ARMv4 inline asm optimizations])
+                AS_IF([test x"$OPUS_ARM_INLINE_EDSP" = x"1"],[
+                    AC_DEFINE([OPUS_ARM_INLINE_EDSP], [1],
+                        [Use ARMv5E inline asm optimizations])
+                    inline_optimization="$inline_optimization (EDSP)"
+                ])
+                AS_IF([test x"$OPUS_ARM_INLINE_MEDIA" = x"1"],[
+                    AC_DEFINE([OPUS_ARM_INLINE_MEDIA], [1],
+                        [Use ARMv6 inline asm optimizations])
+                    inline_optimization="$inline_optimization (Media)"
+                ])
+                AS_IF([test x"$OPUS_ARM_INLINE_NEON" = x"1"],[
+                    AC_DEFINE([OPUS_ARM_INLINE_NEON], 1,
+                        [Use ARM NEON inline asm optimizations])
+                    inline_optimization="$inline_optimization (NEON)"
+                ])
+            ])
+            dnl We need Perl to translate RVCT-syntax asm to gas syntax.
+            AC_CHECK_PROG([HAVE_PERL], perl, yes, no)
+            AS_IF([test x"$HAVE_PERL" = x"yes"],[
+                AM_CONDITIONAL([OPUS_ARM_EXTERNAL_ASM],[true])
+                asm_optimization="ARM"
+                AS_IF([test x"$OPUS_ARM_INLINE_EDSP" = x"1"], [
+                    OPUS_ARM_PRESUME_EDSP=1
+                    OPUS_ARM_MAY_HAVE_EDSP=1
+                ],
+                [
+                    OPUS_ARM_PRESUME_EDSP=0
+                    OPUS_ARM_MAY_HAVE_EDSP=0
+                ])
+                AS_IF([test x"$OPUS_ARM_INLINE_MEDIA" = x"1"], [
+                    OPUS_ARM_PRESUME_MEDIA=1
+                    OPUS_ARM_MAY_HAVE_MEDIA=1
+                ],
+                [
+                    OPUS_ARM_PRESUME_MEDIA=0
+                    OPUS_ARM_MAY_HAVE_MEDIA=0
+                ])
+                AS_IF([test x"$OPUS_ARM_INLINE_NEON" = x"1"], [
+                    OPUS_ARM_PRESUME_NEON=1
+                    OPUS_ARM_MAY_HAVE_NEON=1
+                ],
+                [
+                    OPUS_ARM_PRESUME_NEON=0
+                    OPUS_ARM_MAY_HAVE_NEON=0
+                ])
+                AS_IF([test x"$enable_rtcd" = x"yes"],[
+                    AS_IF([test x"$OPUS_ARM_MAY_HAVE_EDSP" != x"1"],[
+                        AC_MSG_NOTICE(
+                          [Trying to force-enable armv5e EDSP instructions...])
+                        AS_ASM_ARM_EDSP_FORCE([OPUS_ARM_MAY_HAVE_EDSP=1])
+                    ])
+                    AS_IF([test x"$OPUS_ARM_MAY_HAVE_MEDIA" != x"1"],[
+                        AC_MSG_NOTICE(
+                          [Trying to force-enable ARMv6 media instructions...])
+                        AS_ASM_ARM_MEDIA_FORCE([OPUS_ARM_MAY_HAVE_MEDIA=1])
+                    ])
+                    AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON" != x"1"],[
+                        AC_MSG_NOTICE(
+                          [Trying to force-enable NEON instructions...])
+                        AS_ASM_ARM_NEON_FORCE([OPUS_ARM_MAY_HAVE_NEON=1])
+                    ])
+                ])
+                rtcd_support=
+                AS_IF([test x"$OPUS_ARM_MAY_HAVE_EDSP" = x"1"],[
+                    AC_DEFINE(OPUS_ARM_MAY_HAVE_EDSP, 1,
+                        [Define if assembler supports EDSP instructions])
+                    AS_IF([test x"$OPUS_ARM_PRESUME_EDSP" = x"1"],[
+                        AC_DEFINE(OPUS_ARM_PRESUME_EDSP, 1,
+                          [Define if binary requires EDSP instruction support])
+                        asm_optimization="$asm_optimization (EDSP)"
+                    ],
+                        [rtcd_support="$rtcd_support (EDSP)"]
+                    )
+                ])
+                AC_SUBST(OPUS_ARM_MAY_HAVE_EDSP)
+                AS_IF([test x"$OPUS_ARM_MAY_HAVE_MEDIA" = x"1"],[
+                    AC_DEFINE(OPUS_ARM_MAY_HAVE_MEDIA, 1,
+                      [Define if assembler supports ARMv6 media instructions])
+                    AS_IF([test x"$OPUS_ARM_PRESUME_MEDIA" = x"1"],[
+                        AC_DEFINE(OPUS_ARM_PRESUME_MEDIA, 1,
+                          [Define if binary requires ARMv6 media instruction support])
+                        asm_optimization="$asm_optimization (Media)"
+                    ],
+                        [rtcd_support="$rtcd_support (Media)"]
+                    )
+                ])
+                AC_SUBST(OPUS_ARM_MAY_HAVE_MEDIA)
+                AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON" = x"1"],[
+                    AC_DEFINE(OPUS_ARM_MAY_HAVE_NEON, 1,
+                      [Define if compiler supports NEON instructions])
+                    AS_IF([test x"$OPUS_ARM_PRESUME_NEON" = x"1"], [
+                        AC_DEFINE(OPUS_ARM_PRESUME_NEON, 1,
+                          [Define if binary requires NEON instruction support])
+                        asm_optimization="$asm_optimization (NEON)"
+                    ],
+                        [rtcd_support="$rtcd_support (NEON)"]
+                    )
+                ])
+                AC_SUBST(OPUS_ARM_MAY_HAVE_NEON)
+                dnl Make sure turning on RTCD gets us at least one
+                dnl instruction set.
+                AS_IF([test x"$rtcd_support" != x""],
+                    [rtcd_support=ARM"$rtcd_support"],
+                    [rtcd_support="no"]
+                )
+                AC_MSG_CHECKING([for apple style tools])
+                AC_PREPROC_IFELSE([AC_LANG_PROGRAM([
+#ifndef __APPLE__
+#error 1
+#endif],[])],
+                    [AC_MSG_RESULT([yes]); ARM2GNU_PARAMS="--apple"],
+                    [AC_MSG_RESULT([no]); ARM2GNU_PARAMS=""])
+                AC_SUBST(ARM2GNU_PARAMS)
+            ],
+            [
+                AC_MSG_WARN(
+                  [*** ARM assembly requires perl -- disabling optimizations])
+                asm_optimization="(missing perl dependency for ARM)"
+            ])
+        ])
+        ;;
+    esac
+],[
+   inline_optimization="disabled"
+   asm_optimization="disabled"
+])
+
+AM_CONDITIONAL([OPUS_ARM_INLINE_ASM],
+    [test x"${inline_optimization%% *}" = x"ARM"])
+AM_CONDITIONAL([OPUS_ARM_EXTERNAL_ASM],
+    [test x"${asm_optimization%% *}" = x"ARM"])
+
+AM_CONDITIONAL([HAVE_SSE], [false])
+AM_CONDITIONAL([HAVE_SSE2], [false])
+AM_CONDITIONAL([HAVE_SSE4_1], [false])
+AM_CONDITIONAL([HAVE_AVX], [false])
+
+m4_define([DEFAULT_X86_SSE_CFLAGS], [-msse])
+m4_define([DEFAULT_X86_SSE2_CFLAGS], [-msse2])
+m4_define([DEFAULT_X86_SSE4_1_CFLAGS], [-msse4.1])
+m4_define([DEFAULT_X86_AVX_CFLAGS], [-mavx])
+m4_define([DEFAULT_ARM_NEON_INTR_CFLAGS], [-mfpu=neon])
+# With GCC on ARM32 softfp architectures (e.g. Android, or older Ubuntu) you need to specify
+# -mfloat-abi=softfp for -mfpu=neon to work.  However, on ARM32 hardfp architectures (e.g. newer Ubuntu),
+# this option will break things.
+
+# As a heuristic, if host matches arm*eabi* but not arm*hf*, it's probably soft-float.
+m4_define([DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS], [-mfpu=neon -mfloat-abi=softfp])
+
+AS_CASE([$host],
+        [arm*hf*], [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_INTR_CFLAGS")],
+        [arm*eabi*], [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS")],
+        [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_INTR_CFLAGS")])
+
+AC_ARG_VAR([X86_SSE_CFLAGS], [C compiler flags to compile SSE intrinsics @<:@default=]DEFAULT_X86_SSE_CFLAGS[@:>@])
+AC_ARG_VAR([X86_SSE2_CFLAGS], [C compiler flags to compile SSE2 intrinsics @<:@default=]DEFAULT_X86_SSE2_CFLAGS[@:>@])
+AC_ARG_VAR([X86_SSE4_1_CFLAGS], [C compiler flags to compile SSE4.1 intrinsics @<:@default=]DEFAULT_X86_SSE4_1_CFLAGS[@:>@])
+AC_ARG_VAR([X86_AVX_CFLAGS], [C compiler flags to compile AVX intrinsics @<:@default=]DEFAULT_X86_AVX_CFLAGS[@:>@])
+AC_ARG_VAR([ARM_NEON_INTR_CFLAGS], [C compiler flags to compile ARM NEON intrinsics @<:@default=]DEFAULT_ARM_NEON_INTR_CFLAGS / DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS[@:>@])
+
+AS_VAR_SET_IF([X86_SSE_CFLAGS], [], [AS_VAR_SET([X86_SSE_CFLAGS], "DEFAULT_X86_SSE_CFLAGS")])
+AS_VAR_SET_IF([X86_SSE2_CFLAGS], [], [AS_VAR_SET([X86_SSE2_CFLAGS], "DEFAULT_X86_SSE2_CFLAGS")])
+AS_VAR_SET_IF([X86_SSE4_1_CFLAGS], [], [AS_VAR_SET([X86_SSE4_1_CFLAGS], "DEFAULT_X86_SSE4_1_CFLAGS")])
+AS_VAR_SET_IF([X86_AVX_CFLAGS], [], [AS_VAR_SET([X86_AVX_CFLAGS], "DEFAULT_X86_AVX_CFLAGS")])
+AS_VAR_SET_IF([ARM_NEON_INTR_CFLAGS], [], [AS_VAR_SET([ARM_NEON_INTR_CFLAGS], ["$RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS"])])
+
+AC_DEFUN([OPUS_PATH_NE10],
+   [
+      AC_ARG_WITH(NE10,
+                  AC_HELP_STRING([--with-NE10=PFX],[Prefix where libNE10 is installed (optional)]),
+                  NE10_prefix="$withval", NE10_prefix="")
+      AC_ARG_WITH(NE10-libraries,
+                  AC_HELP_STRING([--with-NE10-libraries=DIR],
+                        [Directory where libNE10 library is installed (optional)]),
+                  NE10_libraries="$withval", NE10_libraries="")
+      AC_ARG_WITH(NE10-includes,
+                  AC_HELP_STRING([--with-NE10-includes=DIR],
+                                 [Directory where libNE10 header files are installed (optional)]),
+                  NE10_includes="$withval", NE10_includes="")
+
+      if test "x$NE10_libraries" != "x" ; then
+         NE10_LIBS="-L$NE10_libraries"
+      elif test "x$NE10_prefix" = "xno" || test "x$NE10_prefix" = "xyes" ; then
+         NE10_LIBS=""
+      elif test "x$NE10_prefix" != "x" ; then
+         NE10_LIBS="-L$NE10_prefix/lib"
+      elif test "x$prefix" != "xNONE" ; then
+         NE10_LIBS="-L$prefix/lib"
+      fi
+
+      if test "x$NE10_prefix" != "xno" ; then
+         NE10_LIBS="$NE10_LIBS -lNE10"
+      fi
+
+      if test "x$NE10_includes" != "x" ; then
+         NE10_CFLAGS="-I$NE10_includes"
+      elif test "x$NE10_prefix" = "xno" || test "x$NE10_prefix" = "xyes" ; then
+         NE10_CFLAGS=""
+      elif test "x$ogg_prefix" != "x" ; then
+         NE10_CFLAGS="-I$NE10_prefix/include"
+      elif test "x$prefix" != "xNONE"; then
+         NE10_CFLAGS="-I$prefix/include"
+      fi
+
+      AC_MSG_CHECKING(for NE10)
+      save_CFLAGS="$CFLAGS"; CFLAGS="$NE10_CFLAGS"
+      save_LIBS="$LIBS"; LIBS="$NE10_LIBS $LIBM"
+      AC_LINK_IFELSE(
+         [
+            AC_LANG_PROGRAM(
+               [[#include <NE10_init.h>
+               ]],
+               [[
+                  ne10_fft_cfg_float32_t cfg;
+                  cfg = ne10_fft_alloc_c2c_float32_neon(480);
+               ]]
+            )
+         ],[
+            HAVE_ARM_NE10=1
+            AC_MSG_RESULT([yes])
+         ],[
+            HAVE_ARM_NE10=0
+            AC_MSG_RESULT([no])
+            NE10_CFLAGS=""
+            NE10_LIBS=""
+         ]
+      )
+      CFLAGS="$save_CFLAGS"; LIBS="$save_LIBS"
+      #Now we know if libNE10 is installed or not
+      AS_IF([test x"$HAVE_ARM_NE10" = x"1"],
+         [
+            AC_DEFINE([HAVE_ARM_NE10], 1, [NE10 library is installed on host. Make sure it is on target!])
+            AC_SUBST(HAVE_ARM_NE10)
+            AC_SUBST(NE10_CFLAGS)
+            AC_SUBST(NE10_LIBS)
+         ]
+      )
+   ]
+)
+
+AS_IF([test x"$enable_intrinsics" = x"yes"],[
+   intrinsics_support=""
+   AS_CASE([$host_cpu],
+   [arm*|aarch64*],
+   [
+      cpu_arm=yes
+      OPUS_CHECK_INTRINSICS(
+         [ARM Neon],
+         [$ARM_NEON_INTR_CFLAGS],
+         [OPUS_ARM_MAY_HAVE_NEON_INTR],
+         [OPUS_ARM_PRESUME_NEON_INTR],
+         [[#include <arm_neon.h>
+         ]],
+         [[
+            static float32x4_t A0, A1, SUMM;
+            SUMM = vmlaq_f32(SUMM, A0, A1);
+            return (int)vgetq_lane_f32(SUMM, 0);
+         ]]
+      )
+      AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1" && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"],
+          [
+             OPUS_ARM_NEON_INTR_CFLAGS="$ARM_NEON_INTR_CFLAGS"
+             AC_SUBST([OPUS_ARM_NEON_INTR_CFLAGS])
+          ]
+      )
+
+      AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1"],
+      [
+         AC_DEFINE([OPUS_ARM_MAY_HAVE_NEON_INTR], 1, [Compiler supports ARMv7/Aarch64 Neon Intrinsics])
+         intrinsics_support="$intrinsics_support (NEON)"
+
+         AS_IF([test x"$enable_rtcd" != x"no" && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"],
+            [AS_IF([test x"$rtcd_support" = x"no"],
+               [rtcd_support="ARM (NEON Intrinsics)"],
+               [rtcd_support="$rtcd_support (NEON Intrinsics)"])])
+
+         AS_IF([test x"$OPUS_ARM_PRESUME_NEON_INTR" = x"1"],
+            [AC_DEFINE([OPUS_ARM_PRESUME_NEON_INTR], 1, [Define if binary requires NEON intrinsics support])])
+
+         OPUS_PATH_NE10()
+         AS_IF([test x"$NE10_LIBS" != x""],
+         [
+              intrinsics_support="$intrinsics_support (NE10)"
+              AS_IF([test x"enable_rtcd" != x"" \
+               && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"],
+                 [rtcd_support="$rtcd_support (NE10)"])
+         ])
+
+         OPUS_CHECK_INTRINSICS(
+            [Aarch64 Neon],
+            [$ARM_NEON_INTR_CFLAGS],
+            [OPUS_ARM_MAY_HAVE_AARCH64_NEON_INTR],
+            [OPUS_ARM_PRESUME_AARCH64_NEON_INTR],
+            [[#include <arm_neon.h>
+            ]],
+            [[
+               static int32_t IN;
+               static int16_t OUT;
+               OUT = vqmovns_s32(IN);
+            ]]
+         )
+
+         AS_IF([test x"$OPUS_ARM_PRESUME_AARCH64_NEON_INTR" = x"1"],
+         [
+            AC_DEFINE([OPUS_ARM_PRESUME_AARCH64_NEON_INTR], 1, [Define if binary requires Aarch64 Neon Intrinsics])
+            intrinsics_support="$intrinsics_support (NEON [Aarch64])"
+         ])
+
+         AS_IF([test x"$intrinsics_support" = x""],
+            [intrinsics_support=no],
+            [intrinsics_support="ARM$intrinsics_support"])
+      ],
+      [
+         AC_MSG_WARN([Compiler does not support ARM intrinsics])
+         intrinsics_support=no
+      ])
+   ],
+   [i?86|x86_64],
+   [
+      OPUS_CHECK_INTRINSICS(
+         [SSE],
+         [$X86_SSE_CFLAGS],
+         [OPUS_X86_MAY_HAVE_SSE],
+         [OPUS_X86_PRESUME_SSE],
+         [[#include <xmmintrin.h>
+           #include <time.h>
+         ]],
+         [[
+             __m128 mtest;
+             mtest = _mm_set1_ps((float)time(NULL));
+             mtest = _mm_mul_ps(mtest, mtest);
+             return _mm_cvtss_si32(mtest);
+         ]]
+      )
+      AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE" = x"1" && test x"$OPUS_X86_PRESUME_SSE" != x"1"],
+          [
+             OPUS_X86_SSE_CFLAGS="$X86_SSE_CFLAGS"
+             AC_SUBST([OPUS_X86_SSE_CFLAGS])
+          ]
+      )
+      OPUS_CHECK_INTRINSICS(
+         [SSE2],
+         [$X86_SSE2_CFLAGS],
+         [OPUS_X86_MAY_HAVE_SSE2],
+         [OPUS_X86_PRESUME_SSE2],
+         [[#include <emmintrin.h>
+           #include <time.h>
+         ]],
+         [[
+            __m128i mtest;
+            mtest = _mm_set1_epi32((int)time(NULL));
+            mtest = _mm_mul_epu32(mtest, mtest);
+            return _mm_cvtsi128_si32(mtest);
+         ]]
+      )
+      AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1" && test x"$OPUS_X86_PRESUME_SSE2" != x"1"],
+          [
+             OPUS_X86_SSE2_CFLAGS="$X86_SSE2_CFLAGS"
+             AC_SUBST([OPUS_X86_SSE2_CFLAGS])
+          ]
+      )
+      OPUS_CHECK_INTRINSICS(
+         [SSE4.1],
+         [$X86_SSE4_1_CFLAGS],
+         [OPUS_X86_MAY_HAVE_SSE4_1],
+         [OPUS_X86_PRESUME_SSE4_1],
+         [[#include <smmintrin.h>
+           #include <time.h>
+         ]],
+         [[
+            __m128i mtest;
+            mtest = _mm_set1_epi32((int)time(NULL));
+            mtest = _mm_mul_epi32(mtest, mtest);
+            return _mm_cvtsi128_si32(mtest);
+         ]]
+      )
+      AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1" && test x"$OPUS_X86_PRESUME_SSE4_1" != x"1"],
+          [
+             OPUS_X86_SSE4_1_CFLAGS="$X86_SSE4_1_CFLAGS"
+             AC_SUBST([OPUS_X86_SSE4_1_CFLAGS])
+          ]
+      )
+      OPUS_CHECK_INTRINSICS(
+         [AVX],
+         [$X86_AVX_CFLAGS],
+         [OPUS_X86_MAY_HAVE_AVX],
+         [OPUS_X86_PRESUME_AVX],
+         [[#include <immintrin.h>
+           #include <time.h>
+         ]],
+         [[
+             __m256 mtest;
+             mtest = _mm256_set1_ps((float)time(NULL));
+             mtest = _mm256_addsub_ps(mtest, mtest);
+             return _mm_cvtss_si32(_mm256_extractf128_ps(mtest, 0));
+         ]]
+      )
+      AS_IF([test x"$OPUS_X86_MAY_HAVE_AVX" = x"1" && test x"$OPUS_X86_PRESUME_AVX" != x"1"],
+          [
+             OPUS_X86_AVX_CFLAGS="$X86_AVX_CFLAGS"
+             AC_SUBST([OPUS_X86_AVX_CFLAGS])
+          ]
+      )
+         AS_IF([test x"$rtcd_support" = x"no"], [rtcd_support=""])
+         AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE" = x"1"],
+         [
+            AC_DEFINE([OPUS_X86_MAY_HAVE_SSE], 1, [Compiler supports X86 SSE Intrinsics])
+            intrinsics_support="$intrinsics_support SSE"
+
+            AS_IF([test x"$OPUS_X86_PRESUME_SSE" = x"1"],
+               [AC_DEFINE([OPUS_X86_PRESUME_SSE], 1, [Define if binary requires SSE intrinsics support])],
+               [rtcd_support="$rtcd_support SSE"])
+         ],
+         [
+            AC_MSG_WARN([Compiler does not support SSE intrinsics])
+         ])
+
+         AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1"],
+         [
+            AC_DEFINE([OPUS_X86_MAY_HAVE_SSE2], 1, [Compiler supports X86 SSE2 Intrinsics])
+            intrinsics_support="$intrinsics_support SSE2"
+
+            AS_IF([test x"$OPUS_X86_PRESUME_SSE2" = x"1"],
+               [AC_DEFINE([OPUS_X86_PRESUME_SSE2], 1, [Define if binary requires SSE2 intrinsics support])],
+               [rtcd_support="$rtcd_support SSE2"])
+         ],
+         [
+            AC_MSG_WARN([Compiler does not support SSE2 intrinsics])
+         ])
+
+         AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1"],
+         [
+            AC_DEFINE([OPUS_X86_MAY_HAVE_SSE4_1], 1, [Compiler supports X86 SSE4.1 Intrinsics])
+            intrinsics_support="$intrinsics_support SSE4.1"
+
+            AS_IF([test x"$OPUS_X86_PRESUME_SSE4_1" = x"1"],
+               [AC_DEFINE([OPUS_X86_PRESUME_SSE4_1], 1, [Define if binary requires SSE4.1 intrinsics support])],
+               [rtcd_support="$rtcd_support SSE4.1"])
+         ],
+         [
+            AC_MSG_WARN([Compiler does not support SSE4.1 intrinsics])
+         ])
+         AS_IF([test x"$OPUS_X86_MAY_HAVE_AVX" = x"1"],
+         [
+            AC_DEFINE([OPUS_X86_MAY_HAVE_AVX], 1, [Compiler supports X86 AVX Intrinsics])
+            intrinsics_support="$intrinsics_support AVX"
+
+            AS_IF([test x"$OPUS_X86_PRESUME_AVX" = x"1"],
+               [AC_DEFINE([OPUS_X86_PRESUME_AVX], 1, [Define if binary requires AVX intrinsics support])],
+               [rtcd_support="$rtcd_support AVX"])
+         ],
+         [
+            AC_MSG_WARN([Compiler does not support AVX intrinsics])
+         ])
+
+         AS_IF([test x"$intrinsics_support" = x""],
+            [intrinsics_support=no],
+            [intrinsics_support="x86$intrinsics_support"]
+         )
+         AS_IF([test x"$rtcd_support" = x""],
+            [rtcd_support=no],
+            [rtcd_support="x86$rtcd_support"],
+        )
+
+    AS_IF([test x"$enable_rtcd" = x"yes" && test x"$rtcd_support" != x""],[
+            get_cpuid_by_asm="no"
+            AC_MSG_CHECKING([How to get X86 CPU Info])
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+                 #include <stdio.h>
+            ]],[[
+                 unsigned int CPUInfo0;
+                 unsigned int CPUInfo1;
+                 unsigned int CPUInfo2;
+                 unsigned int CPUInfo3;
+                 unsigned int InfoType;
+                 __asm__ __volatile__ (
+                 "cpuid":
+                 "=a" (CPUInfo0),
+                 "=b" (CPUInfo1),
+                 "=c" (CPUInfo2),
+                 "=d" (CPUInfo3) :
+                 "a" (InfoType), "c" (0)
+                );
+            ]])],
+            [get_cpuid_by_asm="yes"
+             AC_MSG_RESULT([Inline Assembly])
+                 AC_DEFINE([CPU_INFO_BY_ASM], [1], [Get CPU Info by asm method])],
+             [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+                 #include <cpuid.h>
+            ]],[[
+                 unsigned int CPUInfo0;
+                 unsigned int CPUInfo1;
+                 unsigned int CPUInfo2;
+                 unsigned int CPUInfo3;
+                 unsigned int InfoType;
+                 __get_cpuid(InfoType, &CPUInfo0, &CPUInfo1, &CPUInfo2, &CPUInfo3);
+            ]])],
+            [AC_MSG_RESULT([C method])
+                 AC_DEFINE([CPU_INFO_BY_C], [1], [Get CPU Info by c method])],
+            [AC_MSG_ERROR([no supported Get CPU Info method, please disable intrinsics])])])])
+   ],
+   [
+      AC_MSG_WARN([No intrinsics support for your architecture])
+      intrinsics_support="no"
+   ])
+],
+[
+   intrinsics_support="no"
+])
+
+AM_CONDITIONAL([CPU_ARM], [test "$cpu_arm" = "yes"])
+AM_CONDITIONAL([HAVE_ARM_NEON_INTR],
+    [test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1"])
+AM_CONDITIONAL([HAVE_ARM_NE10],
+    [test x"$HAVE_ARM_NE10" = x"1"])
+AM_CONDITIONAL([HAVE_SSE],
+    [test x"$OPUS_X86_MAY_HAVE_SSE" = x"1"])
+AM_CONDITIONAL([HAVE_SSE2],
+    [test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1"])
+AM_CONDITIONAL([HAVE_SSE4_1],
+    [test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1"])
+AM_CONDITIONAL([HAVE_AVX],
+    [test x"$OPUS_X86_MAY_HAVE_AVX" = x"1"])
+
+AS_IF([test x"$enable_rtcd" = x"yes"],[
+    AS_IF([test x"$rtcd_support" != x"no"],[
+        AC_DEFINE([OPUS_HAVE_RTCD], [1],
+            [Use run-time CPU capabilities detection])
+        OPUS_HAVE_RTCD=1
+        AC_SUBST(OPUS_HAVE_RTCD)
+    ])
+],[
+    rtcd_support="disabled"
+])
+
+AC_ARG_ENABLE([assertions],
+    [AS_HELP_STRING([--enable-assertions],[enable additional software error checking])],,
+    [enable_assertions=no])
+
+AS_IF([test "$enable_assertions" = "yes"], [
+  AC_DEFINE([ENABLE_ASSERTIONS], [1], [Assertions])
+])
+
+AC_ARG_ENABLE([fuzzing],
+    [AS_HELP_STRING([--enable-fuzzing],[causes the encoder to make random decisions])],,
+    [enable_fuzzing=no])
+
+AS_IF([test "$enable_fuzzing" = "yes"], [
+  AC_DEFINE([FUZZING], [1], [Fuzzing])
+])
+
+AC_ARG_ENABLE([ambisonics],
+    [AS_HELP_STRING([--enable-ambisonics],[enable experimental ambisonic encoding and decoding support])],,
+    [enable_ambisonics=no])
+
+AS_IF([test "$enable_ambisonics" = "yes"], [
+  AC_DEFINE([ENABLE_EXPERIMENTAL_AMBISONICS], [1], [Ambisonics Support])
+])
+
+AC_ARG_ENABLE([doc],
+    [AS_HELP_STRING([--disable-doc], [Do not build API documentation])],,
+    [enable_doc=yes])
+
+AS_IF([test "$enable_doc" = "yes"], [
+  AC_CHECK_PROG(HAVE_DOXYGEN, [doxygen], [yes], [no])
+],[
+  HAVE_DOXYGEN=no
+])
+
+AM_CONDITIONAL([HAVE_DOXYGEN], [test "$HAVE_DOXYGEN" = "yes"])
+
+AC_ARG_ENABLE([extra-programs],
+    [AS_HELP_STRING([--disable-extra-programs], [Do not build extra programs (demo and tests)])],,
+    [enable_extra_programs=yes])
+
+AM_CONDITIONAL([EXTRA_PROGRAMS], [test "$enable_extra_programs" = "yes"])
+
+
+saved_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -fvisibility=hidden"
+AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
+    [ AC_MSG_RESULT([yes]) ],
+    [ AC_MSG_RESULT([no])
+      CFLAGS="$saved_CFLAGS"
+    ])
+
+CFLAGS="$CFLAGS -W"
+
+warn_CFLAGS="-Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes"
+saved_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS $warn_CFLAGS"
+AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
+    [ AC_MSG_RESULT([yes]) ],
+    [ AC_MSG_RESULT([no])
+      CFLAGS="$saved_CFLAGS"
+    ])
+
+saved_LIBS="$LIBS"
+LIBS="$LIBS $LIBM"
+AC_CHECK_FUNCS([lrintf])
+AC_CHECK_FUNCS([lrint])
+LIBS="$saved_LIBS"
+
+AC_CHECK_FUNCS([__malloc_hook])
+
+AC_SUBST([PC_BUILD])
+
+AC_CONFIG_FILES([
+    Makefile
+    opus.pc
+    opus-uninstalled.pc
+    celt/arm/armopts.s
+    doc/Makefile
+    doc/Doxyfile
+])
+AC_CONFIG_HEADERS([config.h])
+
+AC_OUTPUT
+
+AC_MSG_NOTICE([
+------------------------------------------------------------------------
+  $PACKAGE_NAME $PACKAGE_VERSION:  Automatic configuration OK.
+
+    Compiler support:
+
+      C99 var arrays: ................ ${has_var_arrays}
+      C99 lrintf: .................... ${ac_cv_func_lrintf}
+      Use alloca: .................... ${use_alloca}
+
+    General configuration:
+
+      Floating point support: ........ ${enable_float}
+      Fast float approximations: ..... ${enable_float_approx}
+      Fixed point debugging: ......... ${enable_fixed_point_debug}
+      Inline Assembly Optimizations: . ${inline_optimization}
+      External Assembly Optimizations: ${asm_optimization}
+      Intrinsics Optimizations.......: ${intrinsics_support}
+      Run-time CPU detection: ........ ${rtcd_support}
+      Custom modes: .................. ${enable_custom_modes}
+      Assertion checking: ............ ${enable_assertions}
+      Fuzzing: ....................... ${enable_fuzzing}
+      Ambisonics support: .............${enable_ambisonics}
+
+      API documentation: ............. ${enable_doc}
+      Extra programs: ................ ${enable_extra_programs}
+------------------------------------------------------------------------
+
+ Type "make; make install" to compile and install
+ Type "make check" to run the test suite
+])
+
diff --git a/third_party/opus/src/doc/Doxyfile.in b/third_party/opus/src/doc/Doxyfile.in
new file mode 100644
index 0000000..cd776752
--- /dev/null
+++ b/third_party/opus/src/doc/Doxyfile.in
@@ -0,0 +1,320 @@
+# Doxyfile 1.8.10
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+# Only non-default options are included below to improve portability
+# between doxygen versions.
+#
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = Opus
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = @VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Opus audio codec (RFC 6716): API and operations manual"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @top_srcdir@/include/opus.h \
+                         @top_srcdir@/include/opus_types.h \
+                         @top_srcdir@/include/opus_defines.h \
+                         @top_srcdir@/include/opus_multistream.h \
+                         @top_srcdir@/include/opus_custom.h
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            = @top_srcdir@/doc/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            = @top_srcdir@/doc/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        = @top_srcdir@/doc/customdoxygen.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       = @top_srcdir@/doc/opus_logo.svg
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 0
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = https://www.mathjax.org/mathjax
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = letter
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = OPUS_EXPORT= \
+                         OPUS_CUSTOM_EXPORT= \
+                         OPUS_CUSTOM_EXPORT_STATIC= \
+                         OPUS_WARN_UNUSED_RESULT= \
+                         OPUS_ARG_NONNULL(_x)=
diff --git a/third_party/opus/src/doc/Makefile.am b/third_party/opus/src/doc/Makefile.am
new file mode 100644
index 0000000..31fddab
--- /dev/null
+++ b/third_party/opus/src/doc/Makefile.am
@@ -0,0 +1,45 @@
+## Process this file with automake to produce Makefile.in
+
+DOCINPUTS = $(top_srcdir)/include/opus.h \
+            $(top_srcdir)/include/opus_multistream.h \
+            $(top_srcdir)/include/opus_defines.h \
+            $(top_srcdir)/include/opus_types.h \
+            $(top_srcdir)/include/opus_custom.h \
+            $(top_srcdir)/doc/header.html \
+            $(top_srcdir)/doc/footer.html \
+            $(top_srcdir)/doc/customdoxygen.css
+
+EXTRA_DIST = customdoxygen.css Doxyfile.in footer.html header.html \
+             opus_logo.svg trivial_example.c
+
+
+if HAVE_DOXYGEN
+
+all-local: doxygen-build.stamp
+
+doxygen-build.stamp: Doxyfile $(DOCINPUTS)
+	doxygen
+	touch $@
+
+install-data-local:
+	$(INSTALL) -d $(DESTDIR)$(docdir)/html/search
+	for f in `find html -type f \! -name "installdox"`; do	\
+		$(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f;	\
+	done
+
+	$(INSTALL) -d $(DESTDIR)$(mandir)/man3
+	cd man && find man3 -type f -name opus_*.3 \
+		  -exec $(INSTALL_DATA) \{} $(DESTDIR)$(mandir)/man3 \;
+
+clean-local:
+	$(RM) -r html
+	$(RM) -r latex
+	$(RM) -r man
+	$(RM) doxygen-build.stamp
+	$(RM) doxygen_sqlite3.db
+
+uninstall-local:
+	$(RM) -r $(DESTDIR)$(docdir)/html
+	$(RM) $(DESTDIR)$(mandir)/man3/opus_*.3 $(DESTDIR)$(mandir)/man3/opus.h.3
+
+endif
diff --git a/third_party/opus/src/doc/TODO b/third_party/opus/src/doc/TODO
new file mode 100644
index 0000000..9e1c2d51
--- /dev/null
+++ b/third_party/opus/src/doc/TODO
@@ -0,0 +1,7 @@
+define audio bandwidth as frequency range
+
+repeat padding recommendation
+
+ptime: refer to RFC
+
+Opus does not provide any confidentiality or integrity protection
diff --git a/third_party/opus/src/doc/customdoxygen.css b/third_party/opus/src/doc/customdoxygen.css
new file mode 100644
index 0000000..70047787
--- /dev/null
+++ b/third_party/opus/src/doc/customdoxygen.css
@@ -0,0 +1,1011 @@
+/* The standard CSS for doxygen */
+
+body, table, div, p, dl {
+        font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
+        font-size: 13px;
+        line-height: 1.3;
+}
+
+/* @group Heading Levels */
+
+h1 {
+        font-size: 150%;
+}
+
+.title {
+        font-size: 150%;
+        font-weight: bold;
+        margin: 10px 2px;
+}
+
+h2 {
+        font-size: 120%;
+}
+
+h3 {
+        font-size: 100%;
+}
+
+dt {
+        font-weight: bold;
+}
+
+div.multicol {
+        -moz-column-gap: 1em;
+        -webkit-column-gap: 1em;
+        -moz-column-count: 3;
+        -webkit-column-count: 3;
+}
+
+p.startli, p.startdd, p.starttd {
+        margin-top: 2px;
+}
+
+p.endli {
+        margin-bottom: 0px;
+}
+
+p.enddd {
+        margin-bottom: 4px;
+}
+
+p.endtd {
+        margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+        font-weight: bold;
+}
+
+span.legend {
+        font-size: 70%;
+        text-align: center;
+}
+
+h3.version {
+        font-size: 90%;
+        text-align: center;
+}
+
+div.qindex, div.navtab{
+        background-color: #F1F1F1;
+        border: 1px solid #BDBDBD;
+        text-align: center;
+}
+
+div.qindex, div.navpath {
+        width: 100%;
+        line-height: 140%;
+}
+
+div.navtab {
+        margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a {
+        color: #646464;
+        font-weight: normal;
+        text-decoration: none;
+}
+
+.contents a:visited {
+        color: #747474;
+}
+
+a:hover {
+        text-decoration: underline;
+}
+
+a.qindex {
+        font-weight: bold;
+}
+
+a.qindexHL {
+        font-weight: bold;
+        background-color: #B8B8B8;
+        color: #ffffff;
+        border: 1px double #A8A8A8;
+}
+
+.contents a.qindexHL:visited {
+        color: #ffffff;
+}
+
+a.el {
+        font-weight: bold;
+}
+
+a.elRef {
+}
+
+a.code, a.code:visited {
+        color: #4665A2;
+}
+
+a.codeRef, a.codeRef:visited {
+        color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+        margin-left: -1cm;
+}
+
+.fragment {
+        font-family: monospace, fixed;
+        font-size: 105%;
+}
+
+pre.fragment {
+        border: 1px solid #D5D5D5;
+        background-color: #FCFCFC;
+        padding: 4px 6px;
+        margin: 4px 8px 4px 2px;
+        overflow: auto;
+        word-wrap: break-word;
+        font-size:  9pt;
+        line-height: 125%;
+}
+
+div.ah {
+        background-color: black;
+        font-weight: bold;
+        color: #ffffff;
+        margin-bottom: 3px;
+        margin-top: 3px;
+        padding: 0.2em;
+        border: solid thin #333;
+        border-radius: 0.5em;
+        -webkit-border-radius: .5em;
+        -moz-border-radius: .5em;
+        box-shadow: 2px 2px 3px #999;
+        -webkit-box-shadow: 2px 2px 3px #999;
+        -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+        background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+        background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.groupHeader {
+        margin-left: 16px;
+        margin-top: 12px;
+        font-weight: bold;
+}
+
+div.groupText {
+        margin-left: 16px;
+        font-style: italic;
+}
+
+body {
+        background-color: white;
+        color: black;
+        margin: 0;
+}
+
+div.contents {
+        margin-top: 10px;
+        margin-left: 8px;
+        margin-right: 8px;
+}
+
+td.indexkey {
+        background-color: #F1F1F1;
+        font-weight: bold;
+        border: 1px solid #D5D5D5;
+        margin: 2px 0px 2px 0;
+        padding: 2px 10px;
+        white-space: nowrap;
+        vertical-align: top;
+}
+
+td.indexvalue {
+        background-color: #F1F1F1;
+        border: 1px solid #D5D5D5;
+        padding: 2px 10px;
+        margin: 2px 0px;
+}
+
+tr.memlist {
+        background-color: #F2F2F2;
+}
+
+p.formulaDsp {
+        text-align: center;
+}
+
+img.formulaDsp {
+
+}
+
+img.formulaInl {
+        vertical-align: middle;
+}
+
+div.center {
+        text-align: center;
+        margin-top: 0px;
+        margin-bottom: 0px;
+        padding: 0px;
+}
+
+div.center img {
+        border: 0px;
+}
+
+address.footer {
+        text-align: right;
+        padding-right: 12px;
+}
+
+img.footer {
+        border: 0px;
+        vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+        color: #008000
+}
+
+span.keywordtype {
+        color: #604020
+}
+
+span.keywordflow {
+        color: #e08000
+}
+
+span.comment {
+        color: #800000
+}
+
+span.preprocessor {
+        color: #806020
+}
+
+span.stringliteral {
+        color: #002080
+}
+
+span.charliteral {
+        color: #008080
+}
+
+span.vhdldigit {
+        color: #ff00ff
+}
+
+span.vhdlchar {
+        color: #000000
+}
+
+span.vhdlkeyword {
+        color: #700070
+}
+
+span.vhdllogic {
+        color: #ff0000
+}
+
+blockquote {
+        background-color: #F9F9F9;
+        border-left: 2px solid #B8B8B8;
+        margin: 0 24px 0 4px;
+        padding: 0 12px 0 16px;
+}
+
+/* @end */
+
+/*
+.search {
+        color: #003399;
+        font-weight: bold;
+}
+
+form.search {
+        margin-bottom: 0px;
+        margin-top: 0px;
+}
+
+input.search {
+        font-size: 75%;
+        color: #000080;
+        font-weight: normal;
+        background-color: #e8eef2;
+}
+*/
+
+td.tiny {
+        font-size: 75%;
+}
+
+.dirtab {
+        padding: 4px;
+        border-collapse: collapse;
+        border: 1px solid #BDBDBD;
+}
+
+th.dirtab {
+        background: #F1F1F1;
+        font-weight: bold;
+}
+
+hr {
+        height: 0px;
+        border: none;
+        border-top: 1px solid #7A7A7A;
+}
+
+hr.footer {
+        height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+        border-spacing: 0px;
+        padding: 0px;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+        background-color: #FAFAFA;
+        border: none;
+        margin: 4px;
+        padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+        padding: 0px 8px 4px 8px;
+        color: #555;
+}
+
+.memItemLeft, .memItemRight, .memTemplParams {
+        border-top: 1px solid #D5D5D5;
+}
+
+.memItemLeft, .memTemplItemLeft {
+        white-space: nowrap;
+}
+
+.memItemRight {
+        width: 100%;
+}
+
+.memTemplParams {
+        color: #747474;
+        white-space: nowrap;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+        font-size: 80%;
+        color: #747474;
+        font-weight: normal;
+        margin-left: 9px;
+}
+
+.memnav {
+        background-color: #F1F1F1;
+        border: 1px solid #BDBDBD;
+        text-align: center;
+        margin: 2px;
+        margin-right: 15px;
+        padding: 2px;
+}
+
+.mempage {
+        width: 100%;
+}
+
+.memitem {
+        padding: 0;
+        margin-bottom: 10px;
+        margin-right: 5px;
+}
+
+.memname {
+        white-space: nowrap;
+        font-weight: bold;
+        margin-left: 6px;
+}
+
+.memproto, dl.reflist dt {
+        border-top: 1px solid #C0C0C0;
+        border-left: 1px solid #C0C0C0;
+        border-right: 1px solid #C0C0C0;
+        padding: 6px 0px 6px 0px;
+        color: #3D3D3D;
+        font-weight: bold;
+        text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+        /* opera specific markup */
+        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+        border-top-right-radius: 8px;
+        border-top-left-radius: 8px;
+        /* firefox specific markup */
+        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+        -moz-border-radius-topright: 8px;
+        -moz-border-radius-topleft: 8px;
+        /* webkit specific markup */
+        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+        -webkit-border-top-right-radius: 8px;
+        -webkit-border-top-left-radius: 8px;
+        background-image:url('nav_f.png');
+        background-repeat:repeat-x;
+        background-color: #EAEAEA;
+
+}
+
+.memdoc, dl.reflist dd {
+        border-bottom: 1px solid #C0C0C0;
+        border-left: 1px solid #C0C0C0;
+        border-right: 1px solid #C0C0C0;
+        padding: 2px 5px;
+        background-color: #FCFCFC;
+        border-top-width: 0;
+        /* opera specific markup */
+        border-bottom-left-radius: 8px;
+        border-bottom-right-radius: 8px;
+        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+        /* firefox specific markup */
+        -moz-border-radius-bottomleft: 8px;
+        -moz-border-radius-bottomright: 8px;
+        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+        background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F9F9F9 95%, #F2F2F2);
+        /* webkit specific markup */
+        -webkit-border-bottom-left-radius: 8px;
+        -webkit-border-bottom-right-radius: 8px;
+        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+        background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F9F9F9), to(#F2F2F2));
+}
+
+dl.reflist dt {
+        padding: 5px;
+}
+
+dl.reflist dd {
+        margin: 0px 0px 10px 0px;
+        padding: 5px;
+}
+
+.paramkey {
+        text-align: right;
+}
+
+.paramtype {
+        white-space: nowrap;
+}
+
+.paramname {
+        color: #602020;
+        white-space: nowrap;
+}
+.paramname em {
+        font-style: normal;
+}
+
+.params, .retval, .exception, .tparams {
+        border-spacing: 6px 2px;
+}
+
+.params .paramname, .retval .paramname {
+        font-weight: bold;
+        vertical-align: top;
+}
+
+.params .paramtype {
+        font-style: italic;
+        vertical-align: top;
+}
+
+.params .paramdir {
+        font-family: "courier new",courier,monospace;
+        vertical-align: top;
+}
+
+
+
+
+/* @end */
+
+/* @group Directory (tree) */
+
+/* for the tree view */
+
+.ftvtree {
+        font-family: sans-serif;
+        margin: 0px;
+}
+
+/* these are for tree view when used as main index */
+
+.directory {
+        font-size: 9pt;
+        font-weight: bold;
+        margin: 5px;
+}
+
+.directory h3 {
+        margin: 0px;
+        margin-top: 1em;
+        font-size: 11pt;
+}
+
+/*
+The following two styles can be used to replace the root node title
+with an image of your choice.  Simply uncomment the next two styles,
+specify the name of your image and be sure to set 'height' to the
+proper pixel height of your image.
+*/
+
+/*
+.directory h3.swap {
+        height: 61px;
+        background-repeat: no-repeat;
+        background-image: url("yourimage.gif");
+}
+.directory h3.swap span {
+        display: none;
+}
+*/
+
+.directory > h3 {
+        margin-top: 0;
+}
+
+.directory p {
+        margin: 0px;
+        white-space: nowrap;
+}
+
+.directory div {
+        display: none;
+        margin: 0px;
+}
+
+.directory img {
+        vertical-align: -30%;
+}
+
+/* these are for tree view when not used as main index */
+
+.directory-alt {
+        font-size: 100%;
+        font-weight: bold;
+}
+
+.directory-alt h3 {
+        margin: 0px;
+        margin-top: 1em;
+        font-size: 11pt;
+}
+
+.directory-alt > h3 {
+        margin-top: 0;
+}
+
+.directory-alt p {
+        margin: 0px;
+        white-space: nowrap;
+}
+
+.directory-alt div {
+        display: none;
+        margin: 0px;
+}
+
+.directory-alt img {
+        vertical-align: -30%;
+}
+
+/* @end */
+
+div.dynheader {
+        margin-top: 8px;
+}
+
+address {
+        font-style: normal;
+        color: #464646;
+}
+
+table.doxtable {
+        border-collapse:collapse;
+        margin-top: 4px;
+        margin-bottom: 4px;
+}
+
+table.doxtable td, table.doxtable th {
+        border: 1px solid #4A4A4A;
+        padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+        background-color: #5B5B5B;
+        color: #FFFFFF;
+        font-size: 110%;
+        padding-bottom: 4px;
+        padding-top: 5px;
+}
+
+table.fieldtable {
+        width: 100%;
+        margin-bottom: 10px;
+        border: 1px solid #C0C0C0;
+        border-spacing: 0px;
+        -moz-border-radius: 4px;
+        -webkit-border-radius: 4px;
+        border-radius: 4px;
+        -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+        -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+        box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+}
+
+.fieldtable td, .fieldtable th {
+        padding: 3px 7px 2px;
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+        white-space: nowrap;
+        border-right: 1px solid #C0C0C0;
+        border-bottom: 1px solid #C0C0C0;
+        vertical-align: top;
+}
+
+.fieldtable td.fielddoc {
+        border-bottom: 1px solid #C0C0C0;
+        width: 100%;
+}
+
+.fieldtable tr:last-child td {
+        border-bottom: none;
+}
+
+.fieldtable th {
+        background-image:url('nav_f.png');
+        background-repeat:repeat-x;
+        background-color: #EAEAEA;
+        font-size: 90%;
+        color: #3D3D3D;
+        padding-bottom: 4px;
+        padding-top: 5px;
+        text-align:left;
+        -moz-border-radius-topleft: 4px;
+        -moz-border-radius-topright: 4px;
+        -webkit-border-top-left-radius: 4px;
+        -webkit-border-top-right-radius: 4px;
+        border-top-left-radius: 4px;
+        border-top-right-radius: 4px;
+        border-bottom: 1px solid #C0C0C0;
+}
+
+
+.tabsearch {
+        top: 0px;
+        left: 10px;
+        height: 36px;
+        background-image: url('tab_b.png');
+        z-index: 101;
+        overflow: hidden;
+        font-size: 13px;
+}
+
+.navpath ul
+{
+        font-size: 11px;
+        background-image:url('tab_b.png');
+        background-repeat:repeat-x;
+        height:30px;
+        line-height:30px;
+        color:#ABABAB;
+        border:solid 1px #D3D3D3;
+        overflow:hidden;
+        margin:0px;
+        padding:0px;
+}
+
+.navpath li
+{
+        list-style-type:none;
+        float:left;
+        padding-left:10px;
+        padding-right:15px;
+        background-image:url('bc_s.png');
+        background-repeat:no-repeat;
+        background-position:right;
+        color:#595959;
+}
+
+.navpath li.navelem a
+{
+        height:32px;
+        display:block;
+        text-decoration: none;
+        outline: none;
+}
+
+.navpath li.navelem a:hover
+{
+        color:#929292;
+}
+
+.navpath li.footer
+{
+        list-style-type:none;
+        float:right;
+        padding-left:10px;
+        padding-right:15px;
+        background-image:none;
+        background-repeat:no-repeat;
+        background-position:right;
+        color:#595959;
+        font-size: 8pt;
+}
+
+
+div.summary
+{
+        float: right;
+        font-size: 8pt;
+        padding-right: 5px;
+        width: 50%;
+        text-align: right;
+}
+
+div.summary a
+{
+        white-space: nowrap;
+}
+
+div.ingroups
+{
+        margin-left: 5px;
+        font-size: 8pt;
+        padding-left: 5px;
+        width: 50%;
+        text-align: left;
+}
+
+div.ingroups a
+{
+        white-space: nowrap;
+}
+
+div.header
+{
+        background-image:url('nav_h.png');
+        background-repeat:repeat-x;
+        background-color: #FAFAFA;
+        margin:  0px;
+        border-bottom: 1px solid #D5D5D5;
+}
+
+div.headertitle
+{
+        padding: 5px 5px 5px 7px;
+}
+
+dl
+{
+        padding: 0 0 0 10px;
+}
+
+/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
+dl.section
+{
+        border-left:4px solid;
+        padding: 0 0 0 6px;
+}
+
+dl.note
+{
+        border-color: #D0C000;
+}
+
+dl.warning, dl.attention
+{
+        border-color: #FF0000;
+}
+
+dl.pre, dl.post, dl.invariant
+{
+        border-color: #00D000;
+}
+
+dl.deprecated
+{
+        border-color: #505050;
+}
+
+dl.todo
+{
+        border-color: #00C0E0;
+}
+
+dl.test
+{
+        border-color: #3030E0;
+}
+
+dl.bug
+{
+        border-color: #C08050;
+}
+
+dl.section dd {
+        margin-bottom: 6px;
+}
+
+
+#projectlogo
+{
+        text-align: center;
+        vertical-align: bottom;
+        border-collapse: separate;
+}
+
+#projectlogo img
+{
+        border: 0px none;
+}
+
+#projectname
+{
+        font: 300% Tahoma, Arial,sans-serif;
+        margin: 0px;
+        padding: 2px 0px;
+}
+
+#projectbrief
+{
+        font: 120% Tahoma, Arial,sans-serif;
+        margin: 0px;
+        padding: 0px;
+}
+
+#projectnumber
+{
+        font: 100% Tahoma, Arial,sans-serif;
+        margin: 0px;
+        padding: 0px;
+}
+
+#titlearea
+{
+        padding: 0px;
+        margin: 0px;
+        width: 100%;
+        border-bottom: 1px solid #848484;
+}
+
+.image
+{
+        text-align: center;
+}
+
+.dotgraph
+{
+        text-align: center;
+}
+
+.mscgraph
+{
+        text-align: center;
+}
+
+.caption
+{
+        font-weight: bold;
+}
+
+div.zoom
+{
+        border: 1px solid #AFAFAF;
+}
+
+dl.citelist {
+        margin-bottom:50px;
+}
+
+dl.citelist dt {
+        color:#545454;
+        float:left;
+        font-weight:bold;
+        margin-right:10px;
+        padding:5px;
+}
+
+dl.citelist dd {
+        margin:2px 0;
+        padding:5px 0;
+}
+
+div.toc {
+        padding: 14px 25px;
+        background-color: #F7F7F7;
+        border: 1px solid #E3E3E3;
+        border-radius: 7px 7px 7px 7px;
+        float: right;
+        height: auto;
+        margin: 0 20px 10px 10px;
+        width: 200px;
+}
+
+div.toc li {
+        background: url("bdwn.png") no-repeat scroll 0 5px transparent;
+        font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;
+        margin-top: 5px;
+        padding-left: 10px;
+        padding-top: 2px;
+}
+
+div.toc h3 {
+        font: bold 12px/1.2 Arial,FreeSans,sans-serif;
+        color: #747474;
+        border-bottom: 0 none;
+        margin: 0;
+}
+
+div.toc ul {
+        list-style: none outside none;
+        border: medium none;
+        padding: 0px;
+}
+
+div.toc li.level1 {
+        margin-left: 0px;
+}
+
+div.toc li.level2 {
+        margin-left: 15px;
+}
+
+div.toc li.level3 {
+        margin-left: 30px;
+}
+
+div.toc li.level4 {
+        margin-left: 45px;
+}
+
+
+@media print
+{
+  #top { display: none; }
+  #side-nav { display: none; }
+  #nav-path { display: none; }
+  body { overflow:visible; }
+  h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
+  .summary { display: none; }
+  .memitem { page-break-inside: avoid; }
+  #doc-content
+  {
+    margin-left:0 !important;
+    height:auto !important;
+    width:auto !important;
+    overflow:inherit;
+    display:inline;
+  }
+  pre.fragment
+  {
+    overflow: visible;
+    text-wrap: unrestricted;
+    white-space: -moz-pre-wrap; /* Moz */
+    white-space: -pre-wrap; /* Opera 4-6 */
+    white-space: -o-pre-wrap; /* Opera 7 */
+    white-space: pre-wrap; /* CSS3  */
+    word-wrap: break-word; /* IE 5.5+ */
+  }
+}
diff --git a/third_party/opus/src/doc/footer.html b/third_party/opus/src/doc/footer.html
new file mode 100644
index 0000000..ad4a9259
--- /dev/null
+++ b/third_party/opus/src/doc/footer.html
@@ -0,0 +1,28 @@
+<!--BEGIN GENERATE_TREEVIEW-->
+    <li class="footer">Generated by
+    <a href="https://www.stack.nl/~dimitri/doxygen/">
+    <img class="footer" src="doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+   </ul>
+ </div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/>
+<table width="100%">
+  <tbody>
+    <tr>
+      <td>
+For more information visit the <a href="https://opus-codec.org">Opus Website</a>.
+      </td>
+      <td>
+        <address class="footer"><small>
+          Generated by
+          <a href="https://www.stack.nl/~dimitri/doxygen/">doxygen</a>
+          $doxygenversion
+        </small></address>
+      </td>
+    </tr>
+  </tbody>
+</table>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>
diff --git a/third_party/opus/src/doc/header.html b/third_party/opus/src/doc/header.html
new file mode 100644
index 0000000..b2c906be
--- /dev/null
+++ b/third_party/opus/src/doc/header.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath$tabs.css" rel="stylesheet" type="text/css"/>
+<link href="$relpath$customdoxygen.css" rel="stylesheet" type="text/css" />
+$treeview
+$search
+$mathjax
+</head>
+<body>
+<div id="top"><!-- do not remove this div! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 64px;">
+  <!--BEGIN PROJECT_LOGO-->
+  <td id="projectlogo"><img alt="Logo" src="$relpath$$projectlogo"/></td>
+  <!--END PROJECT_LOGO-->
+  <!--BEGIN PROJECT_NAME-->
+  <td style="padding-left: 0.5em;">
+  <div id="projectname"><img src="opus_logo.svg" width=112 height=64 alt="Opus"/><!--$projectname--></div>
+  </td>
+  <td><table style="padding-left: 0.5em;" cellspacing="0" cellpadding="0"><tbody>
+   <tr><td>
+   <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+   </td></tr>
+  <td><!--BEGIN PROJECT_NUMBER--><span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+   </td></tr>
+   </table>
+  </td>
+  <!--END PROJECT_NAME-->
+  <!--BEGIN !PROJECT_NAME-->
+   <!--BEGIN PROJECT_BRIEF-->
+    <td style="padding-left: 0.5em;">
+    <div id="projectbrief">$projectbrief</div>
+    </td>
+   <!--END PROJECT_BRIEF-->
+  <!--END !PROJECT_NAME-->
+  <!--BEGIN DISABLE_INDEX-->
+   <!--BEGIN SEARCHENGINE-->
+   <td>$searchbox</td>
+   <!--END SEARCHENGINE-->
+  <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
diff --git a/third_party/opus/src/doc/opus_logo.svg b/third_party/opus/src/doc/opus_logo.svg
new file mode 100644
index 0000000..db2879ef
--- /dev/null
+++ b/third_party/opus/src/doc/opus_logo.svg
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   version="1.1"
+   x="0px"
+   y="0px"
+   width="360"
+   height="205"
+   viewBox="-72 -23.757 360 205"
+   overflow="visible"
+   enable-background="new -72 -23.757 504 252"
+   xml:space="preserve"
+   id="svg2"
+   style="overflow:visible">
+<defs
+   id="defs4">
+<linearGradient
+   xlink:href="#SVGID_1_"
+   id="linearGradient3027"
+   gradientUnits="userSpaceOnUse"
+   x1="194.53169"
+   y1="95.107399"
+   x2="194.53169"
+   y2="9.9475983e-14" /><linearGradient
+   xlink:href="#SVGID_2_"
+   id="linearGradient3029"
+   gradientUnits="userSpaceOnUse"
+   x1="229.61819"
+   y1="116.208"
+   x2="229.61819"
+   y2="164.46291" /><linearGradient
+   xlink:href="#SVGID_3_"
+   id="linearGradient3031"
+   gradientUnits="userSpaceOnUse"
+   x1="43.9897"
+   y1="115.4395"
+   x2="43.9897"
+   y2="165.2314" /><linearGradient
+   xlink:href="#SVGID_4_"
+   id="linearGradient3033"
+   gradientUnits="userSpaceOnUse"
+   x1="311.2847"
+   y1="115.7188"
+   x2="311.2847"
+   y2="165.2822" /><linearGradient
+   xlink:href="#SVGID_5_"
+   id="linearGradient3035"
+   gradientUnits="userSpaceOnUse"
+   x1="129.1987"
+   y1="115.5791"
+   x2="129.1987"
+   y2="204.4863" /></defs>
+<linearGradient
+   id="SVGID_1_"
+   gradientUnits="userSpaceOnUse"
+   x1="194.53169"
+   y1="95.107399"
+   x2="194.53169"
+   y2="9.9475983e-14">
+        <stop
+   offset="0.0056"
+   style="stop-color:#8E8E8E"
+   id="stop7" />
+        <stop
+   offset="1"
+   style="stop-color:#B5B5B5"
+   id="stop9" />
+</linearGradient>
+
+<linearGradient
+   id="SVGID_2_"
+   gradientUnits="userSpaceOnUse"
+   x1="229.61819"
+   y1="116.208"
+   x2="229.61819"
+   y2="164.46291">
+        <stop
+   offset="0.0056"
+   style="stop-color:#494748"
+   id="stop14" />
+        <stop
+   offset="1"
+   style="stop-color:#000000"
+   id="stop16" />
+</linearGradient>
+
+<linearGradient
+   id="SVGID_3_"
+   gradientUnits="userSpaceOnUse"
+   x1="43.9897"
+   y1="115.4395"
+   x2="43.9897"
+   y2="165.2314">
+        <stop
+   offset="0.0056"
+   style="stop-color:#494748"
+   id="stop21" />
+        <stop
+   offset="1"
+   style="stop-color:#000000"
+   id="stop23" />
+</linearGradient>
+
+<linearGradient
+   id="SVGID_4_"
+   gradientUnits="userSpaceOnUse"
+   x1="311.2847"
+   y1="115.7188"
+   x2="311.2847"
+   y2="165.2822">
+        <stop
+   offset="0.0056"
+   style="stop-color:#494748"
+   id="stop28" />
+        <stop
+   offset="1"
+   style="stop-color:#000000"
+   id="stop30" />
+</linearGradient>
+
+<linearGradient
+   id="SVGID_5_"
+   gradientUnits="userSpaceOnUse"
+   x1="129.1987"
+   y1="115.5791"
+   x2="129.1987"
+   y2="204.4863">
+        <stop
+   offset="0.0056"
+   style="stop-color:#494748"
+   id="stop35" />
+        <stop
+   offset="1"
+   style="stop-color:#000000"
+   id="stop37" />
+</linearGradient>
+<g
+   id="g3020"
+   transform="translate(-72.001783,-23.243)"><path
+     id="path11"
+     d="M 257.355,13.996 C 249.943,7.826 238.533,3.695 223.153,1.588 l -11.302,35.935 c -0.244,1.318 -0.664,2.815 -1.315,4.54 -1.153,2.883 -2.542,5.258 -4.174,7.127 -1.634,1.874 -3.463,3.335 -5.489,4.4 -2.028,1.059 -4.232,1.79 -6.614,2.193 -2.382,0.4 -4.847,0.526 -7.393,0.378 -2.549,-0.148 -4.717,-0.495 -6.501,-1.042 -1.786,-0.546 -3.428,-1.452 -4.925,-2.72 -1.107,-1.245 -1.751,-2.878 -1.927,-4.902 -0.177,-2.024 0.313,-4.527 1.471,-7.509 1.035,-2.592 2.345,-4.852 3.933,-6.771 1.587,-1.921 3.443,-3.411 5.565,-4.467 2.027,-1.059 4.206,-1.768 6.539,-2.125 2.327,-0.354 4.915,-0.448 7.756,-0.283 2.352,0.139 4.542,0.485 6.574,1.048 0.964,0.265 1.808,0.613 2.542,1.033 L 216.57,0.832 c -2.142,-0.202 -4.333,-0.379 -6.609,-0.51 -21.901,-1.279 -40.308,1.251 -55.229,7.576 -14.918,6.33 -24.865,15.715 -29.833,28.154 -1.491,3.814 -2.292,7.408 -2.41,10.785 l -0.01,-0.005 c -1.426,24.463 14.295,38.245 24.007,44.373 3.897,2.609 7.362,3.901 7.362,3.901 l 4.451,-14.225 1.316,-3.496 c 5.859,1.108 12.375,1.879 19.573,2.298 22.053,1.286 40.539,-1.232 55.458,-7.564 14.916,-6.325 24.78,-15.638 29.591,-27.942 4.806,-12.295 2.514,-22.357 -6.882,-30.181 z"
+     style="fill:url(#linearGradient3027)"/><path
+     id="path18"
+     d="m 269.531,139.499 c -2.511,7.718 -8.23,13.807 -17.156,18.27 -8.926,4.463 -20.223,6.694 -33.891,6.694 -13.484,0 -23.292,-2.208 -29.43,-6.626 -6.136,-4.415 -7.904,-10.528 -5.299,-18.338 l 7.53,-23.291 h 25.663 l -7.252,23.151 c -0.931,2.883 -1.232,5.278 -0.906,7.183 0.326,1.907 1.046,3.417 2.162,4.533 1.394,1.113 2.95,1.88 4.672,2.299 1.72,0.419 3.788,0.629 6.207,0.629 2.417,0 4.742,-0.255 6.974,-0.769 2.231,-0.51 4.275,-1.323 6.138,-2.438 1.858,-1.116 3.508,-2.602 4.951,-4.463 1.44,-1.859 2.626,-4.186 3.557,-6.974 l 7.532,-23.151 h 25.663 l -7.115,23.291 z"
+     style="fill:url(#linearGradient3029)"/><path
+     id="path25"
+     d="m 86.875,140.404 c 2.51,-7.717 0.743,-13.808 -5.301,-18.271 -6.044,-4.463 -15.899,-6.694 -29.567,-6.694 -13.483,0 -24.686,2.21 -33.611,6.625 -8.928,4.417 -14.693,10.53 -17.295,18.34 -2.51,7.72 -0.722,13.786 5.37,18.201 6.089,4.418 15.922,6.626 29.498,6.626 13.575,0 24.826,-2.208 33.753,-6.626 8.924,-4.415 14.642,-10.481 17.153,-18.201 z m -26.082,0.14 c -0.931,2.978 -2.069,5.3 -3.417,6.974 -1.349,1.675 -3.046,3.116 -5.09,4.323 -1.768,1.116 -3.765,1.883 -5.997,2.302 -2.232,0.419 -4.463,0.627 -6.696,0.627 -2.697,0 -4.999,-0.23 -6.903,-0.696 -1.907,-0.465 -3.417,-1.256 -4.533,-2.371 -1.21,-1.116 -1.906,-2.626 -2.092,-4.533 -0.188,-1.904 0.14,-4.114 0.977,-6.625 0.929,-2.88 2.161,-5.275 3.696,-7.183 1.534,-1.904 3.229,-3.417 5.09,-4.533 2.138,-1.115 4.206,-1.882 6.207,-2.301 1.999,-0.419 4.207,-0.627 6.625,-0.627 2.416,0 4.603,0.257 6.555,0.767 1.953,0.512 3.486,1.325 4.603,2.44 1.115,1.116 1.789,2.605 2.021,4.463 0.231,1.86 -0.117,4.185 -1.046,6.973 z"
+     style="fill:url(#linearGradient3031)"/><path
+     id="path32"
+     d="m 310.14,126.807 c 2.928,-0.698 9.041,-1.046 18.339,-1.046 4.833,0 9.506,0.487 14.018,1.465 4.508,0.976 9.042,2.209 13.598,3.696 L 360,119.066 c -2.698,-0.744 -6.625,-1.487 -11.787,-2.231 -5.159,-0.744 -10.669,-1.116 -16.526,-1.116 -17.574,0 -30.405,1.513 -38.493,4.533 -8.089,3.022 -12.879,6.812 -14.366,11.366 -1.115,3.44 -0.348,6.346 2.302,8.717 2.65,2.371 7.322,4.115 14.016,5.229 2.511,0.467 6.624,0.838 12.343,1.117 5.718,0.279 9.46,0.557 11.228,0.836 3.717,0.373 6.205,0.837 7.461,1.396 1.254,0.558 1.695,1.394 1.325,2.511 -0.467,1.303 -1.976,2.279 -4.533,2.928 -2.559,0.652 -6.3,0.977 -11.227,0.977 -0.77,0 -1.513,-0.003 -2.241,-0.007 -1.846,-0.101 -3.858,-0.272 -5.791,-0.476 -2.06,-0.22 -4.118,-0.485 -6.162,-0.795 -4.089,-0.62 -8.132,-1.419 -12.058,-2.439 -3.921,-1.022 -7.734,-2.267 -11.26,-3.813 -0.474,-0.208 -0.932,-0.433 -1.394,-0.654 -2.476,3.979 -5.905,7.451 -10.27,10.396 2.259,1.085 4.539,1.976 6.807,2.742 4.52,1.506 9.034,2.52 13.525,3.266 4.494,0.741 8.969,1.203 13.431,1.472 2.231,0.133 4.459,0.215 6.691,0.248 1.966,0.026 3.882,0.02 5.902,-0.045 12.216,-0.072 22.318,-1.53 30.294,-4.386 8.18,-2.929 13.062,-6.81 14.644,-11.645 1.116,-3.349 0.441,-6.138 -2.021,-8.369 -2.466,-2.231 -6.813,-3.857 -13.041,-4.882 -2.883,-0.371 -5.768,-0.719 -8.647,-1.046 -2.884,-0.324 -5.533,-0.628 -7.951,-0.906 -9.577,-0.65 -14.924,-1.255 -16.039,-1.813 -1.116,-0.558 -1.488,-1.394 -1.116,-2.511 0.467,-1.209 2.164,-2.163 5.094,-2.859 z"
+     style="fill:url(#linearGradient3033)"/><path
+     id="path39"
+     d="m 172.838,122.204 c -6.091,-4.415 -15.924,-6.625 -29.499,-6.625 -13.577,0 -24.826,2.21 -33.751,6.625 -8.926,4.417 -14.4,10.415 -16.911,18.131 l -0.105,0.349 -12.692,39.19 c -5.26,17.631 17.526,24.612 17.526,24.612 l 7.58,-24.612 0.656,-2.106 c 0.592,-1.982 1.192,-3.964 1.781,-5.948 l 1.686,-5.531 c 0.603,-1.832 1.207,-3.662 1.85,-5.481 l 3.979,-10.875 1.993,-5.436 1.429,-3.718 c 0.051,-0.172 0.099,-0.339 0.155,-0.514 0.836,-2.509 1.953,-4.718 3.347,-6.624 1.396,-1.904 3.069,-3.417 5.021,-4.533 1.859,-1.115 3.882,-1.904 6.067,-2.371 2.183,-0.464 4.625,-0.696 7.322,-0.696 2.231,0 4.325,0.208 6.277,0.627 1.952,0.419 3.438,1.186 4.463,2.301 1.301,1.209 2.068,2.65 2.3,4.323 0.231,1.675 -0.117,3.999 -1.046,6.974 -0.931,2.79 -2.116,5.116 -3.557,6.974 -1.442,1.862 -3.091,3.348 -4.951,4.464 -1.861,1.115 -3.905,1.931 -6.136,2.44 -2.231,0.512 -4.558,0.767 -6.973,0.767 -2.419,0 -4.487,-0.208 -6.207,-0.627 -1.721,-0.419 -3.326,-1.186 -4.812,-2.302 -0.112,-0.112 -0.201,-0.247 -0.305,-0.366 l -3.674,10.658 c -0.206,0.613 -0.403,1.228 -0.601,1.842 3.479,0.708 7.507,1.13 12.111,1.256 13.668,0 24.965,-2.231 33.893,-6.694 8.926,-4.464 14.643,-10.552 17.154,-18.271 2.511,-7.719 0.718,-13.786 -5.37,-18.203 z"
+     style="fill:url(#linearGradient3035)"/></g>
+</svg>
diff --git a/third_party/opus/src/doc/trivial_example.c b/third_party/opus/src/doc/trivial_example.c
new file mode 100644
index 0000000..047ca0a
--- /dev/null
+++ b/third_party/opus/src/doc/trivial_example.c
@@ -0,0 +1,160 @@
+/* Copyright (c) 2013 Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This is meant to be a simple example of encoding and decoding audio
+   using Opus. It should make it easy to understand how the Opus API
+   works. For more information, see the full API documentation at:
+   https://www.opus-codec.org/docs/ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <opus.h>
+#include <stdio.h>
+
+/*The frame size is hardcoded for this sample code but it doesn't have to be*/
+#define FRAME_SIZE 960
+#define SAMPLE_RATE 48000
+#define CHANNELS 2
+#define APPLICATION OPUS_APPLICATION_AUDIO
+#define BITRATE 64000
+
+#define MAX_FRAME_SIZE 6*960
+#define MAX_PACKET_SIZE (3*1276)
+
+int main(int argc, char **argv)
+{
+   char *inFile;
+   FILE *fin;
+   char *outFile;
+   FILE *fout;
+   opus_int16 in[FRAME_SIZE*CHANNELS];
+   opus_int16 out[MAX_FRAME_SIZE*CHANNELS];
+   unsigned char cbits[MAX_PACKET_SIZE];
+   int nbBytes;
+   /*Holds the state of the encoder and decoder */
+   OpusEncoder *encoder;
+   OpusDecoder *decoder;
+   int err;
+
+   if (argc != 3)
+   {
+      fprintf(stderr, "usage: trivial_example input.pcm output.pcm\n");
+      fprintf(stderr, "input and output are 16-bit little-endian raw files\n");
+      return EXIT_FAILURE;
+   }
+
+   /*Create a new encoder state */
+   encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err);
+   if (err<0)
+   {
+      fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err));
+      return EXIT_FAILURE;
+   }
+   /* Set the desired bit-rate. You can also set other parameters if needed.
+      The Opus library is designed to have good defaults, so only set
+      parameters you know you need. Doing otherwise is likely to result
+      in worse quality, but better. */
+   err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE));
+   if (err<0)
+   {
+      fprintf(stderr, "failed to set bitrate: %s\n", opus_strerror(err));
+      return EXIT_FAILURE;
+   }
+   inFile = argv[1];
+   fin = fopen(inFile, "r");
+   if (fin==NULL)
+   {
+      fprintf(stderr, "failed to open input file: %s\n", strerror(errno));
+      return EXIT_FAILURE;
+   }
+
+
+   /* Create a new decoder state. */
+   decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err);
+   if (err<0)
+   {
+      fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err));
+      return EXIT_FAILURE;
+   }
+   outFile = argv[2];
+   fout = fopen(outFile, "w");
+   if (fout==NULL)
+   {
+      fprintf(stderr, "failed to open output file: %s\n", strerror(errno));
+      return EXIT_FAILURE;
+   }
+
+   while (1)
+   {
+      int i;
+      unsigned char pcm_bytes[MAX_FRAME_SIZE*CHANNELS*2];
+      int frame_size;
+
+      /* Read a 16 bits/sample audio frame. */
+      fread(pcm_bytes, sizeof(short)*CHANNELS, FRAME_SIZE, fin);
+      if (feof(fin))
+         break;
+      /* Convert from little-endian ordering. */
+      for (i=0;i<CHANNELS*FRAME_SIZE;i++)
+         in[i]=pcm_bytes[2*i+1]<<8|pcm_bytes[2*i];
+
+      /* Encode the frame. */
+      nbBytes = opus_encode(encoder, in, FRAME_SIZE, cbits, MAX_PACKET_SIZE);
+      if (nbBytes<0)
+      {
+         fprintf(stderr, "encode failed: %s\n", opus_strerror(nbBytes));
+         return EXIT_FAILURE;
+      }
+
+
+      /* Decode the data. In this example, frame_size will be constant because
+         the encoder is using a constant frame size. However, that may not
+         be the case for all encoders, so the decoder must always check
+         the frame size returned. */
+      frame_size = opus_decode(decoder, cbits, nbBytes, out, MAX_FRAME_SIZE, 0);
+      if (frame_size<0)
+      {
+         fprintf(stderr, "decoder failed: %s\n", opus_strerror(frame_size));
+         return EXIT_FAILURE;
+      }
+
+      /* Convert to little-endian ordering. */
+      for(i=0;i<CHANNELS*frame_size;i++)
+      {
+         pcm_bytes[2*i]=out[i]&0xFF;
+         pcm_bytes[2*i+1]=(out[i]>>8)&0xFF;
+      }
+      /* Write the decoded audio to file. */
+      fwrite(pcm_bytes, sizeof(short), frame_size*CHANNELS, fout);
+   }
+   /*Destroy the encoder state*/
+   opus_encoder_destroy(encoder);
+   opus_decoder_destroy(decoder);
+   fclose(fin);
+   fclose(fout);
+   return EXIT_SUCCESS;
+}
diff --git a/third_party/opus/src/include/opus.h b/third_party/opus/src/include/opus.h
new file mode 100644
index 0000000..5be73dd
--- /dev/null
+++ b/third_party/opus/src/include/opus.h
@@ -0,0 +1,981 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+   Written by Jean-Marc Valin and Koen Vos */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus.h
+ * @brief Opus reference implementation API
+ */
+
+#ifndef OPUS_H
+#define OPUS_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @mainpage Opus
+ *
+ * The Opus codec is designed for interactive speech and audio transmission over the Internet.
+ * It is designed by the IETF Codec Working Group and incorporates technology from
+ * Skype's SILK codec and Xiph.Org's CELT codec.
+ *
+ * The Opus codec is designed to handle a wide range of interactive audio applications,
+ * including Voice over IP, videoconferencing, in-game chat, and even remote live music
+ * performances. It can scale from low bit-rate narrowband speech to very high quality
+ * stereo music. Its main features are:
+
+ * @li Sampling rates from 8 to 48 kHz
+ * @li Bit-rates from 6 kb/s to 510 kb/s
+ * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)
+ * @li Audio bandwidth from narrowband to full-band
+ * @li Support for speech and music
+ * @li Support for mono and stereo
+ * @li Support for multichannel (up to 255 channels)
+ * @li Frame sizes from 2.5 ms to 60 ms
+ * @li Good loss robustness and packet loss concealment (PLC)
+ * @li Floating point and fixed-point implementation
+ *
+ * Documentation sections:
+ * @li @ref opus_encoder
+ * @li @ref opus_decoder
+ * @li @ref opus_repacketizer
+ * @li @ref opus_multistream
+ * @li @ref opus_libinfo
+ * @li @ref opus_custom
+ */
+
+/** @defgroup opus_encoder Opus Encoder
+  * @{
+  *
+  * @brief This page describes the process and functions used to encode Opus.
+  *
+  * Since Opus is a stateful codec, the encoding process starts with creating an encoder
+  * state. This can be done with:
+  *
+  * @code
+  * int          error;
+  * OpusEncoder *enc;
+  * enc = opus_encoder_create(Fs, channels, application, &error);
+  * @endcode
+  *
+  * From this point, @c enc can be used for encoding an audio stream. An encoder state
+  * @b must @b not be used for more than one stream at the same time. Similarly, the encoder
+  * state @b must @b not be re-initialized for each frame.
+  *
+  * While opus_encoder_create() allocates memory for the state, it's also possible
+  * to initialize pre-allocated memory:
+  *
+  * @code
+  * int          size;
+  * int          error;
+  * OpusEncoder *enc;
+  * size = opus_encoder_get_size(channels);
+  * enc = malloc(size);
+  * error = opus_encoder_init(enc, Fs, channels, application);
+  * @endcode
+  *
+  * where opus_encoder_get_size() returns the required size for the encoder state. Note that
+  * future versions of this code may change the size, so no assuptions should be made about it.
+  *
+  * The encoder state is always continuous in memory and only a shallow copy is sufficient
+  * to copy it (e.g. memcpy())
+  *
+  * It is possible to change some of the encoder's settings using the opus_encoder_ctl()
+  * interface. All these settings already default to the recommended value, so they should
+  * only be changed when necessary. The most common settings one may want to change are:
+  *
+  * @code
+  * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
+  * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
+  * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
+  * @endcode
+  *
+  * where
+  *
+  * @arg bitrate is in bits per second (b/s)
+  * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest
+  * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC
+  *
+  * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream.
+  *
+  * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data:
+  * @code
+  * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet);
+  * @endcode
+  *
+  * where
+  * <ul>
+  * <li>audio_frame is the audio data in opus_int16 (or float for opus_encode_float())</li>
+  * <li>frame_size is the duration of the frame in samples (per channel)</li>
+  * <li>packet is the byte array to which the compressed data is written</li>
+  * <li>max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended).
+  *     Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.</li>
+  * </ul>
+  *
+  * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet.
+  * The return value <b>can be negative</b>, which indicates that an error has occurred. If the return value
+  * is 2 bytes or less, then the packet does not need to be transmitted (DTX).
+  *
+  * Once the encoder state if no longer needed, it can be destroyed with
+  *
+  * @code
+  * opus_encoder_destroy(enc);
+  * @endcode
+  *
+  * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(),
+  * then no action is required aside from potentially freeing the memory that was manually
+  * allocated for it (calling free(enc) for the example above)
+  *
+  */
+
+/** Opus encoder state.
+  * This contains the complete state of an Opus encoder.
+  * It is position independent and can be freely copied.
+  * @see opus_encoder_create,opus_encoder_init
+  */
+typedef struct OpusEncoder OpusEncoder;
+
+/** Gets the size of an <code>OpusEncoder</code> structure.
+  * @param[in] channels <tt>int</tt>: Number of channels.
+  *                                   This must be 1 or 2.
+  * @returns The size in bytes.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
+
+/**
+ */
+
+/** Allocates and initializes an encoder state.
+ * There are three coding modes:
+ *
+ * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice
+ *    signals. It enhances the  input signal by high-pass filtering and
+ *    emphasizing formants and harmonics. Optionally  it includes in-band
+ *    forward error correction to protect against packet loss. Use this
+ *    mode for typical VoIP applications. Because of the enhancement,
+ *    even at high bitrates the output may sound different from the input.
+ *
+ * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most
+ *    non-voice signals like music. Use this mode for music and mixed
+ *    (music/voice) content, broadcast, and applications requiring less
+ *    than 15 ms of coding delay.
+ *
+ * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that
+ *    disables the speech-optimized mode in exchange for slightly reduced delay.
+ *    This mode can only be set on an newly initialized or freshly reset encoder
+ *    because it changes the codec delay.
+ *
+ * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution).
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
+ *                                     This must be one of 8000, 12000, 16000,
+ *                                     24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
+ * @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @param [out] error <tt>int*</tt>: @ref opus_errorcodes
+ * @note Regardless of the sampling rate and number channels selected, the Opus encoder
+ * can switch to a lower audio bandwidth or number of channels if the bitrate
+ * selected is too low. This also means that it is safe to always use 48 kHz stereo input
+ * and let the encoder optimize the encoding.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
+    opus_int32 Fs,
+    int channels,
+    int application,
+    int *error
+);
+
+/** Initializes a previously allocated encoder state
+  * The memory pointed to by st must be at least the size returned by opus_encoder_get_size().
+  * This is intended for applications which use their own allocator instead of malloc.
+  * @see opus_encoder_create(),opus_encoder_get_size()
+  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+  * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+  * @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
+ *                                      This must be one of 8000, 12000, 16000,
+ *                                      24000, or 48000.
+  * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
+  * @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+  * @retval #OPUS_OK Success or @ref opus_errorcodes
+  */
+OPUS_EXPORT int opus_encoder_init(
+    OpusEncoder *st,
+    opus_int32 Fs,
+    int channels,
+    int application
+) OPUS_ARG_NONNULL(1);
+
+/** Encodes an Opus frame.
+  * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+  * @param [in] pcm <tt>opus_int16*</tt>: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)
+  * @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
+  *                                      input signal.
+  *                                      This must be an Opus frame size for
+  *                                      the encoder's sampling rate.
+  *                                      For example, at 48 kHz the permitted
+  *                                      values are 120, 240, 480, 960, 1920,
+  *                                      and 2880.
+  *                                      Passing in a duration of less than
+  *                                      10 ms (480 samples at 48 kHz) will
+  *                                      prevent the encoder from using the LPC
+  *                                      or hybrid modes.
+  * @param [out] data <tt>unsigned char*</tt>: Output payload.
+  *                                            This must contain storage for at
+  *                                            least \a max_data_bytes.
+  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+  *                                                 memory for the output
+  *                                                 payload. This may be
+  *                                                 used to impose an upper limit on
+  *                                                 the instant bitrate, but should
+  *                                                 not be used as the only bitrate
+  *                                                 control. Use #OPUS_SET_BITRATE to
+  *                                                 control the bitrate.
+  * @returns The length of the encoded packet (in bytes) on success or a
+  *          negative error code (see @ref opus_errorcodes) on failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode(
+    OpusEncoder *st,
+    const opus_int16 *pcm,
+    int frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes an Opus frame from floating point input.
+  * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+  * @param [in] pcm <tt>float*</tt>: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0.
+  *          Samples with a range beyond +/-1.0 are supported but will
+  *          be clipped by decoders using the integer API and should
+  *          only be used if it is known that the far end supports
+  *          extended dynamic range.
+  *          length is frame_size*channels*sizeof(float)
+  * @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
+  *                                      input signal.
+  *                                      This must be an Opus frame size for
+  *                                      the encoder's sampling rate.
+  *                                      For example, at 48 kHz the permitted
+  *                                      values are 120, 240, 480, 960, 1920,
+  *                                      and 2880.
+  *                                      Passing in a duration of less than
+  *                                      10 ms (480 samples at 48 kHz) will
+  *                                      prevent the encoder from using the LPC
+  *                                      or hybrid modes.
+  * @param [out] data <tt>unsigned char*</tt>: Output payload.
+  *                                            This must contain storage for at
+  *                                            least \a max_data_bytes.
+  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+  *                                                 memory for the output
+  *                                                 payload. This may be
+  *                                                 used to impose an upper limit on
+  *                                                 the instant bitrate, but should
+  *                                                 not be used as the only bitrate
+  *                                                 control. Use #OPUS_SET_BITRATE to
+  *                                                 control the bitrate.
+  * @returns The length of the encoded packet (in bytes) on success or a
+  *          negative error code (see @ref opus_errorcodes) on failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float(
+    OpusEncoder *st,
+    const float *pcm,
+    int frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an <code>OpusEncoder</code> allocated by opus_encoder_create().
+  * @param[in] st <tt>OpusEncoder*</tt>: State to be freed.
+  */
+OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st);
+
+/** Perform a CTL function on an Opus encoder.
+  *
+  * Generally the request and subsequent arguments are generated
+  * by a convenience macro.
+  * @param st <tt>OpusEncoder*</tt>: Encoder state.
+  * @param request This and all remaining parameters should be replaced by one
+  *                of the convenience macros in @ref opus_genericctls or
+  *                @ref opus_encoderctls.
+  * @see opus_genericctls
+  * @see opus_encoderctls
+  */
+OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+/**@}*/
+
+/** @defgroup opus_decoder Opus Decoder
+  * @{
+  *
+  * @brief This page describes the process and functions used to decode Opus.
+  *
+  * The decoding process also starts with creating a decoder
+  * state. This can be done with:
+  * @code
+  * int          error;
+  * OpusDecoder *dec;
+  * dec = opus_decoder_create(Fs, channels, &error);
+  * @endcode
+  * where
+  * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000
+  * @li channels is the number of channels (1 or 2)
+  * @li error will hold the error code in case of failure (or #OPUS_OK on success)
+  * @li the return value is a newly created decoder state to be used for decoding
+  *
+  * While opus_decoder_create() allocates memory for the state, it's also possible
+  * to initialize pre-allocated memory:
+  * @code
+  * int          size;
+  * int          error;
+  * OpusDecoder *dec;
+  * size = opus_decoder_get_size(channels);
+  * dec = malloc(size);
+  * error = opus_decoder_init(dec, Fs, channels);
+  * @endcode
+  * where opus_decoder_get_size() returns the required size for the decoder state. Note that
+  * future versions of this code may change the size, so no assuptions should be made about it.
+  *
+  * The decoder state is always continuous in memory and only a shallow copy is sufficient
+  * to copy it (e.g. memcpy())
+  *
+  * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data:
+  * @code
+  * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);
+  * @endcode
+  * where
+  *
+  * @li packet is the byte array containing the compressed data
+  * @li len is the exact number of bytes contained in the packet
+  * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())
+  * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array
+  *
+  * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet.
+  * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio
+  * buffer is too small to hold the decoded audio.
+  *
+  * Opus is a stateful codec with overlapping blocks and as a result Opus
+  * packets are not coded independently of each other. Packets must be
+  * passed into the decoder serially and in the correct order for a correct
+  * decode. Lost packets can be replaced with loss concealment by calling
+  * the decoder with a null pointer and zero length for the missing packet.
+  *
+  * A single codec state may only be accessed from a single thread at
+  * a time and any required locking must be performed by the caller. Separate
+  * streams must be decoded with separate decoder states and can be decoded
+  * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK
+  * defined.
+  *
+  */
+
+/** Opus decoder state.
+  * This contains the complete state of an Opus decoder.
+  * It is position independent and can be freely copied.
+  * @see opus_decoder_create,opus_decoder_init
+  */
+typedef struct OpusDecoder OpusDecoder;
+
+/** Gets the size of an <code>OpusDecoder</code> structure.
+  * @param [in] channels <tt>int</tt>: Number of channels.
+  *                                    This must be 1 or 2.
+  * @returns The size in bytes.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels);
+
+/** Allocates and initializes a decoder state.
+  * @param [in] Fs <tt>opus_int32</tt>: Sample rate to decode at (Hz).
+  *                                     This must be one of 8000, 12000, 16000,
+  *                                     24000, or 48000.
+  * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
+  * @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
+  *
+  * Internally Opus stores data at 48000 Hz, so that should be the default
+  * value for Fs. However, the decoder can efficiently decode to buffers
+  * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use
+  * data at the full sample rate, or knows the compressed data doesn't
+  * use the full frequency range, it can request decoding at a reduced
+  * rate. Likewise, the decoder is capable of filling in either mono or
+  * interleaved stereo pcm buffers, at the caller's request.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(
+    opus_int32 Fs,
+    int channels,
+    int *error
+);
+
+/** Initializes a previously allocated decoder state.
+  * The state must be at least the size returned by opus_decoder_get_size().
+  * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size
+  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+  * @param [in] st <tt>OpusDecoder*</tt>: Decoder state.
+  * @param [in] Fs <tt>opus_int32</tt>: Sampling rate to decode to (Hz).
+  *                                     This must be one of 8000, 12000, 16000,
+  *                                     24000, or 48000.
+  * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
+  * @retval #OPUS_OK Success or @ref opus_errorcodes
+  */
+OPUS_EXPORT int opus_decoder_init(
+    OpusDecoder *st,
+    opus_int32 Fs,
+    int channels
+) OPUS_ARG_NONNULL(1);
+
+/** Decode an Opus packet.
+  * @param [in] st <tt>OpusDecoder*</tt>: Decoder state
+  * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+  * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload*
+  * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
+  *  is frame_size*channels*sizeof(opus_int16)
+  * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+  *  If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+  *  not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+  *  then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+  *  decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+  *  FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
+  * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
+  *  decoded. If no such data is available, the frame is decoded as if it were lost.
+  * @returns Number of decoded samples or @ref opus_errorcodes
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
+    OpusDecoder *st,
+    const unsigned char *data,
+    opus_int32 len,
+    opus_int16 *pcm,
+    int frame_size,
+    int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode an Opus packet with floating point output.
+  * @param [in] st <tt>OpusDecoder*</tt>: Decoder state
+  * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+  * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload
+  * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
+  *  is frame_size*channels*sizeof(float)
+  * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+  *  If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+  *  not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+  *  then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+  *  decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+  *  FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
+  * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
+  *  decoded. If no such data is available the frame is decoded as if it were lost.
+  * @returns Number of decoded samples or @ref opus_errorcodes
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float(
+    OpusDecoder *st,
+    const unsigned char *data,
+    opus_int32 len,
+    float *pcm,
+    int frame_size,
+    int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus decoder.
+  *
+  * Generally the request and subsequent arguments are generated
+  * by a convenience macro.
+  * @param st <tt>OpusDecoder*</tt>: Decoder state.
+  * @param request This and all remaining parameters should be replaced by one
+  *                of the convenience macros in @ref opus_genericctls or
+  *                @ref opus_decoderctls.
+  * @see opus_genericctls
+  * @see opus_decoderctls
+  */
+OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an <code>OpusDecoder</code> allocated by opus_decoder_create().
+  * @param[in] st <tt>OpusDecoder*</tt>: State to be freed.
+  */
+OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
+
+/** Parse an opus packet into one or more frames.
+  * Opus_decode will perform this operation internally so most applications do
+  * not need to use this function.
+  * This function does not copy the frames, the returned pointers are pointers into
+  * the input packet.
+  * @param [in] data <tt>char*</tt>: Opus packet to be parsed
+  * @param [in] len <tt>opus_int32</tt>: size of data
+  * @param [out] out_toc <tt>char*</tt>: TOC pointer
+  * @param [out] frames <tt>char*[48]</tt> encapsulated frames
+  * @param [out] size <tt>opus_int16[48]</tt> sizes of the encapsulated frames
+  * @param [out] payload_offset <tt>int*</tt>: returns the position of the payload within the packet (in bytes)
+  * @returns number of frames
+  */
+OPUS_EXPORT int opus_packet_parse(
+   const unsigned char *data,
+   opus_int32 len,
+   unsigned char *out_toc,
+   const unsigned char *frames[48],
+   opus_int16 size[48],
+   int *payload_offset
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Gets the bandwidth of an Opus packet.
+  * @param [in] data <tt>char*</tt>: Opus packet
+  * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)
+  * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)
+  * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)
+  * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)
+  * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)
+  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples per frame from an Opus packet.
+  * @param [in] data <tt>char*</tt>: Opus packet.
+  *                                  This must contain at least one byte of
+  *                                  data.
+  * @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
+  *                                     This must be a multiple of 400, or
+  *                                     inaccurate results will be returned.
+  * @returns Number of samples per frame.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of channels from an Opus packet.
+  * @param [in] data <tt>char*</tt>: Opus packet
+  * @returns Number of channels
+  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of frames in an Opus packet.
+  * @param [in] packet <tt>char*</tt>: Opus packet
+  * @param [in] len <tt>opus_int32</tt>: Length of packet
+  * @returns Number of frames
+  * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+  * @param [in] packet <tt>char*</tt>: Opus packet
+  * @param [in] len <tt>opus_int32</tt>: Length of packet
+  * @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
+  *                                     This must be a multiple of 400, or
+  *                                     inaccurate results will be returned.
+  * @returns Number of samples
+  * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+  * @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
+  * @param [in] packet <tt>char*</tt>: Opus packet
+  * @param [in] len <tt>opus_int32</tt>: Length of packet
+  * @returns Number of samples
+  * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
+  * the signal is already in that range, nothing is done. If there are values
+  * outside of [-1,1], then the signal is clipped as smoothly as possible to
+  * both fit in the range and avoid creating excessive distortion in the
+  * process.
+  * @param [in,out] pcm <tt>float*</tt>: Input PCM and modified PCM
+  * @param [in] frame_size <tt>int</tt> Number of samples per channel to process
+  * @param [in] channels <tt>int</tt>: Number of channels
+  * @param [in,out] softclip_mem <tt>float*</tt>: State memory for the soft clipping process (one float per channel, initialized to zero)
+  */
+OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
+
+
+/**@}*/
+
+/** @defgroup opus_repacketizer Repacketizer
+  * @{
+  *
+  * The repacketizer can be used to merge multiple Opus packets into a single
+  * packet or alternatively to split Opus packets that have previously been
+  * merged. Splitting valid Opus packets is always guaranteed to succeed,
+  * whereas merging valid packets only succeeds if all frames have the same
+  * mode, bandwidth, and frame size, and when the total duration of the merged
+  * packet is no more than 120 ms. The 120 ms limit comes from the
+  * specification and limits decoder memory requirements at a point where
+  * framing overhead becomes negligible.
+  *
+  * The repacketizer currently only operates on elementary Opus
+  * streams. It will not manipualte multistream packets successfully, except in
+  * the degenerate case where they consist of data from a single stream.
+  *
+  * The repacketizing process starts with creating a repacketizer state, either
+  * by calling opus_repacketizer_create() or by allocating the memory yourself,
+  * e.g.,
+  * @code
+  * OpusRepacketizer *rp;
+  * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size());
+  * if (rp != NULL)
+  *     opus_repacketizer_init(rp);
+  * @endcode
+  *
+  * Then the application should submit packets with opus_repacketizer_cat(),
+  * extract new packets with opus_repacketizer_out() or
+  * opus_repacketizer_out_range(), and then reset the state for the next set of
+  * input packets via opus_repacketizer_init().
+  *
+  * For example, to split a sequence of packets into individual frames:
+  * @code
+  * unsigned char *data;
+  * int len;
+  * while (get_next_packet(&data, &len))
+  * {
+  *   unsigned char out[1276];
+  *   opus_int32 out_len;
+  *   int nb_frames;
+  *   int err;
+  *   int i;
+  *   err = opus_repacketizer_cat(rp, data, len);
+  *   if (err != OPUS_OK)
+  *   {
+  *     release_packet(data);
+  *     return err;
+  *   }
+  *   nb_frames = opus_repacketizer_get_nb_frames(rp);
+  *   for (i = 0; i < nb_frames; i++)
+  *   {
+  *     out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out));
+  *     if (out_len < 0)
+  *     {
+  *        release_packet(data);
+  *        return (int)out_len;
+  *     }
+  *     output_next_packet(out, out_len);
+  *   }
+  *   opus_repacketizer_init(rp);
+  *   release_packet(data);
+  * }
+  * @endcode
+  *
+  * Alternatively, to combine a sequence of frames into packets that each
+  * contain up to <code>TARGET_DURATION_MS</code> milliseconds of data:
+  * @code
+  * // The maximum number of packets with duration TARGET_DURATION_MS occurs
+  * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5)
+  * // packets.
+  * unsigned char *data[(TARGET_DURATION_MS*2/5)+1];
+  * opus_int32 len[(TARGET_DURATION_MS*2/5)+1];
+  * int nb_packets;
+  * unsigned char out[1277*(TARGET_DURATION_MS*2/2)];
+  * opus_int32 out_len;
+  * int prev_toc;
+  * nb_packets = 0;
+  * while (get_next_packet(data+nb_packets, len+nb_packets))
+  * {
+  *   int nb_frames;
+  *   int err;
+  *   nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]);
+  *   if (nb_frames < 1)
+  *   {
+  *     release_packets(data, nb_packets+1);
+  *     return nb_frames;
+  *   }
+  *   nb_frames += opus_repacketizer_get_nb_frames(rp);
+  *   // If adding the next packet would exceed our target, or it has an
+  *   // incompatible TOC sequence, output the packets we already have before
+  *   // submitting it.
+  *   // N.B., The nb_packets > 0 check ensures we've submitted at least one
+  *   // packet since the last call to opus_repacketizer_init(). Otherwise a
+  *   // single packet longer than TARGET_DURATION_MS would cause us to try to
+  *   // output an (invalid) empty packet. It also ensures that prev_toc has
+  *   // been set to a valid value. Additionally, len[nb_packets] > 0 is
+  *   // guaranteed by the call to opus_packet_get_nb_frames() above, so the
+  *   // reference to data[nb_packets][0] should be valid.
+  *   if (nb_packets > 0 && (
+  *       ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) ||
+  *       opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames >
+  *       TARGET_DURATION_MS*48))
+  *   {
+  *     out_len = opus_repacketizer_out(rp, out, sizeof(out));
+  *     if (out_len < 0)
+  *     {
+  *        release_packets(data, nb_packets+1);
+  *        return (int)out_len;
+  *     }
+  *     output_next_packet(out, out_len);
+  *     opus_repacketizer_init(rp);
+  *     release_packets(data, nb_packets);
+  *     data[0] = data[nb_packets];
+  *     len[0] = len[nb_packets];
+  *     nb_packets = 0;
+  *   }
+  *   err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]);
+  *   if (err != OPUS_OK)
+  *   {
+  *     release_packets(data, nb_packets+1);
+  *     return err;
+  *   }
+  *   prev_toc = data[nb_packets][0];
+  *   nb_packets++;
+  * }
+  * // Output the final, partial packet.
+  * if (nb_packets > 0)
+  * {
+  *   out_len = opus_repacketizer_out(rp, out, sizeof(out));
+  *   release_packets(data, nb_packets);
+  *   if (out_len < 0)
+  *     return (int)out_len;
+  *   output_next_packet(out, out_len);
+  * }
+  * @endcode
+  *
+  * An alternate way of merging packets is to simply call opus_repacketizer_cat()
+  * unconditionally until it fails. At that point, the merged packet can be
+  * obtained with opus_repacketizer_out() and the input packet for which
+  * opus_repacketizer_cat() needs to be re-added to a newly reinitialized
+  * repacketizer state.
+  */
+
+typedef struct OpusRepacketizer OpusRepacketizer;
+
+/** Gets the size of an <code>OpusRepacketizer</code> structure.
+  * @returns The size in bytes.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void);
+
+/** (Re)initializes a previously allocated repacketizer state.
+  * The state must be at least the size returned by opus_repacketizer_get_size().
+  * This can be used for applications which use their own allocator instead of
+  * malloc().
+  * It must also be called to reset the queue of packets waiting to be
+  * repacketized, which is necessary if the maximum packet duration of 120 ms
+  * is reached or if you wish to submit packets with a different Opus
+  * configuration (coding mode, audio bandwidth, frame size, or channel count).
+  * Failure to do so will prevent a new packet from being added with
+  * opus_repacketizer_cat().
+  * @see opus_repacketizer_create
+  * @see opus_repacketizer_get_size
+  * @see opus_repacketizer_cat
+  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to
+  *                                       (re)initialize.
+  * @returns A pointer to the same repacketizer state that was passed in.
+  */
+OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Allocates memory and initializes the new repacketizer with
+ * opus_repacketizer_init().
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void);
+
+/** Frees an <code>OpusRepacketizer</code> allocated by
+  * opus_repacketizer_create().
+  * @param[in] rp <tt>OpusRepacketizer*</tt>: State to be freed.
+  */
+OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);
+
+/** Add a packet to the current repacketizer state.
+  * This packet must match the configuration of any packets already submitted
+  * for repacketization since the last call to opus_repacketizer_init().
+  * This means that it must have the same coding mode, audio bandwidth, frame
+  * size, and channel count.
+  * This can be checked in advance by examining the top 6 bits of the first
+  * byte of the packet, and ensuring they match the top 6 bits of the first
+  * byte of any previously submitted packet.
+  * The total duration of audio in the repacketizer state also must not exceed
+  * 120 ms, the maximum duration of a single packet, after adding this packet.
+  *
+  * The contents of the current repacketizer state can be extracted into new
+  * packets using opus_repacketizer_out() or opus_repacketizer_out_range().
+  *
+  * In order to add a packet with a different configuration or to add more
+  * audio beyond 120 ms, you must clear the repacketizer state by calling
+  * opus_repacketizer_init().
+  * If a packet is too large to add to the current repacketizer state, no part
+  * of it is added, even if it contains multiple frames, some of which might
+  * fit.
+  * If you wish to be able to add parts of such packets, you should first use
+  * another repacketizer to split the packet into pieces and add them
+  * individually.
+  * @see opus_repacketizer_out_range
+  * @see opus_repacketizer_out
+  * @see opus_repacketizer_init
+  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to which to
+  *                                       add the packet.
+  * @param[in] data <tt>const unsigned char*</tt>: The packet data.
+  *                                                The application must ensure
+  *                                                this pointer remains valid
+  *                                                until the next call to
+  *                                                opus_repacketizer_init() or
+  *                                                opus_repacketizer_destroy().
+  * @param len <tt>opus_int32</tt>: The number of bytes in the packet data.
+  * @returns An error code indicating whether or not the operation succeeded.
+  * @retval #OPUS_OK The packet's contents have been added to the repacketizer
+  *                  state.
+  * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,
+  *                              the packet's TOC sequence was not compatible
+  *                              with previously submitted packets (because
+  *                              the coding mode, audio bandwidth, frame size,
+  *                              or channel count did not match), or adding
+  *                              this packet would increase the total amount of
+  *                              audio stored in the repacketizer state to more
+  *                              than 120 ms.
+  */
+OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+
+/** Construct a new packet from data previously submitted to the repacketizer
+  * state via opus_repacketizer_cat().
+  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
+  *                                       construct the new packet.
+  * @param begin <tt>int</tt>: The index of the first frame in the current
+  *                            repacketizer state to include in the output.
+  * @param end <tt>int</tt>: One past the index of the last frame in the
+  *                          current repacketizer state to include in the
+  *                          output.
+  * @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
+  *                                                 store the output packet.
+  * @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
+  *                                    the output buffer. In order to guarantee
+  *                                    success, this should be at least
+  *                                    <code>1276</code> for a single frame,
+  *                                    or for multiple frames,
+  *                                    <code>1277*(end-begin)</code>.
+  *                                    However, <code>1*(end-begin)</code> plus
+  *                                    the size of all packet data submitted to
+  *                                    the repacketizer since the last call to
+  *                                    opus_repacketizer_init() or
+  *                                    opus_repacketizer_create() is also
+  *                                    sufficient, and possibly much smaller.
+  * @returns The total size of the output packet on success, or an error code
+  *          on failure.
+  * @retval #OPUS_BAD_ARG <code>[begin,end)</code> was an invalid range of
+  *                       frames (begin < 0, begin >= end, or end >
+  *                       opus_repacketizer_get_nb_frames()).
+  * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+  *                                complete output packet.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Return the total number of frames contained in packet data submitted to
+  * the repacketizer state so far via opus_repacketizer_cat() since the last
+  * call to opus_repacketizer_init() or opus_repacketizer_create().
+  * This defines the valid range of packets that can be extracted with
+  * opus_repacketizer_out_range() or opus_repacketizer_out().
+  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state containing the
+  *                                       frames.
+  * @returns The total number of frames contained in the packet data submitted
+  *          to the repacketizer state.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Construct a new packet from data previously submitted to the repacketizer
+  * state via opus_repacketizer_cat().
+  * This is a convenience routine that returns all the data submitted so far
+  * in a single packet.
+  * It is equivalent to calling
+  * @code
+  * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
+  *                             data, maxlen)
+  * @endcode
+  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
+  *                                       construct the new packet.
+  * @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
+  *                                                 store the output packet.
+  * @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
+  *                                    the output buffer. In order to guarantee
+  *                                    success, this should be at least
+  *                                    <code>1277*opus_repacketizer_get_nb_frames(rp)</code>.
+  *                                    However,
+  *                                    <code>1*opus_repacketizer_get_nb_frames(rp)</code>
+  *                                    plus the size of all packet data
+  *                                    submitted to the repacketizer since the
+  *                                    last call to opus_repacketizer_init() or
+  *                                    opus_repacketizer_create() is also
+  *                                    sufficient, and possibly much smaller.
+  * @returns The total size of the output packet on success, or an error code
+  *          on failure.
+  * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+  *                                complete output packet.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);
+
+/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
+  * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+  *                                                   packet to pad.
+  * @param len <tt>opus_int32</tt>: The size of the packet.
+  *                                 This must be at least 1.
+  * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
+  *                                 This must be at least as large as len.
+  * @returns an error code
+  * @retval #OPUS_OK \a on success.
+  * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+  * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+  */
+OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);
+
+/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
+  * minimize space usage.
+  * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+  *                                                   packet to strip.
+  * @param len <tt>opus_int32</tt>: The size of the packet.
+  *                                 This must be at least 1.
+  * @returns The new size of the output packet on success, or an error code
+  *          on failure.
+  * @retval #OPUS_BAD_ARG \a len was less than 1.
+  * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);
+
+/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
+  * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+  *                                                   packet to pad.
+  * @param len <tt>opus_int32</tt>: The size of the packet.
+  *                                 This must be at least 1.
+  * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
+  *                                 This must be at least 1.
+  * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
+  *                                 This must be at least as large as len.
+  * @returns an error code
+  * @retval #OPUS_OK \a on success.
+  * @retval #OPUS_BAD_ARG \a len was less than 1.
+  * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+  */
+OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);
+
+/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
+  * minimize space usage.
+  * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+  *                                                   packet to strip.
+  * @param len <tt>opus_int32</tt>: The size of the packet.
+  *                                 This must be at least 1.
+  * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
+  *                                 This must be at least 1.
+  * @returns The new size of the output packet on success, or an error code
+  *          on failure.
+  * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+  * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_H */
diff --git a/third_party/opus/src/include/opus_custom.h b/third_party/opus/src/include/opus_custom.h
new file mode 100644
index 0000000..41f36bf
--- /dev/null
+++ b/third_party/opus/src/include/opus_custom.h
@@ -0,0 +1,342 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Copyright (c) 2008-2012 Gregory Maxwell
+   Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+  @file opus_custom.h
+  @brief Opus-Custom reference implementation API
+ */
+
+#ifndef OPUS_CUSTOM_H
+#define OPUS_CUSTOM_H
+
+#include "opus_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef CUSTOM_MODES
+# define OPUS_CUSTOM_EXPORT OPUS_EXPORT
+# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
+#else
+# define OPUS_CUSTOM_EXPORT
+# ifdef OPUS_BUILD
+#  define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE
+# else
+#  define OPUS_CUSTOM_EXPORT_STATIC
+# endif
+#endif
+
+/** @defgroup opus_custom Opus Custom
+  * @{
+  *  Opus Custom is an optional part of the Opus specification and
+  * reference implementation which uses a distinct API from the regular
+  * API and supports frame sizes that are not normally supported.\ Use
+  * of Opus Custom is discouraged for all but very special applications
+  * for which a frame size different from 2.5, 5, 10, or 20 ms is needed
+  * (for either complexity or latency reasons) and where interoperability
+  * is less important.
+  *
+  * In addition to the interoperability limitations the use of Opus custom
+  * disables a substantial chunk of the codec and generally lowers the
+  * quality available at a given bitrate. Normally when an application needs
+  * a different frame size from the codec it should buffer to match the
+  * sizes but this adds a small amount of delay which may be important
+  * in some very low latency applications. Some transports (especially
+  * constant rate RF transports) may also work best with frames of
+  * particular durations.
+  *
+  * Libopus only supports custom modes if they are enabled at compile time.
+  *
+  * The Opus Custom API is similar to the regular API but the
+  * @ref opus_encoder_create and @ref opus_decoder_create calls take
+  * an additional mode parameter which is a structure produced by
+  * a call to @ref opus_custom_mode_create. Both the encoder and decoder
+  * must create a mode using the same sample rate (fs) and frame size
+  * (frame size) so these parameters must either be signaled out of band
+  * or fixed in a particular implementation.
+  *
+  * Similar to regular Opus the custom modes support on the fly frame size
+  * switching, but the sizes available depend on the particular frame size in
+  * use. For some initial frame sizes on a single on the fly size is available.
+  */
+
+/** Contains the state of an encoder. One encoder state is needed
+    for each stream. It is initialized once at the beginning of the
+    stream. Do *not* re-initialize the state for every frame.
+   @brief Encoder state
+ */
+typedef struct OpusCustomEncoder OpusCustomEncoder;
+
+/** State of the decoder. One decoder state is needed for each stream.
+    It is initialized once at the beginning of the stream. Do *not*
+    re-initialize the state for every frame.
+   @brief Decoder state
+ */
+typedef struct OpusCustomDecoder OpusCustomDecoder;
+
+/** The mode contains all the information necessary to create an
+    encoder. Both the encoder and decoder need to be initialized
+    with exactly the same mode, otherwise the output will be
+    corrupted.
+   @brief Mode configuration
+ */
+typedef struct OpusCustomMode OpusCustomMode;
+
+/** Creates a new mode struct. This will be passed to an encoder or
+  * decoder. The mode MUST NOT BE DESTROYED until the encoders and
+  * decoders that use it are destroyed as well.
+  * @param [in] Fs <tt>int</tt>: Sampling rate (8000 to 96000 Hz)
+  * @param [in] frame_size <tt>int</tt>: Number of samples (per channel) to encode in each
+  *        packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes)
+  * @param [out] error <tt>int*</tt>: Returned error code (if NULL, no error will be returned)
+  * @return A newly created mode
+  */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error);
+
+/** Destroys a mode struct. Only call this after all encoders and
+  * decoders using this mode are destroyed as well.
+  * @param [in] mode <tt>OpusCustomMode*</tt>: Mode to be freed.
+  */
+OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);
+
+
+#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)
+
+/* Encoder */
+/** Gets the size of an OpusCustomEncoder structure.
+  * @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
+  * @param [in] channels <tt>int</tt>: Number of channels
+  * @returns size
+  */
+OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size(
+    const OpusCustomMode *mode,
+    int channels
+) OPUS_ARG_NONNULL(1);
+
+# ifdef CUSTOM_MODES
+/** Initializes a previously allocated encoder state
+  * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
+  * This is intended for applications which use their own allocator instead of malloc.
+  * @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
+  * To reset a previously initialized state use the OPUS_RESET_STATE CTL.
+  * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+  * @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
+  *  the stream (must be the same characteristics as used for the
+  *  decoder)
+  * @param [in] channels <tt>int</tt>: Number of channels
+  * @return OPUS_OK Success or @ref opus_errorcodes
+  */
+OPUS_CUSTOM_EXPORT int opus_custom_encoder_init(
+    OpusCustomEncoder *st,
+    const OpusCustomMode *mode,
+    int channels
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+# endif
+#endif
+
+
+/** Creates a new encoder state. Each stream needs its own encoder
+  * state (can't be shared across simultaneous streams).
+  * @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of
+  *  the stream (must be the same characteristics as used for the
+  *  decoder)
+  * @param [in] channels <tt>int</tt>: Number of channels
+  * @param [out] error <tt>int*</tt>: Returns an error code
+  * @return Newly created encoder state.
+*/
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create(
+    const OpusCustomMode *mode,
+    int channels,
+    int *error
+) OPUS_ARG_NONNULL(1);
+
+
+/** Destroys a an encoder state.
+  * @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
+  */
+OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
+
+/** Encodes a frame of audio.
+  * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+  * @param [in] pcm <tt>float*</tt>: PCM audio in float format, with a normal range of +/-1.0.
+  *          Samples with a range beyond +/-1.0 are supported but will
+  *          be clipped by decoders using the integer API and should
+  *          only be used if it is known that the far end supports
+  *          extended dynamic range. There must be exactly
+  *          frame_size samples per channel.
+  * @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
+  * @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
+  * @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
+  *          (can change from one frame to another)
+  * @return Number of bytes written to "compressed".
+  *       If negative, an error has occurred (see error codes). It is IMPORTANT that
+  *       the length returned be somehow transmitted to the decoder. Otherwise, no
+  *       decoding is possible.
+  */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float(
+    OpusCustomEncoder *st,
+    const float *pcm,
+    int frame_size,
+    unsigned char *compressed,
+    int maxCompressedBytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes a frame of audio.
+  * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+  * @param [in] pcm <tt>opus_int16*</tt>: PCM audio in signed 16-bit format (native endian).
+  *          There must be exactly frame_size samples per channel.
+  * @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
+  * @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
+  * @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
+  *          (can change from one frame to another)
+  * @return Number of bytes written to "compressed".
+  *       If negative, an error has occurred (see error codes). It is IMPORTANT that
+  *       the length returned be somehow transmitted to the decoder. Otherwise, no
+  *       decoding is possible.
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(
+    OpusCustomEncoder *st,
+    const opus_int16 *pcm,
+    int frame_size,
+    unsigned char *compressed,
+    int maxCompressedBytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus custom encoder.
+  *
+  * Generally the request and subsequent arguments are generated
+  * by a convenience macro.
+  * @see opus_encoderctls
+  */
+OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
+
+
+#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)
+/* Decoder */
+
+/** Gets the size of an OpusCustomDecoder structure.
+  * @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
+  * @param [in] channels <tt>int</tt>: Number of channels
+  * @returns size
+  */
+OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size(
+    const OpusCustomMode *mode,
+    int channels
+) OPUS_ARG_NONNULL(1);
+
+/** Initializes a previously allocated decoder state
+  * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.
+  * This is intended for applications which use their own allocator instead of malloc.
+  * @see opus_custom_decoder_create(),opus_custom_decoder_get_size()
+  * To reset a previously initialized state use the OPUS_RESET_STATE CTL.
+  * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+  * @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
+  *  the stream (must be the same characteristics as used for the
+  *  encoder)
+  * @param [in] channels <tt>int</tt>: Number of channels
+  * @return OPUS_OK Success or @ref opus_errorcodes
+  */
+OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(
+    OpusCustomDecoder *st,
+    const OpusCustomMode *mode,
+    int channels
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+#endif
+
+
+/** Creates a new decoder state. Each stream needs its own decoder state (can't
+  * be shared across simultaneous streams).
+  * @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
+  *          stream (must be the same characteristics as used for the encoder)
+  * @param [in] channels <tt>int</tt>: Number of channels
+  * @param [out] error <tt>int*</tt>: Returns an error code
+  * @return Newly created decoder state.
+  */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
+    const OpusCustomMode *mode,
+    int channels,
+    int *error
+) OPUS_ARG_NONNULL(1);
+
+/** Destroys a an decoder state.
+  * @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
+  */
+OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);
+
+/** Decode an opus custom frame with floating point output
+  * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+  * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+  * @param [in] len <tt>int</tt>: Number of bytes in payload
+  * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
+  *  is frame_size*channels*sizeof(float)
+  * @param [in] frame_size Number of samples per channel of available space in *pcm.
+  * @returns Number of decoded samples or @ref opus_errorcodes
+  */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float(
+    OpusCustomDecoder *st,
+    const unsigned char *data,
+    int len,
+    float *pcm,
+    int frame_size
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode an opus custom frame
+  * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+  * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+  * @param [in] len <tt>int</tt>: Number of bytes in payload
+  * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
+  *  is frame_size*channels*sizeof(opus_int16)
+  * @param [in] frame_size Number of samples per channel of available space in *pcm.
+  * @returns Number of decoded samples or @ref opus_errorcodes
+  */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode(
+    OpusCustomDecoder *st,
+    const unsigned char *data,
+    int len,
+    opus_int16 *pcm,
+    int frame_size
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus custom decoder.
+  *
+  * Generally the request and subsequent arguments are generated
+  * by a convenience macro.
+  * @see opus_genericctls
+  */
+OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_CUSTOM_H */
diff --git a/third_party/opus/src/include/opus_defines.h b/third_party/opus/src/include/opus_defines.h
new file mode 100644
index 0000000..315412dd
--- /dev/null
+++ b/third_party/opus/src/include/opus_defines.h
@@ -0,0 +1,753 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+   Written by Jean-Marc Valin and Koen Vos */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus_defines.h
+ * @brief Opus reference implementation constants
+ */
+
+#ifndef OPUS_DEFINES_H
+#define OPUS_DEFINES_H
+
+#include "opus_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup opus_errorcodes Error codes
+ * @{
+ */
+/** No error @hideinitializer*/
+#define OPUS_OK                0
+/** One or more invalid/out of range arguments @hideinitializer*/
+#define OPUS_BAD_ARG          -1
+/** Not enough bytes allocated in the buffer @hideinitializer*/
+#define OPUS_BUFFER_TOO_SMALL -2
+/** An internal error was detected @hideinitializer*/
+#define OPUS_INTERNAL_ERROR   -3
+/** The compressed data passed is corrupted @hideinitializer*/
+#define OPUS_INVALID_PACKET   -4
+/** Invalid/unsupported request number @hideinitializer*/
+#define OPUS_UNIMPLEMENTED    -5
+/** An encoder or decoder structure is invalid or already freed @hideinitializer*/
+#define OPUS_INVALID_STATE    -6
+/** Memory allocation has failed @hideinitializer*/
+#define OPUS_ALLOC_FAIL       -7
+/**@}*/
+
+/** @cond OPUS_INTERNAL_DOC */
+/**Export control for opus functions */
+
+#ifndef OPUS_EXPORT
+# if defined(WIN32)
+#  if defined(OPUS_BUILD) && defined(DLL_EXPORT)
+#   define OPUS_EXPORT __declspec(dllexport)
+#  else
+#   define OPUS_EXPORT
+#  endif
+# elif defined(__GNUC__) && defined(OPUS_BUILD)
+#  define OPUS_EXPORT __attribute__ ((visibility ("default")))
+# else
+#  define OPUS_EXPORT
+# endif
+#endif
+
+# if !defined(OPUS_GNUC_PREREQ)
+#  if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+#   define OPUS_GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+#  else
+#   define OPUS_GNUC_PREREQ(_maj,_min) 0
+#  endif
+# endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(3,0)
+#  define OPUS_RESTRICT __restrict__
+# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
+#  define OPUS_RESTRICT __restrict
+# else
+#  define OPUS_RESTRICT
+# endif
+#else
+# define OPUS_RESTRICT restrict
+#endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(2,7)
+#  define OPUS_INLINE __inline__
+# elif (defined(_MSC_VER))
+#  define OPUS_INLINE __inline
+# else
+#  define OPUS_INLINE
+# endif
+#else
+# define OPUS_INLINE inline
+#endif
+
+/**Warning attributes for opus functions
+  * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out
+  * some paranoid null checks. */
+#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
+#else
+# define OPUS_WARN_UNUSED_RESULT
+#endif
+#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_ARG_NONNULL(_x)  __attribute__ ((__nonnull__(_x)))
+#else
+# define OPUS_ARG_NONNULL(_x)
+#endif
+
+/** These are the actual Encoder CTL ID numbers.
+  * They should not be used directly by applications.
+  * In general, SETs should be even and GETs should be odd.*/
+#define OPUS_SET_APPLICATION_REQUEST         4000
+#define OPUS_GET_APPLICATION_REQUEST         4001
+#define OPUS_SET_BITRATE_REQUEST             4002
+#define OPUS_GET_BITRATE_REQUEST             4003
+#define OPUS_SET_MAX_BANDWIDTH_REQUEST       4004
+#define OPUS_GET_MAX_BANDWIDTH_REQUEST       4005
+#define OPUS_SET_VBR_REQUEST                 4006
+#define OPUS_GET_VBR_REQUEST                 4007
+#define OPUS_SET_BANDWIDTH_REQUEST           4008
+#define OPUS_GET_BANDWIDTH_REQUEST           4009
+#define OPUS_SET_COMPLEXITY_REQUEST          4010
+#define OPUS_GET_COMPLEXITY_REQUEST          4011
+#define OPUS_SET_INBAND_FEC_REQUEST          4012
+#define OPUS_GET_INBAND_FEC_REQUEST          4013
+#define OPUS_SET_PACKET_LOSS_PERC_REQUEST    4014
+#define OPUS_GET_PACKET_LOSS_PERC_REQUEST    4015
+#define OPUS_SET_DTX_REQUEST                 4016
+#define OPUS_GET_DTX_REQUEST                 4017
+#define OPUS_SET_VBR_CONSTRAINT_REQUEST      4020
+#define OPUS_GET_VBR_CONSTRAINT_REQUEST      4021
+#define OPUS_SET_FORCE_CHANNELS_REQUEST      4022
+#define OPUS_GET_FORCE_CHANNELS_REQUEST      4023
+#define OPUS_SET_SIGNAL_REQUEST              4024
+#define OPUS_GET_SIGNAL_REQUEST              4025
+#define OPUS_GET_LOOKAHEAD_REQUEST           4027
+/* #define OPUS_RESET_STATE 4028 */
+#define OPUS_GET_SAMPLE_RATE_REQUEST         4029
+#define OPUS_GET_FINAL_RANGE_REQUEST         4031
+#define OPUS_GET_PITCH_REQUEST               4033
+#define OPUS_SET_GAIN_REQUEST                4034
+#define OPUS_GET_GAIN_REQUEST                4045 /* Should have been 4035 */
+#define OPUS_SET_LSB_DEPTH_REQUEST           4036
+#define OPUS_GET_LSB_DEPTH_REQUEST           4037
+#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039
+#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040
+#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
+#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
+#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
+
+/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
+
+/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
+#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
+#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
+#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
+#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
+/** @endcond */
+
+/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
+  * @see opus_genericctls, opus_encoderctls
+  * @{
+  */
+/* Values for the various encoder CTLs */
+#define OPUS_AUTO                           -1000 /**<Auto/default setting @hideinitializer*/
+#define OPUS_BITRATE_MAX                       -1 /**<Maximum bitrate @hideinitializer*/
+
+/** Best for most VoIP/videoconference applications where listening quality and intelligibility matter most
+ * @hideinitializer */
+#define OPUS_APPLICATION_VOIP                2048
+/** Best for broadcast/high-fidelity application where the decoded audio should be as close as possible to the input
+ * @hideinitializer */
+#define OPUS_APPLICATION_AUDIO               2049
+/** Only use when lowest-achievable latency is what matters most. Voice-optimized modes cannot be used.
+ * @hideinitializer */
+#define OPUS_APPLICATION_RESTRICTED_LOWDELAY 2051
+
+#define OPUS_SIGNAL_VOICE                    3001 /**< Signal being encoded is voice */
+#define OPUS_SIGNAL_MUSIC                    3002 /**< Signal being encoded is music */
+#define OPUS_BANDWIDTH_NARROWBAND            1101 /**< 4 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_MEDIUMBAND            1102 /**< 6 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_WIDEBAND              1103 /**< 8 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_SUPERWIDEBAND         1104 /**<12 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_FULLBAND              1105 /**<20 kHz bandpass @hideinitializer*/
+
+#define OPUS_FRAMESIZE_ARG                   5000 /**< Select frame size from the argument (default) */
+#define OPUS_FRAMESIZE_2_5_MS                5001 /**< Use 2.5 ms frames */
+#define OPUS_FRAMESIZE_5_MS                  5002 /**< Use 5 ms frames */
+#define OPUS_FRAMESIZE_10_MS                 5003 /**< Use 10 ms frames */
+#define OPUS_FRAMESIZE_20_MS                 5004 /**< Use 20 ms frames */
+#define OPUS_FRAMESIZE_40_MS                 5005 /**< Use 40 ms frames */
+#define OPUS_FRAMESIZE_60_MS                 5006 /**< Use 60 ms frames */
+
+/**@}*/
+
+
+/** @defgroup opus_encoderctls Encoder related CTLs
+  *
+  * These are convenience macros for use with the \c opus_encode_ctl
+  * interface. They are used to generate the appropriate series of
+  * arguments for that call, passing the correct type, size and so
+  * on as expected for each particular request.
+  *
+  * Some usage examples:
+  *
+  * @code
+  * int ret;
+  * ret = opus_encoder_ctl(enc_ctx, OPUS_SET_BANDWIDTH(OPUS_AUTO));
+  * if (ret != OPUS_OK) return ret;
+  *
+  * opus_int32 rate;
+  * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&rate));
+  *
+  * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
+  * @endcode
+  *
+  * @see opus_genericctls, opus_encoder
+  * @{
+  */
+
+/** Configures the encoder's computational complexity.
+  * The supported range is 0-10 inclusive with 10 representing the highest complexity.
+  * @see OPUS_GET_COMPLEXITY
+  * @param[in] x <tt>opus_int32</tt>: Allowed values: 0-10, inclusive.
+  *
+  * @hideinitializer */
+#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x)
+/** Gets the encoder's complexity configuration.
+  * @see OPUS_SET_COMPLEXITY
+  * @param[out] x <tt>opus_int32 *</tt>: Returns a value in the range 0-10,
+  *                                      inclusive.
+  * @hideinitializer */
+#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the bitrate in the encoder.
+  * Rates from 500 to 512000 bits per second are meaningful, as well as the
+  * special values #OPUS_AUTO and #OPUS_BITRATE_MAX.
+  * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much
+  * rate as it can, which is useful for controlling the rate by adjusting the
+  * output buffer size.
+  * @see OPUS_GET_BITRATE
+  * @param[in] x <tt>opus_int32</tt>: Bitrate in bits per second. The default
+  *                                   is determined based on the number of
+  *                                   channels and the input sampling rate.
+  * @hideinitializer */
+#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x)
+/** Gets the encoder's bitrate configuration.
+  * @see OPUS_SET_BITRATE
+  * @param[out] x <tt>opus_int32 *</tt>: Returns the bitrate in bits per second.
+  *                                      The default is determined based on the
+  *                                      number of channels and the input
+  *                                      sampling rate.
+  * @hideinitializer */
+#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables variable bitrate (VBR) in the encoder.
+  * The configured bitrate may not be met exactly because frames must
+  * be an integer number of bytes in length.
+  * @see OPUS_GET_VBR
+  * @see OPUS_SET_VBR_CONSTRAINT
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>0</dt><dd>Hard CBR. For LPC/hybrid modes at very low bit-rate, this can
+  *               cause noticeable quality degradation.</dd>
+  * <dt>1</dt><dd>VBR (default). The exact type of VBR is controlled by
+  *               #OPUS_SET_VBR_CONSTRAINT.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x)
+/** Determine if variable bitrate (VBR) is enabled in the encoder.
+  * @see OPUS_SET_VBR
+  * @see OPUS_GET_VBR_CONSTRAINT
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>0</dt><dd>Hard CBR.</dd>
+  * <dt>1</dt><dd>VBR (default). The exact type of VBR may be retrieved via
+  *               #OPUS_GET_VBR_CONSTRAINT.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables constrained VBR in the encoder.
+  * This setting is ignored when the encoder is in CBR mode.
+  * @warning Only the MDCT mode of Opus currently heeds the constraint.
+  *  Speech mode ignores it completely, hybrid mode may fail to obey it
+  *  if the LPC layer uses more bitrate than the constraint would have
+  *  permitted.
+  * @see OPUS_GET_VBR_CONSTRAINT
+  * @see OPUS_SET_VBR
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>0</dt><dd>Unconstrained VBR.</dd>
+  * <dt>1</dt><dd>Constrained VBR (default). This creates a maximum of one
+  *               frame of buffering delay assuming a transport with a
+  *               serialization speed of the nominal bitrate.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x)
+/** Determine if constrained VBR is enabled in the encoder.
+  * @see OPUS_SET_VBR_CONSTRAINT
+  * @see OPUS_GET_VBR
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>0</dt><dd>Unconstrained VBR.</dd>
+  * <dt>1</dt><dd>Constrained VBR (default).</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures mono/stereo forcing in the encoder.
+  * This can force the encoder to produce packets encoded as either mono or
+  * stereo, regardless of the format of the input audio. This is useful when
+  * the caller knows that the input signal is currently a mono source embedded
+  * in a stereo stream.
+  * @see OPUS_GET_FORCE_CHANNELS
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
+  * <dt>1</dt>         <dd>Forced mono</dd>
+  * <dt>2</dt>         <dd>Forced stereo</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x)
+/** Gets the encoder's forced channel configuration.
+  * @see OPUS_SET_FORCE_CHANNELS
+  * @param[out] x <tt>opus_int32 *</tt>:
+  * <dl>
+  * <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
+  * <dt>1</dt>         <dd>Forced mono</dd>
+  * <dt>2</dt>         <dd>Forced stereo</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the maximum bandpass that the encoder will select automatically.
+  * Applications should normally use this instead of #OPUS_SET_BANDWIDTH
+  * (leaving that set to the default, #OPUS_AUTO). This allows the
+  * application to set an upper bound based on the type of input it is
+  * providing, but still gives the encoder the freedom to reduce the bandpass
+  * when the bitrate becomes too low, for better overall quality.
+  * @see OPUS_GET_MAX_BANDWIDTH
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>OPUS_BANDWIDTH_NARROWBAND</dt>    <dd>4 kHz passband</dd>
+  * <dt>OPUS_BANDWIDTH_MEDIUMBAND</dt>    <dd>6 kHz passband</dd>
+  * <dt>OPUS_BANDWIDTH_WIDEBAND</dt>      <dd>8 kHz passband</dd>
+  * <dt>OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+  * <dt>OPUS_BANDWIDTH_FULLBAND</dt>     <dd>20 kHz passband (default)</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Gets the encoder's configured maximum allowed bandpass.
+  * @see OPUS_SET_MAX_BANDWIDTH
+  * @param[out] x <tt>opus_int32 *</tt>: Allowed values:
+  * <dl>
+  * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt>    <dd>4 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt>    <dd>6 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt>      <dd>8 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_FULLBAND</dt>     <dd>20 kHz passband (default)</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Sets the encoder's bandpass to a specific value.
+  * This prevents the encoder from automatically selecting the bandpass based
+  * on the available bitrate. If an application knows the bandpass of the input
+  * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH
+  * instead, which still gives the encoder the freedom to reduce the bandpass
+  * when the bitrate becomes too low, for better overall quality.
+  * @see OPUS_GET_BANDWIDTH
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>#OPUS_AUTO</dt>                    <dd>(default)</dd>
+  * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt>    <dd>4 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt>    <dd>6 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt>      <dd>8 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_FULLBAND</dt>     <dd>20 kHz passband</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Configures the type of signal being encoded.
+  * This is a hint which helps the encoder's mode selection.
+  * @see OPUS_GET_SIGNAL
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>#OPUS_AUTO</dt>        <dd>(default)</dd>
+  * <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>
+  * <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal type.
+  * @see OPUS_SET_SIGNAL
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>#OPUS_AUTO</dt>        <dd>(default)</dd>
+  * <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>
+  * <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x)
+
+
+/** Configures the encoder's intended application.
+  * The initial value is a mandatory argument to the encoder_create function.
+  * @see OPUS_GET_APPLICATION
+  * @param[in] x <tt>opus_int32</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>#OPUS_APPLICATION_VOIP</dt>
+  * <dd>Process signal for improved speech intelligibility.</dd>
+  * <dt>#OPUS_APPLICATION_AUDIO</dt>
+  * <dd>Favor faithfulness to the original input.</dd>
+  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+  * <dd>Configure the minimum possible coding delay by disabling certain modes
+  * of operation.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured application.
+  * @see OPUS_SET_APPLICATION
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>#OPUS_APPLICATION_VOIP</dt>
+  * <dd>Process signal for improved speech intelligibility.</dd>
+  * <dt>#OPUS_APPLICATION_AUDIO</dt>
+  * <dd>Favor faithfulness to the original input.</dd>
+  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+  * <dd>Configure the minimum possible coding delay by disabling certain modes
+  * of operation.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the total samples of delay added by the entire codec.
+  * This can be queried by the encoder and then the provided number of samples can be
+  * skipped on from the start of the decoder's output to provide time aligned input
+  * and output. From the perspective of a decoding application the real data begins this many
+  * samples late.
+  *
+  * The decoder contribution to this delay is identical for all decoders, but the
+  * encoder portion of the delay may vary from implementation to implementation,
+  * version to version, or even depend on the encoder's initial configuration.
+  * Applications needing delay compensation should call this CTL rather than
+  * hard-coding a value.
+  * @param[out] x <tt>opus_int32 *</tt>:   Number of lookahead samples
+  * @hideinitializer */
+#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of inband forward error correction (FEC).
+  * @note This is only applicable to the LPC layer
+  * @see OPUS_GET_INBAND_FEC
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>0</dt><dd>Disable inband FEC (default).</dd>
+  * <dt>1</dt><dd>Enable inband FEC.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of inband forward error correction.
+  * @see OPUS_SET_INBAND_FEC
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>0</dt><dd>Inband FEC disabled (default).</dd>
+  * <dt>1</dt><dd>Inband FEC enabled.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's expected packet loss percentage.
+  * Higher values trigger progressively more loss resistant behavior in the encoder
+  * at the expense of quality at a given bitrate in the absence of packet loss, but
+  * greater quality under loss.
+  * @see OPUS_GET_PACKET_LOSS_PERC
+  * @param[in] x <tt>opus_int32</tt>:   Loss percentage in the range 0-100, inclusive (default: 0).
+  * @hideinitializer */
+#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured packet loss percentage.
+  * @see OPUS_SET_PACKET_LOSS_PERC
+  * @param[out] x <tt>opus_int32 *</tt>: Returns the configured loss percentage
+  *                                      in the range 0-100, inclusive (default: 0).
+  * @hideinitializer */
+#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of discontinuous transmission (DTX).
+  * @note This is only applicable to the LPC layer
+  * @see OPUS_GET_DTX
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>0</dt><dd>Disable DTX (default).</dd>
+  * <dt>1</dt><dd>Enabled DTX.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of discontinuous transmission.
+  * @see OPUS_SET_DTX
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>0</dt><dd>DTX disabled (default).</dd>
+  * <dt>1</dt><dd>DTX enabled.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x)
+/** Configures the depth of signal being encoded.
+  *
+  * This is a hint which helps the encoder identify silence and near-silence.
+  * It represents the number of significant bits of linear intensity below
+  * which the signal contains ignorable quantization or other noise.
+  *
+  * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting
+  * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate
+  * for 16-bit linear pcm input with opus_encode_float().
+  *
+  * When using opus_encode() instead of opus_encode_float(), or when libopus
+  * is compiled for fixed-point, the encoder uses the minimum of the value
+  * set here and the value 16.
+  *
+  * @see OPUS_GET_LSB_DEPTH
+  * @param[in] x <tt>opus_int32</tt>: Input precision in bits, between 8 and 24
+  *                                   (default: 24).
+  * @hideinitializer */
+#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal depth.
+  * @see OPUS_SET_LSB_DEPTH
+  * @param[out] x <tt>opus_int32 *</tt>: Input precision in bits, between 8 and
+  *                                      24 (default: 24).
+  * @hideinitializer */
+#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of variable duration frames.
+  * When variable duration is enabled, the encoder is free to use a shorter frame
+  * size than the one requested in the opus_encode*() call.
+  * It is then the user's responsibility
+  * to verify how much audio was encoded by checking the ToC byte of the encoded
+  * packet. The part of the audio that was not encoded needs to be resent to the
+  * encoder for the next call. Do not use this option unless you <b>really</b>
+  * know what you are doing.
+  * @see OPUS_GET_EXPERT_FRAME_DURATION
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
+  * <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 5 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured use of variable duration frames.
+  * @see OPUS_SET_EXPERT_FRAME_DURATION
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
+  * <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 5 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
+  * <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** If set to 1, disables almost all use of prediction, making frames almost
+  * completely independent. This reduces quality.
+  * @see OPUS_GET_PREDICTION_DISABLED
+  * @param[in] x <tt>opus_int32</tt>: Allowed values:
+  * <dl>
+  * <dt>0</dt><dd>Enable prediction (default).</dd>
+  * <dt>1</dt><dd>Disable prediction.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured prediction status.
+  * @see OPUS_SET_PREDICTION_DISABLED
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>0</dt><dd>Prediction enabled (default).</dd>
+  * <dt>1</dt><dd>Prediction disabled.</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_genericctls Generic CTLs
+  *
+  * These macros are used with the \c opus_decoder_ctl and
+  * \c opus_encoder_ctl calls to generate a particular
+  * request.
+  *
+  * When called on an \c OpusDecoder they apply to that
+  * particular decoder instance. When called on an
+  * \c OpusEncoder they apply to the corresponding setting
+  * on that encoder instance, if present.
+  *
+  * Some usage examples:
+  *
+  * @code
+  * int ret;
+  * opus_int32 pitch;
+  * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch));
+  * if (ret == OPUS_OK) return ret;
+  *
+  * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
+  * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE);
+  *
+  * opus_int32 enc_bw, dec_bw;
+  * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw));
+  * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw));
+  * if (enc_bw != dec_bw) {
+  *   printf("packet bandwidth mismatch!\n");
+  * }
+  * @endcode
+  *
+  * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls
+  * @{
+  */
+
+/** Resets the codec state to be equivalent to a freshly initialized state.
+  * This should be called when switching streams in order to prevent
+  * the back to back decoding from giving different results from
+  * one at a time decoding.
+  * @hideinitializer */
+#define OPUS_RESET_STATE 4028
+
+/** Gets the final state of the codec's entropy coder.
+  * This is used for testing purposes,
+  * The encoder and decoder state should be identical after coding a payload
+  * (assuming no data corruption or software bugs)
+  *
+  * @param[out] x <tt>opus_uint32 *</tt>: Entropy coder state
+  *
+  * @hideinitializer */
+#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)
+
+/** Gets the encoder's configured bandpass or the decoder's last bandpass.
+  * @see OPUS_SET_BANDWIDTH
+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+  * <dl>
+  * <dt>#OPUS_AUTO</dt>                    <dd>(default)</dd>
+  * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt>    <dd>4 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt>    <dd>6 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt>      <dd>8 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+  * <dt>#OPUS_BANDWIDTH_FULLBAND</dt>     <dd>20 kHz passband</dd>
+  * </dl>
+  * @hideinitializer */
+#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the sampling rate the encoder or decoder was initialized with.
+  * This simply returns the <code>Fs</code> value passed to opus_encoder_init()
+  * or opus_decoder_init().
+  * @param[out] x <tt>opus_int32 *</tt>: Sampling rate of encoder or decoder.
+  * @hideinitializer
+  */
+#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_decoderctls Decoder related CTLs
+  * @see opus_genericctls, opus_encoderctls, opus_decoder
+  * @{
+  */
+
+/** Configures decoder gain adjustment.
+  * Scales the decoded output by a factor specified in Q8 dB units.
+  * This has a maximum range of -32768 to 32767 inclusive, and returns
+  * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment.
+  * This setting survives decoder reset.
+  *
+  * gain = pow(10, x/(20.0*256))
+  *
+  * @param[in] x <tt>opus_int32</tt>:   Amount to scale PCM signal by in Q8 dB units.
+  * @hideinitializer */
+#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x)
+/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN
+  *
+  * @param[out] x <tt>opus_int32 *</tt>: Amount to scale PCM signal by in Q8 dB units.
+  * @hideinitializer */
+#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
+  * @param[out] x <tt>opus_int32 *</tt>: Number of samples (at current sampling rate).
+  * @hideinitializer */
+#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the pitch of the last decoded frame, if available.
+  * This can be used for any post-processing algorithm requiring the use of pitch,
+  * e.g. time stretching/shortening. If the last frame was not voiced, or if the
+  * pitch was not coded in the frame, then zero is returned.
+  *
+  * This CTL is only implemented for decoder instances.
+  *
+  * @param[out] x <tt>opus_int32 *</tt>: pitch period at 48 kHz (or 0 if not available)
+  *
+  * @hideinitializer */
+#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_libinfo Opus library information functions
+  * @{
+  */
+
+/** Converts an opus error code into a human readable string.
+  *
+  * @param[in] error <tt>int</tt>: Error number
+  * @returns Error string
+  */
+OPUS_EXPORT const char *opus_strerror(int error);
+
+/** Gets the libopus version string.
+  *
+  * Applications may look for the substring "-fixed" in the version string to
+  * determine whether they have a fixed-point or floating-point build at
+  * runtime.
+  *
+  * @returns Version string
+  */
+OPUS_EXPORT const char *opus_get_version_string(void);
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_DEFINES_H */
diff --git a/third_party/opus/src/include/opus_multistream.h b/third_party/opus/src/include/opus_multistream.h
new file mode 100644
index 0000000..3622e00
--- /dev/null
+++ b/third_party/opus/src/include/opus_multistream.h
@@ -0,0 +1,660 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus_multistream.h
+ * @brief Opus reference implementation multistream API
+ */
+
+#ifndef OPUS_MULTISTREAM_H
+#define OPUS_MULTISTREAM_H
+
+#include "opus.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond OPUS_INTERNAL_DOC */
+
+/** Macros to trigger compilation errors when the wrong types are provided to a
+  * CTL. */
+/**@{*/
+#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr)))
+#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr)))
+/**@}*/
+
+/** These are the actual encoder and decoder CTL ID numbers.
+  * They should not be used directly by applications.
+  * In general, SETs should be even and GETs should be odd.*/
+/**@{*/
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120
+#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122
+/**@}*/
+
+/** @endcond */
+
+/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs
+  *
+  * These are convenience macros that are specific to the
+  * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl()
+  * interface.
+  * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and
+  * @ref opus_decoderctls may be applied to a multistream encoder or decoder as
+  * well.
+  * In addition, you may retrieve the encoder or decoder state for an specific
+  * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or
+  * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually.
+  */
+/**@{*/
+
+/** Gets the encoder state for an individual stream of a multistream encoder.
+  * @param[in] x <tt>opus_int32</tt>: The index of the stream whose encoder you
+  *                                   wish to retrieve.
+  *                                   This must be non-negative and less than
+  *                                   the <code>streams</code> parameter used
+  *                                   to initialize the encoder.
+  * @param[out] y <tt>OpusEncoder**</tt>: Returns a pointer to the given
+  *                                       encoder state.
+  * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+  * @hideinitializer
+  */
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y)
+
+/** Gets the decoder state for an individual stream of a multistream decoder.
+  * @param[in] x <tt>opus_int32</tt>: The index of the stream whose decoder you
+  *                                   wish to retrieve.
+  *                                   This must be non-negative and less than
+  *                                   the <code>streams</code> parameter used
+  *                                   to initialize the decoder.
+  * @param[out] y <tt>OpusDecoder**</tt>: Returns a pointer to the given
+  *                                       decoder state.
+  * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+  * @hideinitializer
+  */
+#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y)
+
+/**@}*/
+
+/** @defgroup opus_multistream Opus Multistream API
+  * @{
+  *
+  * The multistream API allows individual Opus streams to be combined into a
+  * single packet, enabling support for up to 255 channels. Unlike an
+  * elementary Opus stream, the encoder and decoder must negotiate the channel
+  * configuration before the decoder can successfully interpret the data in the
+  * packets produced by the encoder. Some basic information, such as packet
+  * duration, can be computed without any special negotiation.
+  *
+  * The format for multistream Opus packets is defined in
+  * <a href="https://tools.ietf.org/html/rfc7845">RFC 7845</a>
+  * and is based on the self-delimited Opus framing described in Appendix B of
+  * <a href="https://tools.ietf.org/html/rfc6716">RFC 6716</a>.
+  * Normal Opus packets are just a degenerate case of multistream Opus packets,
+  * and can be encoded or decoded with the multistream API by setting
+  * <code>streams</code> to <code>1</code> when initializing the encoder or
+  * decoder.
+  *
+  * Multistream Opus streams can contain up to 255 elementary Opus streams.
+  * These may be either "uncoupled" or "coupled", indicating that the decoder
+  * is configured to decode them to either 1 or 2 channels, respectively.
+  * The streams are ordered so that all coupled streams appear at the
+  * beginning.
+  *
+  * A <code>mapping</code> table defines which decoded channel <code>i</code>
+  * should be used for each input/output (I/O) channel <code>j</code>. This table is
+  * typically provided as an unsigned char array.
+  * Let <code>i = mapping[j]</code> be the index for I/O channel <code>j</code>.
+  * If <code>i < 2*coupled_streams</code>, then I/O channel <code>j</code> is
+  * encoded as the left channel of stream <code>(i/2)</code> if <code>i</code>
+  * is even, or  as the right channel of stream <code>(i/2)</code> if
+  * <code>i</code> is odd. Otherwise, I/O channel <code>j</code> is encoded as
+  * mono in stream <code>(i - coupled_streams)</code>, unless it has the special
+  * value 255, in which case it is omitted from the encoding entirely (the
+  * decoder will reproduce it as silence). Each value <code>i</code> must either
+  * be the special value 255 or be less than <code>streams + coupled_streams</code>.
+  *
+  * The output channels specified by the encoder
+  * should use the
+  * <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
+  * channel ordering</a>. A decoder may wish to apply an additional permutation
+  * to the mapping the encoder used to achieve a different output channel
+  * order (e.g. for outputing in WAV order).
+  *
+  * Each multistream packet contains an Opus packet for each stream, and all of
+  * the Opus packets in a single multistream packet must have the same
+  * duration. Therefore the duration of a multistream packet can be extracted
+  * from the TOC sequence of the first stream, which is located at the
+  * beginning of the packet, just like an elementary Opus stream:
+  *
+  * @code
+  * int nb_samples;
+  * int nb_frames;
+  * nb_frames = opus_packet_get_nb_frames(data, len);
+  * if (nb_frames < 1)
+  *   return nb_frames;
+  * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames;
+  * @endcode
+  *
+  * The general encoding and decoding process proceeds exactly the same as in
+  * the normal @ref opus_encoder and @ref opus_decoder APIs.
+  * See their documentation for an overview of how to use the corresponding
+  * multistream functions.
+  */
+
+/** Opus multistream encoder state.
+  * This contains the complete state of a multistream Opus encoder.
+  * It is position independent and can be freely copied.
+  * @see opus_multistream_encoder_create
+  * @see opus_multistream_encoder_init
+  */
+typedef struct OpusMSEncoder OpusMSEncoder;
+
+/** Opus multistream decoder state.
+  * This contains the complete state of a multistream Opus decoder.
+  * It is position independent and can be freely copied.
+  * @see opus_multistream_decoder_create
+  * @see opus_multistream_decoder_init
+  */
+typedef struct OpusMSDecoder OpusMSDecoder;
+
+/**\name Multistream encoder functions */
+/**@{*/
+
+/** Gets the size of an OpusMSEncoder structure.
+  * @param streams <tt>int</tt>: The total number of streams to encode from the
+  *                              input.
+  *                              This must be no more than 255.
+  * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+  *                                      to encode.
+  *                                      This must be no larger than the total
+  *                                      number of streams.
+  *                                      Additionally, The total number of
+  *                                      encoded channels (<code>streams +
+  *                                      coupled_streams</code>) must be no
+  *                                      more than 255.
+  * @returns The size in bytes on success, or a negative error code
+  *          (see @ref opus_errorcodes) on error.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size(
+      int streams,
+      int coupled_streams
+);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size(
+      int channels,
+      int mapping_family
+);
+
+
+/** Allocates and initializes a multistream encoder state.
+  * Call opus_multistream_encoder_destroy() to release
+  * this object when finished.
+  * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).
+  *                                This must be one of 8000, 12000, 16000,
+  *                                24000, or 48000.
+  * @param channels <tt>int</tt>: Number of channels in the input signal.
+  *                               This must be at most 255.
+  *                               It may be greater than the number of
+  *                               coded channels (<code>streams +
+  *                               coupled_streams</code>).
+  * @param streams <tt>int</tt>: The total number of streams to encode from the
+  *                              input.
+  *                              This must be no more than the number of channels.
+  * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+  *                                      to encode.
+  *                                      This must be no larger than the total
+  *                                      number of streams.
+  *                                      Additionally, The total number of
+  *                                      encoded channels (<code>streams +
+  *                                      coupled_streams</code>) must be no
+  *                                      more than the number of input channels.
+  * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+  *                    encoded channels to input channels, as described in
+  *                    @ref opus_multistream. As an extra constraint, the
+  *                    multistream encoder does not allow encoding coupled
+  *                    streams for which one channel is unused since this
+  *                    is never a good idea.
+  * @param application <tt>int</tt>: The target encoder application.
+  *                                  This must be one of the following:
+  * <dl>
+  * <dt>#OPUS_APPLICATION_VOIP</dt>
+  * <dd>Process signal for improved speech intelligibility.</dd>
+  * <dt>#OPUS_APPLICATION_AUDIO</dt>
+  * <dd>Favor faithfulness to the original input.</dd>
+  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+  * <dd>Configure the minimum possible coding delay by disabling certain modes
+  * of operation.</dd>
+  * </dl>
+  * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error
+  *                                   code (see @ref opus_errorcodes) on
+  *                                   failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create(
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping,
+      int application,
+      int *error
+) OPUS_ARG_NONNULL(5);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create(
+      opus_int32 Fs,
+      int channels,
+      int mapping_family,
+      int *streams,
+      int *coupled_streams,
+      unsigned char *mapping,
+      int application,
+      int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Initialize a previously allocated multistream encoder state.
+  * The memory pointed to by \a st must be at least the size returned by
+  * opus_multistream_encoder_get_size().
+  * This is intended for applications which use their own allocator instead of
+  * malloc.
+  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+  * @see opus_multistream_encoder_create
+  * @see opus_multistream_encoder_get_size
+  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to initialize.
+  * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).
+  *                                This must be one of 8000, 12000, 16000,
+  *                                24000, or 48000.
+  * @param channels <tt>int</tt>: Number of channels in the input signal.
+  *                               This must be at most 255.
+  *                               It may be greater than the number of
+  *                               coded channels (<code>streams +
+  *                               coupled_streams</code>).
+  * @param streams <tt>int</tt>: The total number of streams to encode from the
+  *                              input.
+  *                              This must be no more than the number of channels.
+  * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+  *                                      to encode.
+  *                                      This must be no larger than the total
+  *                                      number of streams.
+  *                                      Additionally, The total number of
+  *                                      encoded channels (<code>streams +
+  *                                      coupled_streams</code>) must be no
+  *                                      more than the number of input channels.
+  * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+  *                    encoded channels to input channels, as described in
+  *                    @ref opus_multistream. As an extra constraint, the
+  *                    multistream encoder does not allow encoding coupled
+  *                    streams for which one channel is unused since this
+  *                    is never a good idea.
+  * @param application <tt>int</tt>: The target encoder application.
+  *                                  This must be one of the following:
+  * <dl>
+  * <dt>#OPUS_APPLICATION_VOIP</dt>
+  * <dd>Process signal for improved speech intelligibility.</dd>
+  * <dt>#OPUS_APPLICATION_AUDIO</dt>
+  * <dd>Favor faithfulness to the original input.</dd>
+  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+  * <dd>Configure the minimum possible coding delay by disabling certain modes
+  * of operation.</dd>
+  * </dl>
+  * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+  *          on failure.
+  */
+OPUS_EXPORT int opus_multistream_encoder_init(
+      OpusMSEncoder *st,
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping,
+      int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+OPUS_EXPORT int opus_multistream_surround_encoder_init(
+      OpusMSEncoder *st,
+      opus_int32 Fs,
+      int channels,
+      int mapping_family,
+      int *streams,
+      int *coupled_streams,
+      unsigned char *mapping,
+      int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Encodes a multistream Opus frame.
+  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+  * @param[in] pcm <tt>const opus_int16*</tt>: The input signal as interleaved
+  *                                            samples.
+  *                                            This must contain
+  *                                            <code>frame_size*channels</code>
+  *                                            samples.
+  * @param frame_size <tt>int</tt>: Number of samples per channel in the input
+  *                                 signal.
+  *                                 This must be an Opus frame size for the
+  *                                 encoder's sampling rate.
+  *                                 For example, at 48 kHz the permitted values
+  *                                 are 120, 240, 480, 960, 1920, and 2880.
+  *                                 Passing in a duration of less than 10 ms
+  *                                 (480 samples at 48 kHz) will prevent the
+  *                                 encoder from using the LPC or hybrid modes.
+  * @param[out] data <tt>unsigned char*</tt>: Output payload.
+  *                                           This must contain storage for at
+  *                                           least \a max_data_bytes.
+  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+  *                                                 memory for the output
+  *                                                 payload. This may be
+  *                                                 used to impose an upper limit on
+  *                                                 the instant bitrate, but should
+  *                                                 not be used as the only bitrate
+  *                                                 control. Use #OPUS_SET_BITRATE to
+  *                                                 control the bitrate.
+  * @returns The length of the encoded packet (in bytes) on success or a
+  *          negative error code (see @ref opus_errorcodes) on failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode(
+    OpusMSEncoder *st,
+    const opus_int16 *pcm,
+    int frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes a multistream Opus frame from floating point input.
+  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+  * @param[in] pcm <tt>const float*</tt>: The input signal as interleaved
+  *                                       samples with a normal range of
+  *                                       +/-1.0.
+  *                                       Samples with a range beyond +/-1.0
+  *                                       are supported but will be clipped by
+  *                                       decoders using the integer API and
+  *                                       should only be used if it is known
+  *                                       that the far end supports extended
+  *                                       dynamic range.
+  *                                       This must contain
+  *                                       <code>frame_size*channels</code>
+  *                                       samples.
+  * @param frame_size <tt>int</tt>: Number of samples per channel in the input
+  *                                 signal.
+  *                                 This must be an Opus frame size for the
+  *                                 encoder's sampling rate.
+  *                                 For example, at 48 kHz the permitted values
+  *                                 are 120, 240, 480, 960, 1920, and 2880.
+  *                                 Passing in a duration of less than 10 ms
+  *                                 (480 samples at 48 kHz) will prevent the
+  *                                 encoder from using the LPC or hybrid modes.
+  * @param[out] data <tt>unsigned char*</tt>: Output payload.
+  *                                           This must contain storage for at
+  *                                           least \a max_data_bytes.
+  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+  *                                                 memory for the output
+  *                                                 payload. This may be
+  *                                                 used to impose an upper limit on
+  *                                                 the instant bitrate, but should
+  *                                                 not be used as the only bitrate
+  *                                                 control. Use #OPUS_SET_BITRATE to
+  *                                                 control the bitrate.
+  * @returns The length of the encoded packet (in bytes) on success or a
+  *          negative error code (see @ref opus_errorcodes) on failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float(
+      OpusMSEncoder *st,
+      const float *pcm,
+      int frame_size,
+      unsigned char *data,
+      opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an <code>OpusMSEncoder</code> allocated by
+  * opus_multistream_encoder_create().
+  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to be freed.
+  */
+OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st);
+
+/** Perform a CTL function on a multistream Opus encoder.
+  *
+  * Generally the request and subsequent arguments are generated by a
+  * convenience macro.
+  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+  * @param request This and all remaining parameters should be replaced by one
+  *                of the convenience macros in @ref opus_genericctls,
+  *                @ref opus_encoderctls, or @ref opus_multistream_ctls.
+  * @see opus_genericctls
+  * @see opus_encoderctls
+  * @see opus_multistream_ctls
+  */
+OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/**@}*/
+
+/**\name Multistream decoder functions */
+/**@{*/
+
+/** Gets the size of an <code>OpusMSDecoder</code> structure.
+  * @param streams <tt>int</tt>: The total number of streams coded in the
+  *                              input.
+  *                              This must be no more than 255.
+  * @param coupled_streams <tt>int</tt>: Number streams to decode as coupled
+  *                                      (2 channel) streams.
+  *                                      This must be no larger than the total
+  *                                      number of streams.
+  *                                      Additionally, The total number of
+  *                                      coded channels (<code>streams +
+  *                                      coupled_streams</code>) must be no
+  *                                      more than 255.
+  * @returns The size in bytes on success, or a negative error code
+  *          (see @ref opus_errorcodes) on error.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size(
+      int streams,
+      int coupled_streams
+);
+
+/** Allocates and initializes a multistream decoder state.
+  * Call opus_multistream_decoder_destroy() to release
+  * this object when finished.
+  * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).
+  *                                This must be one of 8000, 12000, 16000,
+  *                                24000, or 48000.
+  * @param channels <tt>int</tt>: Number of channels to output.
+  *                               This must be at most 255.
+  *                               It may be different from the number of coded
+  *                               channels (<code>streams +
+  *                               coupled_streams</code>).
+  * @param streams <tt>int</tt>: The total number of streams coded in the
+  *                              input.
+  *                              This must be no more than 255.
+  * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled
+  *                                      (2 channel) streams.
+  *                                      This must be no larger than the total
+  *                                      number of streams.
+  *                                      Additionally, The total number of
+  *                                      coded channels (<code>streams +
+  *                                      coupled_streams</code>) must be no
+  *                                      more than 255.
+  * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+  *                    coded channels to output channels, as described in
+  *                    @ref opus_multistream.
+  * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error
+  *                                   code (see @ref opus_errorcodes) on
+  *                                   failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create(
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping,
+      int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Intialize a previously allocated decoder state object.
+  * The memory pointed to by \a st must be at least the size returned by
+  * opus_multistream_encoder_get_size().
+  * This is intended for applications which use their own allocator instead of
+  * malloc.
+  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+  * @see opus_multistream_decoder_create
+  * @see opus_multistream_deocder_get_size
+  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to initialize.
+  * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).
+  *                                This must be one of 8000, 12000, 16000,
+  *                                24000, or 48000.
+  * @param channels <tt>int</tt>: Number of channels to output.
+  *                               This must be at most 255.
+  *                               It may be different from the number of coded
+  *                               channels (<code>streams +
+  *                               coupled_streams</code>).
+  * @param streams <tt>int</tt>: The total number of streams coded in the
+  *                              input.
+  *                              This must be no more than 255.
+  * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled
+  *                                      (2 channel) streams.
+  *                                      This must be no larger than the total
+  *                                      number of streams.
+  *                                      Additionally, The total number of
+  *                                      coded channels (<code>streams +
+  *                                      coupled_streams</code>) must be no
+  *                                      more than 255.
+  * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+  *                    coded channels to output channels, as described in
+  *                    @ref opus_multistream.
+  * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+  *          on failure.
+  */
+OPUS_EXPORT int opus_multistream_decoder_init(
+      OpusMSDecoder *st,
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Decode a multistream Opus packet.
+  * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+  * @param[in] data <tt>const unsigned char*</tt>: Input payload.
+  *                                                Use a <code>NULL</code>
+  *                                                pointer to indicate packet
+  *                                                loss.
+  * @param len <tt>opus_int32</tt>: Number of bytes in payload.
+  * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved
+  *                                       samples.
+  *                                       This must contain room for
+  *                                       <code>frame_size*channels</code>
+  *                                       samples.
+  * @param frame_size <tt>int</tt>: The number of samples per channel of
+  *                                 available space in \a pcm.
+  *                                 If this is less than the maximum packet duration
+  *                                 (120 ms; 5760 for 48kHz), this function will not be capable
+  *                                 of decoding some packets. In the case of PLC (data==NULL)
+  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly
+  *                                 the duration of audio that is missing, otherwise the
+  *                                 decoder will not be in the optimal state to decode the
+  *                                 next incoming packet. For the PLC and FEC cases, frame_size
+  *                                 <b>must</b> be a multiple of 2.5 ms.
+  * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
+  *                                 forward error correction data be decoded.
+  *                                 If no such data is available, the frame is
+  *                                 decoded as if it were lost.
+  * @returns Number of samples decoded on success or a negative error code
+  *          (see @ref opus_errorcodes) on failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode(
+    OpusMSDecoder *st,
+    const unsigned char *data,
+    opus_int32 len,
+    opus_int16 *pcm,
+    int frame_size,
+    int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode a multistream Opus packet with floating point output.
+  * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+  * @param[in] data <tt>const unsigned char*</tt>: Input payload.
+  *                                                Use a <code>NULL</code>
+  *                                                pointer to indicate packet
+  *                                                loss.
+  * @param len <tt>opus_int32</tt>: Number of bytes in payload.
+  * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved
+  *                                       samples.
+  *                                       This must contain room for
+  *                                       <code>frame_size*channels</code>
+  *                                       samples.
+  * @param frame_size <tt>int</tt>: The number of samples per channel of
+  *                                 available space in \a pcm.
+  *                                 If this is less than the maximum packet duration
+  *                                 (120 ms; 5760 for 48kHz), this function will not be capable
+  *                                 of decoding some packets. In the case of PLC (data==NULL)
+  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly
+  *                                 the duration of audio that is missing, otherwise the
+  *                                 decoder will not be in the optimal state to decode the
+  *                                 next incoming packet. For the PLC and FEC cases, frame_size
+  *                                 <b>must</b> be a multiple of 2.5 ms.
+  * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
+  *                                 forward error correction data be decoded.
+  *                                 If no such data is available, the frame is
+  *                                 decoded as if it were lost.
+  * @returns Number of samples decoded on success or a negative error code
+  *          (see @ref opus_errorcodes) on failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float(
+    OpusMSDecoder *st,
+    const unsigned char *data,
+    opus_int32 len,
+    float *pcm,
+    int frame_size,
+    int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on a multistream Opus decoder.
+  *
+  * Generally the request and subsequent arguments are generated by a
+  * convenience macro.
+  * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+  * @param request This and all remaining parameters should be replaced by one
+  *                of the convenience macros in @ref opus_genericctls,
+  *                @ref opus_decoderctls, or @ref opus_multistream_ctls.
+  * @see opus_genericctls
+  * @see opus_decoderctls
+  * @see opus_multistream_ctls
+  */
+OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an <code>OpusMSDecoder</code> allocated by
+  * opus_multistream_decoder_create().
+  * @param st <tt>OpusMSDecoder</tt>: Multistream decoder state to be freed.
+  */
+OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st);
+
+/**@}*/
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_MULTISTREAM_H */
diff --git a/third_party/opus/src/include/opus_types.h b/third_party/opus/src/include/opus_types.h
new file mode 100644
index 0000000..b28e03a
--- /dev/null
+++ b/third_party/opus/src/include/opus_types.h
@@ -0,0 +1,159 @@
+/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */
+/* Modified by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/* opus_types.h based on ogg_types.h from libogg */
+
+/**
+   @file opus_types.h
+   @brief Opus reference implementation types
+*/
+#ifndef OPUS_TYPES_H
+#define OPUS_TYPES_H
+
+/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
+#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
+#include <stdint.h>
+
+   typedef int16_t opus_int16;
+   typedef uint16_t opus_uint16;
+   typedef int32_t opus_int32;
+   typedef uint32_t opus_uint32;
+#elif defined(_WIN32)
+
+#  if defined(__CYGWIN__)
+#    include <_G_config.h>
+     typedef _G_int32_t opus_int32;
+     typedef _G_uint32_t opus_uint32;
+     typedef _G_int16 opus_int16;
+     typedef _G_uint16 opus_uint16;
+#  elif defined(__MINGW32__)
+     typedef short opus_int16;
+     typedef unsigned short opus_uint16;
+     typedef int opus_int32;
+     typedef unsigned int opus_uint32;
+#  elif defined(__MWERKS__)
+     typedef int opus_int32;
+     typedef unsigned int opus_uint32;
+     typedef short opus_int16;
+     typedef unsigned short opus_uint16;
+#  else
+     /* MSVC/Borland */
+     typedef __int32 opus_int32;
+     typedef unsigned __int32 opus_uint32;
+     typedef __int16 opus_int16;
+     typedef unsigned __int16 opus_uint16;
+#  endif
+
+#elif defined(__MACOS__)
+
+#  include <sys/types.h>
+   typedef SInt16 opus_int16;
+   typedef UInt16 opus_uint16;
+   typedef SInt32 opus_int32;
+   typedef UInt32 opus_uint32;
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+#  include <sys/types.h>
+   typedef int16_t opus_int16;
+   typedef u_int16_t opus_uint16;
+   typedef int32_t opus_int32;
+   typedef u_int32_t opus_uint32;
+
+#elif defined(__BEOS__)
+
+   /* Be */
+#  include <inttypes.h>
+   typedef int16 opus_int16;
+   typedef u_int16 opus_uint16;
+   typedef int32_t opus_int32;
+   typedef u_int32_t opus_uint32;
+
+#elif defined (__EMX__)
+
+   /* OS/2 GCC */
+   typedef short opus_int16;
+   typedef unsigned short opus_uint16;
+   typedef int opus_int32;
+   typedef unsigned int opus_uint32;
+
+#elif defined (DJGPP)
+
+   /* DJGPP */
+   typedef short opus_int16;
+   typedef unsigned short opus_uint16;
+   typedef int opus_int32;
+   typedef unsigned int opus_uint32;
+
+#elif defined(R5900)
+
+   /* PS2 EE */
+   typedef int opus_int32;
+   typedef unsigned opus_uint32;
+   typedef short opus_int16;
+   typedef unsigned short opus_uint16;
+
+#elif defined(__SYMBIAN32__)
+
+   /* Symbian GCC */
+   typedef signed short opus_int16;
+   typedef unsigned short opus_uint16;
+   typedef signed int opus_int32;
+   typedef unsigned int opus_uint32;
+
+#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+   typedef short opus_int16;
+   typedef unsigned short opus_uint16;
+   typedef long opus_int32;
+   typedef unsigned long opus_uint32;
+
+#elif defined(CONFIG_TI_C6X)
+
+   typedef short opus_int16;
+   typedef unsigned short opus_uint16;
+   typedef int opus_int32;
+   typedef unsigned int opus_uint32;
+
+#else
+
+   /* Give up, take a reasonable guess */
+   typedef short opus_int16;
+   typedef unsigned short opus_uint16;
+   typedef int opus_int32;
+   typedef unsigned int opus_uint32;
+
+#endif
+
+#define opus_int         int                     /* used for counters etc; at least 16 bits */
+#define opus_int64       long long
+#define opus_int8        signed char
+
+#define opus_uint        unsigned int            /* used for counters etc; at least 16 bits */
+#define opus_uint64      unsigned long long
+#define opus_uint8       unsigned char
+
+#endif  /* OPUS_TYPES_H */
diff --git a/third_party/opus/src/m4/as-gcc-inline-assembly.m4 b/third_party/opus/src/m4/as-gcc-inline-assembly.m4
new file mode 100644
index 0000000..b0d2da4
--- /dev/null
+++ b/third_party/opus/src/m4/as-gcc-inline-assembly.m4
@@ -0,0 +1,98 @@
+dnl as-gcc-inline-assembly.m4 0.1.0
+
+dnl autostars m4 macro for detection of gcc inline assembly
+
+dnl David Schleef <ds@schleef.org>
+
+dnl AS_COMPILER_FLAG(ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED])
+dnl Tries to compile with the given CFLAGS.
+dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags,
+dnl and ACTION-IF-NOT-ACCEPTED otherwise.
+
+AC_DEFUN([AS_GCC_INLINE_ASSEMBLY],
+[
+  AC_MSG_CHECKING([if compiler supports gcc-style inline assembly])
+
+  AC_TRY_COMPILE([], [
+#ifdef __GNUC_MINOR__
+#if (__GNUC__ * 1000 + __GNUC_MINOR__) < 3004
+#error GCC before 3.4 has critical bugs compiling inline assembly
+#endif
+#endif
+__asm__ (""::) ], [flag_ok=yes], [flag_ok=no])
+
+  if test "X$flag_ok" = Xyes ; then
+    $1
+    true
+  else
+    $2
+    true
+  fi
+  AC_MSG_RESULT([$flag_ok])
+])
+
+AC_DEFUN([AS_ASM_ARM_NEON],
+[
+  AC_MSG_CHECKING([if assembler supports NEON instructions on ARM])
+
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("vorr d0,d0,d0")])],
+                    [AC_MSG_RESULT([yes])
+                     $1],
+                    [AC_MSG_RESULT([no])
+                     $2])
+])
+
+AC_DEFUN([AS_ASM_ARM_NEON_FORCE],
+[
+  AC_MSG_CHECKING([if assembler supports NEON instructions on ARM])
+
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv7-a\n.fpu neon\n.object_arch armv4t\nvorr d0,d0,d0")])],
+                    [AC_MSG_RESULT([yes])
+                     $1],
+                    [AC_MSG_RESULT([no])
+                     $2])
+])
+
+AC_DEFUN([AS_ASM_ARM_MEDIA],
+[
+  AC_MSG_CHECKING([if assembler supports ARMv6 media instructions on ARM])
+
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("shadd8 r3,r3,r3")])],
+                    [AC_MSG_RESULT([yes])
+                     $1],
+                    [AC_MSG_RESULT([no])
+                     $2])
+])
+
+AC_DEFUN([AS_ASM_ARM_MEDIA_FORCE],
+[
+  AC_MSG_CHECKING([if assembler supports ARMv6 media instructions on ARM])
+
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv6\n.object_arch armv4t\nshadd8 r3,r3,r3")])],
+                    [AC_MSG_RESULT([yes])
+                     $1],
+                    [AC_MSG_RESULT([no])
+                     $2])
+])
+
+AC_DEFUN([AS_ASM_ARM_EDSP],
+[
+  AC_MSG_CHECKING([if assembler supports EDSP instructions on ARM])
+
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("qadd r3,r3,r3")])],
+                    [AC_MSG_RESULT([yes])
+                     $1],
+                    [AC_MSG_RESULT([no])
+                     $2])
+])
+
+AC_DEFUN([AS_ASM_ARM_EDSP_FORCE],
+[
+  AC_MSG_CHECKING([if assembler supports EDSP instructions on ARM])
+
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv5te\n.object_arch armv4t\nqadd r3,r3,r3")])],
+                    [AC_MSG_RESULT([yes])
+                     $1],
+                    [AC_MSG_RESULT([no])
+                     $2])
+])
diff --git a/third_party/opus/src/m4/opus-intrinsics.m4 b/third_party/opus/src/m4/opus-intrinsics.m4
new file mode 100644
index 0000000..a262ca1
--- /dev/null
+++ b/third_party/opus/src/m4/opus-intrinsics.m4
@@ -0,0 +1,29 @@
+dnl opus-intrinsics.m4
+dnl macro for testing for support for compiler intrinsics, either by default or with a compiler flag
+
+dnl OPUS_CHECK_INTRINSICS(NAME-OF-INTRINSICS, COMPILER-FLAG-FOR-INTRINSICS, VAR-IF-PRESENT, VAR-IF-DEFAULT, TEST-PROGRAM-HEADER, TEST-PROGRAM-BODY)
+AC_DEFUN([OPUS_CHECK_INTRINSICS],
+[
+   AC_MSG_CHECKING([if compiler supports $1 intrinsics])
+   AC_LINK_IFELSE(
+     [AC_LANG_PROGRAM($5, $6)],
+     [
+        $3=1
+        $4=1
+        AC_MSG_RESULT([yes])
+      ],[
+        $4=0
+        AC_MSG_RESULT([no])
+        AC_MSG_CHECKING([if compiler supports $1 intrinsics with $2])
+        save_CFLAGS="$CFLAGS"; CFLAGS="$CFLAGS $2"
+        AC_LINK_IFELSE([AC_LANG_PROGRAM($5, $6)],
+        [
+           AC_MSG_RESULT([yes])
+           $3=1
+        ],[
+           AC_MSG_RESULT([no])
+           $3=0
+        ])
+        CFLAGS="$save_CFLAGS"
+     ])
+])
diff --git a/third_party/opus/src/opus-uninstalled.pc.in b/third_party/opus/src/opus-uninstalled.pc.in
new file mode 100644
index 0000000..3f2d674
--- /dev/null
+++ b/third_party/opus/src/opus-uninstalled.pc.in
@@ -0,0 +1,12 @@
+# Opus codec reference implementation uninstalled pkg-config file
+
+libdir=${pcfiledir}/.libs
+includedir=${pcfiledir}
+
+Name: opus uninstalled
+Description: Opus IETF audio codec (not installed, @PC_BUILD@)
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: ${libdir}/libopus.a @LIBM@
+Cflags: -I${pcfiledir}/@top_srcdir@/include
diff --git a/third_party/opus/src/opus.m4 b/third_party/opus/src/opus.m4
new file mode 100644
index 0000000..47f5ec4
--- /dev/null
+++ b/third_party/opus/src/opus.m4
@@ -0,0 +1,117 @@
+# Configure paths for libopus
+# Gregory Maxwell <greg@xiph.org> 08-30-2012
+# Shamelessly stolen from Jack Moffitt (libogg) who
+# Shamelessly stole from Owen Taylor and Manish Singh
+
+dnl XIPH_PATH_OPUS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libopus, and define OPUS_CFLAGS and OPUS_LIBS
+dnl
+AC_DEFUN([XIPH_PATH_OPUS],
+[dnl
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(opus,AC_HELP_STRING([--with-opus=PFX],[Prefix where opus is installed (optional)]), opus_prefix="$withval", opus_prefix="")
+AC_ARG_WITH(opus-libraries,AC_HELP_STRING([--with-opus-libraries=DIR],[Directory where the opus library is installed (optional)]), opus_libraries="$withval", opus_libraries="")
+AC_ARG_WITH(opus-includes,AC_HELP_STRING([--with-opus-includes=DIR],[Directory where the opus header files are installed (optional)]), opus_includes="$withval", opus_includes="")
+AC_ARG_ENABLE(opustest,AC_HELP_STRING([--disable-opustest],[Do not try to compile and run a test opus program]),, enable_opustest=yes)
+
+  if test "x$opus_libraries" != "x" ; then
+    OPUS_LIBS="-L$opus_libraries"
+  elif test "x$opus_prefix" = "xno" || test "x$opus_prefix" = "xyes" ; then
+    OPUS_LIBS=""
+  elif test "x$opus_prefix" != "x" ; then
+    OPUS_LIBS="-L$opus_prefix/lib"
+  elif test "x$prefix" != "xNONE" ; then
+    OPUS_LIBS="-L$prefix/lib"
+  fi
+
+  if test "x$opus_prefix" != "xno" ; then
+    OPUS_LIBS="$OPUS_LIBS -lopus"
+  fi
+
+  if test "x$opus_includes" != "x" ; then
+    OPUS_CFLAGS="-I$opus_includes"
+  elif test "x$opus_prefix" = "xno" || test "x$opus_prefix" = "xyes" ; then
+    OPUS_CFLAGS=""
+  elif test "x$opus_prefix" != "x" ; then
+    OPUS_CFLAGS="-I$opus_prefix/include"
+  elif test "x$prefix" != "xNONE"; then
+    OPUS_CFLAGS="-I$prefix/include"
+  fi
+
+  AC_MSG_CHECKING(for Opus)
+  if test "x$opus_prefix" = "xno" ; then
+    no_opus="disabled"
+    enable_opustest="no"
+  else
+    no_opus=""
+  fi
+
+
+  if test "x$enable_opustest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $OPUS_CFLAGS"
+    LIBS="$LIBS $OPUS_LIBS"
+dnl
+dnl Now check if the installed Opus is sufficiently new.
+dnl
+      rm -f conf.opustest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <opus.h>
+
+int main ()
+{
+  system("touch conf.opustest");
+  return 0;
+}
+
+],, no_opus=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_opus" = "xdisabled" ; then
+     AC_MSG_RESULT(no)
+     ifelse([$2], , :, [$2])
+  elif test "x$no_opus" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.opustest ; then
+       :
+     else
+       echo "*** Could not run Opus test program, checking why..."
+       CFLAGS="$CFLAGS $OPUS_CFLAGS"
+       LIBS="$LIBS $OPUS_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <opus.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding Opus or finding the wrong"
+       echo "*** version of Opus. If it is not finding Opus, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occurred. This usually means Opus was incorrectly installed"
+       echo "*** or that you have moved Opus since it was installed." ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     OPUS_CFLAGS=""
+     OPUS_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(OPUS_CFLAGS)
+  AC_SUBST(OPUS_LIBS)
+  rm -f conf.opustest
+])
diff --git a/third_party/opus/src/opus.pc.in b/third_party/opus/src/opus.pc.in
new file mode 100644
index 0000000..6946e7d
--- /dev/null
+++ b/third_party/opus/src/opus.pc.in
@@ -0,0 +1,16 @@
+# Opus codec reference implementation pkg-config file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Opus
+Description: Opus IETF audio codec (@PC_BUILD@ build)
+URL: https://opus-codec.org/
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -lopus
+Libs.private: @LIBM@
+Cflags: -I${includedir}/opus
diff --git a/third_party/opus/src/silk/A2NLSF.c b/third_party/opus/src/silk/A2NLSF.c
new file mode 100644
index 0000000..b6e9e5f
--- /dev/null
+++ b/third_party/opus/src/silk/A2NLSF.c
@@ -0,0 +1,267 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+/* Conversion between prediction filter coefficients and NLSFs  */
+/* Requires the order to be an even number                      */
+/* A piecewise linear approximation maps LSF <-> cos(LSF)       */
+/* Therefore the result is not accurate NLSFs, but the two      */
+/* functions are accurate inverses of each other                */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "tables.h"
+
+/* Number of binary divisions, when not in low complexity mode */
+#define BIN_DIV_STEPS_A2NLSF_FIX      3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */
+#define MAX_ITERATIONS_A2NLSF_FIX    30
+
+/* Helper function for A2NLSF(..)                    */
+/* Transforms polynomials from cos(n*f) to cos(f)^n  */
+static OPUS_INLINE void silk_A2NLSF_trans_poly(
+    opus_int32          *p,                     /* I/O    Polynomial                                */
+    const opus_int      dd                      /* I      Polynomial order (= filter order / 2 )    */
+)
+{
+    opus_int k, n;
+
+    for( k = 2; k <= dd; k++ ) {
+        for( n = dd; n > k; n-- ) {
+            p[ n - 2 ] -= p[ n ];
+        }
+        p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 );
+    }
+}
+/* Helper function for A2NLSF(..) */
+/* Polynomial evaluation          */
+static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16     */
+    opus_int32          *p,                     /* I    Polynomial, Q16                         */
+    const opus_int32    x,                      /* I    Evaluation point, Q12                   */
+    const opus_int      dd                      /* I    Order                                   */
+)
+{
+    opus_int   n;
+    opus_int32 x_Q16, y32;
+
+    y32 = p[ dd ];                                  /* Q16 */
+    x_Q16 = silk_LSHIFT( x, 4 );
+
+    if ( opus_likely( 8 == dd ) )
+    {
+        y32 = silk_SMLAWW( p[ 7 ], y32, x_Q16 );
+        y32 = silk_SMLAWW( p[ 6 ], y32, x_Q16 );
+        y32 = silk_SMLAWW( p[ 5 ], y32, x_Q16 );
+        y32 = silk_SMLAWW( p[ 4 ], y32, x_Q16 );
+        y32 = silk_SMLAWW( p[ 3 ], y32, x_Q16 );
+        y32 = silk_SMLAWW( p[ 2 ], y32, x_Q16 );
+        y32 = silk_SMLAWW( p[ 1 ], y32, x_Q16 );
+        y32 = silk_SMLAWW( p[ 0 ], y32, x_Q16 );
+    }
+    else
+    {
+        for( n = dd - 1; n >= 0; n-- ) {
+            y32 = silk_SMLAWW( p[ n ], y32, x_Q16 );    /* Q16 */
+        }
+    }
+    return y32;
+}
+
+static OPUS_INLINE void silk_A2NLSF_init(
+     const opus_int32    *a_Q16,
+     opus_int32          *P,
+     opus_int32          *Q,
+     const opus_int      dd
+)
+{
+    opus_int k;
+
+    /* Convert filter coefs to even and odd polynomials */
+    P[dd] = silk_LSHIFT( 1, 16 );
+    Q[dd] = silk_LSHIFT( 1, 16 );
+    for( k = 0; k < dd; k++ ) {
+        P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ];    /* Q16 */
+        Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ];    /* Q16 */
+    }
+
+    /* Divide out zeros as we have that for even filter orders, */
+    /* z =  1 is always a root in Q, and                        */
+    /* z = -1 is always a root in P                             */
+    for( k = dd; k > 0; k-- ) {
+        P[ k - 1 ] -= P[ k ];
+        Q[ k - 1 ] += Q[ k ];
+    }
+
+    /* Transform polynomials from cos(n*f) to cos(f)^n */
+    silk_A2NLSF_trans_poly( P, dd );
+    silk_A2NLSF_trans_poly( Q, dd );
+}
+
+/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients      */
+/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
+void silk_A2NLSF(
+    opus_int16                  *NLSF,              /* O    Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
+    opus_int32                  *a_Q16,             /* I/O  Monic whitening filter coefficients in Q16 [d]              */
+    const opus_int              d                   /* I    Filter order (must be even)                                 */
+)
+{
+    opus_int      i, k, m, dd, root_ix, ffrac;
+    opus_int32 xlo, xhi, xmid;
+    opus_int32 ylo, yhi, ymid, thr;
+    opus_int32 nom, den;
+    opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+    opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+    opus_int32 *PQ[ 2 ];
+    opus_int32 *p;
+
+    /* Store pointers to array */
+    PQ[ 0 ] = P;
+    PQ[ 1 ] = Q;
+
+    dd = silk_RSHIFT( d, 1 );
+
+    silk_A2NLSF_init( a_Q16, P, Q, dd );
+
+    /* Find roots, alternating between P and Q */
+    p = P;                          /* Pointer to polynomial */
+
+    xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
+    ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+
+    if( ylo < 0 ) {
+        /* Set the first NLSF to zero and move on to the next */
+        NLSF[ 0 ] = 0;
+        p = Q;                      /* Pointer to polynomial */
+        ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+        root_ix = 1;                /* Index of current root */
+    } else {
+        root_ix = 0;                /* Index of current root */
+    }
+    k = 1;                          /* Loop counter */
+    i = 0;                          /* Counter for bandwidth expansions applied */
+    thr = 0;
+    while( 1 ) {
+        /* Evaluate polynomial */
+        xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */
+        yhi = silk_A2NLSF_eval_poly( p, xhi, dd );
+
+        /* Detect zero crossing */
+        if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) {
+            if( yhi == 0 ) {
+                /* If the root lies exactly at the end of the current       */
+                /* interval, look for the next root in the next interval    */
+                thr = 1;
+            } else {
+                thr = 0;
+            }
+            /* Binary division */
+            ffrac = -256;
+            for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) {
+                /* Evaluate polynomial */
+                xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 );
+                ymid = silk_A2NLSF_eval_poly( p, xmid, dd );
+
+                /* Detect zero crossing */
+                if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) {
+                    /* Reduce frequency */
+                    xhi = xmid;
+                    yhi = ymid;
+                } else {
+                    /* Increase frequency */
+                    xlo = xmid;
+                    ylo = ymid;
+                    ffrac = silk_ADD_RSHIFT( ffrac, 128, m );
+                }
+            }
+
+            /* Interpolate */
+            if( silk_abs( ylo ) < 65536 ) {
+                /* Avoid dividing by zero */
+                den = ylo - yhi;
+                nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 );
+                if( den != 0 ) {
+                    ffrac += silk_DIV32( nom, den );
+                }
+            } else {
+                /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */
+                ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) );
+            }
+            NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX );
+
+            silk_assert( NLSF[ root_ix ] >= 0 );
+
+            root_ix++;        /* Next root */
+            if( root_ix >= d ) {
+                /* Found all roots */
+                break;
+            }
+            /* Alternate pointer to polynomial */
+            p = PQ[ root_ix & 1 ];
+
+            /* Evaluate polynomial */
+            xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/
+            ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 );
+        } else {
+            /* Increment loop counter */
+            k++;
+            xlo = xhi;
+            ylo = yhi;
+            thr = 0;
+
+            if( k > LSF_COS_TAB_SZ_FIX ) {
+                i++;
+                if( i > MAX_ITERATIONS_A2NLSF_FIX ) {
+                    /* Set NLSFs to white spectrum and exit */
+                    NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 );
+                    for( k = 1; k < d; k++ ) {
+                        NLSF[ k ] = (opus_int16)silk_SMULBB( k + 1, NLSF[ 0 ] );
+                    }
+                    return;
+                }
+
+                /* Error: Apply progressively more bandwidth expansion and run again */
+                silk_bwexpander_32( a_Q16, d, 65536 - silk_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015*/
+
+                silk_A2NLSF_init( a_Q16, P, Q, dd );
+                p = P;                            /* Pointer to polynomial */
+                xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
+                ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+                if( ylo < 0 ) {
+                    /* Set the first NLSF to zero and move on to the next */
+                    NLSF[ 0 ] = 0;
+                    p = Q;                        /* Pointer to polynomial */
+                    ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+                    root_ix = 1;                  /* Index of current root */
+                } else {
+                    root_ix = 0;                  /* Index of current root */
+                }
+                k = 1;                            /* Reset loop counter */
+            }
+        }
+    }
+}
diff --git a/third_party/opus/src/silk/API.h b/third_party/opus/src/silk/API.h
new file mode 100644
index 0000000..0131acb
--- /dev/null
+++ b/third_party/opus/src/silk/API.h
@@ -0,0 +1,134 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_API_H
+#define SILK_API_H
+
+#include "control.h"
+#include "typedef.h"
+#include "errors.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define SILK_MAX_FRAMES_PER_PACKET  3
+
+/* Struct for TOC (Table of Contents) */
+typedef struct {
+    opus_int    VADFlag;                                /* Voice activity for packet                            */
+    opus_int    VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet              */
+    opus_int    inbandFECFlag;                          /* Flag indicating if packet contains in-band FEC       */
+} silk_TOC_struct;
+
+/****************************************/
+/* Encoder functions                    */
+/****************************************/
+
+/***********************************************/
+/* Get size in bytes of the Silk encoder state */
+/***********************************************/
+opus_int silk_Get_Encoder_Size(                         /* O    Returns error code                              */
+    opus_int                        *encSizeBytes       /* O    Number of bytes in SILK encoder state           */
+);
+
+/*************************/
+/* Init or reset encoder */
+/*************************/
+opus_int silk_InitEncoder(                              /* O    Returns error code                              */
+    void                            *encState,          /* I/O  State                                           */
+    int                              arch,              /* I    Run-time architecture                           */
+    silk_EncControlStruct           *encStatus          /* O    Encoder Status                                  */
+);
+
+/**************************/
+/* Encode frame with Silk */
+/**************************/
+/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what                     */
+/* encControl->payloadSize_ms is set to                                                                         */
+opus_int silk_Encode(                                   /* O    Returns error code                              */
+    void                            *encState,          /* I/O  State                                           */
+    silk_EncControlStruct           *encControl,        /* I    Control status                                  */
+    const opus_int16                *samplesIn,         /* I    Speech sample input vector                      */
+    opus_int                        nSamplesIn,         /* I    Number of samples in input vector               */
+    ec_enc                          *psRangeEnc,        /* I/O  Compressor data structure                       */
+    opus_int32                      *nBytesOut,         /* I/O  Number of bytes in payload (input: Max bytes)   */
+    const opus_int                  prefillFlag         /* I    Flag to indicate prefilling buffers no coding   */
+);
+
+/****************************************/
+/* Decoder functions                    */
+/****************************************/
+
+/***********************************************/
+/* Get size in bytes of the Silk decoder state */
+/***********************************************/
+opus_int silk_Get_Decoder_Size(                         /* O    Returns error code                              */
+    opus_int                        *decSizeBytes       /* O    Number of bytes in SILK decoder state           */
+);
+
+/*************************/
+/* Init or Reset decoder */
+/*************************/
+opus_int silk_InitDecoder(                              /* O    Returns error code                              */
+    void                            *decState           /* I/O  State                                           */
+);
+
+/******************/
+/* Decode a frame */
+/******************/
+opus_int silk_Decode(                                   /* O    Returns error code                              */
+    void*                           decState,           /* I/O  State                                           */
+    silk_DecControlStruct*          decControl,         /* I/O  Control Structure                               */
+    opus_int                        lostFlag,           /* I    0: no loss, 1 loss, 2 decode fec                */
+    opus_int                        newPacketFlag,      /* I    Indicates first decoder call for this packet    */
+    ec_dec                          *psRangeDec,        /* I/O  Compressor data structure                       */
+    opus_int16                      *samplesOut,        /* O    Decoded output speech vector                    */
+    opus_int32                      *nSamplesOut,       /* O    Number of samples decoded                       */
+    int                             arch                /* I    Run-time architecture                           */
+);
+
+#if 0
+/**************************************/
+/* Get table of contents for a packet */
+/**************************************/
+opus_int silk_get_TOC(
+    const opus_uint8                *payload,           /* I    Payload data                                */
+    const opus_int                  nBytesIn,           /* I    Number of input bytes                       */
+    const opus_int                  nFramesPerPayload,  /* I    Number of SILK frames per payload           */
+    silk_TOC_struct                 *Silk_TOC           /* O    Type of content                             */
+);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/CNG.c b/third_party/opus/src/silk/CNG.c
new file mode 100644
index 0000000..8443ad6
--- /dev/null
+++ b/third_party/opus/src/silk/CNG.c
@@ -0,0 +1,184 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Generates excitation for CNG LPC synthesis */
+static OPUS_INLINE void silk_CNG_exc(
+    opus_int32                       exc_Q14[],          /* O    CNG excitation signal Q10                   */
+    opus_int32                       exc_buf_Q14[],      /* I    Random samples buffer Q10                   */
+    opus_int                         length,             /* I    Length                                      */
+    opus_int32                       *rand_seed          /* I/O  Seed to random index generator              */
+)
+{
+    opus_int32 seed;
+    opus_int   i, idx, exc_mask;
+
+    exc_mask = CNG_BUF_MASK_MAX;
+    while( exc_mask > length ) {
+        exc_mask = silk_RSHIFT( exc_mask, 1 );
+    }
+
+    seed = *rand_seed;
+    for( i = 0; i < length; i++ ) {
+        seed = silk_RAND( seed );
+        idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask );
+        silk_assert( idx >= 0 );
+        silk_assert( idx <= CNG_BUF_MASK_MAX );
+        exc_Q14[ i ] = exc_buf_Q14[ idx ];
+    }
+    *rand_seed = seed;
+}
+
+void silk_CNG_Reset(
+    silk_decoder_state          *psDec                          /* I/O  Decoder state                               */
+)
+{
+    opus_int i, NLSF_step_Q15, NLSF_acc_Q15;
+
+    NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 );
+    NLSF_acc_Q15 = 0;
+    for( i = 0; i < psDec->LPC_order; i++ ) {
+        NLSF_acc_Q15 += NLSF_step_Q15;
+        psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15;
+    }
+    psDec->sCNG.CNG_smth_Gain_Q16 = 0;
+    psDec->sCNG.rand_seed = 3176576;
+}
+
+/* Updates CNG estimate, and applies the CNG when packet was lost   */
+void silk_CNG(
+    silk_decoder_state          *psDec,                         /* I/O  Decoder state                               */
+    silk_decoder_control        *psDecCtrl,                     /* I/O  Decoder control                             */
+    opus_int16                  frame[],                        /* I/O  Signal                                      */
+    opus_int                    length                          /* I    Length of residual                          */
+)
+{
+    opus_int   i, subfr;
+    opus_int32 LPC_pred_Q10, max_Gain_Q16, gain_Q16, gain_Q10;
+    opus_int16 A_Q12[ MAX_LPC_ORDER ];
+    silk_CNG_struct *psCNG = &psDec->sCNG;
+    SAVE_STACK;
+
+    if( psDec->fs_kHz != psCNG->fs_kHz ) {
+        /* Reset state */
+        silk_CNG_Reset( psDec );
+
+        psCNG->fs_kHz = psDec->fs_kHz;
+    }
+    if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) {
+        /* Update CNG parameters */
+
+        /* Smoothing of LSF's  */
+        for( i = 0; i < psDec->LPC_order; i++ ) {
+            psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 );
+        }
+        /* Find the subframe with the highest gain */
+        max_Gain_Q16 = 0;
+        subfr        = 0;
+        for( i = 0; i < psDec->nb_subfr; i++ ) {
+            if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) {
+                max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ];
+                subfr        = i;
+            }
+        }
+        /* Update CNG excitation buffer with excitation from this subframe */
+        silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) );
+        silk_memcpy(   psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) );
+
+        /* Smooth gains */
+        for( i = 0; i < psDec->nb_subfr; i++ ) {
+            psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 );
+        }
+    }
+
+    /* Add CNG when packet is lost or during DTX */
+    if( psDec->lossCnt ) {
+        VARDECL( opus_int32, CNG_sig_Q14 );
+        ALLOC( CNG_sig_Q14, length + MAX_LPC_ORDER, opus_int32 );
+
+        /* Generate CNG excitation */
+        gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] );
+        if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) {
+            gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 );
+            gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 );
+            gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 );
+        } else {
+            gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 );
+            gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 );
+            gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 );
+        }
+        gain_Q10 = silk_RSHIFT( gain_Q16, 6 );
+        
+        silk_CNG_exc( CNG_sig_Q14 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed );
+
+        /* Convert CNG NLSF to filter representation */
+        silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
+
+        /* Generate CNG signal, by synthesis filtering */
+        silk_memcpy( CNG_sig_Q14, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+        for( i = 0; i < length; i++ ) {
+            silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
+            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+            LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
+            if( psDec->LPC_order == 16 ) {
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] );
+            }
+
+            /* Update states */
+            CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q14[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
+            
+            /* Scale with Gain and add to input signal */
+            frame[ i ] = (opus_int16)silk_ADD_SAT16( frame[ i ], silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( CNG_sig_Q14[ MAX_LPC_ORDER + i ], gain_Q10 ), 8 ) ) );
+            
+        }
+        silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q14[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+    } else {
+        silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order *  sizeof( opus_int32 ) );
+    }
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/HP_variable_cutoff.c b/third_party/opus/src/silk/HP_variable_cutoff.c
new file mode 100644
index 0000000..bbe10f0
--- /dev/null
+++ b/third_party/opus/src/silk/HP_variable_cutoff.c
@@ -0,0 +1,77 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#else
+#include "main_FLP.h"
+#endif
+#include "tuning_parameters.h"
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+    silk_encoder_state_Fxx          state_Fxx[]                         /* I/O  Encoder states                              */
+)
+{
+   opus_int   quality_Q15;
+   opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7;
+   silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn;
+
+   /* Adaptive cutoff frequency: estimate low end of pitch frequency range */
+   if( psEncC1->prevSignalType == TYPE_VOICED ) {
+      /* difference, in log domain */
+      pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag );
+      pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 );
+
+      /* adjustment based on quality */
+      quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ];
+      pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ),
+            pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) );
+
+      /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */
+      delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 );
+      if( delta_freq_Q7 < 0 ) {
+         /* less smoothing for decreasing pitch frequency, to track something close to the minimum */
+         delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 );
+      }
+
+      /* limit delta, to reduce impact of outliers in pitch estimation */
+      delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) );
+
+      /* update smoother */
+      psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15,
+            silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) );
+
+      /* limit frequency range */
+      psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15,
+            silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ),
+            silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) );
+   }
+}
diff --git a/third_party/opus/src/silk/Inlines.h b/third_party/opus/src/silk/Inlines.h
new file mode 100644
index 0000000..ec986cd
--- /dev/null
+++ b/third_party/opus/src/silk/Inlines.h
@@ -0,0 +1,188 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+/*! \file silk_Inlines.h
+ *  \brief silk_Inlines.h defines OPUS_INLINE signal processing functions.
+ */
+
+#ifndef SILK_FIX_INLINES_H
+#define SILK_FIX_INLINES_H
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+/* count leading zeros of opus_int64 */
+static OPUS_INLINE opus_int32 silk_CLZ64( opus_int64 in )
+{
+    opus_int32 in_upper;
+
+    in_upper = (opus_int32)silk_RSHIFT64(in, 32);
+    if (in_upper == 0) {
+        /* Search in the lower 32 bits */
+        return 32 + silk_CLZ32( (opus_int32) in );
+    } else {
+        /* Search in the upper 32 bits */
+        return silk_CLZ32( in_upper );
+    }
+}
+
+/* get number of leading zeros and fractional part (the bits right after the leading one */
+static OPUS_INLINE void silk_CLZ_FRAC(
+    opus_int32 in,            /* I  input                               */
+    opus_int32 *lz,           /* O  number of leading zeros             */
+    opus_int32 *frac_Q7       /* O  the 7 bits right after the leading one */
+)
+{
+    opus_int32 lzeros = silk_CLZ32(in);
+
+    * lz = lzeros;
+    * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f;
+}
+
+/* Approximation of square root                                          */
+/* Accuracy: < +/- 10%  for output values > 15                           */
+/*           < +/- 2.5% for output values > 120                          */
+static OPUS_INLINE opus_int32 silk_SQRT_APPROX( opus_int32 x )
+{
+    opus_int32 y, lz, frac_Q7;
+
+    if( x <= 0 ) {
+        return 0;
+    }
+
+    silk_CLZ_FRAC(x, &lz, &frac_Q7);
+
+    if( lz & 1 ) {
+        y = 32768;
+    } else {
+        y = 46214;        /* 46214 = sqrt(2) * 32768 */
+    }
+
+    /* get scaling right */
+    y >>= silk_RSHIFT(lz, 1);
+
+    /* increment using fractional part of input */
+    y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7));
+
+    return y;
+}
+
+/* Divide two int32 values and return result as int32 in a given Q-domain */
+static OPUS_INLINE opus_int32 silk_DIV32_varQ(   /* O    returns a good approximation of "(a32 << Qres) / b32" */
+    const opus_int32     a32,               /* I    numerator (Q0)                  */
+    const opus_int32     b32,               /* I    denominator (Q0)                */
+    const opus_int       Qres               /* I    Q-domain of result (>= 0)       */
+)
+{
+    opus_int   a_headrm, b_headrm, lshift;
+    opus_int32 b32_inv, a32_nrm, b32_nrm, result;
+
+    silk_assert( b32 != 0 );
+    silk_assert( Qres >= 0 );
+
+    /* Compute number of bits head room and normalize inputs */
+    a_headrm = silk_CLZ32( silk_abs(a32) ) - 1;
+    a32_nrm = silk_LSHIFT(a32, a_headrm);                                       /* Q: a_headrm                  */
+    b_headrm = silk_CLZ32( silk_abs(b32) ) - 1;
+    b32_nrm = silk_LSHIFT(b32, b_headrm);                                       /* Q: b_headrm                  */
+
+    /* Inverse of b32, with 14 bits of precision */
+    b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) );   /* Q: 29 + 16 - b_headrm        */
+
+    /* First approximation */
+    result = silk_SMULWB(a32_nrm, b32_inv);                                     /* Q: 29 + a_headrm - b_headrm  */
+
+    /* Compute residual by subtracting product of denominator and first approximation */
+    /* It's OK to overflow because the final value of a32_nrm should always be small */
+    a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 ));  /* Q: a_headrm   */
+
+    /* Refinement */
+    result = silk_SMLAWB(result, a32_nrm, b32_inv);                             /* Q: 29 + a_headrm - b_headrm  */
+
+    /* Convert to Qres domain */
+    lshift = 29 + a_headrm - b_headrm - Qres;
+    if( lshift < 0 ) {
+        return silk_LSHIFT_SAT32(result, -lshift);
+    } else {
+        if( lshift < 32){
+            return silk_RSHIFT(result, lshift);
+        } else {
+            /* Avoid undefined result */
+            return 0;
+        }
+    }
+}
+
+/* Invert int32 value and return result as int32 in a given Q-domain */
+static OPUS_INLINE opus_int32 silk_INVERSE32_varQ(   /* O    returns a good approximation of "(1 << Qres) / b32" */
+    const opus_int32     b32,                   /* I    denominator (Q0)                */
+    const opus_int       Qres                   /* I    Q-domain of result (> 0)        */
+)
+{
+    opus_int   b_headrm, lshift;
+    opus_int32 b32_inv, b32_nrm, err_Q32, result;
+
+    silk_assert( b32 != 0 );
+    silk_assert( Qres > 0 );
+
+    /* Compute number of bits head room and normalize input */
+    b_headrm = silk_CLZ32( silk_abs(b32) ) - 1;
+    b32_nrm = silk_LSHIFT(b32, b_headrm);                                       /* Q: b_headrm                */
+
+    /* Inverse of b32, with 14 bits of precision */
+    b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) );   /* Q: 29 + 16 - b_headrm    */
+
+    /* First approximation */
+    result = silk_LSHIFT(b32_inv, 16);                                          /* Q: 61 - b_headrm            */
+
+    /* Compute residual by subtracting product of denominator and first approximation from one */
+    err_Q32 = silk_LSHIFT( ((opus_int32)1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 );        /* Q32                        */
+
+    /* Refinement */
+    result = silk_SMLAWW(result, err_Q32, b32_inv);                             /* Q: 61 - b_headrm            */
+
+    /* Convert to Qres domain */
+    lshift = 61 - b_headrm - Qres;
+    if( lshift <= 0 ) {
+        return silk_LSHIFT_SAT32(result, -lshift);
+    } else {
+        if( lshift < 32){
+            return silk_RSHIFT(result, lshift);
+        }else{
+            /* Avoid undefined result */
+            return 0;
+        }
+    }
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* SILK_FIX_INLINES_H */
diff --git a/third_party/opus/src/silk/LPC_analysis_filter.c b/third_party/opus/src/silk/LPC_analysis_filter.c
new file mode 100644
index 0000000..20906673
--- /dev/null
+++ b/third_party/opus/src/silk/LPC_analysis_filter.c
@@ -0,0 +1,108 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "celt_lpc.h"
+
+/*******************************************/
+/* LPC analysis filter                     */
+/* NB! State is kept internally and the    */
+/* filter always starts with zero state    */
+/* first d output samples are set to zero  */
+/*******************************************/
+
+void silk_LPC_analysis_filter(
+    opus_int16                  *out,               /* O    Output signal                                               */
+    const opus_int16            *in,                /* I    Input signal                                                */
+    const opus_int16            *B,                 /* I    MA prediction coefficients, Q12 [order]                     */
+    const opus_int32            len,                /* I    Signal length                                               */
+    const opus_int32            d,                  /* I    Filter order                                                */
+    int                         arch                /* I    Run-time architecture                                       */
+)
+{
+    opus_int   j;
+#ifdef FIXED_POINT
+    opus_int16 mem[SILK_MAX_ORDER_LPC];
+    opus_int16 num[SILK_MAX_ORDER_LPC];
+#else
+    int ix;
+    opus_int32       out32_Q12, out32;
+    const opus_int16 *in_ptr;
+#endif
+
+    silk_assert( d >= 6 );
+    silk_assert( (d & 1) == 0 );
+    silk_assert( d <= len );
+
+#ifdef FIXED_POINT
+    silk_assert( d <= SILK_MAX_ORDER_LPC );
+    for ( j = 0; j < d; j++ ) {
+        num[ j ] = -B[ j ];
+    }
+    for (j=0;j<d;j++) {
+        mem[ j ] = in[ d - j - 1 ];
+    }
+    celt_fir( in + d, num, out + d, len - d, d, mem, arch );
+    for ( j = 0; j < d; j++ ) {
+        out[ j ] = 0;
+    }
+#else
+    (void)arch;
+    for( ix = d; ix < len; ix++ ) {
+        in_ptr = &in[ ix - 1 ];
+
+        out32_Q12 = silk_SMULBB( in_ptr[  0 ], B[ 0 ] );
+        /* Allowing wrap around so that two wraps can cancel each other. The rare
+           cases where the result wraps around can only be triggered by invalid streams*/
+        out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] );
+        out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] );
+        out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] );
+        out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] );
+        out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] );
+        for( j = 6; j < d; j += 2 ) {
+            out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j     ], B[ j     ] );
+            out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] );
+        }
+
+        /* Subtract prediction */
+        out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 );
+
+        /* Scale to Q0 */
+        out32 = silk_RSHIFT_ROUND( out32_Q12, 12 );
+
+        /* Saturate output */
+        out[ ix ] = (opus_int16)silk_SAT16( out32 );
+    }
+
+    /* Set first d output samples to zero */
+    silk_memset( out, 0, d * sizeof( opus_int16 ) );
+#endif
+}
diff --git a/third_party/opus/src/silk/LPC_inv_pred_gain.c b/third_party/opus/src/silk/LPC_inv_pred_gain.c
new file mode 100644
index 0000000..4af89aa
--- /dev/null
+++ b/third_party/opus/src/silk/LPC_inv_pred_gain.c
@@ -0,0 +1,154 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+#define QA                          24
+#define A_LIMIT                     SILK_FIX_CONST( 0.99975, QA )
+
+#define MUL32_FRAC_Q(a32, b32, Q)   ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q)))
+
+/* Compute inverse of LPC prediction gain, and                          */
+/* test if LPC coefficients are stable (all poles within unit circle)   */
+static opus_int32 LPC_inverse_pred_gain_QA(                 /* O   Returns inverse prediction gain in energy domain, Q30    */
+    opus_int32           A_QA[ 2 ][ SILK_MAX_ORDER_LPC ],   /* I   Prediction coefficients                                  */
+    const opus_int       order                              /* I   Prediction order                                         */
+)
+{
+    opus_int   k, n, mult2Q;
+    opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
+    opus_int32 *Aold_QA, *Anew_QA;
+
+    Anew_QA = A_QA[ order & 1 ];
+
+    invGain_Q30 = (opus_int32)1 << 30;
+    for( k = order - 1; k > 0; k-- ) {
+        /* Check for stability */
+        if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) {
+            return 0;
+        }
+
+        /* Set RC equal to negated AR coef */
+        rc_Q31 = -silk_LSHIFT( Anew_QA[ k ], 31 - QA );
+
+        /* rc_mult1_Q30 range: [ 1 : 2^30 ] */
+        rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+        silk_assert( rc_mult1_Q30 > ( 1 << 15 ) );                   /* reduce A_LIMIT if fails */
+        silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) );
+
+        /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
+        mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) );
+        rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 );
+
+        /* Update inverse gain */
+        /* invGain_Q30 range: [ 0 : 2^30 ] */
+        invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
+        silk_assert( invGain_Q30 >= 0           );
+        silk_assert( invGain_Q30 <= ( 1 << 30 ) );
+
+        /* Swap pointers */
+        Aold_QA = Anew_QA;
+        Anew_QA = A_QA[ k & 1 ];
+
+        /* Update AR coefficient */
+        for( n = 0; n < k; n++ ) {
+            tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 );
+            Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q );
+        }
+    }
+
+    /* Check for stability */
+    if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) {
+        return 0;
+    }
+
+    /* Set RC equal to negated AR coef */
+    rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA );
+
+    /* Range: [ 1 : 2^30 ] */
+    rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+
+    /* Update inverse gain */
+    /* Range: [ 0 : 2^30 ] */
+    invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
+    silk_assert( invGain_Q30 >= 0     );
+    silk_assert( invGain_Q30 <= 1<<30 );
+
+    return invGain_Q30;
+}
+
+/* For input in Q12 domain */
+opus_int32 silk_LPC_inverse_pred_gain(              /* O   Returns inverse prediction gain in energy domain, Q30        */
+    const opus_int16            *A_Q12,             /* I   Prediction coefficients, Q12 [order]                         */
+    const opus_int              order               /* I   Prediction order                                             */
+)
+{
+    opus_int   k;
+    opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
+    opus_int32 *Anew_QA;
+    opus_int32 DC_resp = 0;
+
+    Anew_QA = Atmp_QA[ order & 1 ];
+
+    /* Increase Q domain of the AR coefficients */
+    for( k = 0; k < order; k++ ) {
+        DC_resp += (opus_int32)A_Q12[ k ];
+        Anew_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 );
+    }
+    /* If the DC is unstable, we don't even need to do the full calculations */
+    if( DC_resp >= 4096 ) {
+        return 0;
+    }
+    return LPC_inverse_pred_gain_QA( Atmp_QA, order );
+}
+
+#ifdef FIXED_POINT
+
+/* For input in Q24 domain */
+opus_int32 silk_LPC_inverse_pred_gain_Q24(          /* O    Returns inverse prediction gain in energy domain, Q30       */
+    const opus_int32            *A_Q24,             /* I    Prediction coefficients [order]                             */
+    const opus_int              order               /* I    Prediction order                                            */
+)
+{
+    opus_int   k;
+    opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
+    opus_int32 *Anew_QA;
+
+    Anew_QA = Atmp_QA[ order & 1 ];
+
+    /* Increase Q domain of the AR coefficients */
+    for( k = 0; k < order; k++ ) {
+        Anew_QA[ k ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA );
+    }
+
+    return LPC_inverse_pred_gain_QA( Atmp_QA, order );
+}
+#endif
diff --git a/third_party/opus/src/silk/LP_variable_cutoff.c b/third_party/opus/src/silk/LP_variable_cutoff.c
new file mode 100644
index 0000000..f639e1f
--- /dev/null
+++ b/third_party/opus/src/silk/LP_variable_cutoff.c
@@ -0,0 +1,135 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+    Elliptic/Cauer filters designed with 0.1 dB passband ripple,
+    80 dB minimum stopband attenuation, and
+    [0.95 : 0.15 : 0.35] normalized cut off frequencies.
+*/
+
+#include "main.h"
+
+/* Helper function, interpolates the filter taps */
+static OPUS_INLINE void silk_LP_interpolate_filter_taps(
+    opus_int32           B_Q28[ TRANSITION_NB ],
+    opus_int32           A_Q28[ TRANSITION_NA ],
+    const opus_int       ind,
+    const opus_int32     fac_Q16
+)
+{
+    opus_int nb, na;
+
+    if( ind < TRANSITION_INT_NUM - 1 ) {
+        if( fac_Q16 > 0 ) {
+            if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */
+                /* Piece-wise linear interpolation of B and A */
+                for( nb = 0; nb < TRANSITION_NB; nb++ ) {
+                    B_Q28[ nb ] = silk_SMLAWB(
+                        silk_Transition_LP_B_Q28[ ind     ][ nb ],
+                        silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] -
+                        silk_Transition_LP_B_Q28[ ind     ][ nb ],
+                        fac_Q16 );
+                }
+                for( na = 0; na < TRANSITION_NA; na++ ) {
+                    A_Q28[ na ] = silk_SMLAWB(
+                        silk_Transition_LP_A_Q28[ ind     ][ na ],
+                        silk_Transition_LP_A_Q28[ ind + 1 ][ na ] -
+                        silk_Transition_LP_A_Q28[ ind     ][ na ],
+                        fac_Q16 );
+                }
+            } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */
+                silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) );
+                /* Piece-wise linear interpolation of B and A */
+                for( nb = 0; nb < TRANSITION_NB; nb++ ) {
+                    B_Q28[ nb ] = silk_SMLAWB(
+                        silk_Transition_LP_B_Q28[ ind + 1 ][ nb ],
+                        silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] -
+                        silk_Transition_LP_B_Q28[ ind     ][ nb ],
+                        fac_Q16 - ( (opus_int32)1 << 16 ) );
+                }
+                for( na = 0; na < TRANSITION_NA; na++ ) {
+                    A_Q28[ na ] = silk_SMLAWB(
+                        silk_Transition_LP_A_Q28[ ind + 1 ][ na ],
+                        silk_Transition_LP_A_Q28[ ind + 1 ][ na ] -
+                        silk_Transition_LP_A_Q28[ ind     ][ na ],
+                        fac_Q16 - ( (opus_int32)1 << 16 ) );
+                }
+            }
+        } else {
+            silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) );
+            silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) );
+        }
+    } else {
+        silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) );
+        silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) );
+    }
+}
+
+/* Low-pass filter with variable cutoff frequency based on  */
+/* piece-wise linear interpolation between elliptic filters */
+/* Start by setting psEncC->mode <> 0;                      */
+/* Deactivate by setting psEncC->mode = 0;                  */
+void silk_LP_variable_cutoff(
+    silk_LP_state               *psLP,                          /* I/O  LP filter state                             */
+    opus_int16                  *frame,                         /* I/O  Low-pass filtered output signal             */
+    const opus_int              frame_length                    /* I    Frame length                                */
+)
+{
+    opus_int32   B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0;
+    opus_int     ind = 0;
+
+    silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES );
+
+    /* Run filter if needed */
+    if( psLP->mode != 0 ) {
+        /* Calculate index and interpolation factor for interpolation */
+#if( TRANSITION_INT_STEPS == 64 )
+        fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 );
+#else
+        fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES );
+#endif
+        ind      = silk_RSHIFT( fac_Q16, 16 );
+        fac_Q16 -= silk_LSHIFT( ind, 16 );
+
+        silk_assert( ind >= 0 );
+        silk_assert( ind < TRANSITION_INT_NUM );
+
+        /* Interpolate filter coefficients */
+        silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 );
+
+        /* Update transition frame number for next frame */
+        psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES );
+
+        /* ARMA low-pass filtering */
+        silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 );
+        silk_biquad_alt( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length, 1);
+    }
+}
diff --git a/third_party/opus/src/silk/MacroCount.h b/third_party/opus/src/silk/MacroCount.h
new file mode 100644
index 0000000..834817d0
--- /dev/null
+++ b/third_party/opus/src/silk/MacroCount.h
@@ -0,0 +1,718 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SIGPROCFIX_API_MACROCOUNT_H
+#define SIGPROCFIX_API_MACROCOUNT_H
+#include <stdio.h>
+
+#ifdef    silk_MACRO_COUNT
+#define varDefine opus_int64 ops_count = 0;
+
+extern opus_int64 ops_count;
+
+static OPUS_INLINE opus_int64 silk_SaveCount(){
+    return(ops_count);
+}
+
+static OPUS_INLINE opus_int64 silk_SaveResetCount(){
+    opus_int64 ret;
+
+    ret = ops_count;
+    ops_count = 0;
+    return(ret);
+}
+
+static OPUS_INLINE silk_PrintCount(){
+    printf("ops_count = %d \n ", (opus_int32)ops_count);
+}
+
+#undef silk_MUL
+static OPUS_INLINE opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){
+    opus_int32 ret;
+    ops_count += 4;
+    ret = a32 * b32;
+    return ret;
+}
+
+#undef silk_MUL_uint
+static OPUS_INLINE opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){
+    opus_uint32 ret;
+    ops_count += 4;
+    ret = a32 * b32;
+    return ret;
+}
+#undef silk_MLA
+static OPUS_INLINE opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+    opus_int32 ret;
+    ops_count += 4;
+    ret = a32 + b32 * c32;
+    return ret;
+}
+
+#undef silk_MLA_uint
+static OPUS_INLINE opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){
+    opus_uint32 ret;
+    ops_count += 4;
+    ret = a32 + b32 * c32;
+    return ret;
+}
+
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){
+    opus_int32 ret;
+    ops_count += 5;
+    ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16);
+    return ret;
+}
+#undef    silk_SMLAWB
+static OPUS_INLINE opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+    opus_int32 ret;
+    ops_count += 5;
+    ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16)));
+    return ret;
+}
+
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){
+    opus_int32 ret;
+    ops_count += 4;
+    ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16);
+    return ret;
+}
+#undef silk_SMLAWT
+static OPUS_INLINE opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+    opus_int32 ret;
+    ops_count += 4;
+    ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16));
+    return ret;
+}
+
+#undef silk_SMULBB
+static OPUS_INLINE opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32);
+    return ret;
+}
+#undef silk_SMLABB
+static OPUS_INLINE opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32);
+    return ret;
+}
+
+#undef silk_SMULBT
+static OPUS_INLINE opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){
+    opus_int32 ret;
+    ops_count += 4;
+    ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16);
+    return ret;
+}
+
+#undef silk_SMLABT
+static OPUS_INLINE opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16);
+    return ret;
+}
+
+#undef silk_SMULTT
+static OPUS_INLINE opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = (a32 >> 16) * (b32 >> 16);
+    return ret;
+}
+
+#undef    silk_SMLATT
+static OPUS_INLINE opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a32 + (b32 >> 16) * (c32 >> 16);
+    return ret;
+}
+
+
+/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/
+#undef    silk_MLA_ovflw
+#define silk_MLA_ovflw silk_MLA
+
+#undef silk_SMLABB_ovflw
+#define silk_SMLABB_ovflw silk_SMLABB
+
+#undef silk_SMLABT_ovflw
+#define silk_SMLABT_ovflw silk_SMLABT
+
+#undef silk_SMLATT_ovflw
+#define silk_SMLATT_ovflw silk_SMLATT
+
+#undef silk_SMLAWB_ovflw
+#define silk_SMLAWB_ovflw silk_SMLAWB
+
+#undef silk_SMLAWT_ovflw
+#define silk_SMLAWT_ovflw silk_SMLAWT
+
+#undef silk_SMULL
+static OPUS_INLINE opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){
+    opus_int64 ret;
+    ops_count += 8;
+    ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32));
+    return ret;
+}
+
+#undef    silk_SMLAL
+static OPUS_INLINE opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){
+    opus_int64 ret;
+    ops_count += 8;
+    ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32));
+    return ret;
+}
+#undef    silk_SMLALBB
+static OPUS_INLINE opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){
+    opus_int64 ret;
+    ops_count += 4;
+    ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16));
+    return ret;
+}
+
+#undef    SigProcFIX_CLZ16
+static OPUS_INLINE opus_int32 SigProcFIX_CLZ16(opus_int16 in16)
+{
+    opus_int32 out32 = 0;
+    ops_count += 10;
+    if( in16 == 0 ) {
+        return 16;
+    }
+    /* test nibbles */
+    if( in16 & 0xFF00 ) {
+        if( in16 & 0xF000 ) {
+            in16 >>= 12;
+        } else {
+            out32 += 4;
+            in16 >>= 8;
+        }
+    } else {
+        if( in16 & 0xFFF0 ) {
+            out32 += 8;
+            in16 >>= 4;
+        } else {
+            out32 += 12;
+        }
+    }
+    /* test bits and return */
+    if( in16 & 0xC ) {
+        if( in16 & 0x8 )
+            return out32 + 0;
+        else
+            return out32 + 1;
+    } else {
+        if( in16 & 0xE )
+            return out32 + 2;
+        else
+            return out32 + 3;
+    }
+}
+
+#undef SigProcFIX_CLZ32
+static OPUS_INLINE opus_int32 SigProcFIX_CLZ32(opus_int32 in32)
+{
+    /* test highest 16 bits and convert to opus_int16 */
+    ops_count += 2;
+    if( in32 & 0xFFFF0000 ) {
+        return SigProcFIX_CLZ16((opus_int16)(in32 >> 16));
+    } else {
+        return SigProcFIX_CLZ16((opus_int16)in32) + 16;
+    }
+}
+
+#undef silk_DIV32
+static OPUS_INLINE opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){
+    ops_count += 64;
+    return a32 / b32;
+}
+
+#undef silk_DIV32_16
+static OPUS_INLINE opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){
+    ops_count += 32;
+    return a32 / b32;
+}
+
+#undef silk_SAT8
+static OPUS_INLINE opus_int8 silk_SAT8(opus_int64 a){
+    opus_int8 tmp;
+    ops_count += 1;
+    tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX  : \
+                    ((a) < silk_int8_MIN ? silk_int8_MIN  : (a)));
+    return(tmp);
+}
+
+#undef silk_SAT16
+static OPUS_INLINE opus_int16 silk_SAT16(opus_int64 a){
+    opus_int16 tmp;
+    ops_count += 1;
+    tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX  : \
+                     ((a) < silk_int16_MIN ? silk_int16_MIN  : (a)));
+    return(tmp);
+}
+#undef silk_SAT32
+static OPUS_INLINE opus_int32 silk_SAT32(opus_int64 a){
+    opus_int32 tmp;
+    ops_count += 1;
+    tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX  : \
+                     ((a) < silk_int32_MIN ? silk_int32_MIN  : (a)));
+    return(tmp);
+}
+#undef silk_POS_SAT32
+static OPUS_INLINE opus_int32 silk_POS_SAT32(opus_int64 a){
+    opus_int32 tmp;
+    ops_count += 1;
+    tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a));
+    return(tmp);
+}
+
+#undef silk_ADD_POS_SAT8
+static OPUS_INLINE opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){
+    opus_int8 tmp;
+    ops_count += 1;
+    tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX  : ((a)+(b)));
+    return(tmp);
+}
+#undef silk_ADD_POS_SAT16
+static OPUS_INLINE opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){
+    opus_int16 tmp;
+    ops_count += 1;
+    tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b)));
+    return(tmp);
+}
+
+#undef silk_ADD_POS_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){
+    opus_int32 tmp;
+    ops_count += 1;
+    tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b)));
+    return(tmp);
+}
+
+#undef silk_ADD_POS_SAT64
+static OPUS_INLINE opus_int64 silk_ADD_POS_SAT64(opus_int64 a, opus_int64 b){
+    opus_int64 tmp;
+    ops_count += 1;
+    tmp = ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)));
+    return(tmp);
+}
+
+#undef    silk_LSHIFT8
+static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){
+    opus_int8 ret;
+    ops_count += 1;
+    ret = a << shift;
+    return ret;
+}
+#undef    silk_LSHIFT16
+static OPUS_INLINE opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){
+    opus_int16 ret;
+    ops_count += 1;
+    ret = a << shift;
+    return ret;
+}
+#undef    silk_LSHIFT32
+static OPUS_INLINE opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a << shift;
+    return ret;
+}
+#undef    silk_LSHIFT64
+static OPUS_INLINE opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){
+    ops_count += 1;
+    return a << shift;
+}
+
+#undef    silk_LSHIFT_ovflw
+static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){
+    ops_count += 1;
+    return a << shift;
+}
+
+#undef    silk_LSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){
+    opus_uint32 ret;
+    ops_count += 1;
+    ret = a << shift;
+    return ret;
+}
+
+#undef    silk_RSHIFT8
+static OPUS_INLINE opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){
+    ops_count += 1;
+    return a >> shift;
+}
+#undef    silk_RSHIFT16
+static OPUS_INLINE opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){
+    ops_count += 1;
+    return a >> shift;
+}
+#undef    silk_RSHIFT32
+static OPUS_INLINE opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){
+    ops_count += 1;
+    return a >> shift;
+}
+#undef    silk_RSHIFT64
+static OPUS_INLINE opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){
+    ops_count += 1;
+    return a >> shift;
+}
+
+#undef    silk_RSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){
+    ops_count += 1;
+    return a >> shift;
+}
+
+#undef    silk_ADD_LSHIFT
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a + (b << shift);
+    return ret;                /* shift >= 0*/
+}
+#undef    silk_ADD_LSHIFT32
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a + (b << shift);
+    return ret;                /* shift >= 0*/
+}
+#undef    silk_ADD_LSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){
+    opus_uint32 ret;
+    ops_count += 1;
+    ret = a + (b << shift);
+    return ret;                /* shift >= 0*/
+}
+#undef    silk_ADD_RSHIFT
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a + (b >> shift);
+    return ret;                /* shift  > 0*/
+}
+#undef    silk_ADD_RSHIFT32
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a + (b >> shift);
+    return ret;                /* shift  > 0*/
+}
+#undef    silk_ADD_RSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){
+    opus_uint32 ret;
+    ops_count += 1;
+    ret = a + (b >> shift);
+    return ret;                /* shift  > 0*/
+}
+#undef    silk_SUB_LSHIFT32
+static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a - (b << shift);
+    return ret;                /* shift >= 0*/
+}
+#undef    silk_SUB_RSHIFT32
+static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a - (b >> shift);
+    return ret;                /* shift  > 0*/
+}
+
+#undef    silk_RSHIFT_ROUND
+static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){
+    opus_int32 ret;
+    ops_count += 3;
+    ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+    return ret;
+}
+
+#undef    silk_RSHIFT_ROUND64
+static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){
+    opus_int64 ret;
+    ops_count += 6;
+    ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+    return ret;
+}
+
+#undef    silk_abs_int64
+static OPUS_INLINE opus_int64 silk_abs_int64(opus_int64 a){
+    ops_count += 1;
+    return (((a) >  0)  ? (a) : -(a));            /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/
+}
+
+#undef    silk_abs_int32
+static OPUS_INLINE opus_int32 silk_abs_int32(opus_int32 a){
+    ops_count += 1;
+    return silk_abs(a);
+}
+
+
+#undef silk_min
+static silk_min(a, b){
+    ops_count += 1;
+    return (((a) < (b)) ? (a) :  (b));
+}
+#undef silk_max
+static silk_max(a, b){
+    ops_count += 1;
+    return (((a) > (b)) ? (a) :  (b));
+}
+#undef silk_sign
+static silk_sign(a){
+    ops_count += 1;
+    return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 ));
+}
+
+#undef    silk_ADD16
+static OPUS_INLINE opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){
+    opus_int16 ret;
+    ops_count += 1;
+    ret = a + b;
+    return ret;
+}
+
+#undef    silk_ADD32
+static OPUS_INLINE opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a + b;
+    return ret;
+}
+
+#undef    silk_ADD64
+static OPUS_INLINE opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){
+    opus_int64 ret;
+    ops_count += 2;
+    ret = a + b;
+    return ret;
+}
+
+#undef    silk_SUB16
+static OPUS_INLINE opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){
+    opus_int16 ret;
+    ops_count += 1;
+    ret = a - b;
+    return ret;
+}
+
+#undef    silk_SUB32
+static OPUS_INLINE opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){
+    opus_int32 ret;
+    ops_count += 1;
+    ret = a - b;
+    return ret;
+}
+
+#undef    silk_SUB64
+static OPUS_INLINE opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){
+    opus_int64 ret;
+    ops_count += 2;
+    ret = a - b;
+    return ret;
+}
+
+#undef silk_ADD_SAT16
+static OPUS_INLINE opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) {
+    opus_int16 res;
+    /* Nb will be counted in AKP_add32 and silk_SAT16*/
+    res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) );
+    return res;
+}
+
+#undef silk_ADD_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){
+    opus_int32 res;
+    ops_count += 1;
+    res =    ((((a32) + (b32)) & 0x80000000) == 0 ?                                    \
+            ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) :    \
+            ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) );
+    return res;
+}
+
+#undef silk_ADD_SAT64
+static OPUS_INLINE opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) {
+    opus_int64 res;
+    ops_count += 1;
+    res =    ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ?                                \
+            ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) :    \
+            ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) );
+    return res;
+}
+
+#undef silk_SUB_SAT16
+static OPUS_INLINE opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) {
+    opus_int16 res;
+    silk_assert(0);
+    /* Nb will be counted in sub-macros*/
+    res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) );
+    return res;
+}
+
+#undef silk_SUB_SAT32
+static OPUS_INLINE opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) {
+    opus_int32 res;
+    ops_count += 1;
+    res =     ((((a32)-(b32)) & 0x80000000) == 0 ?                                            \
+            (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) :    \
+            ((((a32)^0x80000000) & (b32)  & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) );
+    return res;
+}
+
+#undef silk_SUB_SAT64
+static OPUS_INLINE opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) {
+    opus_int64 res;
+    ops_count += 1;
+    res =    ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ?                                                        \
+            (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) :    \
+            ((((a64)^0x8000000000000000LL) & (b64)  & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) );
+
+    return res;
+}
+
+#undef    silk_SMULWW
+static OPUS_INLINE opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){
+    opus_int32 ret;
+    /* Nb will be counted in sub-macros*/
+    ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16));
+    return ret;
+}
+
+#undef    silk_SMLAWW
+static OPUS_INLINE opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+    opus_int32 ret;
+    /* Nb will be counted in sub-macros*/
+    ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16));
+    return ret;
+}
+
+#undef    silk_min_int
+static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b)
+{
+    ops_count += 1;
+    return (((a) < (b)) ? (a) : (b));
+}
+
+#undef    silk_min_16
+static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b)
+{
+    ops_count += 1;
+    return (((a) < (b)) ? (a) : (b));
+}
+#undef    silk_min_32
+static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b)
+{
+    ops_count += 1;
+    return (((a) < (b)) ? (a) : (b));
+}
+#undef    silk_min_64
+static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b)
+{
+    ops_count += 1;
+    return (((a) < (b)) ? (a) : (b));
+}
+
+/* silk_min() versions with typecast in the function call */
+#undef    silk_max_int
+static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b)
+{
+    ops_count += 1;
+    return (((a) > (b)) ? (a) : (b));
+}
+#undef    silk_max_16
+static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b)
+{
+    ops_count += 1;
+    return (((a) > (b)) ? (a) : (b));
+}
+#undef    silk_max_32
+static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b)
+{
+    ops_count += 1;
+    return (((a) > (b)) ? (a) : (b));
+}
+
+#undef    silk_max_64
+static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b)
+{
+    ops_count += 1;
+    return (((a) > (b)) ? (a) : (b));
+}
+
+
+#undef silk_LIMIT_int
+static OPUS_INLINE opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2)
+{
+    opus_int ret;
+    ops_count += 6;
+
+    ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+        : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+
+    return(ret);
+}
+
+#undef silk_LIMIT_16
+static OPUS_INLINE opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2)
+{
+    opus_int16 ret;
+    ops_count += 6;
+
+    ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+        : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+
+return(ret);
+}
+
+
+#undef silk_LIMIT_32
+static OPUS_INLINE opus_int silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2)
+{
+    opus_int32 ret;
+    ops_count += 6;
+
+    ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+        : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+    return(ret);
+}
+
+#else
+#define varDefine
+#define silk_SaveCount()
+
+#endif
+#endif
+
diff --git a/third_party/opus/src/silk/MacroDebug.h b/third_party/opus/src/silk/MacroDebug.h
new file mode 100644
index 0000000..35aedc5
--- /dev/null
+++ b/third_party/opus/src/silk/MacroDebug.h
@@ -0,0 +1,952 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (C) 2012 Xiph.Org Foundation
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef MACRO_DEBUG_H
+#define MACRO_DEBUG_H
+
+/* Redefine macro functions with extensive assertion in DEBUG mode.
+   As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */
+
+#if ( defined (FIXED_DEBUG) || ( 0 && defined (_DEBUG) ) ) && !defined (silk_MACRO_COUNT)
+
+#undef silk_ADD16
+#define silk_ADD16(a,b) silk_ADD16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_ADD16_(opus_int16 a, opus_int16 b, char *file, int line){
+    opus_int16 ret;
+
+    ret = a + b;
+    if ( ret != silk_ADD_SAT16( a, b ) )
+    {
+        fprintf (stderr, "silk_ADD16(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_ADD32
+#define silk_ADD32(a,b) silk_ADD32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD32_(opus_int32 a, opus_int32 b, char *file, int line){
+    opus_int32 ret;
+
+    ret = a + b;
+    if ( ret != silk_ADD_SAT32( a, b ) )
+    {
+        fprintf (stderr, "silk_ADD32(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_ADD64
+#define silk_ADD64(a,b) silk_ADD64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_ADD64_(opus_int64 a, opus_int64 b, char *file, int line){
+    opus_int64 ret;
+
+    ret = a + b;
+    if ( ret != silk_ADD_SAT64( a, b ) )
+    {
+        fprintf (stderr, "silk_ADD64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SUB16
+#define silk_SUB16(a,b) silk_SUB16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_SUB16_(opus_int16 a, opus_int16 b, char *file, int line){
+    opus_int16 ret;
+
+    ret = a - b;
+    if ( ret != silk_SUB_SAT16( a, b ) )
+    {
+        fprintf (stderr, "silk_SUB16(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SUB32
+#define silk_SUB32(a,b) silk_SUB32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB32_(opus_int32 a, opus_int32 b, char *file, int line){
+    opus_int32 ret;
+
+    ret = a - b;
+    if ( ret != silk_SUB_SAT32( a, b ) )
+    {
+        fprintf (stderr, "silk_SUB32(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SUB64
+#define silk_SUB64(a,b) silk_SUB64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SUB64_(opus_int64 a, opus_int64 b, char *file, int line){
+    opus_int64 ret;
+
+    ret = a - b;
+    if ( ret != silk_SUB_SAT64( a, b ) )
+    {
+        fprintf (stderr, "silk_SUB64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_ADD_SAT16
+#define silk_ADD_SAT16(a,b) silk_ADD_SAT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_ADD_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line) {
+    opus_int16 res;
+    res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) );
+    if ( res != silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) )
+    {
+        fprintf (stderr, "silk_ADD_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return res;
+}
+
+#undef silk_ADD_SAT32
+#define silk_ADD_SAT32(a,b) silk_ADD_SAT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_SAT32_(opus_int32 a32, opus_int32 b32, char *file, int line){
+    opus_int32 res;
+    res =   ((((opus_uint32)(a32) + (opus_uint32)(b32)) & 0x80000000) == 0 ?       \
+            ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \
+            ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) );
+    if ( res != silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) )
+    {
+        fprintf (stderr, "silk_ADD_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return res;
+}
+
+#undef silk_ADD_SAT64
+#define silk_ADD_SAT64(a,b) silk_ADD_SAT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_ADD_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line) {
+    opus_int64 res;
+    int        fail = 0;
+    res =   ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ?                                 \
+            ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \
+            ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) );
+    if( res != a64 + b64 ) {
+        /* Check that we saturated to the correct extreme value */
+        if ( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) ||
+               ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ) )
+        {
+            fail = 1;
+        }
+    } else {
+        /* Saturation not necessary */
+        fail = res != a64 + b64;
+    }
+    if ( fail )
+    {
+        fprintf (stderr, "silk_ADD_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return res;
+}
+
+#undef silk_SUB_SAT16
+#define silk_SUB_SAT16(a,b) silk_SUB_SAT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_SUB_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line ) {
+    opus_int16 res;
+    res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) );
+    if ( res != silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) )
+    {
+        fprintf (stderr, "silk_SUB_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return res;
+}
+
+#undef silk_SUB_SAT32
+#define silk_SUB_SAT32(a,b) silk_SUB_SAT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_SAT32_( opus_int32 a32, opus_int32 b32, char *file, int line ) {
+    opus_int32 res;
+    res =   ((((opus_uint32)(a32)-(opus_uint32)(b32)) & 0x80000000) == 0 ?                \
+            (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \
+            ((((a32)^0x80000000) & (b32)  & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) );
+    if ( res != silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) )
+    {
+        fprintf (stderr, "silk_SUB_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return res;
+}
+
+#undef silk_SUB_SAT64
+#define silk_SUB_SAT64(a,b) silk_SUB_SAT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SUB_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line ) {
+    opus_int64 res;
+    int        fail = 0;
+    res =   ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ?                                                    \
+            (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \
+            ((((a64)^0x8000000000000000LL) & (b64)  & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) );
+    if( res != a64 - b64 ) {
+        /* Check that we saturated to the correct extreme value */
+        if( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) ||
+              ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ))
+        {
+            fail = 1;
+        }
+    } else {
+        /* Saturation not necessary */
+        fail = res != a64 - b64;
+    }
+    if ( fail )
+    {
+        fprintf (stderr, "silk_SUB_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return res;
+}
+
+#undef silk_MUL
+#define silk_MUL(a,b) silk_MUL_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MUL_(opus_int32 a32, opus_int32 b32, char *file, int line){
+    opus_int32 ret;
+    opus_int64 ret64;
+    ret = a32 * b32;
+    ret64 = (opus_int64)a32 * (opus_int64)b32;
+    if ( (opus_int64)ret != ret64 )
+    {
+        fprintf (stderr, "silk_MUL(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_MUL_uint
+#define silk_MUL_uint(a,b) silk_MUL_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_MUL_uint_(opus_uint32 a32, opus_uint32 b32, char *file, int line){
+    opus_uint32 ret;
+    ret = a32 * b32;
+    if ( (opus_uint64)ret != (opus_uint64)a32 * (opus_uint64)b32 )
+    {
+        fprintf (stderr, "silk_MUL_uint(%u, %u) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_MLA
+#define silk_MLA(a,b,c) silk_MLA_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MLA_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+    opus_int32 ret;
+    ret = a32 + b32 * c32;
+    if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 )
+    {
+        fprintf (stderr, "silk_MLA(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_MLA_uint
+#define silk_MLA_uint(a,b,c) silk_MLA_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MLA_uint_(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32, char *file, int line){
+    opus_uint32 ret;
+    ret = a32 + b32 * c32;
+    if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 )
+    {
+        fprintf (stderr, "silk_MLA_uint(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SMULWB
+#define silk_SMULWB(a,b) silk_SMULWB_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWB_(opus_int32 a32, opus_int32 b32, char *file, int line){
+    opus_int32 ret;
+    ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16);
+    if ( (opus_int64)ret != ((opus_int64)a32 * (opus_int16)b32) >> 16 )
+    {
+        fprintf (stderr, "silk_SMULWB(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SMLAWB
+#define silk_SMLAWB(a,b,c) silk_SMLAWB_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+    opus_int32 ret;
+    ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) );
+    if ( silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) != silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) ) )
+    {
+        fprintf (stderr, "silk_SMLAWB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SMULWT
+#define silk_SMULWT(a,b) silk_SMULWT_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWT_(opus_int32 a32, opus_int32 b32, char *file, int line){
+    opus_int32 ret;
+    ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16);
+    if ( (opus_int64)ret != ((opus_int64)a32 * (b32 >> 16)) >> 16 )
+    {
+        fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SMLAWT
+#define silk_SMLAWT(a,b,c) silk_SMLAWT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+    opus_int32 ret;
+    ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16));
+    if ( (opus_int64)ret != (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16) )
+    {
+        fprintf (stderr, "silk_SMLAWT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SMULL
+#define silk_SMULL(a,b) silk_SMULL_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SMULL_(opus_int64 a64, opus_int64 b64, char *file, int line){
+    opus_int64 ret64;
+    int        fail = 0;
+    ret64 = a64 * b64;
+    if( b64 != 0 ) {
+        fail = a64 != (ret64 / b64);
+    } else if( a64 != 0 ) {
+        fail = b64 != (ret64 / a64);
+    }
+    if ( fail )
+    {
+        fprintf (stderr, "silk_SMULL(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret64;
+}
+
+/* no checking needed for silk_SMULBB */
+#undef silk_SMLABB
+#define silk_SMLABB(a,b,c) silk_SMLABB_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLABB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+    opus_int32 ret;
+    ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32);
+    if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32 )
+    {
+        fprintf (stderr, "silk_SMLABB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+/* no checking needed for silk_SMULBT */
+#undef silk_SMLABT
+#define silk_SMLABT(a,b,c) silk_SMLABT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLABT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+    opus_int32 ret;
+    ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16);
+    if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16) )
+    {
+        fprintf (stderr, "silk_SMLABT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+/* no checking needed for silk_SMULTT */
+#undef silk_SMLATT
+#define silk_SMLATT(a,b,c) silk_SMLATT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLATT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+    opus_int32 ret;
+    ret = a32 + (b32 >> 16) * (c32 >> 16);
+    if ( (opus_int64)ret != (opus_int64)a32 + (b32 >> 16) * (c32 >> 16) )
+    {
+        fprintf (stderr, "silk_SMLATT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_SMULWW
+#define silk_SMULWW(a,b) silk_SMULWW_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWW_(opus_int32 a32, opus_int32 b32, char *file, int line){
+    opus_int32 ret, tmp1, tmp2;
+    opus_int64 ret64;
+    int        fail = 0;
+
+    ret  = silk_SMULWB( a32, b32 );
+    tmp1 = silk_RSHIFT_ROUND( b32, 16 );
+    tmp2 = silk_MUL( a32, tmp1 );
+
+    fail |= (opus_int64)tmp2 != (opus_int64) a32 * (opus_int64) tmp1;
+
+    tmp1 = ret;
+    ret  = silk_ADD32( tmp1, tmp2 );
+    fail |= silk_ADD32( tmp1, tmp2 ) != silk_ADD_SAT32( tmp1, tmp2 );
+
+    ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 );
+    fail |= (opus_int64)ret != ret64;
+
+    if ( fail )
+    {
+        fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+
+    return ret;
+}
+
+#undef silk_SMLAWW
+#define silk_SMLAWW(a,b,c) silk_SMLAWW_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWW_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+    opus_int32 ret, tmp;
+
+    tmp = silk_SMULWW( b32, c32 );
+    ret = silk_ADD32( a32, tmp );
+    if ( ret != silk_ADD_SAT32( a32, tmp ) )
+    {
+        fprintf (stderr, "silk_SMLAWW(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */
+#undef  silk_MLA_ovflw
+#define silk_MLA_ovflw(a32, b32, c32)    ((a32) + ((b32) * (c32)))
+#undef  silk_SMLABB_ovflw
+#define silk_SMLABB_ovflw(a32, b32, c32)    ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))
+
+/* no checking needed for silk_SMULL
+   no checking needed for silk_SMLAL
+   no checking needed for silk_SMLALBB
+   no checking needed for SigProcFIX_CLZ16
+   no checking needed for SigProcFIX_CLZ32*/
+
+#undef silk_DIV32
+#define silk_DIV32(a,b) silk_DIV32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_DIV32_(opus_int32 a32, opus_int32 b32, char *file, int line){
+    if ( b32 == 0 )
+    {
+        fprintf (stderr, "silk_DIV32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return a32 / b32;
+}
+
+#undef silk_DIV32_16
+#define silk_DIV32_16(a,b) silk_DIV32_16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, char *file, int line){
+    int fail = 0;
+    fail |= b32 == 0;
+    fail |= b32 > silk_int16_MAX;
+    fail |= b32 < silk_int16_MIN;
+    if ( fail )
+    {
+        fprintf (stderr, "silk_DIV32_16(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return a32 / b32;
+}
+
+/* no checking needed for silk_SAT8
+   no checking needed for silk_SAT16
+   no checking needed for silk_SAT32
+   no checking needed for silk_POS_SAT32
+   no checking needed for silk_ADD_POS_SAT8
+   no checking needed for silk_ADD_POS_SAT16
+   no checking needed for silk_ADD_POS_SAT32
+   no checking needed for silk_ADD_POS_SAT64 */
+
+#undef silk_LSHIFT8
+#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_LSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){
+    opus_int8 ret;
+    int       fail = 0;
+    ret = a << shift;
+    fail |= shift < 0;
+    fail |= shift >= 8;
+    fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+    if ( fail )
+    {
+        fprintf (stderr, "silk_LSHIFT8(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_LSHIFT16
+#define silk_LSHIFT16(a,b) silk_LSHIFT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_LSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){
+    opus_int16 ret;
+    int        fail = 0;
+    ret = a << shift;
+    fail |= shift < 0;
+    fail |= shift >= 16;
+    fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+    if ( fail )
+    {
+        fprintf (stderr, "silk_LSHIFT16(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_LSHIFT32
+#define silk_LSHIFT32(a,b) silk_LSHIFT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_LSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){
+    opus_int32 ret;
+    int        fail = 0;
+    ret = a << shift;
+    fail |= shift < 0;
+    fail |= shift >= 32;
+    fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+    if ( fail )
+    {
+        fprintf (stderr, "silk_LSHIFT32(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_LSHIFT64
+#define silk_LSHIFT64(a,b) silk_LSHIFT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_LSHIFT64_(opus_int64 a, opus_int shift, char *file, int line){
+    opus_int64 ret;
+    int        fail = 0;
+    ret = a << shift;
+    fail |= shift < 0;
+    fail |= shift >= 64;
+    fail |= (ret>>shift) != ((opus_int64)a);
+    if ( fail )
+    {
+        fprintf (stderr, "silk_LSHIFT64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_LSHIFT_ovflw
+#define silk_LSHIFT_ovflw(a,b) silk_LSHIFT_ovflw_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw_(opus_int32 a, opus_int32 shift, char *file, int line){
+    if ( (shift < 0) || (shift >= 32) ) /* no check for overflow */
+    {
+        fprintf (stderr, "silk_LSHIFT_ovflw(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return a << shift;
+}
+
+#undef silk_LSHIFT_uint
+#define silk_LSHIFT_uint(a,b) silk_LSHIFT_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_LSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){
+    opus_uint32 ret;
+    ret = a << shift;
+    if ( (shift < 0) || ((opus_int64)ret != ((opus_int64)a) << shift))
+    {
+        fprintf (stderr, "silk_LSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_RSHIFT8
+#define silk_RSHITF8(a,b) silk_RSHIFT8_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_RSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){
+    if ( (shift < 0) || (shift>=8) )
+    {
+        fprintf (stderr, "silk_RSHITF8(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return a >> shift;
+}
+
+#undef silk_RSHIFT16
+#define silk_RSHITF16(a,b) silk_RSHIFT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_RSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){
+    if ( (shift < 0) || (shift>=16) )
+    {
+        fprintf (stderr, "silk_RSHITF16(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return a >> shift;
+}
+
+#undef silk_RSHIFT32
+#define silk_RSHIFT32(a,b) silk_RSHIFT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_RSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){
+    if ( (shift < 0) || (shift>=32) )
+    {
+        fprintf (stderr, "silk_RSHITF32(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return a >> shift;
+}
+
+#undef silk_RSHIFT64
+#define silk_RSHIFT64(a,b) silk_RSHIFT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_RSHIFT64_(opus_int64 a, opus_int64 shift, char *file, int line){
+    if ( (shift < 0) || (shift>=64) )
+    {
+        fprintf (stderr, "silk_RSHITF64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return a >> shift;
+}
+
+#undef silk_RSHIFT_uint
+#define silk_RSHIFT_uint(a,b) silk_RSHIFT_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_RSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){
+    if ( (shift < 0) || (shift>32) )
+    {
+        fprintf (stderr, "silk_RSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return a >> shift;
+}
+
+#undef silk_ADD_LSHIFT
+#define silk_ADD_LSHIFT(a,b,c) silk_ADD_LSHIFT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE int silk_ADD_LSHIFT_(int a, int b, int shift, char *file, int line){
+    opus_int16 ret;
+    ret = a + (b << shift);
+    if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+    {
+        fprintf (stderr, "silk_ADD_LSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;                /* shift >= 0 */
+}
+
+#undef silk_ADD_LSHIFT32
+#define silk_ADD_LSHIFT32(a,b,c) silk_ADD_LSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+    opus_int32 ret;
+    ret = a + (b << shift);
+    if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+    {
+        fprintf (stderr, "silk_ADD_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;                /* shift >= 0 */
+}
+
+#undef silk_ADD_LSHIFT_uint
+#define silk_ADD_LSHIFT_uint(a,b,c) silk_ADD_LSHIFT_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){
+    opus_uint32 ret;
+    ret = a + (b << shift);
+    if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+    {
+        fprintf (stderr, "silk_ADD_LSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;                /* shift >= 0 */
+}
+
+#undef silk_ADD_RSHIFT
+#define silk_ADD_RSHIFT(a,b,c) silk_ADD_RSHIFT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE int silk_ADD_RSHIFT_(int a, int b, int shift, char *file, int line){
+    opus_int16 ret;
+    ret = a + (b >> shift);
+    if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+    {
+        fprintf (stderr, "silk_ADD_RSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;                /* shift  > 0 */
+}
+
+#undef silk_ADD_RSHIFT32
+#define silk_ADD_RSHIFT32(a,b,c) silk_ADD_RSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+    opus_int32 ret;
+    ret = a + (b >> shift);
+    if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+    {
+        fprintf (stderr, "silk_ADD_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;                /* shift  > 0 */
+}
+
+#undef silk_ADD_RSHIFT_uint
+#define silk_ADD_RSHIFT_uint(a,b,c) silk_ADD_RSHIFT_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){
+    opus_uint32 ret;
+    ret = a + (b >> shift);
+    if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+    {
+        fprintf (stderr, "silk_ADD_RSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;                /* shift  > 0 */
+}
+
+#undef silk_SUB_LSHIFT32
+#define silk_SUB_LSHIFT32(a,b,c) silk_SUB_LSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+    opus_int32 ret;
+    ret = a - (b << shift);
+    if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) << shift)) )
+    {
+        fprintf (stderr, "silk_SUB_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;                /* shift >= 0 */
+}
+
+#undef silk_SUB_RSHIFT32
+#define silk_SUB_RSHIFT32(a,b,c) silk_SUB_RSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+    opus_int32 ret;
+    ret = a - (b >> shift);
+    if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) >> shift)) )
+    {
+        fprintf (stderr, "silk_SUB_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;                /* shift  > 0 */
+}
+
+#undef silk_RSHIFT_ROUND
+#define silk_RSHIFT_ROUND(a,b) silk_RSHIFT_ROUND_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){
+    opus_int32 ret;
+    ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+    /* the marco definition can't handle a shift of zero */
+    if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) )
+    {
+        fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return ret;
+}
+
+#undef silk_RSHIFT_ROUND64
+#define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){
+    opus_int64 ret;
+    /* the marco definition can't handle a shift of zero */
+    if ( (shift <= 0) || (shift>=64) )
+    {
+        fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+    return ret;
+}
+
+/* silk_abs is used on floats also, so doesn't work... */
+/*#undef silk_abs
+static OPUS_INLINE opus_int32 silk_abs(opus_int32 a){
+    silk_assert(a != 0x80000000);
+    return (((a) >  0)  ? (a) : -(a));            // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN
+}*/
+
+#undef silk_abs_int64
+#define silk_abs_int64(a) silk_abs_int64_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_abs_int64_(opus_int64 a, char *file, int line){
+    if ( a == silk_int64_MIN )
+    {
+        fprintf (stderr, "silk_abs_int64(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return (((a) >  0)  ? (a) : -(a));            /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */
+}
+
+#undef silk_abs_int32
+#define silk_abs_int32(a) silk_abs_int32_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_abs_int32_(opus_int32 a, char *file, int line){
+    if ( a == silk_int32_MIN )
+    {
+        fprintf (stderr, "silk_abs_int32(%d) in %s: line %d\n", a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return silk_abs(a);
+}
+
+#undef silk_CHECK_FIT8
+#define silk_CHECK_FIT8(a) silk_CHECK_FIT8_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_CHECK_FIT8_( opus_int64 a, char *file, int line ){
+    opus_int8 ret;
+    ret = (opus_int8)a;
+    if ( (opus_int64)ret != a )
+    {
+        fprintf (stderr, "silk_CHECK_FIT8(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return( ret );
+}
+
+#undef silk_CHECK_FIT16
+#define silk_CHECK_FIT16(a) silk_CHECK_FIT16_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_CHECK_FIT16_( opus_int64 a, char *file, int line ){
+    opus_int16 ret;
+    ret = (opus_int16)a;
+    if ( (opus_int64)ret != a )
+    {
+        fprintf (stderr, "silk_CHECK_FIT16(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return( ret );
+}
+
+#undef silk_CHECK_FIT32
+#define silk_CHECK_FIT32(a) silk_CHECK_FIT32_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_CHECK_FIT32_( opus_int64 a, char *file, int line ){
+    opus_int32 ret;
+    ret = (opus_int32)a;
+    if ( (opus_int64)ret != a )
+    {
+        fprintf (stderr, "silk_CHECK_FIT32(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+        silk_assert( 0 );
+#endif
+    }
+    return( ret );
+}
+
+/* no checking for silk_NSHIFT_MUL_32_32
+   no checking for silk_NSHIFT_MUL_16_16
+   no checking needed for silk_min
+   no checking needed for silk_max
+   no checking needed for silk_sign
+*/
+
+#endif
+#endif /* MACRO_DEBUG_H */
diff --git a/third_party/opus/src/silk/NLSF2A.c b/third_party/opus/src/silk/NLSF2A.c
new file mode 100644
index 0000000..b1c559ea
--- /dev/null
+++ b/third_party/opus/src/silk/NLSF2A.c
@@ -0,0 +1,178 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* conversion between prediction filter coefficients and LSFs   */
+/* order should be even                                         */
+/* a piecewise linear approximation maps LSF <-> cos(LSF)       */
+/* therefore the result is not accurate LSFs, but the two       */
+/* functions are accurate inverses of each other                */
+
+#include "SigProc_FIX.h"
+#include "tables.h"
+
+#define QA      16
+
+/* helper function for NLSF2A(..) */
+static OPUS_INLINE void silk_NLSF2A_find_poly(
+    opus_int32          *out,      /* O    intermediate polynomial, QA [dd+1]        */
+    const opus_int32    *cLSF,     /* I    vector of interleaved 2*cos(LSFs), QA [d] */
+    opus_int            dd         /* I    polynomial order (= 1/2 * filter order)   */
+)
+{
+    opus_int   k, n;
+    opus_int32 ftmp;
+
+    out[0] = silk_LSHIFT( 1, QA );
+    out[1] = -cLSF[0];
+    for( k = 1; k < dd; k++ ) {
+        ftmp = cLSF[2*k];            /* QA*/
+        out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA );
+        for( n = k; n > 1; n-- ) {
+            out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA );
+        }
+        out[1] -= ftmp;
+    }
+}
+
+/* compute whitening filter coefficients from normalized line spectral frequencies */
+void silk_NLSF2A(
+    opus_int16                  *a_Q12,             /* O    monic whitening filter coefficients in Q12,  [ d ]          */
+    const opus_int16            *NLSF,              /* I    normalized line spectral frequencies in Q15, [ d ]          */
+    const opus_int              d                   /* I    filter order (should be even)                               */
+)
+{
+    /* This ordering was found to maximize quality. It improves numerical accuracy of
+       silk_NLSF2A_find_poly() compared to "standard" ordering. */
+    static const unsigned char ordering16[16] = {
+      0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1
+    };
+    static const unsigned char ordering10[10] = {
+      0, 9, 6, 3, 4, 5, 8, 1, 2, 7
+    };
+    const unsigned char *ordering;
+    opus_int   k, i, dd;
+    opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ];
+    opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+    opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
+    opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
+    opus_int32 maxabs, absval, idx=0, sc_Q16;
+
+    silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
+    silk_assert( d==10||d==16 );
+
+    /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */
+    ordering = d == 16 ? ordering16 : ordering10;
+    for( k = 0; k < d; k++ ) {
+        silk_assert(NLSF[k] >= 0 );
+
+        /* f_int on a scale 0-127 (rounded down) */
+        f_int = silk_RSHIFT( NLSF[k], 15 - 7 );
+
+        /* f_frac, range: 0..255 */
+        f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 );
+
+        silk_assert(f_int >= 0);
+        silk_assert(f_int < LSF_COS_TAB_SZ_FIX );
+
+        /* Read start and end value from table */
+        cos_val = silk_LSFCosTab_FIX_Q12[ f_int ];                /* Q12 */
+        delta   = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val;  /* Q12, with a range of 0..200 */
+
+        /* Linear interpolation */
+        cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */
+    }
+
+    dd = silk_RSHIFT( d, 1 );
+
+    /* generate even and odd polynomials using convolution */
+    silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd );
+    silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd );
+
+    /* convert even and odd polynomials to opus_int32 Q12 filter coefs */
+    for( k = 0; k < dd; k++ ) {
+        Ptmp = P[ k+1 ] + P[ k ];
+        Qtmp = Q[ k+1 ] - Q[ k ];
+
+        /* the Ptmp and Qtmp values at this stage need to fit in int32 */
+        a32_QA1[ k ]     = -Qtmp - Ptmp;        /* QA+1 */
+        a32_QA1[ d-k-1 ] =  Qtmp - Ptmp;        /* QA+1 */
+    }
+
+    /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
+    for( i = 0; i < 10; i++ ) {
+        /* Find maximum absolute value and its index */
+        maxabs = 0;
+        for( k = 0; k < d; k++ ) {
+            absval = silk_abs( a32_QA1[k] );
+            if( absval > maxabs ) {
+                maxabs = absval;
+                idx    = k;
+            }
+        }
+        maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 );                                          /* QA+1 -> Q12 */
+
+        if( maxabs > silk_int16_MAX ) {
+            /* Reduce magnitude of prediction coefficients */
+            maxabs = silk_min( maxabs, 163838 );  /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
+            sc_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ),
+                                        silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) );
+            silk_bwexpander_32( a32_QA1, d, sc_Q16 );
+        } else {
+            break;
+        }
+    }
+
+    if( i == 10 ) {
+        /* Reached the last iteration, clip the coefficients */
+        for( k = 0; k < d; k++ ) {
+            a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) );  /* QA+1 -> Q12 */
+            a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 );
+        }
+    } else {
+        for( k = 0; k < d; k++ ) {
+            a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 );                /* QA+1 -> Q12 */
+        }
+    }
+
+    for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
+        if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
+            /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion   */
+            /* on the unscaled coefficients, convert to Q12 and measure again                   */
+            silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) );
+            for( k = 0; k < d; k++ ) {
+                a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 );            /* QA+1 -> Q12 */
+            }
+        } else {
+            break;
+        }
+    }
+}
+
diff --git a/third_party/opus/src/silk/NLSF_VQ.c b/third_party/opus/src/silk/NLSF_VQ.c
new file mode 100644
index 0000000..69b6e22
--- /dev/null
+++ b/third_party/opus/src/silk/NLSF_VQ.c
@@ -0,0 +1,68 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */
+void silk_NLSF_VQ(
+    opus_int32                  err_Q26[],                      /* O    Quantization errors [K]                     */
+    const opus_int16            in_Q15[],                       /* I    Input vectors to be quantized [LPC_order]   */
+    const opus_uint8            pCB_Q8[],                       /* I    Codebook vectors [K*LPC_order]              */
+    const opus_int              K,                              /* I    Number of codebook vectors                  */
+    const opus_int              LPC_order                       /* I    Number of LPCs                              */
+)
+{
+    opus_int        i, m;
+    opus_int32      diff_Q15, sum_error_Q30, sum_error_Q26;
+
+    silk_assert( LPC_order <= 16 );
+    silk_assert( ( LPC_order & 1 ) == 0 );
+
+    /* Loop over codebook */
+    for( i = 0; i < K; i++ ) {
+        sum_error_Q26 = 0;
+        for( m = 0; m < LPC_order; m += 2 ) {
+            /* Compute weighted squared quantization error for index m */
+            diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
+            sum_error_Q30 = silk_SMULBB( diff_Q15, diff_Q15 );
+
+            /* Compute weighted squared quantization error for index m + 1 */
+            diff_Q15 = silk_SUB_LSHIFT32( in_Q15[m + 1], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
+            sum_error_Q30 = silk_SMLABB( sum_error_Q30, diff_Q15, diff_Q15 );
+
+            sum_error_Q26 = silk_ADD_RSHIFT32( sum_error_Q26, sum_error_Q30, 4 );
+
+            silk_assert( sum_error_Q26 >= 0 );
+            silk_assert( sum_error_Q30 >= 0 );
+        }
+        err_Q26[ i ] = sum_error_Q26;
+    }
+}
diff --git a/third_party/opus/src/silk/NLSF_VQ_weights_laroia.c b/third_party/opus/src/silk/NLSF_VQ_weights_laroia.c
new file mode 100644
index 0000000..04894c5
--- /dev/null
+++ b/third_party/opus/src/silk/NLSF_VQ_weights_laroia.c
@@ -0,0 +1,80 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "define.h"
+#include "SigProc_FIX.h"
+
+/*
+R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP
+Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech,
+Signal Processing, pp. 641-644, 1991.
+*/
+
+/* Laroia low complexity NLSF weights */
+void silk_NLSF_VQ_weights_laroia(
+    opus_int16                  *pNLSFW_Q_OUT,      /* O     Pointer to input vector weights [D]                        */
+    const opus_int16            *pNLSF_Q15,         /* I     Pointer to input vector         [D]                        */
+    const opus_int              D                   /* I     Input vector dimension (even)                              */
+)
+{
+    opus_int   k;
+    opus_int32 tmp1_int, tmp2_int;
+
+    silk_assert( D > 0 );
+    silk_assert( ( D & 1 ) == 0 );
+
+    /* First value */
+    tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 );
+    tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+    tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 );
+    tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int );
+    pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+    silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 );
+
+    /* Main loop */
+    for( k = 1; k < D - 1; k += 2 ) {
+        tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 );
+        tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+        pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+        silk_assert( pNLSFW_Q_OUT[ k ] > 0 );
+
+        tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 );
+        tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int );
+        pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+        silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 );
+    }
+
+    /* Last value */
+    tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 );
+    tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+    pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+    silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 );
+}
diff --git a/third_party/opus/src/silk/NLSF_decode.c b/third_party/opus/src/silk/NLSF_decode.c
new file mode 100644
index 0000000..9f71506
--- /dev/null
+++ b/third_party/opus/src/silk/NLSF_decode.c
@@ -0,0 +1,101 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Predictive dequantizer for NLSF residuals */
+static OPUS_INLINE void silk_NLSF_residual_dequant(               /* O    Returns RD value in Q30                     */
+          opus_int16         x_Q10[],                        /* O    Output [ order ]                            */
+    const opus_int8          indices[],                      /* I    Quantization indices [ order ]              */
+    const opus_uint8         pred_coef_Q8[],                 /* I    Backward predictor coefs [ order ]          */
+    const opus_int           quant_step_size_Q16,            /* I    Quantization step size                      */
+    const opus_int16         order                           /* I    Number of input values                      */
+)
+{
+    opus_int     i, out_Q10, pred_Q10;
+
+    out_Q10 = 0;
+    for( i = order-1; i >= 0; i-- ) {
+        pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 );
+        out_Q10  = silk_LSHIFT( indices[ i ], 10 );
+        if( out_Q10 > 0 ) {
+            out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+        } else if( out_Q10 < 0 ) {
+            out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+        }
+        out_Q10  = silk_SMLAWB( pred_Q10, (opus_int32)out_Q10, quant_step_size_Q16 );
+        x_Q10[ i ] = out_Q10;
+    }
+}
+
+
+/***********************/
+/* NLSF vector decoder */
+/***********************/
+void silk_NLSF_decode(
+          opus_int16            *pNLSF_Q15,                     /* O    Quantized NLSF vector [ LPC_ORDER ]         */
+          opus_int8             *NLSFIndices,                   /* I    Codebook path vector [ LPC_ORDER + 1 ]      */
+    const silk_NLSF_CB_struct   *psNLSF_CB                      /* I    Codebook object                             */
+)
+{
+    opus_int         i;
+    opus_uint8       pred_Q8[  MAX_LPC_ORDER ];
+    opus_int16       ec_ix[    MAX_LPC_ORDER ];
+    opus_int16       res_Q10[  MAX_LPC_ORDER ];
+    opus_int16       W_tmp_QW[ MAX_LPC_ORDER ];
+    opus_int32       W_tmp_Q9, NLSF_Q15_tmp;
+    const opus_uint8 *pCB_element;
+
+    /* Decode first stage */
+    pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ];
+    for( i = 0; i < psNLSF_CB->order; i++ ) {
+        pNLSF_Q15[ i ] = silk_LSHIFT( (opus_int16)pCB_element[ i ], 7 );
+    }
+
+    /* Unpack entropy table indices and predictor for current CB1 index */
+    silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] );
+
+    /* Predictive residual dequantizer */
+    silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order );
+
+    /* Weights from codebook vector */
+    silk_NLSF_VQ_weights_laroia( W_tmp_QW, pNLSF_Q15, psNLSF_CB->order );
+
+    /* Apply inverse square-rooted weights and add to output */
+    for( i = 0; i < psNLSF_CB->order; i++ ) {
+        W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
+        NLSF_Q15_tmp = silk_ADD32( pNLSF_Q15[ i ], silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), W_tmp_Q9 ) );
+        pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 );
+    }
+
+    /* NLSF stabilization */
+    silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order );
+}
diff --git a/third_party/opus/src/silk/NLSF_del_dec_quant.c b/third_party/opus/src/silk/NLSF_del_dec_quant.c
new file mode 100644
index 0000000..de88fee
--- /dev/null
+++ b/third_party/opus/src/silk/NLSF_del_dec_quant.c
@@ -0,0 +1,217 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Delayed-decision quantizer for NLSF residuals */
+opus_int32 silk_NLSF_del_dec_quant(                             /* O    Returns RD value in Q25                     */
+    opus_int8                   indices[],                      /* O    Quantization indices [ order ]              */
+    const opus_int16            x_Q10[],                        /* I    Input [ order ]                             */
+    const opus_int16            w_Q5[],                         /* I    Weights [ order ]                           */
+    const opus_uint8            pred_coef_Q8[],                 /* I    Backward predictor coefs [ order ]          */
+    const opus_int16            ec_ix[],                        /* I    Indices to entropy coding tables [ order ]  */
+    const opus_uint8            ec_rates_Q5[],                  /* I    Rates []                                    */
+    const opus_int              quant_step_size_Q16,            /* I    Quantization step size                      */
+    const opus_int16            inv_quant_step_size_Q6,         /* I    Inverse quantization step size              */
+    const opus_int32            mu_Q20,                         /* I    R/D tradeoff                                */
+    const opus_int16            order                           /* I    Number of input values                      */
+)
+{
+    opus_int         i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10;
+    opus_int         pred_Q10, diff_Q10, rate0_Q5, rate1_Q5;
+    opus_int16       out0_Q10, out1_Q10;
+    opus_int32       RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25;
+    opus_int         ind_sort[         NLSF_QUANT_DEL_DEC_STATES ];
+    opus_int8        ind[              NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ];
+    opus_int16       prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ];
+    opus_int32       RD_Q25[       2 * NLSF_QUANT_DEL_DEC_STATES ];
+    opus_int32       RD_min_Q25[       NLSF_QUANT_DEL_DEC_STATES ];
+    opus_int32       RD_max_Q25[       NLSF_QUANT_DEL_DEC_STATES ];
+    const opus_uint8 *rates_Q5;
+
+    opus_int out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT];
+    opus_int out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT];
+
+    for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT-1; i++)
+    {
+        out0_Q10 = silk_LSHIFT( i, 10 );
+        out1_Q10 = silk_ADD16( out0_Q10, 1024 );
+        if( i > 0 ) {
+            out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+            out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+        } else if( i == 0 ) {
+            out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+        } else if( i == -1 ) {
+            out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+        } else {
+            out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+            out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+        }
+        out0_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out0_Q10, quant_step_size_Q16 ), 16 );
+        out1_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out1_Q10, quant_step_size_Q16 ), 16 );
+    }
+
+    silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 );     /* must be power of two */
+
+    nStates = 1;
+    RD_Q25[ 0 ] = 0;
+    prev_out_Q10[ 0 ] = 0;
+    for( i = order - 1; ; i-- ) {
+        rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ];
+        in_Q10 = x_Q10[ i ];
+        for( j = 0; j < nStates; j++ ) {
+            pred_Q10 = silk_RSHIFT( silk_SMULBB( (opus_int16)pred_coef_Q8[ i ], prev_out_Q10[ j ] ), 8 );
+            res_Q10  = silk_SUB16( in_Q10, pred_Q10 );
+            ind_tmp  = silk_RSHIFT( silk_SMULBB( inv_quant_step_size_Q6, res_Q10 ), 16 );
+            ind_tmp  = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 );
+            ind[ j ][ i ] = (opus_int8)ind_tmp;
+
+            /* compute outputs for ind_tmp and ind_tmp + 1 */
+            out0_Q10 = out0_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ];
+            out1_Q10 = out1_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ];
+
+            out0_Q10  = silk_ADD16( out0_Q10, pred_Q10 );
+            out1_Q10  = silk_ADD16( out1_Q10, pred_Q10 );
+            prev_out_Q10[ j           ] = out0_Q10;
+            prev_out_Q10[ j + nStates ] = out1_Q10;
+
+            /* compute RD for ind_tmp and ind_tmp + 1 */
+            if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) {
+                if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) {
+                    rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
+                    rate1_Q5 = 280;
+                } else {
+                    rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp );
+                    rate1_Q5 = silk_ADD16( rate0_Q5, 43 );
+                }
+            } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) {
+                if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) {
+                    rate0_Q5 = 280;
+                    rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
+                } else {
+                    rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp );
+                    rate1_Q5 = silk_SUB16( rate0_Q5, 43 );
+                }
+            } else {
+                rate0_Q5 = rates_Q5[ ind_tmp +     NLSF_QUANT_MAX_AMPLITUDE ];
+                rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
+            }
+            RD_tmp_Q25            = RD_Q25[ j ];
+            diff_Q10              = silk_SUB16( in_Q10, out0_Q10 );
+            RD_Q25[ j ]           = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 );
+            diff_Q10              = silk_SUB16( in_Q10, out1_Q10 );
+            RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 );
+        }
+
+        if( nStates <= ( NLSF_QUANT_DEL_DEC_STATES >> 1 ) ) {
+            /* double number of states and copy */
+            for( j = 0; j < nStates; j++ ) {
+                ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1;
+            }
+            nStates = silk_LSHIFT( nStates, 1 );
+            for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+                ind[ j ][ i ] = ind[ j - nStates ][ i ];
+            }
+        } else if( i > 0 ) {
+            /* sort lower and upper half of RD_Q25, pairwise */
+            for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+                if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) {
+                    RD_max_Q25[ j ]                         = RD_Q25[ j ];
+                    RD_min_Q25[ j ]                         = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
+                    RD_Q25[ j ]                             = RD_min_Q25[ j ];
+                    RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ];
+                    /* swap prev_out values */
+                    out0_Q10 = prev_out_Q10[ j ];
+                    prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ];
+                    prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10;
+                    ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES;
+                } else {
+                    RD_min_Q25[ j ] = RD_Q25[ j ];
+                    RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
+                    ind_sort[ j ] = j;
+                }
+            }
+            /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */
+            /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */
+            while( 1 ) {
+                min_max_Q25 = silk_int32_MAX;
+                max_min_Q25 = 0;
+                ind_min_max = 0;
+                ind_max_min = 0;
+                for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+                    if( min_max_Q25 > RD_max_Q25[ j ] ) {
+                        min_max_Q25 = RD_max_Q25[ j ];
+                        ind_min_max = j;
+                    }
+                    if( max_min_Q25 < RD_min_Q25[ j ] ) {
+                        max_min_Q25 = RD_min_Q25[ j ];
+                        ind_max_min = j;
+                    }
+                }
+                if( min_max_Q25 >= max_min_Q25 ) {
+                    break;
+                }
+                /* copy ind_min_max to ind_max_min */
+                ind_sort[     ind_max_min ] = ind_sort[     ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES;
+                RD_Q25[       ind_max_min ] = RD_Q25[       ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
+                prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
+                RD_min_Q25[   ind_max_min ] = 0;
+                RD_max_Q25[   ind_min_max ] = silk_int32_MAX;
+                silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) );
+            }
+            /* increment index if it comes from the upper half */
+            for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+                ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 );
+            }
+        } else {  /* i == 0 */
+            break;
+        }
+    }
+
+    /* last sample: find winner, copy indices and return RD value */
+    ind_tmp = 0;
+    min_Q25 = silk_int32_MAX;
+    for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+        if( min_Q25 > RD_Q25[ j ] ) {
+            min_Q25 = RD_Q25[ j ];
+            ind_tmp = j;
+        }
+    }
+    for( j = 0; j < order; j++ ) {
+        indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ];
+        silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT );
+        silk_assert( indices[ j ] <=  NLSF_QUANT_MAX_AMPLITUDE_EXT );
+    }
+    indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 );
+    silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT );
+    silk_assert( min_Q25 >= 0 );
+    return min_Q25;
+}
diff --git a/third_party/opus/src/silk/NLSF_encode.c b/third_party/opus/src/silk/NLSF_encode.c
new file mode 100644
index 0000000..f03c3f1c
--- /dev/null
+++ b/third_party/opus/src/silk/NLSF_encode.c
@@ -0,0 +1,137 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/***********************/
+/* NLSF vector encoder */
+/***********************/
+opus_int32 silk_NLSF_encode(                                    /* O    Returns RD value in Q25                     */
+          opus_int8             *NLSFIndices,                   /* I    Codebook path vector [ LPC_ORDER + 1 ]      */
+          opus_int16            *pNLSF_Q15,                     /* I/O  Quantized NLSF vector [ LPC_ORDER ]         */
+    const silk_NLSF_CB_struct   *psNLSF_CB,                     /* I    Codebook object                             */
+    const opus_int16            *pW_QW,                         /* I    NLSF weight vector [ LPC_ORDER ]            */
+    const opus_int              NLSF_mu_Q20,                    /* I    Rate weight for the RD optimization         */
+    const opus_int              nSurvivors,                     /* I    Max survivors after first stage             */
+    const opus_int              signalType                      /* I    Signal type: 0/1/2                          */
+)
+{
+    opus_int         i, s, ind1, bestIndex, prob_Q8, bits_q7;
+    opus_int32       W_tmp_Q9, ret;
+    VARDECL( opus_int32, err_Q26 );
+    VARDECL( opus_int32, RD_Q25 );
+    VARDECL( opus_int, tempIndices1 );
+    VARDECL( opus_int8, tempIndices2 );
+    opus_int16       res_Q15[      MAX_LPC_ORDER ];
+    opus_int16       res_Q10[      MAX_LPC_ORDER ];
+    opus_int16       NLSF_tmp_Q15[ MAX_LPC_ORDER ];
+    opus_int16       W_tmp_QW[     MAX_LPC_ORDER ];
+    opus_int16       W_adj_Q5[     MAX_LPC_ORDER ];
+    opus_uint8       pred_Q8[      MAX_LPC_ORDER ];
+    opus_int16       ec_ix[        MAX_LPC_ORDER ];
+    const opus_uint8 *pCB_element, *iCDF_ptr;
+    SAVE_STACK;
+
+    silk_assert( nSurvivors <= NLSF_VQ_MAX_SURVIVORS );
+    silk_assert( signalType >= 0 && signalType <= 2 );
+    silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 );
+
+    /* NLSF stabilization */
+    silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order );
+
+    /* First stage: VQ */
+    ALLOC( err_Q26, psNLSF_CB->nVectors, opus_int32 );
+    silk_NLSF_VQ( err_Q26, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->nVectors, psNLSF_CB->order );
+
+    /* Sort the quantization errors */
+    ALLOC( tempIndices1, nSurvivors, opus_int );
+    silk_insertion_sort_increasing( err_Q26, tempIndices1, psNLSF_CB->nVectors, nSurvivors );
+
+    ALLOC( RD_Q25, nSurvivors, opus_int32 );
+    ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 );
+
+    /* Loop over survivors */
+    for( s = 0; s < nSurvivors; s++ ) {
+        ind1 = tempIndices1[ s ];
+
+        /* Residual after first stage */
+        pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ];
+        for( i = 0; i < psNLSF_CB->order; i++ ) {
+            NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 );
+            res_Q15[ i ] = pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ];
+        }
+
+        /* Weights from codebook vector */
+        silk_NLSF_VQ_weights_laroia( W_tmp_QW, NLSF_tmp_Q15, psNLSF_CB->order );
+
+        /* Apply square-rooted weights */
+        for( i = 0; i < psNLSF_CB->order; i++ ) {
+            W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
+            res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( res_Q15[ i ], W_tmp_Q9 ), 14 );
+        }
+
+        /* Modify input weights accordingly */
+        for( i = 0; i < psNLSF_CB->order; i++ ) {
+            W_adj_Q5[ i ] = silk_DIV32_16( silk_LSHIFT( (opus_int32)pW_QW[ i ], 5 ), W_tmp_QW[ i ] );
+        }
+
+        /* Unpack entropy table indices and predictor for current CB1 index */
+        silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 );
+
+        /* Trellis quantizer */
+        RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix,
+            psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order );
+
+        /* Add rate for first stage */
+        iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ];
+        if( ind1 == 0 ) {
+            prob_Q8 = 256 - iCDF_ptr[ ind1 ];
+        } else {
+            prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ];
+        }
+        bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 );
+        RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) );
+    }
+
+    /* Find the lowest rate-distortion error */
+    silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 );
+
+    NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ];
+    silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) );
+
+    /* Decode */
+    silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB );
+
+    ret = RD_Q25[ 0 ];
+    RESTORE_STACK;
+    return ret;
+}
diff --git a/third_party/opus/src/silk/NLSF_stabilize.c b/third_party/opus/src/silk/NLSF_stabilize.c
new file mode 100644
index 0000000..1fa1ea3
--- /dev/null
+++ b/third_party/opus/src/silk/NLSF_stabilize.c
@@ -0,0 +1,142 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* NLSF stabilizer:                                         */
+/*                                                          */
+/* - Moves NLSFs further apart if they are too close        */
+/* - Moves NLSFs away from borders if they are too close    */
+/* - High effort to achieve a modification with minimum     */
+/*     Euclidean distance to input vector                   */
+/* - Output are sorted NLSF coefficients                    */
+/*                                                          */
+
+#include "SigProc_FIX.h"
+
+/* Constant Definitions */
+#define MAX_LOOPS        20
+
+/* NLSF stabilizer, for a single input data vector */
+void silk_NLSF_stabilize(
+          opus_int16            *NLSF_Q15,          /* I/O   Unstable/stabilized normalized LSF vector in Q15 [L]       */
+    const opus_int16            *NDeltaMin_Q15,     /* I     Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1]   */
+    const opus_int              L                   /* I     Number of NLSF parameters in the input vector              */
+)
+{
+    opus_int   i, I=0, k, loops;
+    opus_int16 center_freq_Q15;
+    opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15;
+
+    /* This is necessary to ensure an output within range of a opus_int16 */
+    silk_assert( NDeltaMin_Q15[L] >= 1 );
+
+    for( loops = 0; loops < MAX_LOOPS; loops++ ) {
+        /**************************/
+        /* Find smallest distance */
+        /**************************/
+        /* First element */
+        min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0];
+        I = 0;
+        /* Middle elements */
+        for( i = 1; i <= L-1; i++ ) {
+            diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] );
+            if( diff_Q15 < min_diff_Q15 ) {
+                min_diff_Q15 = diff_Q15;
+                I = i;
+            }
+        }
+        /* Last element */
+        diff_Q15 = ( 1 << 15 ) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] );
+        if( diff_Q15 < min_diff_Q15 ) {
+            min_diff_Q15 = diff_Q15;
+            I = L;
+        }
+
+        /***************************************************/
+        /* Now check if the smallest distance non-negative */
+        /***************************************************/
+        if( min_diff_Q15 >= 0 ) {
+            return;
+        }
+
+        if( I == 0 ) {
+            /* Move away from lower limit */
+            NLSF_Q15[0] = NDeltaMin_Q15[0];
+
+        } else if( I == L) {
+            /* Move away from higher limit */
+            NLSF_Q15[L-1] = ( 1 << 15 ) - NDeltaMin_Q15[L];
+
+        } else {
+            /* Find the lower extreme for the location of the current center frequency */
+            min_center_Q15 = 0;
+            for( k = 0; k < I; k++ ) {
+                min_center_Q15 += NDeltaMin_Q15[k];
+            }
+            min_center_Q15 += silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+
+            /* Find the upper extreme for the location of the current center frequency */
+            max_center_Q15 = 1 << 15;
+            for( k = L; k > I; k-- ) {
+                max_center_Q15 -= NDeltaMin_Q15[k];
+            }
+            max_center_Q15 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+
+            /* Move apart, sorted by value, keeping the same center frequency */
+            center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ),
+                min_center_Q15, max_center_Q15 );
+            NLSF_Q15[I-1] = center_freq_Q15 - silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+            NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I];
+        }
+    }
+
+    /* Safe and simple fall back method, which is less ideal than the above */
+    if( loops == MAX_LOOPS )
+    {
+        /* Insertion sort (fast for already almost sorted arrays):   */
+        /* Best case:  O(n)   for an already sorted array            */
+        /* Worst case: O(n^2) for an inversely sorted array          */
+        silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L );
+
+        /* First NLSF should be no less than NDeltaMin[0] */
+        NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] );
+
+        /* Keep delta_min distance between the NLSFs */
+        for( i = 1; i < L; i++ )
+            NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] );
+
+        /* Last NLSF should be no higher than 1 - NDeltaMin[L] */
+        NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] );
+
+        /* Keep NDeltaMin distance between the NLSFs */
+        for( i = L-2; i >= 0; i-- )
+            NLSF_Q15[i] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] );
+    }
+}
diff --git a/third_party/opus/src/silk/NLSF_unpack.c b/third_party/opus/src/silk/NLSF_unpack.c
new file mode 100644
index 0000000..17bd23f75
--- /dev/null
+++ b/third_party/opus/src/silk/NLSF_unpack.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Unpack predictor values and indices for entropy coding tables */
+void silk_NLSF_unpack(
+          opus_int16            ec_ix[],                        /* O    Indices to entropy tables [ LPC_ORDER ]     */
+          opus_uint8            pred_Q8[],                      /* O    LSF predictor [ LPC_ORDER ]                 */
+    const silk_NLSF_CB_struct   *psNLSF_CB,                     /* I    Codebook object                             */
+    const opus_int              CB1_index                       /* I    Index of vector in first LSF codebook       */
+)
+{
+    opus_int   i;
+    opus_uint8 entry;
+    const opus_uint8 *ec_sel_ptr;
+
+    ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ];
+    for( i = 0; i < psNLSF_CB->order; i += 2 ) {
+        entry = *ec_sel_ptr++;
+        ec_ix  [ i     ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 );
+        pred_Q8[ i     ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ];
+        ec_ix  [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 );
+        pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ];
+    }
+}
+
diff --git a/third_party/opus/src/silk/NSQ.c b/third_party/opus/src/silk/NSQ.c
new file mode 100644
index 0000000..43e3fee
--- /dev/null
+++ b/third_party/opus/src/silk/NSQ.c
@@ -0,0 +1,429 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "NSQ.h"
+
+
+static OPUS_INLINE void silk_nsq_scale_states(
+    const silk_encoder_state *psEncC,           /* I    Encoder State                   */
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    const opus_int32    x_Q3[],                 /* I    input in Q3                     */
+    opus_int32          x_sc_Q10[],             /* O    input scaled with 1/Gain        */
+    const opus_int16    sLTP[],                 /* I    re-whitened LTP state in Q0     */
+    opus_int32          sLTP_Q15[],             /* O    LTP state matching scaled input */
+    opus_int            subfr,                  /* I    subframe number                 */
+    const opus_int      LTP_scale_Q14,          /* I                                    */
+    const opus_int32    Gains_Q16[ MAX_NB_SUBFR ], /* I                                 */
+    const opus_int      pitchL[ MAX_NB_SUBFR ], /* I    Pitch lag                       */
+    const opus_int      signal_type             /* I    Signal type                     */
+);
+
+#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE void silk_noise_shape_quantizer(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    opus_int            signalType,             /* I    Signal type                     */
+    const opus_int32    x_sc_Q10[],             /* I                                    */
+    opus_int8           pulses[],               /* O                                    */
+    opus_int16          xq[],                   /* O                                    */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP state                       */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs     */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs      */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping AR coefs          */
+    opus_int            lag,                    /* I    Pitch lag                       */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                    */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                   */
+    opus_int32          LF_shp_Q14,             /* I                                    */
+    opus_int32          Gain_Q16,               /* I                                    */
+    opus_int            Lambda_Q10,             /* I                                    */
+    opus_int            offset_Q10,             /* I                                    */
+    opus_int            length,                 /* I    Input length                    */
+    opus_int            shapingLPCOrder,        /* I    Noise shaping AR filter order   */
+    opus_int            predictLPCOrder,        /* I    Prediction filter order         */
+    int                 arch                    /* I    Architecture                    */
+);
+#endif
+
+void silk_NSQ_c
+(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+)
+{
+    opus_int            k, lag, start_idx, LSF_interpolation_flag;
+    const opus_int16    *A_Q12, *B_Q14, *AR_shp_Q13;
+    opus_int16          *pxq;
+    VARDECL( opus_int32, sLTP_Q15 );
+    VARDECL( opus_int16, sLTP );
+    opus_int32          HarmShapeFIRPacked_Q14;
+    opus_int            offset_Q10;
+    VARDECL( opus_int32, x_sc_Q10 );
+    SAVE_STACK;
+
+    NSQ->rand_seed = psIndices->Seed;
+
+    /* Set unvoiced lag to the previous one, overwrite later for voiced */
+    lag = NSQ->lagPrev;
+
+    silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+    offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+
+    if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+        LSF_interpolation_flag = 0;
+    } else {
+        LSF_interpolation_flag = 1;
+    }
+
+    ALLOC( sLTP_Q15,
+           psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+    ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+    ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+    /* Set up pointers to start of sub frame */
+    NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+    NSQ->sLTP_buf_idx     = psEncC->ltp_mem_length;
+    pxq                   = &NSQ->xq[ psEncC->ltp_mem_length ];
+    for( k = 0; k < psEncC->nb_subfr; k++ ) {
+        A_Q12      = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ];
+        B_Q14      = &LTPCoef_Q14[ k * LTP_ORDER ];
+        AR_shp_Q13 = &AR2_Q13[     k * MAX_SHAPE_LPC_ORDER ];
+
+        /* Noise shape parameters */
+        silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+        HarmShapeFIRPacked_Q14  =                          silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+        HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+        NSQ->rewhite_flag = 0;
+        if( psIndices->signalType == TYPE_VOICED ) {
+            /* Voiced */
+            lag = pitchL[ k ];
+
+            /* Re-whitening */
+            if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+                /* Rewhiten with new A coefs */
+                start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+                silk_assert( start_idx > 0 );
+
+                silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+                    A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+                NSQ->rewhite_flag = 1;
+                NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+            }
+        }
+
+        silk_nsq_scale_states( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType );
+
+        silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
+            AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10,
+            offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch );
+
+        x_Q3   += psEncC->subfr_length;
+        pulses += psEncC->subfr_length;
+        pxq    += psEncC->subfr_length;
+    }
+
+    /* Update lagPrev for next frame */
+    NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+    /* Save quantized speech and noise shaping signals */
+    /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */
+    silk_memmove( NSQ->xq,           &NSQ->xq[           psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+    silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+    RESTORE_STACK;
+}
+
+/***********************************/
+/* silk_noise_shape_quantizer  */
+/***********************************/
+
+#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE
+#endif
+void silk_noise_shape_quantizer(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    opus_int            signalType,             /* I    Signal type                     */
+    const opus_int32    x_sc_Q10[],             /* I                                    */
+    opus_int8           pulses[],               /* O                                    */
+    opus_int16          xq[],                   /* O                                    */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP state                       */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs     */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs      */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping AR coefs          */
+    opus_int            lag,                    /* I    Pitch lag                       */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                    */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                   */
+    opus_int32          LF_shp_Q14,             /* I                                    */
+    opus_int32          Gain_Q16,               /* I                                    */
+    opus_int            Lambda_Q10,             /* I                                    */
+    opus_int            offset_Q10,             /* I                                    */
+    opus_int            length,                 /* I    Input length                    */
+    opus_int            shapingLPCOrder,        /* I    Noise shaping AR filter order   */
+    opus_int            predictLPCOrder,        /* I    Prediction filter order         */
+    int                 arch                    /* I    Architecture                    */
+)
+{
+    opus_int     i;
+    opus_int32   LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
+    opus_int32   n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
+    opus_int32   exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+    opus_int32   tmp1, tmp2, sLF_AR_shp_Q14;
+    opus_int32   *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr;
+#ifdef silk_short_prediction_create_arch_coef
+    opus_int32   a_Q12_arch[MAX_LPC_ORDER];
+#endif
+
+    shp_lag_ptr  = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+    pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+    Gain_Q10     = silk_RSHIFT( Gain_Q16, 6 );
+
+    /* Set up short term AR state */
+    psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ];
+
+#ifdef silk_short_prediction_create_arch_coef
+    silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder);
+#endif
+
+    for( i = 0; i < length; i++ ) {
+        /* Generate dither */
+        NSQ->rand_seed = silk_RAND( NSQ->rand_seed );
+
+        /* Short-term prediction */
+        LPC_pred_Q10 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch);
+
+        /* Long-term prediction */
+        if( signalType == TYPE_VOICED ) {
+            /* Unrolled loop */
+            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+            LTP_pred_Q13 = 2;
+            LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[  0 ], b_Q14[ 0 ] );
+            LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
+            LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
+            LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
+            LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+            pred_lag_ptr++;
+        } else {
+            LTP_pred_Q13 = 0;
+        }
+
+        /* Noise shape feedback */
+        silk_assert( ( shapingLPCOrder & 1 ) == 0 );   /* check that order is even */
+        n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(psLPC_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch);
+
+        n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 );
+
+        n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 );
+        n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 );
+
+        silk_assert( lag > 0 || signalType != TYPE_VOICED );
+
+        /* Combine prediction and noise shaping signals */
+        tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 );        /* Q12 */
+        tmp1 = silk_SUB32( tmp1, n_LF_Q12 );                                    /* Q12 */
+        if( lag > 0 ) {
+            /* Symmetric, packed FIR coefficients */
+            n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+            n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ],                      HarmShapeFIRPacked_Q14 );
+            n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 );
+            shp_lag_ptr++;
+
+            tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 );                       /* Q13 */
+            tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 );                          /* Q13 */
+            tmp1 = silk_RSHIFT_ROUND( tmp1, 3 );                                /* Q10 */
+        } else {
+            tmp1 = silk_RSHIFT_ROUND( tmp1, 2 );                                /* Q10 */
+        }
+
+        r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 );                              /* residual error Q10 */
+
+        /* Flip sign depending on dither */
+        if ( NSQ->rand_seed < 0 ) {
+           r_Q10 = -r_Q10;
+        }
+        r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+        /* Find two quantization level candidates and measure their rate-distortion */
+        q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+        q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+        if( q1_Q0 > 0 ) {
+            q1_Q10  = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+            q1_Q10  = silk_ADD32( q1_Q10, offset_Q10 );
+            q2_Q10  = silk_ADD32( q1_Q10, 1024 );
+            rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+            rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+        } else if( q1_Q0 == 0 ) {
+            q1_Q10  = offset_Q10;
+            q2_Q10  = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+            rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+            rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+        } else if( q1_Q0 == -1 ) {
+            q2_Q10  = offset_Q10;
+            q1_Q10  = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+            rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+            rd2_Q20 = silk_SMULBB(  q2_Q10, Lambda_Q10 );
+        } else {            /* Q1_Q0 < -1 */
+            q1_Q10  = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+            q1_Q10  = silk_ADD32( q1_Q10, offset_Q10 );
+            q2_Q10  = silk_ADD32( q1_Q10, 1024 );
+            rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+            rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+        }
+        rr_Q10  = silk_SUB32( r_Q10, q1_Q10 );
+        rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 );
+        rr_Q10  = silk_SUB32( r_Q10, q2_Q10 );
+        rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 );
+
+        if( rd2_Q20 < rd1_Q20 ) {
+            q1_Q10 = q2_Q10;
+        }
+
+        pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 );
+
+        /* Excitation */
+        exc_Q14 = silk_LSHIFT( q1_Q10, 4 );
+        if ( NSQ->rand_seed < 0 ) {
+           exc_Q14 = -exc_Q14;
+        }
+
+        /* Add predictions */
+        LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 );
+        xq_Q14      = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 );
+
+        /* Scale XQ back to normal level before saving */
+        xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) );
+
+        /* Update states */
+        psLPC_Q14++;
+        *psLPC_Q14 = xq_Q14;
+        sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 );
+        NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14;
+
+        NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 );
+        sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 );
+        NSQ->sLTP_shp_buf_idx++;
+        NSQ->sLTP_buf_idx++;
+
+        /* Make dither dependent on quantized signal */
+        NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] );
+    }
+
+    /* Update LPC synth buffer */
+    silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+}
+
+static OPUS_INLINE void silk_nsq_scale_states(
+    const silk_encoder_state *psEncC,           /* I    Encoder State                   */
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    const opus_int32    x_Q3[],                 /* I    input in Q3                     */
+    opus_int32          x_sc_Q10[],             /* O    input scaled with 1/Gain        */
+    const opus_int16    sLTP[],                 /* I    re-whitened LTP state in Q0     */
+    opus_int32          sLTP_Q15[],             /* O    LTP state matching scaled input */
+    opus_int            subfr,                  /* I    subframe number                 */
+    const opus_int      LTP_scale_Q14,          /* I                                    */
+    const opus_int32    Gains_Q16[ MAX_NB_SUBFR ], /* I                                 */
+    const opus_int      pitchL[ MAX_NB_SUBFR ], /* I    Pitch lag                       */
+    const opus_int      signal_type             /* I    Signal type                     */
+)
+{
+    opus_int   i, lag;
+    opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+
+    lag          = pitchL[ subfr ];
+    inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+    silk_assert( inv_gain_Q31 != 0 );
+
+    /* Calculate gain adjustment factor */
+    if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+        gain_adj_Q16 =  silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+    } else {
+        gain_adj_Q16 = (opus_int32)1 << 16;
+    }
+
+    /* Scale input */
+    inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+    for( i = 0; i < psEncC->subfr_length; i++ ) {
+        x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+    }
+
+    /* Save inverse gain */
+    NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+    /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+    if( NSQ->rewhite_flag ) {
+        if( subfr == 0 ) {
+            /* Do LTP downscaling */
+            inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+        }
+        for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+            silk_assert( i < MAX_FRAME_LENGTH );
+            sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+        }
+    }
+
+    /* Adjust for changing gain */
+    if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+        /* Scale long-term shaping state */
+        for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+            NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+        }
+
+        /* Scale long-term prediction state */
+        if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+            for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+                sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+            }
+        }
+
+        NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 );
+
+        /* Scale short-term prediction and shaping states */
+        for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+            NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] );
+        }
+        for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+            NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] );
+        }
+    }
+}
diff --git a/third_party/opus/src/silk/NSQ.h b/third_party/opus/src/silk/NSQ.h
new file mode 100644
index 0000000..971832f6
--- /dev/null
+++ b/third_party/opus/src/silk/NSQ.h
@@ -0,0 +1,101 @@
+/***********************************************************************
+Copyright (c) 2014 Vidyo.
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+#ifndef SILK_NSQ_H
+#define SILK_NSQ_H
+
+#include "SigProc_FIX.h"
+
+#undef silk_short_prediction_create_arch_coef
+
+static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(const opus_int32 *buf32, const opus_int16 *coef16, opus_int order)
+{
+    opus_int32 out;
+    silk_assert( order == 10 || order == 16 );
+
+    /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+    out = silk_RSHIFT( order, 1 );
+    out = silk_SMLAWB( out, buf32[  0 ], coef16[ 0 ] );
+    out = silk_SMLAWB( out, buf32[ -1 ], coef16[ 1 ] );
+    out = silk_SMLAWB( out, buf32[ -2 ], coef16[ 2 ] );
+    out = silk_SMLAWB( out, buf32[ -3 ], coef16[ 3 ] );
+    out = silk_SMLAWB( out, buf32[ -4 ], coef16[ 4 ] );
+    out = silk_SMLAWB( out, buf32[ -5 ], coef16[ 5 ] );
+    out = silk_SMLAWB( out, buf32[ -6 ], coef16[ 6 ] );
+    out = silk_SMLAWB( out, buf32[ -7 ], coef16[ 7 ] );
+    out = silk_SMLAWB( out, buf32[ -8 ], coef16[ 8 ] );
+    out = silk_SMLAWB( out, buf32[ -9 ], coef16[ 9 ] );
+
+    if( order == 16 )
+    {
+        out = silk_SMLAWB( out, buf32[ -10 ], coef16[ 10 ] );
+        out = silk_SMLAWB( out, buf32[ -11 ], coef16[ 11 ] );
+        out = silk_SMLAWB( out, buf32[ -12 ], coef16[ 12 ] );
+        out = silk_SMLAWB( out, buf32[ -13 ], coef16[ 13 ] );
+        out = silk_SMLAWB( out, buf32[ -14 ], coef16[ 14 ] );
+        out = silk_SMLAWB( out, buf32[ -15 ], coef16[ 15 ] );
+    }
+    return out;
+}
+
+#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch)  ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
+
+static OPUS_INLINE opus_int32 silk_NSQ_noise_shape_feedback_loop_c(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
+{
+    opus_int32 out;
+    opus_int32 tmp1, tmp2;
+    opus_int j;
+
+    tmp2 = data0[0];
+    tmp1 = data1[0];
+    data1[0] = tmp2;
+
+    out = silk_RSHIFT(order, 1);
+    out = silk_SMLAWB(out, tmp2, coef[0]);
+
+    for (j = 2; j < order; j += 2) {
+        tmp2 = data1[j - 1];
+        data1[j - 1] = tmp1;
+        out = silk_SMLAWB(out, tmp1, coef[j - 1]);
+        tmp1 = data1[j + 0];
+        data1[j + 0] = tmp2;
+        out = silk_SMLAWB(out, tmp2, coef[j]);
+    }
+    data1[order - 1] = tmp1;
+    out = silk_SMLAWB(out, tmp1, coef[order - 1]);
+    /* Q11 -> Q12 */
+    out = silk_LSHIFT32( out, 1 );
+    return out;
+}
+
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch)  ((void)arch,silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order))
+
+#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+#include "arm/NSQ_neon.h"
+#endif
+
+#endif /* SILK_NSQ_H */
diff --git a/third_party/opus/src/silk/NSQ_del_dec.c b/third_party/opus/src/silk/NSQ_del_dec.c
new file mode 100644
index 0000000..ab6feeac
--- /dev/null
+++ b/third_party/opus/src/silk/NSQ_del_dec.c
@@ -0,0 +1,716 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "NSQ.h"
+
+
+typedef struct {
+    opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+    opus_int32 RandState[ DECISION_DELAY ];
+    opus_int32 Q_Q10[     DECISION_DELAY ];
+    opus_int32 Xq_Q14[    DECISION_DELAY ];
+    opus_int32 Pred_Q15[  DECISION_DELAY ];
+    opus_int32 Shape_Q14[ DECISION_DELAY ];
+    opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+    opus_int32 LF_AR_Q14;
+    opus_int32 Seed;
+    opus_int32 SeedInit;
+    opus_int32 RD_Q10;
+} NSQ_del_dec_struct;
+
+typedef struct {
+    opus_int32 Q_Q10;
+    opus_int32 RD_Q10;
+    opus_int32 xq_Q14;
+    opus_int32 LF_AR_Q14;
+    opus_int32 sLTP_shp_Q14;
+    opus_int32 LPC_exc_Q14;
+} NSQ_sample_struct;
+
+typedef NSQ_sample_struct  NSQ_sample_pair[ 2 ];
+
+#if defined(MIPSr1_ASM)
+#include "mips/NSQ_del_dec_mipsr1.h"
+#endif
+static OPUS_INLINE void silk_nsq_del_dec_scale_states(
+    const silk_encoder_state *psEncC,               /* I    Encoder State                       */
+    silk_nsq_state      *NSQ,                       /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],                 /* I/O  Delayed decision states             */
+    const opus_int32    x_Q3[],                     /* I    Input in Q3                         */
+    opus_int32          x_sc_Q10[],                 /* O    Input scaled with 1/Gain in Q10     */
+    const opus_int16    sLTP[],                     /* I    Re-whitened LTP state in Q0         */
+    opus_int32          sLTP_Q15[],                 /* O    LTP state matching scaled input     */
+    opus_int            subfr,                      /* I    Subframe number                     */
+    opus_int            nStatesDelayedDecision,     /* I    Number of del dec states            */
+    const opus_int      LTP_scale_Q14,              /* I    LTP state scaling                   */
+    const opus_int32    Gains_Q16[ MAX_NB_SUBFR ],  /* I                                        */
+    const opus_int      pitchL[ MAX_NB_SUBFR ],     /* I    Pitch lag                           */
+    const opus_int      signal_type,                /* I    Signal type                         */
+    const opus_int      decisionDelay               /* I    Decision delay                      */
+);
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],             /* I/O  Delayed decision states             */
+    opus_int            signalType,             /* I    Signal type                         */
+    const opus_int32    x_Q10[],                /* I                                        */
+    opus_int8           pulses[],               /* O                                        */
+    opus_int16          xq[],                   /* O                                        */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP filter state                    */
+    opus_int32          delayedGain_Q10[],      /* I/O  Gain delay buffer                   */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs         */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs          */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping coefs                 */
+    opus_int            lag,                    /* I    Pitch lag                           */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                        */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                       */
+    opus_int32          LF_shp_Q14,             /* I                                        */
+    opus_int32          Gain_Q16,               /* I                                        */
+    opus_int            Lambda_Q10,             /* I                                        */
+    opus_int            offset_Q10,             /* I                                        */
+    opus_int            length,                 /* I    Input length                        */
+    opus_int            subfr,                  /* I    Subframe number                     */
+    opus_int            shapingLPCOrder,        /* I    Shaping LPC filter order            */
+    opus_int            predictLPCOrder,        /* I    Prediction filter order             */
+    opus_int            warping_Q16,            /* I                                        */
+    opus_int            nStatesDelayedDecision, /* I    Number of states in decision tree   */
+    opus_int            *smpl_buf_idx,          /* I    Index to newest samples in buffers  */
+    opus_int            decisionDelay,          /* I                                        */
+    int                 arch                    /* I                                        */
+);
+
+void silk_NSQ_del_dec_c(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+)
+{
+    opus_int            i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr;
+    opus_int            last_smple_idx, smpl_buf_idx, decisionDelay;
+    const opus_int16    *A_Q12, *B_Q14, *AR_shp_Q13;
+    opus_int16          *pxq;
+    VARDECL( opus_int32, sLTP_Q15 );
+    VARDECL( opus_int16, sLTP );
+    opus_int32          HarmShapeFIRPacked_Q14;
+    opus_int            offset_Q10;
+    opus_int32          RDmin_Q10, Gain_Q10;
+    VARDECL( opus_int32, x_sc_Q10 );
+    VARDECL( opus_int32, delayedGain_Q10 );
+    VARDECL( NSQ_del_dec_struct, psDelDec );
+    NSQ_del_dec_struct  *psDD;
+    SAVE_STACK;
+
+    /* Set unvoiced lag to the previous one, overwrite later for voiced */
+    lag = NSQ->lagPrev;
+
+    silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+    /* Initialize delayed decision states */
+    ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct );
+    silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) );
+    for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) {
+        psDD                 = &psDelDec[ k ];
+        psDD->Seed           = ( k + psIndices->Seed ) & 3;
+        psDD->SeedInit       = psDD->Seed;
+        psDD->RD_Q10         = 0;
+        psDD->LF_AR_Q14      = NSQ->sLF_AR_shp_Q14;
+        psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ];
+        silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+        silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) );
+    }
+
+    offset_Q10   = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+    smpl_buf_idx = 0; /* index of oldest samples */
+
+    decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length );
+
+    /* For voiced frames limit the decision delay to lower than the pitch lag */
+    if( psIndices->signalType == TYPE_VOICED ) {
+        for( k = 0; k < psEncC->nb_subfr; k++ ) {
+            decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 );
+        }
+    } else {
+        if( lag > 0 ) {
+            decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 );
+        }
+    }
+
+    if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+        LSF_interpolation_flag = 0;
+    } else {
+        LSF_interpolation_flag = 1;
+    }
+
+    ALLOC( sLTP_Q15,
+           psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+    ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+    ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+    ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 );
+    /* Set up pointers to start of sub frame */
+    pxq                   = &NSQ->xq[ psEncC->ltp_mem_length ];
+    NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+    NSQ->sLTP_buf_idx     = psEncC->ltp_mem_length;
+    subfr = 0;
+    for( k = 0; k < psEncC->nb_subfr; k++ ) {
+        A_Q12      = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ];
+        B_Q14      = &LTPCoef_Q14[ k * LTP_ORDER           ];
+        AR_shp_Q13 = &AR2_Q13[     k * MAX_SHAPE_LPC_ORDER ];
+
+        /* Noise shape parameters */
+        silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+        HarmShapeFIRPacked_Q14  =                          silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+        HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+        NSQ->rewhite_flag = 0;
+        if( psIndices->signalType == TYPE_VOICED ) {
+            /* Voiced */
+            lag = pitchL[ k ];
+
+            /* Re-whitening */
+            if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+                if( k == 2 ) {
+                    /* RESET DELAYED DECISIONS */
+                    /* Find winner */
+                    RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+                    Winner_ind = 0;
+                    for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) {
+                        if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) {
+                            RDmin_Q10 = psDelDec[ i ].RD_Q10;
+                            Winner_ind = i;
+                        }
+                    }
+                    for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) {
+                        if( i != Winner_ind ) {
+                            psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 );
+                            silk_assert( psDelDec[ i ].RD_Q10 >= 0 );
+                        }
+                    }
+
+                    /* Copy final part of signals from winner state to output and long-term filter states */
+                    psDD = &psDelDec[ Winner_ind ];
+                    last_smple_idx = smpl_buf_idx + decisionDelay;
+                    for( i = 0; i < decisionDelay; i++ ) {
+                        last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+                        pulses[   i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+                        pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+                            silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) );
+                        NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+                    }
+
+                    subfr = 0;
+                }
+
+                /* Rewhiten with new A coefs */
+                start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+                silk_assert( start_idx > 0 );
+
+                silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+                    A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+                NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+                NSQ->rewhite_flag = 1;
+            }
+        }
+
+        silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k,
+            psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay );
+
+        silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15,
+            delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ],
+            Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder,
+            psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay, psEncC->arch );
+
+        x_Q3   += psEncC->subfr_length;
+        pulses += psEncC->subfr_length;
+        pxq    += psEncC->subfr_length;
+    }
+
+    /* Find winner */
+    RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+    Winner_ind = 0;
+    for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) {
+        if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) {
+            RDmin_Q10 = psDelDec[ k ].RD_Q10;
+            Winner_ind = k;
+        }
+    }
+
+    /* Copy final part of signals from winner state to output and long-term filter states */
+    psDD = &psDelDec[ Winner_ind ];
+    psIndices->Seed = psDD->SeedInit;
+    last_smple_idx = smpl_buf_idx + decisionDelay;
+    Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 );
+    for( i = 0; i < decisionDelay; i++ ) {
+        last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+        pulses[   i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+        pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+            silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) );
+        NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+    }
+    silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+    silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) );
+
+    /* Update states */
+    NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14;
+    NSQ->lagPrev        = pitchL[ psEncC->nb_subfr - 1 ];
+
+    /* Save quantized speech signal */
+    /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */
+    silk_memmove( NSQ->xq,           &NSQ->xq[           psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+    silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+    RESTORE_STACK;
+}
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+#ifndef OVERRIDE_silk_noise_shape_quantizer_del_dec
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],             /* I/O  Delayed decision states             */
+    opus_int            signalType,             /* I    Signal type                         */
+    const opus_int32    x_Q10[],                /* I                                        */
+    opus_int8           pulses[],               /* O                                        */
+    opus_int16          xq[],                   /* O                                        */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP filter state                    */
+    opus_int32          delayedGain_Q10[],      /* I/O  Gain delay buffer                   */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs         */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs          */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping coefs                 */
+    opus_int            lag,                    /* I    Pitch lag                           */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                        */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                       */
+    opus_int32          LF_shp_Q14,             /* I                                        */
+    opus_int32          Gain_Q16,               /* I                                        */
+    opus_int            Lambda_Q10,             /* I                                        */
+    opus_int            offset_Q10,             /* I                                        */
+    opus_int            length,                 /* I    Input length                        */
+    opus_int            subfr,                  /* I    Subframe number                     */
+    opus_int            shapingLPCOrder,        /* I    Shaping LPC filter order            */
+    opus_int            predictLPCOrder,        /* I    Prediction filter order             */
+    opus_int            warping_Q16,            /* I                                        */
+    opus_int            nStatesDelayedDecision, /* I    Number of states in decision tree   */
+    opus_int            *smpl_buf_idx,          /* I    Index to newest samples in buffers  */
+    opus_int            decisionDelay,          /* I                                        */
+    int                 arch                    /* I                                        */
+)
+{
+    opus_int     i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+    opus_int32   Winner_rand_state;
+    opus_int32   LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+    opus_int32   n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+    opus_int32   q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+    opus_int32   tmp1, tmp2, sLF_AR_shp_Q14;
+    opus_int32   *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
+#ifdef silk_short_prediction_create_arch_coef
+    opus_int32   a_Q12_arch[MAX_LPC_ORDER];
+#endif
+
+    VARDECL( NSQ_sample_pair, psSampleState );
+    NSQ_del_dec_struct *psDD;
+    NSQ_sample_struct  *psSS;
+    SAVE_STACK;
+
+    silk_assert( nStatesDelayedDecision > 0 );
+    ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair );
+
+    shp_lag_ptr  = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+    pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+    Gain_Q10     = silk_RSHIFT( Gain_Q16, 6 );
+
+#ifdef silk_short_prediction_create_arch_coef
+    silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder);
+#endif
+
+    for( i = 0; i < length; i++ ) {
+        /* Perform common calculations used in all states */
+
+        /* Long-term prediction */
+        if( signalType == TYPE_VOICED ) {
+            /* Unrolled loop */
+            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+            LTP_pred_Q14 = 2;
+            LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[  0 ], b_Q14[ 0 ] );
+            LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
+            LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
+            LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
+            LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+            LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 );                          /* Q13 -> Q14 */
+            pred_lag_ptr++;
+        } else {
+            LTP_pred_Q14 = 0;
+        }
+
+        /* Long-term shaping */
+        if( lag > 0 ) {
+            /* Symmetric, packed FIR coefficients */
+            n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+            n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ],                      HarmShapeFIRPacked_Q14 );
+            n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 );            /* Q12 -> Q14 */
+            shp_lag_ptr++;
+        } else {
+            n_LTP_Q14 = 0;
+        }
+
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            /* Delayed decision state */
+            psDD = &psDelDec[ k ];
+
+            /* Sample state */
+            psSS = psSampleState[ k ];
+
+            /* Generate dither */
+            psDD->Seed = silk_RAND( psDD->Seed );
+
+            /* Pointer used in short term prediction and shaping */
+            psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
+            /* Short-term prediction */
+            LPC_pred_Q14 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch);
+            LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 );                              /* Q10 -> Q14 */
+
+            /* Noise shape feedback */
+            silk_assert( ( shapingLPCOrder & 1 ) == 0 );   /* check that order is even */
+            /* Output of lowpass section */
+            tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 );
+            /* Output of allpass section */
+            tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 );
+            psDD->sAR2_Q14[ 0 ] = tmp2;
+            n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 );
+            n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] );
+            /* Loop over allpass sections */
+            for( j = 2; j < shapingLPCOrder; j += 2 ) {
+                /* Output of allpass section */
+                tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 );
+                psDD->sAR2_Q14[ j - 1 ] = tmp1;
+                n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] );
+                /* Output of allpass section */
+                tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 );
+                psDD->sAR2_Q14[ j + 0 ] = tmp2;
+                n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] );
+            }
+            psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+            n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+
+            n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 );                                      /* Q11 -> Q12 */
+            n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 );              /* Q12 */
+            n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 );                                      /* Q12 -> Q14 */
+
+            n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 );     /* Q12 */
+            n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 );            /* Q12 */
+            n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 );                                      /* Q12 -> Q14 */
+
+            /* Input minus prediction plus noise feedback                       */
+            /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP  */
+            tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 );                                    /* Q14 */
+            tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 );                               /* Q13 */
+            tmp1 = silk_SUB32( tmp2, tmp1 );                                            /* Q13 */
+            tmp1 = silk_RSHIFT_ROUND( tmp1, 4 );                                        /* Q10 */
+
+            r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 );                                     /* residual error Q10 */
+
+            /* Flip sign depending on dither */
+            if ( psDD->Seed < 0 ) {
+                r_Q10 = -r_Q10;
+            }
+            r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+            /* Find two quantization level candidates and measure their rate-distortion */
+            q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+            q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+            if( q1_Q0 > 0 ) {
+                q1_Q10  = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+                q1_Q10  = silk_ADD32( q1_Q10, offset_Q10 );
+                q2_Q10  = silk_ADD32( q1_Q10, 1024 );
+                rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+                rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+            } else if( q1_Q0 == 0 ) {
+                q1_Q10  = offset_Q10;
+                q2_Q10  = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+                rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+                rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+            } else if( q1_Q0 == -1 ) {
+                q2_Q10  = offset_Q10;
+                q1_Q10  = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+                rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+                rd2_Q10 = silk_SMULBB(  q2_Q10, Lambda_Q10 );
+            } else {            /* q1_Q0 < -1 */
+                q1_Q10  = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+                q1_Q10  = silk_ADD32( q1_Q10, offset_Q10 );
+                q2_Q10  = silk_ADD32( q1_Q10, 1024 );
+                rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+                rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+            }
+            rr_Q10  = silk_SUB32( r_Q10, q1_Q10 );
+            rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
+            rr_Q10  = silk_SUB32( r_Q10, q2_Q10 );
+            rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
+
+            if( rd1_Q10 < rd2_Q10 ) {
+                psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+                psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+                psSS[ 0 ].Q_Q10  = q1_Q10;
+                psSS[ 1 ].Q_Q10  = q2_Q10;
+            } else {
+                psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+                psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+                psSS[ 0 ].Q_Q10  = q2_Q10;
+                psSS[ 1 ].Q_Q10  = q1_Q10;
+            }
+
+            /* Update states for best quantization */
+
+            /* Quantized excitation */
+            exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
+            if ( psDD->Seed < 0 ) {
+                exc_Q14 = -exc_Q14;
+            }
+
+            /* Add predictions */
+            LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+            xq_Q14      = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+            /* Update states */
+            sLF_AR_shp_Q14         = silk_SUB32( xq_Q14, n_AR_Q14 );
+            psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+            psSS[ 0 ].LF_AR_Q14    = sLF_AR_shp_Q14;
+            psSS[ 0 ].LPC_exc_Q14  = LPC_exc_Q14;
+            psSS[ 0 ].xq_Q14       = xq_Q14;
+
+            /* Update states for second best quantization */
+
+            /* Quantized excitation */
+            exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
+            if ( psDD->Seed < 0 ) {
+                exc_Q14 = -exc_Q14;
+            }
+
+
+            /* Add predictions */
+            LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+            xq_Q14      = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+            /* Update states */
+            sLF_AR_shp_Q14         = silk_SUB32( xq_Q14, n_AR_Q14 );
+            psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+            psSS[ 1 ].LF_AR_Q14    = sLF_AR_shp_Q14;
+            psSS[ 1 ].LPC_exc_Q14  = LPC_exc_Q14;
+            psSS[ 1 ].xq_Q14       = xq_Q14;
+        }
+
+        *smpl_buf_idx  = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK;                   /* Index to newest samples              */
+        last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK;       /* Index to decisionDelay old samples   */
+
+        /* Find winner */
+        RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+        Winner_ind = 0;
+        for( k = 1; k < nStatesDelayedDecision; k++ ) {
+            if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
+                RDmin_Q10  = psSampleState[ k ][ 0 ].RD_Q10;
+                Winner_ind = k;
+            }
+        }
+
+        /* Increase RD values of expired states */
+        Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
+                psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
+                psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
+                silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
+            }
+        }
+
+        /* Find worst in first set and best in second set */
+        RDmax_Q10  = psSampleState[ 0 ][ 0 ].RD_Q10;
+        RDmin_Q10  = psSampleState[ 0 ][ 1 ].RD_Q10;
+        RDmax_ind = 0;
+        RDmin_ind = 0;
+        for( k = 1; k < nStatesDelayedDecision; k++ ) {
+            /* find worst in first set */
+            if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
+                RDmax_Q10  = psSampleState[ k ][ 0 ].RD_Q10;
+                RDmax_ind = k;
+            }
+            /* find best in second set */
+            if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
+                RDmin_Q10  = psSampleState[ k ][ 1 ].RD_Q10;
+                RDmin_ind = k;
+            }
+        }
+
+        /* Replace a state if best from second set outperforms worst in first set */
+        if( RDmin_Q10 < RDmax_Q10 ) {
+            silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
+                         ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
+            silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
+        }
+
+        /* Write samples from winner to output and long-term filter states */
+        psDD = &psDelDec[ Winner_ind ];
+        if( subfr > 0 || i >= decisionDelay ) {
+            pulses[  i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+            xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+                silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
+            NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
+            sLTP_Q15[          NSQ->sLTP_buf_idx     - decisionDelay ] = psDD->Pred_Q15[  last_smple_idx ];
+        }
+        NSQ->sLTP_shp_buf_idx++;
+        NSQ->sLTP_buf_idx++;
+
+        /* Update states */
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            psDD                                     = &psDelDec[ k ];
+            psSS                                     = &psSampleState[ k ][ 0 ];
+            psDD->LF_AR_Q14                          = psSS->LF_AR_Q14;
+            psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
+            psDD->Xq_Q14[    *smpl_buf_idx ]         = psSS->xq_Q14;
+            psDD->Q_Q10[     *smpl_buf_idx ]         = psSS->Q_Q10;
+            psDD->Pred_Q15[  *smpl_buf_idx ]         = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
+            psDD->Shape_Q14[ *smpl_buf_idx ]         = psSS->sLTP_shp_Q14;
+            psDD->Seed                               = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
+            psDD->RandState[ *smpl_buf_idx ]         = psDD->Seed;
+            psDD->RD_Q10                             = psSS->RD_Q10;
+        }
+        delayedGain_Q10[     *smpl_buf_idx ]         = Gain_Q10;
+    }
+    /* Update LPC states */
+    for( k = 0; k < nStatesDelayedDecision; k++ ) {
+        psDD = &psDelDec[ k ];
+        silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+    }
+    RESTORE_STACK;
+}
+#endif /* OVERRIDE_silk_noise_shape_quantizer_del_dec */
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states(
+    const silk_encoder_state *psEncC,               /* I    Encoder State                       */
+    silk_nsq_state      *NSQ,                       /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],                 /* I/O  Delayed decision states             */
+    const opus_int32    x_Q3[],                     /* I    Input in Q3                         */
+    opus_int32          x_sc_Q10[],                 /* O    Input scaled with 1/Gain in Q10     */
+    const opus_int16    sLTP[],                     /* I    Re-whitened LTP state in Q0         */
+    opus_int32          sLTP_Q15[],                 /* O    LTP state matching scaled input     */
+    opus_int            subfr,                      /* I    Subframe number                     */
+    opus_int            nStatesDelayedDecision,     /* I    Number of del dec states            */
+    const opus_int      LTP_scale_Q14,              /* I    LTP state scaling                   */
+    const opus_int32    Gains_Q16[ MAX_NB_SUBFR ],  /* I                                        */
+    const opus_int      pitchL[ MAX_NB_SUBFR ],     /* I    Pitch lag                           */
+    const opus_int      signal_type,                /* I    Signal type                         */
+    const opus_int      decisionDelay               /* I    Decision delay                      */
+)
+{
+    opus_int            i, k, lag;
+    opus_int32          gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+    NSQ_del_dec_struct  *psDD;
+
+    lag          = pitchL[ subfr ];
+    inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+    silk_assert( inv_gain_Q31 != 0 );
+
+    /* Calculate gain adjustment factor */
+    if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+        gain_adj_Q16 =  silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+    } else {
+        gain_adj_Q16 = (opus_int32)1 << 16;
+    }
+
+    /* Scale input */
+    inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+    for( i = 0; i < psEncC->subfr_length; i++ ) {
+        x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+    }
+
+    /* Save inverse gain */
+    NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+    /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+    if( NSQ->rewhite_flag ) {
+        if( subfr == 0 ) {
+            /* Do LTP downscaling */
+            inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+        }
+        for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+            silk_assert( i < MAX_FRAME_LENGTH );
+            sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+        }
+    }
+
+    /* Adjust for changing gain */
+    if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+        /* Scale long-term shaping state */
+        for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+            NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+        }
+
+        /* Scale long-term prediction state */
+        if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+            for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) {
+                sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+            }
+        }
+
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            psDD = &psDelDec[ k ];
+
+            /* Scale scalar states */
+            psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 );
+
+            /* Scale short-term prediction and shaping states */
+            for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+                psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] );
+            }
+            for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+                psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] );
+            }
+            for( i = 0; i < DECISION_DELAY; i++ ) {
+                psDD->Pred_Q15[  i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[  i ] );
+                psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] );
+            }
+        }
+    }
+}
diff --git a/third_party/opus/src/silk/PLC.c b/third_party/opus/src/silk/PLC.c
new file mode 100644
index 0000000..fb6ea88
--- /dev/null
+++ b/third_party/opus/src/silk/PLC.c
@@ -0,0 +1,446 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "PLC.h"
+
+#define NB_ATT 2
+static const opus_int16 HARM_ATT_Q15[NB_ATT]              = { 32440, 31130 }; /* 0.99, 0.95 */
+static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT]  = { 31130, 26214 }; /* 0.95, 0.8 */
+static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
+
+static OPUS_INLINE void silk_PLC_update(
+    silk_decoder_state                  *psDec,             /* I/O Decoder state        */
+    silk_decoder_control                *psDecCtrl          /* I/O Decoder control      */
+);
+
+static OPUS_INLINE void silk_PLC_conceal(
+    silk_decoder_state                  *psDec,             /* I/O Decoder state        */
+    silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
+    opus_int16                          frame[],            /* O LPC residual signal    */
+    int                                 arch                /* I  Run-time architecture */
+);
+
+
+void silk_PLC_Reset(
+    silk_decoder_state                  *psDec              /* I/O Decoder state        */
+)
+{
+    psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
+    psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
+    psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
+    psDec->sPLC.subfr_length = 20;
+    psDec->sPLC.nb_subfr = 2;
+}
+
+void silk_PLC(
+    silk_decoder_state                  *psDec,             /* I/O Decoder state        */
+    silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
+    opus_int16                          frame[],            /* I/O  signal              */
+    opus_int                            lost,               /* I Loss flag              */
+    int                                 arch                /* I Run-time architecture  */
+)
+{
+    /* PLC control function */
+    if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
+        silk_PLC_Reset( psDec );
+        psDec->sPLC.fs_kHz = psDec->fs_kHz;
+    }
+
+    if( lost ) {
+        /****************************/
+        /* Generate Signal          */
+        /****************************/
+        silk_PLC_conceal( psDec, psDecCtrl, frame, arch );
+
+        psDec->lossCnt++;
+    } else {
+        /****************************/
+        /* Update state             */
+        /****************************/
+        silk_PLC_update( psDec, psDecCtrl );
+    }
+}
+
+/**************************************************/
+/* Update state of PLC                            */
+/**************************************************/
+static OPUS_INLINE void silk_PLC_update(
+    silk_decoder_state                  *psDec,             /* I/O Decoder state        */
+    silk_decoder_control                *psDecCtrl          /* I/O Decoder control      */
+)
+{
+    opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
+    opus_int   i, j;
+    silk_PLC_struct *psPLC;
+
+    psPLC = &psDec->sPLC;
+
+    /* Update parameters used in case of packet loss */
+    psDec->prevSignalType = psDec->indices.signalType;
+    LTP_Gain_Q14 = 0;
+    if( psDec->indices.signalType == TYPE_VOICED ) {
+        /* Find the parameters for the last subframe which contains a pitch pulse */
+        for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
+            if( j == psDec->nb_subfr ) {
+                break;
+            }
+            temp_LTP_Gain_Q14 = 0;
+            for( i = 0; i < LTP_ORDER; i++ ) {
+                temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER  + i ];
+            }
+            if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
+                LTP_Gain_Q14 = temp_LTP_Gain_Q14;
+                silk_memcpy( psPLC->LTPCoef_Q14,
+                    &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
+                    LTP_ORDER * sizeof( opus_int16 ) );
+
+                psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
+            }
+        }
+
+        silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
+        psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
+
+        /* Limit LT coefs */
+        if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
+            opus_int   scale_Q10;
+            opus_int32 tmp;
+
+            tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
+            scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
+            for( i = 0; i < LTP_ORDER; i++ ) {
+                psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
+            }
+        } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
+            opus_int   scale_Q14;
+            opus_int32 tmp;
+
+            tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
+            scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
+            for( i = 0; i < LTP_ORDER; i++ ) {
+                psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
+            }
+        }
+    } else {
+        psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
+        silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
+    }
+
+    /* Save LPC coeficients */
+    silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
+    psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
+
+    /* Save last two gains */
+    silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
+
+    psPLC->subfr_length = psDec->subfr_length;
+    psPLC->nb_subfr = psDec->nb_subfr;
+}
+
+static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2,
+      const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr)
+{
+    int i, k;
+    VARDECL( opus_int16, exc_buf );
+    opus_int16 *exc_buf_ptr;
+    SAVE_STACK;
+    ALLOC( exc_buf, 2*subfr_length, opus_int16 );
+    /* Find random noise component */
+    /* Scale previous excitation signal */
+    exc_buf_ptr = exc_buf;
+    for( k = 0; k < 2; k++ ) {
+        for( i = 0; i < subfr_length; i++ ) {
+            exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT(
+                silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) );
+        }
+        exc_buf_ptr += subfr_length;
+    }
+    /* Find the subframe with lowest energy of the last two and use that as random noise generator */
+    silk_sum_sqr_shift( energy1, shift1, exc_buf,                  subfr_length );
+    silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length );
+    RESTORE_STACK;
+}
+
+static OPUS_INLINE void silk_PLC_conceal(
+    silk_decoder_state                  *psDec,             /* I/O Decoder state        */
+    silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
+    opus_int16                          frame[],            /* O LPC residual signal    */
+    int                                 arch                /* I Run-time architecture  */
+)
+{
+    opus_int   i, j, k;
+    opus_int   lag, idx, sLTP_buf_idx, shift1, shift2;
+    opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
+    opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
+    opus_int32 LPC_pred_Q10, LTP_pred_Q12;
+    opus_int16 rand_scale_Q14;
+    opus_int16 *B_Q14;
+    opus_int32 *sLPC_Q14_ptr;
+    opus_int16 A_Q12[ MAX_LPC_ORDER ];
+#ifdef SMALL_FOOTPRINT
+    opus_int16 *sLTP;
+#else
+    VARDECL( opus_int16, sLTP );
+#endif
+    VARDECL( opus_int32, sLTP_Q14 );
+    silk_PLC_struct *psPLC = &psDec->sPLC;
+    opus_int32 prevGain_Q10[2];
+    SAVE_STACK;
+
+    ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
+#ifdef SMALL_FOOTPRINT
+    /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */
+    sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length;
+#else
+    ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
+#endif
+
+    prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6);
+    prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6);
+
+    if( psDec->first_frame_after_reset ) {
+       silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) );
+    }
+
+    silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr);
+
+    if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
+        /* First sub-frame has lowest energy */
+        rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
+    } else {
+        /* Second sub-frame has lowest energy */
+        rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
+    }
+
+    /* Set up Gain to random noise component */
+    B_Q14          = psPLC->LTPCoef_Q14;
+    rand_scale_Q14 = psPLC->randScale_Q14;
+
+    /* Set up attenuation gains */
+    harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+    if( psDec->prevSignalType == TYPE_VOICED ) {
+        rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[  silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+    } else {
+        rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+    }
+
+    /* LPC concealment. Apply BWE to previous LPC */
+    silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
+
+    /* Preload LPC coeficients to array on stack. Gives small performance gain */
+    silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
+
+    /* First Lost frame */
+    if( psDec->lossCnt == 0 ) {
+        rand_scale_Q14 = 1 << 14;
+
+        /* Reduce random noise Gain for voiced frames */
+        if( psDec->prevSignalType == TYPE_VOICED ) {
+            for( i = 0; i < LTP_ORDER; i++ ) {
+                rand_scale_Q14 -= B_Q14[ i ];
+            }
+            rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
+            rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
+        } else {
+            /* Reduce random noise for unvoiced frames with high LPC gain */
+            opus_int32 invGain_Q30, down_scale_Q30;
+
+            invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order );
+
+            down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
+            down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
+            down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
+
+            rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
+        }
+    }
+
+    rand_seed    = psPLC->rand_seed;
+    lag          = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
+    sLTP_buf_idx = psDec->ltp_mem_length;
+
+    /* Rewhiten LTP state */
+    idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
+    silk_assert( idx > 0 );
+    silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch );
+    /* Scale LTP state */
+    inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
+    inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
+    for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
+        sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
+    }
+
+    /***************************/
+    /* LTP synthesis filtering */
+    /***************************/
+    for( k = 0; k < psDec->nb_subfr; k++ ) {
+        /* Set up pointer */
+        pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+        for( i = 0; i < psDec->subfr_length; i++ ) {
+            /* Unrolled loop */
+            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+            LTP_pred_Q12 = 2;
+            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[  0 ], B_Q14[ 0 ] );
+            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
+            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
+            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
+            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
+            pred_lag_ptr++;
+
+            /* Generate LPC excitation */
+            rand_seed = silk_RAND( rand_seed );
+            idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
+            sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
+            sLTP_buf_idx++;
+        }
+
+        /* Gradually reduce LTP gain */
+        for( j = 0; j < LTP_ORDER; j++ ) {
+            B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
+        }
+        /* Gradually reduce excitation gain */
+        rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
+
+        /* Slowly increase pitch lag */
+        psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
+        psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
+        lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
+    }
+
+    /***************************/
+    /* LPC synthesis filtering */
+    /***************************/
+    sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
+
+    /* Copy LPC state */
+    silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+    silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
+    for( i = 0; i < psDec->frame_length; i++ ) {
+        /* partly unrolled */
+        /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+        LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
+        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
+        for( j = 10; j < psDec->LPC_order; j++ ) {
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
+        }
+
+        /* Add prediction to LPC excitation */
+        sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ],
+                                            silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ));
+
+        /* Scale with Gain */
+        frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );
+    }
+
+    /* Save LPC state */
+    silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+    /**************************************/
+    /* Update states                      */
+    /**************************************/
+    psPLC->rand_seed     = rand_seed;
+    psPLC->randScale_Q14 = rand_scale_Q14;
+    for( i = 0; i < MAX_NB_SUBFR; i++ ) {
+        psDecCtrl->pitchL[ i ] = lag;
+    }
+    RESTORE_STACK;
+}
+
+/* Glues concealed frames with new good received frames */
+void silk_PLC_glue_frames(
+    silk_decoder_state                  *psDec,             /* I/O decoder state        */
+    opus_int16                          frame[],            /* I/O signal               */
+    opus_int                            length              /* I length of signal       */
+)
+{
+    opus_int   i, energy_shift;
+    opus_int32 energy;
+    silk_PLC_struct *psPLC;
+    psPLC = &psDec->sPLC;
+
+    if( psDec->lossCnt ) {
+        /* Calculate energy in concealed residual */
+        silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
+
+        psPLC->last_frame_lost = 1;
+    } else {
+        if( psDec->sPLC.last_frame_lost ) {
+            /* Calculate residual in decoded signal if last frame was lost */
+            silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
+
+            /* Normalize energies */
+            if( energy_shift > psPLC->conc_energy_shift ) {
+                psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
+            } else if( energy_shift < psPLC->conc_energy_shift ) {
+                energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
+            }
+
+            /* Fade in the energy difference */
+            if( energy > psPLC->conc_energy ) {
+                opus_int32 frac_Q24, LZ;
+                opus_int32 gain_Q16, slope_Q16;
+
+                LZ = silk_CLZ32( psPLC->conc_energy );
+                LZ = LZ - 1;
+                psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
+                energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
+
+                frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
+
+                gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
+                slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
+                /* Make slope 4x steeper to avoid missing onsets after DTX */
+                slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
+
+                for( i = 0; i < length; i++ ) {
+                    frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
+                    gain_Q16 += slope_Q16;
+                    if( gain_Q16 > (opus_int32)1 << 16 ) {
+                        break;
+                    }
+                }
+            }
+        }
+        psPLC->last_frame_lost = 0;
+    }
+}
diff --git a/third_party/opus/src/silk/PLC.h b/third_party/opus/src/silk/PLC.h
new file mode 100644
index 0000000..6438f51
--- /dev/null
+++ b/third_party/opus/src/silk/PLC.h
@@ -0,0 +1,62 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_PLC_H
+#define SILK_PLC_H
+
+#include "main.h"
+
+#define BWE_COEF                        0.99
+#define V_PITCH_GAIN_START_MIN_Q14      11469               /* 0.7 in Q14               */
+#define V_PITCH_GAIN_START_MAX_Q14      15565               /* 0.95 in Q14              */
+#define MAX_PITCH_LAG_MS                18
+#define RAND_BUF_SIZE                   128
+#define RAND_BUF_MASK                   ( RAND_BUF_SIZE - 1 )
+#define LOG2_INV_LPC_GAIN_HIGH_THRES    3                   /* 2^3 = 8 dB LPC gain      */
+#define LOG2_INV_LPC_GAIN_LOW_THRES     8                   /* 2^8 = 24 dB LPC gain     */
+#define PITCH_DRIFT_FAC_Q16             655                 /* 0.01 in Q16              */
+
+void silk_PLC_Reset(
+    silk_decoder_state                  *psDec              /* I/O Decoder state        */
+);
+
+void silk_PLC(
+    silk_decoder_state                  *psDec,             /* I/O Decoder state        */
+    silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
+    opus_int16                          frame[],            /* I/O  signal              */
+    opus_int                            lost,               /* I Loss flag              */
+    int                                 arch                /* I Run-time architecture  */
+);
+
+void silk_PLC_glue_frames(
+    silk_decoder_state                  *psDec,             /* I/O decoder state        */
+    opus_int16                          frame[],            /* I/O signal               */
+    opus_int                            length              /* I length of signal       */
+);
+
+#endif
+
diff --git a/third_party/opus/src/silk/SigProc_FIX.h b/third_party/opus/src/silk/SigProc_FIX.h
new file mode 100644
index 0000000..b632994
--- /dev/null
+++ b/third_party/opus/src/silk/SigProc_FIX.h
@@ -0,0 +1,615 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_H
+#define SILK_SIGPROC_FIX_H
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+/*#define silk_MACRO_COUNT */          /* Used to enable WMOPS counting */
+
+#define SILK_MAX_ORDER_LPC            16            /* max order of the LPC analysis in schur() and k2a() */
+
+#include <string.h>                                 /* for memset(), memcpy(), memmove() */
+#include "typedef.h"
+#include "resampler_structs.h"
+#include "macros.h"
+#include "cpu_support.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#include "x86/SigProc_FIX_sse.h"
+#endif
+
+/********************************************************************/
+/*                    SIGNAL PROCESSING FUNCTIONS                   */
+/********************************************************************/
+
+/*!
+ * Initialize/reset the resampler state for a given pair of input/output sampling rates
+*/
+opus_int silk_resampler_init(
+    silk_resampler_state_struct *S,                 /* I/O  Resampler state                                             */
+    opus_int32                  Fs_Hz_in,           /* I    Input sampling rate (Hz)                                    */
+    opus_int32                  Fs_Hz_out,          /* I    Output sampling rate (Hz)                                   */
+    opus_int                    forEnc              /* I    If 1: encoder; if 0: decoder                                */
+);
+
+/*!
+ * Resampler: convert from one sampling rate to another
+ */
+opus_int silk_resampler(
+    silk_resampler_state_struct *S,                 /* I/O  Resampler state                                             */
+    opus_int16                  out[],              /* O    Output signal                                               */
+    const opus_int16            in[],               /* I    Input signal                                                */
+    opus_int32                  inLen               /* I    Number of input samples                                     */
+);
+
+/*!
+* Downsample 2x, mediocre quality
+*/
+void silk_resampler_down2(
+    opus_int32                  *S,                 /* I/O  State vector [ 2 ]                                          */
+    opus_int16                  *out,               /* O    Output signal [ len ]                                       */
+    const opus_int16            *in,                /* I    Input signal [ floor(len/2) ]                               */
+    opus_int32                  inLen               /* I    Number of input samples                                     */
+);
+
+/*!
+ * Downsample by a factor 2/3, low quality
+*/
+void silk_resampler_down2_3(
+    opus_int32                  *S,                 /* I/O  State vector [ 6 ]                                          */
+    opus_int16                  *out,               /* O    Output signal [ floor(2*inLen/3) ]                          */
+    const opus_int16            *in,                /* I    Input signal [ inLen ]                                      */
+    opus_int32                  inLen               /* I    Number of input samples                                     */
+);
+
+/*!
+ * second order ARMA filter;
+ * slower than biquad() but uses more precise coefficients
+ * can handle (slowly) varying coefficients
+ */
+void silk_biquad_alt(
+    const opus_int16            *in,                /* I     input signal                                               */
+    const opus_int32            *B_Q28,             /* I     MA coefficients [3]                                        */
+    const opus_int32            *A_Q28,             /* I     AR coefficients [2]                                        */
+    opus_int32                  *S,                 /* I/O   State vector [2]                                           */
+    opus_int16                  *out,               /* O     output signal                                              */
+    const opus_int32            len,                /* I     signal length (must be even)                               */
+    opus_int                    stride              /* I     Operate on interleaved signal if > 1                       */
+);
+
+/* Variable order MA prediction error filter. */
+void silk_LPC_analysis_filter(
+    opus_int16                  *out,               /* O    Output signal                                               */
+    const opus_int16            *in,                /* I    Input signal                                                */
+    const opus_int16            *B,                 /* I    MA prediction coefficients, Q12 [order]                     */
+    const opus_int32            len,                /* I    Signal length                                               */
+    const opus_int32            d,                  /* I    Filter order                                                */
+    int                         arch                /* I    Run-time architecture                                       */
+);
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander(
+    opus_int16                  *ar,                /* I/O  AR filter to be expanded (without leading 1)                */
+    const opus_int              d,                  /* I    Length of ar                                                */
+    opus_int32                  chirp_Q16           /* I    Chirp factor (typically in the range 0 to 1)                */
+);
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander_32(
+    opus_int32                  *ar,                /* I/O  AR filter to be expanded (without leading 1)                */
+    const opus_int              d,                  /* I    Length of ar                                                */
+    opus_int32                  chirp_Q16           /* I    Chirp factor in Q16                                         */
+);
+
+/* Compute inverse of LPC prediction gain, and                           */
+/* test if LPC coefficients are stable (all poles within unit circle)    */
+opus_int32 silk_LPC_inverse_pred_gain(              /* O   Returns inverse prediction gain in energy domain, Q30        */
+    const opus_int16            *A_Q12,             /* I   Prediction coefficients, Q12 [order]                         */
+    const opus_int              order               /* I   Prediction order                                             */
+);
+
+/* For input in Q24 domain */
+opus_int32 silk_LPC_inverse_pred_gain_Q24(          /* O    Returns inverse prediction gain in energy domain, Q30       */
+    const opus_int32            *A_Q24,             /* I    Prediction coefficients [order]                             */
+    const opus_int              order               /* I    Prediction order                                            */
+);
+
+/* Split signal in two decimated bands using first-order allpass filters */
+void silk_ana_filt_bank_1(
+    const opus_int16            *in,                /* I    Input signal [N]                                            */
+    opus_int32                  *S,                 /* I/O  State vector [2]                                            */
+    opus_int16                  *outL,              /* O    Low band [N/2]                                              */
+    opus_int16                  *outH,              /* O    High band [N/2]                                             */
+    const opus_int32            N                   /* I    Number of input samples                                     */
+);
+
+/********************************************************************/
+/*                        SCALAR FUNCTIONS                          */
+/********************************************************************/
+
+/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */
+/* Convert input to a log scale    */
+opus_int32 silk_lin2log(
+    const opus_int32            inLin               /* I  input in linear scale                                         */
+);
+
+/* Approximation of a sigmoid function */
+opus_int silk_sigm_Q15(
+    opus_int                    in_Q5               /* I                                                                */
+);
+
+/* Approximation of 2^() (exact inverse of approx log2() above) */
+/* Convert input to a linear scale */
+opus_int32 silk_log2lin(
+    const opus_int32            inLog_Q7            /* I  input on log scale                                            */
+);
+
+/* Compute number of bits to right shift the sum of squares of a vector    */
+/* of int16s to make it fit in an int32                                    */
+void silk_sum_sqr_shift(
+    opus_int32                  *energy,            /* O   Energy of x, after shifting to the right                     */
+    opus_int                    *shift,             /* O   Number of bits right shift applied to energy                 */
+    const opus_int16            *x,                 /* I   Input vector                                                 */
+    opus_int                    len                 /* I   Length of input vector                                       */
+);
+
+/* Calculates the reflection coefficients from the correlation sequence    */
+/* Faster than schur64(), but much less accurate.                          */
+/* uses SMLAWB(), requiring armv5E and higher.                             */
+opus_int32 silk_schur(                              /* O    Returns residual energy                                     */
+    opus_int16                  *rc_Q15,            /* O    reflection coefficients [order] Q15                         */
+    const opus_int32            *c,                 /* I    correlations [order+1]                                      */
+    const opus_int32            order               /* I    prediction order                                            */
+);
+
+/* Calculates the reflection coefficients from the correlation sequence    */
+/* Slower than schur(), but more accurate.                                 */
+/* Uses SMULL(), available on armv4                                        */
+opus_int32 silk_schur64(                            /* O    returns residual energy                                     */
+    opus_int32                  rc_Q16[],           /* O    Reflection coefficients [order] Q16                         */
+    const opus_int32            c[],                /* I    Correlations [order+1]                                      */
+    opus_int32                  order               /* I    Prediction order                                            */
+);
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a(
+    opus_int32                  *A_Q24,             /* O    Prediction coefficients [order] Q24                         */
+    const opus_int16            *rc_Q15,            /* I    Reflection coefficients [order] Q15                         */
+    const opus_int32            order               /* I    Prediction order                                            */
+);
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_Q16(
+    opus_int32                  *A_Q24,             /* O    Prediction coefficients [order] Q24                         */
+    const opus_int32            *rc_Q16,            /* I    Reflection coefficients [order] Q16                         */
+    const opus_int32            order               /* I    Prediction order                                            */
+);
+
+/* Apply sine window to signal vector.                              */
+/* Window types:                                                    */
+/*    1 -> sine window from 0 to pi/2                               */
+/*    2 -> sine window from pi/2 to pi                              */
+/* every other sample of window is linearly interpolated, for speed */
+void silk_apply_sine_window(
+    opus_int16                  px_win[],           /* O    Pointer to windowed signal                                  */
+    const opus_int16            px[],               /* I    Pointer to input signal                                     */
+    const opus_int              win_type,           /* I    Selects a window type                                       */
+    const opus_int              length              /* I    Window length, multiple of 4                                */
+);
+
+/* Compute autocorrelation */
+void silk_autocorr(
+    opus_int32                  *results,           /* O    Result (length correlationCount)                            */
+    opus_int                    *scale,             /* O    Scaling of the correlation vector                           */
+    const opus_int16            *inputData,         /* I    Input data to correlate                                     */
+    const opus_int              inputDataSize,      /* I    Length of input                                             */
+    const opus_int              correlationCount,   /* I    Number of correlation taps to compute                       */
+    int                         arch                /* I    Run-time architecture                                       */
+);
+
+void silk_decode_pitch(
+    opus_int16                  lagIndex,           /* I                                                                */
+    opus_int8                   contourIndex,       /* O                                                                */
+    opus_int                    pitch_lags[],       /* O    4 pitch values                                              */
+    const opus_int              Fs_kHz,             /* I    sampling frequency (kHz)                                    */
+    const opus_int              nb_subfr            /* I    number of sub frames                                        */
+);
+
+opus_int silk_pitch_analysis_core(                  /* O    Voicing estimate: 0 voiced, 1 unvoiced                      */
+    const opus_int16            *frame,             /* I    Signal of length PE_FRAME_LENGTH_MS*Fs_kHz                  */
+    opus_int                    *pitch_out,         /* O    4 pitch lag values                                          */
+    opus_int16                  *lagIndex,          /* O    Lag Index                                                   */
+    opus_int8                   *contourIndex,      /* O    Pitch contour Index                                         */
+    opus_int                    *LTPCorr_Q15,       /* I/O  Normalized correlation; input: value from previous frame    */
+    opus_int                    prevLag,            /* I    Last lag of previous frame; set to zero is unvoiced         */
+    const opus_int32            search_thres1_Q16,  /* I    First stage threshold for lag candidates 0 - 1              */
+    const opus_int              search_thres2_Q13,  /* I    Final threshold for lag candidates 0 - 1                    */
+    const opus_int              Fs_kHz,             /* I    Sample frequency (kHz)                                      */
+    const opus_int              complexity,         /* I    Complexity setting, 0-2, where 2 is highest                 */
+    const opus_int              nb_subfr,           /* I    number of 5 ms subframes                                    */
+    int                         arch                /* I    Run-time architecture                                       */
+);
+
+/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients      */
+/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
+void silk_A2NLSF(
+    opus_int16                  *NLSF,              /* O    Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
+    opus_int32                  *a_Q16,             /* I/O  Monic whitening filter coefficients in Q16 [d]              */
+    const opus_int              d                   /* I    Filter order (must be even)                                 */
+);
+
+/* compute whitening filter coefficients from normalized line spectral frequencies */
+void silk_NLSF2A(
+    opus_int16                  *a_Q12,             /* O    monic whitening filter coefficients in Q12,  [ d ]          */
+    const opus_int16            *NLSF,              /* I    normalized line spectral frequencies in Q15, [ d ]          */
+    const opus_int              d                   /* I    filter order (should be even)                               */
+);
+
+void silk_insertion_sort_increasing(
+    opus_int32                  *a,                 /* I/O   Unsorted / Sorted vector                                   */
+    opus_int                    *idx,               /* O     Index vector for the sorted elements                       */
+    const opus_int              L,                  /* I     Vector length                                              */
+    const opus_int              K                   /* I     Number of correctly sorted positions                       */
+);
+
+void silk_insertion_sort_decreasing_int16(
+    opus_int16                  *a,                 /* I/O   Unsorted / Sorted vector                                   */
+    opus_int                    *idx,               /* O     Index vector for the sorted elements                       */
+    const opus_int              L,                  /* I     Vector length                                              */
+    const opus_int              K                   /* I     Number of correctly sorted positions                       */
+);
+
+void silk_insertion_sort_increasing_all_values_int16(
+     opus_int16                 *a,                 /* I/O   Unsorted / Sorted vector                                   */
+     const opus_int             L                   /* I     Vector length                                              */
+);
+
+/* NLSF stabilizer, for a single input data vector */
+void silk_NLSF_stabilize(
+          opus_int16            *NLSF_Q15,          /* I/O   Unstable/stabilized normalized LSF vector in Q15 [L]       */
+    const opus_int16            *NDeltaMin_Q15,     /* I     Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1]   */
+    const opus_int              L                   /* I     Number of NLSF parameters in the input vector              */
+);
+
+/* Laroia low complexity NLSF weights */
+void silk_NLSF_VQ_weights_laroia(
+    opus_int16                  *pNLSFW_Q_OUT,      /* O     Pointer to input vector weights [D]                        */
+    const opus_int16            *pNLSF_Q15,         /* I     Pointer to input vector         [D]                        */
+    const opus_int              D                   /* I     Input vector dimension (even)                              */
+);
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified_c(
+    opus_int32                  *res_nrg,           /* O    Residual energy                                             */
+    opus_int                    *res_nrg_Q,         /* O    Residual energy Q value                                     */
+    opus_int32                  A_Q16[],            /* O    Prediction coefficients (length order)                      */
+    const opus_int16            x[],                /* I    Input signal, length: nb_subfr * ( D + subfr_length )       */
+    const opus_int32            minInvGain_Q30,     /* I    Inverse of max prediction gain                              */
+    const opus_int              subfr_length,       /* I    Input signal subframe length (incl. D preceding samples)    */
+    const opus_int              nb_subfr,           /* I    Number of subframes stacked in x                            */
+    const opus_int              D,                  /* I    Order                                                       */
+    int                         arch                /* I    Run-time architecture                                       */
+);
+
+/* Copy and multiply a vector by a constant */
+void silk_scale_copy_vector16(
+    opus_int16                  *data_out,
+    const opus_int16            *data_in,
+    opus_int32                  gain_Q16,           /* I    Gain in Q16                                                 */
+    const opus_int              dataSize            /* I    Length                                                      */
+);
+
+/* Some for the LTP related function requires Q26 to work.*/
+void silk_scale_vector32_Q26_lshift_18(
+    opus_int32                  *data1,             /* I/O  Q0/Q18                                                      */
+    opus_int32                  gain_Q26,           /* I    Q26                                                         */
+    opus_int                    dataSize            /* I    length                                                      */
+);
+
+/********************************************************************/
+/*                        INLINE ARM MATH                           */
+/********************************************************************/
+
+/*    return sum( inVec1[i] * inVec2[i] ) */
+
+opus_int32 silk_inner_prod_aligned(
+    const opus_int16 *const     inVec1,             /*    I input vector 1                                              */
+    const opus_int16 *const     inVec2,             /*    I input vector 2                                              */
+    const opus_int              len,                /*    I vector lengths                                              */
+    int                         arch                /*    I Run-time architecture                                       */
+);
+
+
+opus_int32 silk_inner_prod_aligned_scale(
+    const opus_int16 *const     inVec1,             /*    I input vector 1                                              */
+    const opus_int16 *const     inVec2,             /*    I input vector 2                                              */
+    const opus_int              scale,              /*    I number of bits to shift                                     */
+    const opus_int              len                 /*    I vector lengths                                              */
+);
+
+opus_int64 silk_inner_prod16_aligned_64_c(
+    const opus_int16            *inVec1,            /*    I input vector 1                                              */
+    const opus_int16            *inVec2,            /*    I input vector 2                                              */
+    const opus_int              len                 /*    I vector lengths                                              */
+);
+
+/********************************************************************/
+/*                                MACROS                            */
+/********************************************************************/
+
+/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating
+   left. Output is 32bit int.
+   Note: contemporary compilers recognize the C expression below and
+   compile it into a 'ror' instruction if available. No need for OPUS_INLINE ASM! */
+static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot )
+{
+    opus_uint32 x = (opus_uint32) a32;
+    opus_uint32 r = (opus_uint32) rot;
+    opus_uint32 m = (opus_uint32) -rot;
+    if( rot == 0 ) {
+        return a32;
+    } else if( rot < 0 ) {
+        return (opus_int32) ((x << m) | (x >> (32 - m)));
+    } else {
+        return (opus_int32) ((x << (32 - r)) | (x >> r));
+    }
+}
+
+/* Allocate opus_int16 aligned to 4-byte memory address */
+#if EMBEDDED_ARM
+#define silk_DWORD_ALIGN __attribute__((aligned(4)))
+#else
+#define silk_DWORD_ALIGN
+#endif
+
+/* Useful Macros that can be adjusted to other platforms */
+#define silk_memcpy(dest, src, size)        memcpy((dest), (src), (size))
+#define silk_memset(dest, src, size)        memset((dest), (src), (size))
+#define silk_memmove(dest, src, size)       memmove((dest), (src), (size))
+
+/* Fixed point macros */
+
+/* (a32 * b32) output have to be 32bit int */
+#define silk_MUL(a32, b32)                  ((a32) * (b32))
+
+/* (a32 * b32) output have to be 32bit uint */
+#define silk_MUL_uint(a32, b32)             silk_MUL(a32, b32)
+
+/* a32 + (b32 * c32) output have to be 32bit int */
+#define silk_MLA(a32, b32, c32)             silk_ADD32((a32),((b32) * (c32)))
+
+/* a32 + (b32 * c32) output have to be 32bit uint */
+#define silk_MLA_uint(a32, b32, c32)        silk_MLA(a32, b32, c32)
+
+/* ((a32 >> 16)  * (b32 >> 16)) output have to be 32bit int */
+#define silk_SMULTT(a32, b32)               (((a32) >> 16) * ((b32) >> 16))
+
+/* a32 + ((a32 >> 16)  * (b32 >> 16)) output have to be 32bit int */
+#define silk_SMLATT(a32, b32, c32)          silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16))
+
+#define silk_SMLALBB(a64, b16, c16)         silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16)))
+
+/* (a32 * b32) */
+#define silk_SMULL(a32, b32)                ((opus_int64)(a32) * /*(opus_int64)*/(b32))
+
+/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
+   (just standard two's complement implementation-specific behaviour) */
+#define silk_ADD32_ovflw(a, b)              ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b)))
+/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
+   (just standard two's complement implementation-specific behaviour) */
+#define silk_SUB32_ovflw(a, b)              ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b)))
+
+/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */
+#define silk_MLA_ovflw(a32, b32, c32)       silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32))
+#define silk_SMLABB_ovflw(a32, b32, c32)    (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))))
+
+#define silk_DIV32_16(a32, b16)             ((opus_int32)((a32) / (b16)))
+#define silk_DIV32(a32, b32)                ((opus_int32)((a32) / (b32)))
+
+/* These macros enables checking for overflow in silk_API_Debug.h*/
+#define silk_ADD16(a, b)                    ((a) + (b))
+#define silk_ADD32(a, b)                    ((a) + (b))
+#define silk_ADD64(a, b)                    ((a) + (b))
+
+#define silk_SUB16(a, b)                    ((a) - (b))
+#define silk_SUB32(a, b)                    ((a) - (b))
+#define silk_SUB64(a, b)                    ((a) - (b))
+
+#define silk_SAT8(a)                        ((a) > silk_int8_MAX ? silk_int8_MAX  :       \
+                                            ((a) < silk_int8_MIN ? silk_int8_MIN  : (a)))
+#define silk_SAT16(a)                       ((a) > silk_int16_MAX ? silk_int16_MAX :      \
+                                            ((a) < silk_int16_MIN ? silk_int16_MIN : (a)))
+#define silk_SAT32(a)                       ((a) > silk_int32_MAX ? silk_int32_MAX :      \
+                                            ((a) < silk_int32_MIN ? silk_int32_MIN : (a)))
+
+#define silk_CHECK_FIT8(a)                  (a)
+#define silk_CHECK_FIT16(a)                 (a)
+#define silk_CHECK_FIT32(a)                 (a)
+
+#define silk_ADD_SAT16(a, b)                (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) )
+#define silk_ADD_SAT64(a, b)                ((((a) + (b)) & 0x8000000000000000LL) == 0 ?                            \
+                                            ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \
+                                            ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) )
+
+#define silk_SUB_SAT16(a, b)                (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) )
+#define silk_SUB_SAT64(a, b)                ((((a)-(b)) & 0x8000000000000000LL) == 0 ?                                               \
+                                            (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \
+                                            ((((a)^0x8000000000000000LL) & (b)  & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) )
+
+/* Saturation for positive input values */
+#define silk_POS_SAT32(a)                   ((a) > silk_int32_MAX ? silk_int32_MAX : (a))
+
+/* Add with saturation for positive input values */
+#define silk_ADD_POS_SAT8(a, b)             ((((a)+(b)) & 0x80)                 ? silk_int8_MAX  : ((a)+(b)))
+#define silk_ADD_POS_SAT16(a, b)            ((((a)+(b)) & 0x8000)               ? silk_int16_MAX : ((a)+(b)))
+#define silk_ADD_POS_SAT32(a, b)            ((((a)+(b)) & 0x80000000)           ? silk_int32_MAX : ((a)+(b)))
+#define silk_ADD_POS_SAT64(a, b)            ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)))
+
+#define silk_LSHIFT8(a, shift)              ((opus_int8)((opus_uint8)(a)<<(shift)))         /* shift >= 0, shift < 8  */
+#define silk_LSHIFT16(a, shift)             ((opus_int16)((opus_uint16)(a)<<(shift)))       /* shift >= 0, shift < 16 */
+#define silk_LSHIFT32(a, shift)             ((opus_int32)((opus_uint32)(a)<<(shift)))       /* shift >= 0, shift < 32 */
+#define silk_LSHIFT64(a, shift)             ((opus_int64)((opus_uint64)(a)<<(shift)))       /* shift >= 0, shift < 64 */
+#define silk_LSHIFT(a, shift)               silk_LSHIFT32(a, shift)                         /* shift >= 0, shift < 32 */
+
+#define silk_RSHIFT8(a, shift)              ((a)>>(shift))                                  /* shift >= 0, shift < 8  */
+#define silk_RSHIFT16(a, shift)             ((a)>>(shift))                                  /* shift >= 0, shift < 16 */
+#define silk_RSHIFT32(a, shift)             ((a)>>(shift))                                  /* shift >= 0, shift < 32 */
+#define silk_RSHIFT64(a, shift)             ((a)>>(shift))                                  /* shift >= 0, shift < 64 */
+#define silk_RSHIFT(a, shift)               silk_RSHIFT32(a, shift)                         /* shift >= 0, shift < 32 */
+
+/* saturates before shifting */
+#define silk_LSHIFT_SAT32(a, shift)         (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \
+                                                    silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) ))
+
+#define silk_LSHIFT_ovflw(a, shift)         ((opus_int32)((opus_uint32)(a) << (shift)))     /* shift >= 0, allowed to overflow */
+#define silk_LSHIFT_uint(a, shift)          ((a) << (shift))                                /* shift >= 0 */
+#define silk_RSHIFT_uint(a, shift)          ((a) >> (shift))                                /* shift >= 0 */
+
+#define silk_ADD_LSHIFT(a, b, shift)        ((a) + silk_LSHIFT((b), (shift)))               /* shift >= 0 */
+#define silk_ADD_LSHIFT32(a, b, shift)      silk_ADD32((a), silk_LSHIFT32((b), (shift)))    /* shift >= 0 */
+#define silk_ADD_LSHIFT_uint(a, b, shift)   ((a) + silk_LSHIFT_uint((b), (shift)))          /* shift >= 0 */
+#define silk_ADD_RSHIFT(a, b, shift)        ((a) + silk_RSHIFT((b), (shift)))               /* shift >= 0 */
+#define silk_ADD_RSHIFT32(a, b, shift)      silk_ADD32((a), silk_RSHIFT32((b), (shift)))    /* shift >= 0 */
+#define silk_ADD_RSHIFT_uint(a, b, shift)   ((a) + silk_RSHIFT_uint((b), (shift)))          /* shift >= 0 */
+#define silk_SUB_LSHIFT32(a, b, shift)      silk_SUB32((a), silk_LSHIFT32((b), (shift)))    /* shift >= 0 */
+#define silk_SUB_RSHIFT32(a, b, shift)      silk_SUB32((a), silk_RSHIFT32((b), (shift)))    /* shift >= 0 */
+
+/* Requires that shift > 0 */
+#define silk_RSHIFT_ROUND(a, shift)         ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1)
+#define silk_RSHIFT_ROUND64(a, shift)       ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1)
+
+/* Number of rightshift required to fit the multiplication */
+#define silk_NSHIFT_MUL_32_32(a, b)         ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) )
+#define silk_NSHIFT_MUL_16_16(a, b)         ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) )
+
+
+#define silk_min(a, b)                      (((a) < (b)) ? (a) : (b))
+#define silk_max(a, b)                      (((a) > (b)) ? (a) : (b))
+
+/* Macro to convert floating-point constants to fixed-point */
+#define SILK_FIX_CONST( C, Q )              ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5))
+
+/* silk_min() versions with typecast in the function call */
+static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b)
+{
+    return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b)
+{
+    return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b)
+{
+    return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b)
+{
+    return (((a) < (b)) ? (a) : (b));
+}
+
+/* silk_min() versions with typecast in the function call */
+static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b)
+{
+    return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b)
+{
+    return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b)
+{
+    return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b)
+{
+    return (((a) > (b)) ? (a) : (b));
+}
+
+#define silk_LIMIT( a, limit1, limit2)      ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+                                                                 : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))))
+
+#define silk_LIMIT_int                      silk_LIMIT
+#define silk_LIMIT_16                       silk_LIMIT
+#define silk_LIMIT_32                       silk_LIMIT
+
+#define silk_abs(a)                         (((a) >  0)  ? (a) : -(a))            /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */
+#define silk_abs_int(a)                     (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1)))
+#define silk_abs_int32(a)                   (((a) ^ ((a) >> 31)) - ((a) >> 31))
+#define silk_abs_int64(a)                   (((a) >  0)  ? (a) : -(a))
+
+#define silk_sign(a)                        ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 ))
+
+/* PSEUDO-RANDOM GENERATOR                                                          */
+/* Make sure to store the result as the seed for the next call (also in between     */
+/* frames), otherwise result won't be random at all. When only using some of the    */
+/* bits, take the most significant bits by right-shifting.                          */
+#define silk_RAND(seed)                     (silk_MLA_ovflw(907633515, (seed), 196314165))
+
+/*  Add some multiplication functions that can be easily mapped to ARM. */
+
+/*    silk_SMMUL: Signed top word multiply.
+          ARMv6        2 instruction cycles.
+          ARMv3M+      3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/
+/*#define silk_SMMUL(a32, b32)                (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/
+/* the following seems faster on x86 */
+#define silk_SMMUL(a32, b32)                (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32)
+
+#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \
+    ((void)(arch), silk_burg_modified_c(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch))
+
+#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \
+    ((void)(arch),silk_inner_prod16_aligned_64_c(inVec1, inVec2, len))
+#endif
+
+#include "Inlines.h"
+#include "MacroCount.h"
+#include "MacroDebug.h"
+
+#ifdef OPUS_ARM_INLINE_ASM
+#include "arm/SigProc_FIX_armv4.h"
+#endif
+
+#ifdef OPUS_ARM_INLINE_EDSP
+#include "arm/SigProc_FIX_armv5e.h"
+#endif
+
+#if defined(MIPSr1_ASM)
+#include "mips/sigproc_fix_mipsr1.h"
+#endif
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* SILK_SIGPROC_FIX_H */
diff --git a/third_party/opus/src/silk/VAD.c b/third_party/opus/src/silk/VAD.c
new file mode 100644
index 0000000..0a782af
--- /dev/null
+++ b/third_party/opus/src/silk/VAD.c
@@ -0,0 +1,362 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Silk VAD noise level estimation */
+# if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE void silk_VAD_GetNoiseLevels(
+    const opus_int32             pX[ VAD_N_BANDS ], /* I    subband energies                            */
+    silk_VAD_state              *psSilk_VAD         /* I/O  Pointer to Silk VAD state                   */
+);
+#endif
+
+/**********************************/
+/* Initialization of the Silk VAD */
+/**********************************/
+opus_int silk_VAD_Init(                                         /* O    Return value, 0 if success                  */
+    silk_VAD_state              *psSilk_VAD                     /* I/O  Pointer to Silk VAD state                   */
+)
+{
+    opus_int b, ret = 0;
+
+    /* reset state memory */
+    silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) );
+
+    /* init noise levels */
+    /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 );
+    }
+
+    /* Initialize state */
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        psSilk_VAD->NL[ b ]     = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] );
+        psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] );
+    }
+    psSilk_VAD->counter = 15;
+
+    /* init smoothed energy-to-noise ratio*/
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256;       /* 100 * 256 --> 20 dB SNR */
+    }
+
+    return( ret );
+}
+
+/* Weighting factors for tilt measure */
+static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 };
+
+/***************************************/
+/* Get the speech activity level in Q8 */
+/***************************************/
+opus_int silk_VAD_GetSA_Q8_c(                                   /* O    Return value, 0 if success                  */
+    silk_encoder_state          *psEncC,                        /* I/O  Encoder state                               */
+    const opus_int16            pIn[]                           /* I    PCM input                                   */
+)
+{
+    opus_int   SA_Q15, pSNR_dB_Q7, input_tilt;
+    opus_int   decimated_framelength1, decimated_framelength2;
+    opus_int   decimated_framelength;
+    opus_int   dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
+    opus_int32 sumSquared, smooth_coef_Q16;
+    opus_int16 HPstateTmp;
+    VARDECL( opus_int16, X );
+    opus_int32 Xnrg[ VAD_N_BANDS ];
+    opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ];
+    opus_int32 speech_nrg, x_tmp;
+    opus_int   X_offset[ VAD_N_BANDS ];
+    opus_int   ret = 0;
+    silk_VAD_state *psSilk_VAD = &psEncC->sVAD;
+    SAVE_STACK;
+
+    /* Safety checks */
+    silk_assert( VAD_N_BANDS == 4 );
+    silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length );
+    silk_assert( psEncC->frame_length <= 512 );
+    silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) );
+
+    /***********************/
+    /* Filter and Decimate */
+    /***********************/
+    decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 );
+    decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 );
+    decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 );
+    /* Decimate into 4 bands:
+       0       L      3L       L              3L                             5L
+               -      --       -              --                             --
+               8       8       2               4                              4
+
+       [0-1 kHz| temp. |1-2 kHz|    2-4 kHz    |            4-8 kHz           |
+
+       They're arranged to allow the minimal ( frame_length / 4 ) extra
+       scratch space during the downsampling process */
+    X_offset[ 0 ] = 0;
+    X_offset[ 1 ] = decimated_framelength + decimated_framelength2;
+    X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength;
+    X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2;
+    ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 );
+
+    /* 0-8 kHz to 0-4 kHz and 4-8 kHz */
+    silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[  0 ],
+        X, &X[ X_offset[ 3 ] ], psEncC->frame_length );
+
+    /* 0-4 kHz to 0-2 kHz and 2-4 kHz */
+    silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ],
+        X, &X[ X_offset[ 2 ] ], decimated_framelength1 );
+
+    /* 0-2 kHz to 0-1 kHz and 1-2 kHz */
+    silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ],
+        X, &X[ X_offset[ 1 ] ], decimated_framelength2 );
+
+    /*********************************************/
+    /* HP filter on lowest band (differentiator) */
+    /*********************************************/
+    X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 );
+    HPstateTmp = X[ decimated_framelength - 1 ];
+    for( i = decimated_framelength - 1; i > 0; i-- ) {
+        X[ i - 1 ]  = silk_RSHIFT( X[ i - 1 ], 1 );
+        X[ i ]     -= X[ i - 1 ];
+    }
+    X[ 0 ] -= psSilk_VAD->HPstate;
+    psSilk_VAD->HPstate = HPstateTmp;
+
+    /*************************************/
+    /* Calculate the energy in each band */
+    /*************************************/
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        /* Find the decimated framelength in the non-uniformly divided bands */
+        decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) );
+
+        /* Split length into subframe lengths */
+        dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 );
+        dec_subframe_offset = 0;
+
+        /* Compute energy per sub-frame */
+        /* initialize with summed energy of last subframe */
+        Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ];
+        for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) {
+            sumSquared = 0;
+            for( i = 0; i < dec_subframe_length; i++ ) {
+                /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2.            */
+                /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128)  */
+                x_tmp = silk_RSHIFT(
+                    X[ X_offset[ b ] + i + dec_subframe_offset ], 3 );
+                sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp );
+
+                /* Safety check */
+                silk_assert( sumSquared >= 0 );
+            }
+
+            /* Add/saturate summed energy of current subframe */
+            if( s < VAD_INTERNAL_SUBFRAMES - 1 ) {
+                Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared );
+            } else {
+                /* Look-ahead subframe */
+                Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) );
+            }
+
+            dec_subframe_offset += dec_subframe_length;
+        }
+        psSilk_VAD->XnrgSubfr[ b ] = sumSquared;
+    }
+
+    /********************/
+    /* Noise estimation */
+    /********************/
+    silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD );
+
+    /***********************************************/
+    /* Signal-plus-noise to noise ratio estimation */
+    /***********************************************/
+    sumSquared = 0;
+    input_tilt = 0;
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ];
+        if( speech_nrg > 0 ) {
+            /* Divide, with sufficient resolution */
+            if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) {
+                NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 );
+            } else {
+                NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 );
+            }
+
+            /* Convert to log domain */
+            SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128;
+
+            /* Sum-of-squares */
+            sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 );          /* Q14 */
+
+            /* Tilt measure */
+            if( speech_nrg < ( (opus_int32)1 << 20 ) ) {
+                /* Scale down SNR value for small subband speech energies */
+                SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 );
+            }
+            input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 );
+        } else {
+            NrgToNoiseRatio_Q8[ b ] = 256;
+        }
+    }
+
+    /* Mean-of-squares */
+    sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */
+
+    /* Root-mean-square approximation, scale to dBs, and write to output pointer */
+    pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */
+
+    /*********************************/
+    /* Speech Probability Estimation */
+    /*********************************/
+    SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 );
+
+    /**************************/
+    /* Frequency Tilt Measure */
+    /**************************/
+    psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 );
+
+    /**************************************************/
+    /* Scale the sigmoid output based on power levels */
+    /**************************************************/
+    speech_nrg = 0;
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        /* Accumulate signal-without-noise energies, higher frequency bands have more weight */
+        speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 );
+    }
+
+    /* Power scaling */
+    if( speech_nrg <= 0 ) {
+        SA_Q15 = silk_RSHIFT( SA_Q15, 1 );
+    } else if( speech_nrg < 32768 ) {
+        if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+            speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 );
+        } else {
+            speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 );
+        }
+
+        /* square-root */
+        speech_nrg = silk_SQRT_APPROX( speech_nrg );
+        SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 );
+    }
+
+    /* Copy the resulting speech activity in Q8 */
+    psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX );
+
+    /***********************************/
+    /* Energy Level and SNR estimation */
+    /***********************************/
+    /* Smoothing coefficient */
+    smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) );
+
+    if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+        smooth_coef_Q16 >>= 1;
+    }
+
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        /* compute smoothed energy-to-noise ratio per band */
+        psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ],
+            NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 );
+
+        /* signal to noise ratio in dB per band */
+        SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 );
+        /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
+        psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) );
+    }
+
+    RESTORE_STACK;
+    return( ret );
+}
+
+/**************************/
+/* Noise level estimation */
+/**************************/
+# if  !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE
+#endif
+void silk_VAD_GetNoiseLevels(
+    const opus_int32            pX[ VAD_N_BANDS ],  /* I    subband energies                            */
+    silk_VAD_state              *psSilk_VAD         /* I/O  Pointer to Silk VAD state                   */
+)
+{
+    opus_int   k;
+    opus_int32 nl, nrg, inv_nrg;
+    opus_int   coef, min_coef;
+
+    /* Initially faster smoothing */
+    if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */
+        min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 );
+    } else {
+        min_coef = 0;
+    }
+
+    for( k = 0; k < VAD_N_BANDS; k++ ) {
+        /* Get old noise level estimate for current band */
+        nl = psSilk_VAD->NL[ k ];
+        silk_assert( nl >= 0 );
+
+        /* Add bias */
+        nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] );
+        silk_assert( nrg > 0 );
+
+        /* Invert energies */
+        inv_nrg = silk_DIV32( silk_int32_MAX, nrg );
+        silk_assert( inv_nrg >= 0 );
+
+        /* Less update when subband energy is high */
+        if( nrg > silk_LSHIFT( nl, 3 ) ) {
+            coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3;
+        } else if( nrg < nl ) {
+            coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16;
+        } else {
+            coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 );
+        }
+
+        /* Initially faster smoothing */
+        coef = silk_max_int( coef, min_coef );
+
+        /* Smooth inverse energies */
+        psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef );
+        silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 );
+
+        /* Compute noise level by inverting again */
+        nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] );
+        silk_assert( nl >= 0 );
+
+        /* Limit noise levels (guarantee 7 bits of head room) */
+        nl = silk_min( nl, 0x00FFFFFF );
+
+        /* Store as part of state */
+        psSilk_VAD->NL[ k ] = nl;
+    }
+
+    /* Increment frame counter */
+    psSilk_VAD->counter++;
+}
diff --git a/third_party/opus/src/silk/VQ_WMat_EC.c b/third_party/opus/src/silk/VQ_WMat_EC.c
new file mode 100644
index 0000000..7983f1d
--- /dev/null
+++ b/third_party/opus/src/silk/VQ_WMat_EC.c
@@ -0,0 +1,120 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
+void silk_VQ_WMat_EC_c(
+    opus_int8                   *ind,                           /* O    index of best codebook vector               */
+    opus_int32                  *rate_dist_Q14,                 /* O    best weighted quant error + mu * rate       */
+    opus_int                    *gain_Q7,                       /* O    sum of absolute LTP coefficients            */
+    const opus_int16            *in_Q14,                        /* I    input vector to be quantized                */
+    const opus_int32            *W_Q18,                         /* I    weighting matrix                            */
+    const opus_int8             *cb_Q7,                         /* I    codebook                                    */
+    const opus_uint8            *cb_gain_Q7,                    /* I    codebook effective gain                     */
+    const opus_uint8            *cl_Q5,                         /* I    code length for each codebook vector        */
+    const opus_int              mu_Q9,                          /* I    tradeoff betw. weighted error and rate      */
+    const opus_int32            max_gain_Q7,                    /* I    maximum sum of absolute LTP coefficients    */
+    opus_int                    L                               /* I    number of vectors in codebook               */
+)
+{
+    opus_int   k, gain_tmp_Q7;
+    const opus_int8 *cb_row_Q7;
+    opus_int16 diff_Q14[ 5 ];
+    opus_int32 sum1_Q14, sum2_Q16;
+
+    /* Loop over codebook */
+    *rate_dist_Q14 = silk_int32_MAX;
+    cb_row_Q7 = cb_Q7;
+    for( k = 0; k < L; k++ ) {
+        gain_tmp_Q7 = cb_gain_Q7[k];
+
+        diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 );
+        diff_Q14[ 1 ] = in_Q14[ 1 ] - silk_LSHIFT( cb_row_Q7[ 1 ], 7 );
+        diff_Q14[ 2 ] = in_Q14[ 2 ] - silk_LSHIFT( cb_row_Q7[ 2 ], 7 );
+        diff_Q14[ 3 ] = in_Q14[ 3 ] - silk_LSHIFT( cb_row_Q7[ 3 ], 7 );
+        diff_Q14[ 4 ] = in_Q14[ 4 ] - silk_LSHIFT( cb_row_Q7[ 4 ], 7 );
+
+        /* Weighted rate */
+        sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] );
+
+        /* Penalty for too large gain */
+        sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 );
+
+        silk_assert( sum1_Q14 >= 0 );
+
+        /* first row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[  1 ], diff_Q14[ 1 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  2 ], diff_Q14[ 2 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  3 ], diff_Q14[ 3 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  4 ], diff_Q14[ 4 ] );
+        sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  0 ], diff_Q14[ 0 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 0 ] );
+
+        /* second row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[  7 ], diff_Q14[ 2 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  8 ], diff_Q14[ 3 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  9 ], diff_Q14[ 4 ] );
+        sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  6 ], diff_Q14[ 1 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 1 ] );
+
+        /* third row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[ 13 ], diff_Q14[ 3 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] );
+        sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 2 ] );
+
+        /* fourth row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[ 19 ], diff_Q14[ 4 ] );
+        sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 3 ] );
+
+        /* last row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[ 24 ], diff_Q14[ 4 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 4 ] );
+
+        silk_assert( sum1_Q14 >= 0 );
+
+        /* find best */
+        if( sum1_Q14 < *rate_dist_Q14 ) {
+            *rate_dist_Q14 = sum1_Q14;
+            *ind = (opus_int8)k;
+            *gain_Q7 = gain_tmp_Q7;
+        }
+
+        /* Go to next cbk vector */
+        cb_row_Q7 += LTP_ORDER;
+    }
+}
diff --git a/third_party/opus/src/silk/ana_filt_bank_1.c b/third_party/opus/src/silk/ana_filt_bank_1.c
new file mode 100644
index 0000000..24cfb03f
--- /dev/null
+++ b/third_party/opus/src/silk/ana_filt_bank_1.c
@@ -0,0 +1,74 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Coefficients for 2-band filter bank based on first-order allpass filters */
+static opus_int16 A_fb1_20 = 5394 << 1;
+static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */
+
+/* Split signal into two decimated bands using first-order allpass filters */
+void silk_ana_filt_bank_1(
+    const opus_int16            *in,                /* I    Input signal [N]                                            */
+    opus_int32                  *S,                 /* I/O  State vector [2]                                            */
+    opus_int16                  *outL,              /* O    Low band [N/2]                                              */
+    opus_int16                  *outH,              /* O    High band [N/2]                                             */
+    const opus_int32            N                   /* I    Number of input samples                                     */
+)
+{
+    opus_int      k, N2 = silk_RSHIFT( N, 1 );
+    opus_int32    in32, X, Y, out_1, out_2;
+
+    /* Internal variables and state are in Q10 format */
+    for( k = 0; k < N2; k++ ) {
+        /* Convert to Q10 */
+        in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 );
+
+        /* All-pass section for even input sample */
+        Y      = silk_SUB32( in32, S[ 0 ] );
+        X      = silk_SMLAWB( Y, Y, A_fb1_21 );
+        out_1  = silk_ADD32( S[ 0 ], X );
+        S[ 0 ] = silk_ADD32( in32, X );
+
+        /* Convert to Q10 */
+        in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 );
+
+        /* All-pass section for odd input sample, and add to output of previous section */
+        Y      = silk_SUB32( in32, S[ 1 ] );
+        X      = silk_SMULWB( Y, A_fb1_20 );
+        out_2  = silk_ADD32( S[ 1 ], X );
+        S[ 1 ] = silk_ADD32( in32, X );
+
+        /* Add/subtract, convert back to int16 and store to output */
+        outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) );
+        outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) );
+    }
+}
diff --git a/third_party/opus/src/silk/arm/NSQ_neon.c b/third_party/opus/src/silk/arm/NSQ_neon.c
new file mode 100644
index 0000000..9642529
--- /dev/null
+++ b/third_party/opus/src/silk/arm/NSQ_neon.c
@@ -0,0 +1,112 @@
+/***********************************************************************
+Copyright (C) 2014 Vidyo
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <arm_neon.h>
+#include "main.h"
+#include "stack_alloc.h"
+#include "NSQ.h"
+#include "celt/cpu_support.h"
+#include "celt/arm/armcpu.h"
+
+opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order)
+{
+    int32x4_t coef0 = vld1q_s32(coef32);
+    int32x4_t coef1 = vld1q_s32(coef32 + 4);
+    int32x4_t coef2 = vld1q_s32(coef32 + 8);
+    int32x4_t coef3 = vld1q_s32(coef32 + 12);
+
+    int32x4_t a0 = vld1q_s32(buf32 - 15);
+    int32x4_t a1 = vld1q_s32(buf32 - 11);
+    int32x4_t a2 = vld1q_s32(buf32 - 7);
+    int32x4_t a3 = vld1q_s32(buf32 - 3);
+
+    int32x4_t b0 = vqdmulhq_s32(coef0, a0);
+    int32x4_t b1 = vqdmulhq_s32(coef1, a1);
+    int32x4_t b2 = vqdmulhq_s32(coef2, a2);
+    int32x4_t b3 = vqdmulhq_s32(coef3, a3);
+
+    int32x4_t c0 = vaddq_s32(b0, b1);
+    int32x4_t c1 = vaddq_s32(b2, b3);
+
+    int32x4_t d = vaddq_s32(c0, c1);
+
+    int64x2_t e = vpaddlq_s32(d);
+
+    int64x1_t f = vadd_s64(vget_low_s64(e), vget_high_s64(e));
+
+    opus_int32 out = vget_lane_s32(vreinterpret_s32_s64(f), 0);
+
+    out += silk_RSHIFT( order, 1 );
+
+    return out;
+}
+
+
+opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
+{
+    opus_int32 out;
+    if (order == 8)
+    {
+        int32x4_t a00 = vdupq_n_s32(data0[0]);
+        int32x4_t a01 = vld1q_s32(data1);  /* data1[0] ... [3] */
+
+        int32x4_t a0 = vextq_s32 (a00, a01, 3); /* data0[0] data1[0] ...[2] */
+        int32x4_t a1 = vld1q_s32(data1 + 3);  /* data1[3] ... [6] */
+
+        /*TODO: Convert these once in advance instead of once per sample, like
+          silk_noise_shape_quantizer_short_prediction_neon() does.*/
+        int16x8_t coef16 = vld1q_s16(coef);
+        int32x4_t coef0 = vmovl_s16(vget_low_s16(coef16));
+        int32x4_t coef1 = vmovl_s16(vget_high_s16(coef16));
+
+        /*This is not bit-exact with the C version, since we do not drop the
+          lower 16 bits of each multiply, but wait until the end to truncate
+          precision. This is an encoder-specific calculation (and unlike
+          silk_noise_shape_quantizer_short_prediction_neon(), is not meant to
+          simulate what the decoder will do). We still could use vqdmulhq_s32()
+          like silk_noise_shape_quantizer_short_prediction_neon() and save
+          half the multiplies, but the speed difference is not large, since we
+          then need two extra adds.*/
+        int64x2_t b0 = vmull_s32(vget_low_s32(a0), vget_low_s32(coef0));
+        int64x2_t b1 = vmlal_s32(b0, vget_high_s32(a0), vget_high_s32(coef0));
+        int64x2_t b2 = vmlal_s32(b1, vget_low_s32(a1), vget_low_s32(coef1));
+        int64x2_t b3 = vmlal_s32(b2, vget_high_s32(a1), vget_high_s32(coef1));
+
+        int64x1_t c = vadd_s64(vget_low_s64(b3), vget_high_s64(b3));
+        int64x1_t cS = vrshr_n_s64(c, 15);
+        int32x2_t d = vreinterpret_s32_s64(cS);
+
+        out = vget_lane_s32(d, 0);
+        vst1q_s32(data1, a0);
+        vst1q_s32(data1 + 4, a1);
+        return out;
+    }
+    return silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order);
+}
diff --git a/third_party/opus/src/silk/arm/NSQ_neon.h b/third_party/opus/src/silk/arm/NSQ_neon.h
new file mode 100644
index 0000000..77c946a
--- /dev/null
+++ b/third_party/opus/src/silk/arm/NSQ_neon.h
@@ -0,0 +1,113 @@
+/***********************************************************************
+Copyright (C) 2014 Vidyo
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+#ifndef SILK_NSQ_NEON_H
+#define SILK_NSQ_NEON_H
+
+#include "cpu_support.h"
+
+#undef silk_short_prediction_create_arch_coef
+/* For vectorized calc, reverse a_Q12 coefs, convert to 32-bit, and shift for vqdmulhq_s32. */
+static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon(opus_int32 *out, const opus_int16 *in, opus_int order)
+{
+    out[15] = in[0] << 15;
+    out[14] = in[1] << 15;
+    out[13] = in[2] << 15;
+    out[12] = in[3] << 15;
+    out[11] = in[4] << 15;
+    out[10] = in[5] << 15;
+    out[9]  = in[6] << 15;
+    out[8]  = in[7] << 15;
+    out[7]  = in[8] << 15;
+    out[6]  = in[9] << 15;
+
+    if (order == 16)
+    {
+        out[5] = in[10] << 15;
+        out[4] = in[11] << 15;
+        out[3] = in[12] << 15;
+        out[2] = in[13] << 15;
+        out[1] = in[14] << 15;
+        out[0] = in[15] << 15;
+    }
+    else
+    {
+        out[5] = 0;
+        out[4] = 0;
+        out[3] = 0;
+        out[2] = 0;
+        out[1] = 0;
+        out[0] = 0;
+    }
+}
+
+#if defined(OPUS_ARM_PRESUME_NEON_INTR)
+
+#define silk_short_prediction_create_arch_coef(out, in, order) \
+    (silk_short_prediction_create_arch_coef_neon(out, in, order))
+
+#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+
+#define silk_short_prediction_create_arch_coef(out, in, order) \
+    do { if (arch == OPUS_ARCH_ARM_NEON) { silk_short_prediction_create_arch_coef_neon(out, in, order); } } while (0)
+
+#endif
+
+opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order);
+
+opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order);
+
+#if defined(OPUS_ARM_PRESUME_NEON_INTR)
+#undef silk_noise_shape_quantizer_short_prediction
+#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \
+    ((void)arch,silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order))
+
+#undef silk_NSQ_noise_shape_feedback_loop
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch)  ((void)arch,silk_NSQ_noise_shape_feedback_loop_neon(data0, data1, coef, order))
+
+#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
+
+/* silk_noise_shape_quantizer_short_prediction implementations take different parameters based on arch
+   (coef vs. coefRev) so can't use the usual IMPL table implementation */
+#undef silk_noise_shape_quantizer_short_prediction
+#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch)  \
+    (arch == OPUS_ARCH_ARM_NEON ? \
+        silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order) : \
+        silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
+
+extern opus_int32
+ (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])(
+ const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef,
+ opus_int order);
+
+#undef silk_NSQ_noise_shape_feedback_loop
+#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) \
+ (SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[(arch)&OPUS_ARCHMASK](data0, data1, \
+ coef, order))
+
+#endif
+
+#endif /* SILK_NSQ_NEON_H */
diff --git a/third_party/opus/src/silk/arm/SigProc_FIX_armv4.h b/third_party/opus/src/silk/arm/SigProc_FIX_armv4.h
new file mode 100644
index 0000000..ff62b1e
--- /dev/null
+++ b/third_party/opus/src/silk/arm/SigProc_FIX_armv4.h
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (C) 2013 Xiph.Org Foundation and contributors
+Copyright (c) 2013       Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_ARMv4_H
+#define SILK_SIGPROC_FIX_ARMv4_H
+
+#undef silk_MLA
+static OPUS_INLINE opus_int32 silk_MLA_armv4(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+  opus_int32 res;
+  __asm__(
+      "#silk_MLA\n\t"
+      "mla %0, %1, %2, %3\n\t"
+      : "=&r"(res)
+      : "r"(b), "r"(c), "r"(a)
+  );
+  return res;
+}
+#define silk_MLA(a, b, c) (silk_MLA_armv4(a, b, c))
+
+#endif
diff --git a/third_party/opus/src/silk/arm/SigProc_FIX_armv5e.h b/third_party/opus/src/silk/arm/SigProc_FIX_armv5e.h
new file mode 100644
index 0000000..617a09c
--- /dev/null
+++ b/third_party/opus/src/silk/arm/SigProc_FIX_armv5e.h
@@ -0,0 +1,61 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (c) 2013       Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_ARMv5E_H
+#define SILK_SIGPROC_FIX_ARMv5E_H
+
+#undef silk_SMULTT
+static OPUS_INLINE opus_int32 silk_SMULTT_armv5e(opus_int32 a, opus_int32 b)
+{
+  opus_int32 res;
+  __asm__(
+      "#silk_SMULTT\n\t"
+      "smultt %0, %1, %2\n\t"
+      : "=r"(res)
+      : "%r"(a), "r"(b)
+  );
+  return res;
+}
+#define silk_SMULTT(a, b) (silk_SMULTT_armv5e(a, b))
+
+#undef silk_SMLATT
+static OPUS_INLINE opus_int32 silk_SMLATT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+  opus_int32 res;
+  __asm__(
+      "#silk_SMLATT\n\t"
+      "smlatt %0, %1, %2, %3\n\t"
+      : "=r"(res)
+      : "%r"(b), "r"(c), "r"(a)
+  );
+  return res;
+}
+#define silk_SMLATT(a, b, c) (silk_SMLATT_armv5e(a, b, c))
+
+#endif
diff --git a/third_party/opus/src/silk/arm/arm_silk_map.c b/third_party/opus/src/silk/arm/arm_silk_map.c
new file mode 100644
index 0000000..9bd86a7
--- /dev/null
+++ b/third_party/opus/src/silk/arm/arm_silk_map.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+Copyright (C) 2014 Vidyo
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "NSQ.h"
+
+#if defined(OPUS_HAVE_RTCD)
+
+# if (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \
+ !defined(OPUS_ARM_PRESUME_NEON_INTR))
+
+/*There is no table for silk_noise_shape_quantizer_short_prediction because the
+   NEON version takes different parameters than the C version.
+  Instead RTCD is done via if statements at the call sites.
+  See NSQ_neon.h for details.*/
+
+opus_int32
+ (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])(
+ const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef,
+ opus_int order) = {
+  silk_NSQ_noise_shape_feedback_loop_c,    /* ARMv4 */
+  silk_NSQ_noise_shape_feedback_loop_c,    /* EDSP */
+  silk_NSQ_noise_shape_feedback_loop_c,    /* Media */
+  silk_NSQ_noise_shape_feedback_loop_neon, /* NEON */
+};
+
+# endif
+
+#endif /* OPUS_HAVE_RTCD */
diff --git a/third_party/opus/src/silk/arm/macros_arm64.h b/third_party/opus/src/silk/arm/macros_arm64.h
new file mode 100644
index 0000000..ed030413
--- /dev/null
+++ b/third_party/opus/src/silk/arm/macros_arm64.h
@@ -0,0 +1,39 @@
+/***********************************************************************
+Copyright (C) 2015 Vidyo
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MACROS_ARM64_H
+#define SILK_MACROS_ARM64_H
+
+#include <arm_neon.h>
+
+#undef silk_ADD_SAT32
+#define silk_ADD_SAT32(a, b) (vqadds_s32((a), (b)))
+
+#undef silk_SUB_SAT32
+#define silk_SUB_SAT32(a, b) (vqsubs_s32((a), (b)))
+
+#endif /* SILK_MACROS_ARM64_H */
diff --git a/third_party/opus/src/silk/arm/macros_armv4.h b/third_party/opus/src/silk/arm/macros_armv4.h
new file mode 100644
index 0000000..3f30e97
--- /dev/null
+++ b/third_party/opus/src/silk/arm/macros_armv4.h
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (C) 2013 Xiph.Org Foundation and contributors.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MACROS_ARMv4_H
+#define SILK_MACROS_ARMv4_H
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b)
+{
+  unsigned rd_lo;
+  int rd_hi;
+  __asm__(
+      "#silk_SMULWB\n\t"
+      "smull %0, %1, %2, %3\n\t"
+      : "=&r"(rd_lo), "=&r"(rd_hi)
+      : "%r"(a), "r"(b<<16)
+  );
+  return rd_hi;
+}
+#define silk_SMULWB(a, b) (silk_SMULWB_armv4(a, b))
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#undef silk_SMLAWB
+#define silk_SMLAWB(a, b, c) ((a) + silk_SMULWB(b, c))
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT_armv4(opus_int32 a, opus_int32 b)
+{
+  unsigned rd_lo;
+  int rd_hi;
+  __asm__(
+      "#silk_SMULWT\n\t"
+      "smull %0, %1, %2, %3\n\t"
+      : "=&r"(rd_lo), "=&r"(rd_hi)
+      : "%r"(a), "r"(b&~0xFFFF)
+  );
+  return rd_hi;
+}
+#define silk_SMULWT(a, b) (silk_SMULWT_armv4(a, b))
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#undef silk_SMLAWT
+#define silk_SMLAWT(a, b, c) ((a) + silk_SMULWT(b, c))
+
+/* (a32 * b32) >> 16 */
+#undef silk_SMULWW
+static OPUS_INLINE opus_int32 silk_SMULWW_armv4(opus_int32 a, opus_int32 b)
+{
+  unsigned rd_lo;
+  int rd_hi;
+  __asm__(
+    "#silk_SMULWW\n\t"
+    "smull %0, %1, %2, %3\n\t"
+    : "=&r"(rd_lo), "=&r"(rd_hi)
+    : "%r"(a), "r"(b)
+  );
+  return (rd_hi<<16)+(rd_lo>>16);
+}
+#define silk_SMULWW(a, b) (silk_SMULWW_armv4(a, b))
+
+#undef silk_SMLAWW
+static OPUS_INLINE opus_int32 silk_SMLAWW_armv4(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+  unsigned rd_lo;
+  int rd_hi;
+  __asm__(
+    "#silk_SMLAWW\n\t"
+    "smull %0, %1, %2, %3\n\t"
+    : "=&r"(rd_lo), "=&r"(rd_hi)
+    : "%r"(b), "r"(c)
+  );
+  return a+(rd_hi<<16)+(rd_lo>>16);
+}
+#define silk_SMLAWW(a, b, c) (silk_SMLAWW_armv4(a, b, c))
+
+#endif /* SILK_MACROS_ARMv4_H */
diff --git a/third_party/opus/src/silk/arm/macros_armv5e.h b/third_party/opus/src/silk/arm/macros_armv5e.h
new file mode 100644
index 0000000..aad4117
--- /dev/null
+++ b/third_party/opus/src/silk/arm/macros_armv5e.h
@@ -0,0 +1,213 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (c) 2013       Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MACROS_ARMv5E_H
+#define SILK_MACROS_ARMv5E_H
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB_armv5e(opus_int32 a, opus_int16 b)
+{
+  int res;
+  __asm__(
+      "#silk_SMULWB\n\t"
+      "smulwb %0, %1, %2\n\t"
+      : "=r"(res)
+      : "r"(a), "r"(b)
+  );
+  return res;
+}
+#define silk_SMULWB(a, b) (silk_SMULWB_armv5e(a, b))
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#undef silk_SMLAWB
+static OPUS_INLINE opus_int32 silk_SMLAWB_armv5e(opus_int32 a, opus_int32 b,
+ opus_int16 c)
+{
+  int res;
+  __asm__(
+      "#silk_SMLAWB\n\t"
+      "smlawb %0, %1, %2, %3\n\t"
+      : "=r"(res)
+      : "r"(b), "r"(c), "r"(a)
+  );
+  return res;
+}
+#define silk_SMLAWB(a, b, c) (silk_SMLAWB_armv5e(a, b, c))
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT_armv5e(opus_int32 a, opus_int32 b)
+{
+  int res;
+  __asm__(
+      "#silk_SMULWT\n\t"
+      "smulwt %0, %1, %2\n\t"
+      : "=r"(res)
+      : "r"(a), "r"(b)
+  );
+  return res;
+}
+#define silk_SMULWT(a, b) (silk_SMULWT_armv5e(a, b))
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#undef silk_SMLAWT
+static OPUS_INLINE opus_int32 silk_SMLAWT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+  int res;
+  __asm__(
+      "#silk_SMLAWT\n\t"
+      "smlawt %0, %1, %2, %3\n\t"
+      : "=r"(res)
+      : "r"(b), "r"(c), "r"(a)
+  );
+  return res;
+}
+#define silk_SMLAWT(a, b, c) (silk_SMLAWT_armv5e(a, b, c))
+
+/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */
+#undef silk_SMULBB
+static OPUS_INLINE opus_int32 silk_SMULBB_armv5e(opus_int32 a, opus_int32 b)
+{
+  int res;
+  __asm__(
+      "#silk_SMULBB\n\t"
+      "smulbb %0, %1, %2\n\t"
+      : "=r"(res)
+      : "%r"(a), "r"(b)
+  );
+  return res;
+}
+#define silk_SMULBB(a, b) (silk_SMULBB_armv5e(a, b))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */
+#undef silk_SMLABB
+static OPUS_INLINE opus_int32 silk_SMLABB_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+  int res;
+  __asm__(
+      "#silk_SMLABB\n\t"
+      "smlabb %0, %1, %2, %3\n\t"
+      : "=r"(res)
+      : "%r"(b), "r"(c), "r"(a)
+  );
+  return res;
+}
+#define silk_SMLABB(a, b, c) (silk_SMLABB_armv5e(a, b, c))
+
+/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */
+#undef silk_SMULBT
+static OPUS_INLINE opus_int32 silk_SMULBT_armv5e(opus_int32 a, opus_int32 b)
+{
+  int res;
+  __asm__(
+      "#silk_SMULBT\n\t"
+      "smulbt %0, %1, %2\n\t"
+      : "=r"(res)
+      : "r"(a), "r"(b)
+  );
+  return res;
+}
+#define silk_SMULBT(a, b) (silk_SMULBT_armv5e(a, b))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */
+#undef silk_SMLABT
+static OPUS_INLINE opus_int32 silk_SMLABT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+  int res;
+  __asm__(
+      "#silk_SMLABT\n\t"
+      "smlabt %0, %1, %2, %3\n\t"
+      : "=r"(res)
+      : "r"(b), "r"(c), "r"(a)
+  );
+  return res;
+}
+#define silk_SMLABT(a, b, c) (silk_SMLABT_armv5e(a, b, c))
+
+/* add/subtract with output saturated */
+#undef silk_ADD_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_SAT32_armv5e(opus_int32 a, opus_int32 b)
+{
+  int res;
+  __asm__(
+      "#silk_ADD_SAT32\n\t"
+      "qadd %0, %1, %2\n\t"
+      : "=r"(res)
+      : "%r"(a), "r"(b)
+  );
+  return res;
+}
+#define silk_ADD_SAT32(a, b) (silk_ADD_SAT32_armv5e(a, b))
+
+#undef silk_SUB_SAT32
+static OPUS_INLINE opus_int32 silk_SUB_SAT32_armv5e(opus_int32 a, opus_int32 b)
+{
+  int res;
+  __asm__(
+      "#silk_SUB_SAT32\n\t"
+      "qsub %0, %1, %2\n\t"
+      : "=r"(res)
+      : "r"(a), "r"(b)
+  );
+  return res;
+}
+#define silk_SUB_SAT32(a, b) (silk_SUB_SAT32_armv5e(a, b))
+
+#undef silk_CLZ16
+static OPUS_INLINE opus_int32 silk_CLZ16_armv5(opus_int16 in16)
+{
+  int res;
+  __asm__(
+      "#silk_CLZ16\n\t"
+      "clz %0, %1;\n"
+      : "=r"(res)
+      : "r"(in16<<16|0x8000)
+  );
+  return res;
+}
+#define silk_CLZ16(in16) (silk_CLZ16_armv5(in16))
+
+#undef silk_CLZ32
+static OPUS_INLINE opus_int32 silk_CLZ32_armv5(opus_int32 in32)
+{
+  int res;
+  __asm__(
+      "#silk_CLZ32\n\t"
+      "clz %0, %1\n\t"
+      : "=r"(res)
+      : "r"(in32)
+  );
+  return res;
+}
+#define silk_CLZ32(in32) (silk_CLZ32_armv5(in32))
+
+#endif /* SILK_MACROS_ARMv5E_H */
diff --git a/third_party/opus/src/silk/biquad_alt.c b/third_party/opus/src/silk/biquad_alt.c
new file mode 100644
index 0000000..d55f5ee9
--- /dev/null
+++ b/third_party/opus/src/silk/biquad_alt.c
@@ -0,0 +1,78 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+/*                                                                      *
+ * silk_biquad_alt.c                                              *
+ *                                                                      *
+ * Second order ARMA filter                                             *
+ * Can handle slowly varying filter coefficients                        *
+ *                                                                      */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Second order ARMA filter, alternative implementation */
+void silk_biquad_alt(
+    const opus_int16            *in,                /* I     input signal                                               */
+    const opus_int32            *B_Q28,             /* I     MA coefficients [3]                                        */
+    const opus_int32            *A_Q28,             /* I     AR coefficients [2]                                        */
+    opus_int32                  *S,                 /* I/O   State vector [2]                                           */
+    opus_int16                  *out,               /* O     output signal                                              */
+    const opus_int32            len,                /* I     signal length (must be even)                               */
+    opus_int                    stride              /* I     Operate on interleaved signal if > 1                       */
+)
+{
+    /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
+    opus_int   k;
+    opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
+
+    /* Negate A_Q28 values and split in two parts */
+    A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF;        /* lower part */
+    A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 );      /* upper part */
+    A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF;        /* lower part */
+    A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 );      /* upper part */
+
+    for( k = 0; k < len; k++ ) {
+        /* S[ 0 ], S[ 1 ]: Q12 */
+        inval = in[ k * stride ];
+        out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 );
+
+        S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 );
+        S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 );
+        S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval);
+
+        S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 );
+        S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 );
+        S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval );
+
+        /* Scale back to Q0 and saturate */
+        out[ k * stride ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) );
+    }
+}
diff --git a/third_party/opus/src/silk/bwexpander.c b/third_party/opus/src/silk/bwexpander.c
new file mode 100644
index 0000000..2eb4456
--- /dev/null
+++ b/third_party/opus/src/silk/bwexpander.c
@@ -0,0 +1,51 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander(
+    opus_int16                  *ar,                /* I/O  AR filter to be expanded (without leading 1)                */
+    const opus_int              d,                  /* I    Length of ar                                                */
+    opus_int32                  chirp_Q16           /* I    Chirp factor (typically in the range 0 to 1)                */
+)
+{
+    opus_int   i;
+    opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536;
+
+    /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below.  */
+    /* Bias in silk_SMULWB can lead to unstable filters                                */
+    for( i = 0; i < d - 1; i++ ) {
+        ar[ i ]    = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ]             ), 16 );
+        chirp_Q16 +=            silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 );
+    }
+    ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 );
+}
diff --git a/third_party/opus/src/silk/bwexpander_32.c b/third_party/opus/src/silk/bwexpander_32.c
new file mode 100644
index 0000000..d0010f73
--- /dev/null
+++ b/third_party/opus/src/silk/bwexpander_32.c
@@ -0,0 +1,50 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander_32(
+    opus_int32                  *ar,                /* I/O  AR filter to be expanded (without leading 1)                */
+    const opus_int              d,                  /* I    Length of ar                                                */
+    opus_int32                  chirp_Q16           /* I    Chirp factor in Q16                                         */
+)
+{
+    opus_int   i;
+    opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536;
+
+    for( i = 0; i < d - 1; i++ ) {
+        ar[ i ]    = silk_SMULWW( chirp_Q16, ar[ i ] );
+        chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 );
+    }
+    ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] );
+}
+
diff --git a/third_party/opus/src/silk/check_control_input.c b/third_party/opus/src/silk/check_control_input.c
new file mode 100644
index 0000000..b5de9ce
--- /dev/null
+++ b/third_party/opus/src/silk/check_control_input.c
@@ -0,0 +1,106 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "control.h"
+#include "errors.h"
+
+/* Check encoder control struct */
+opus_int check_control_input(
+    silk_EncControlStruct        *encControl                    /* I    Control structure                           */
+)
+{
+    silk_assert( encControl != NULL );
+
+    if( ( ( encControl->API_sampleRate            !=  8000 ) &&
+          ( encControl->API_sampleRate            != 12000 ) &&
+          ( encControl->API_sampleRate            != 16000 ) &&
+          ( encControl->API_sampleRate            != 24000 ) &&
+          ( encControl->API_sampleRate            != 32000 ) &&
+          ( encControl->API_sampleRate            != 44100 ) &&
+          ( encControl->API_sampleRate            != 48000 ) ) ||
+        ( ( encControl->desiredInternalSampleRate !=  8000 ) &&
+          ( encControl->desiredInternalSampleRate != 12000 ) &&
+          ( encControl->desiredInternalSampleRate != 16000 ) ) ||
+        ( ( encControl->maxInternalSampleRate     !=  8000 ) &&
+          ( encControl->maxInternalSampleRate     != 12000 ) &&
+          ( encControl->maxInternalSampleRate     != 16000 ) ) ||
+        ( ( encControl->minInternalSampleRate     !=  8000 ) &&
+          ( encControl->minInternalSampleRate     != 12000 ) &&
+          ( encControl->minInternalSampleRate     != 16000 ) ) ||
+          ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) ||
+          ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) ||
+          ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) {
+        silk_assert( 0 );
+        return SILK_ENC_FS_NOT_SUPPORTED;
+    }
+    if( encControl->payloadSize_ms != 10 &&
+        encControl->payloadSize_ms != 20 &&
+        encControl->payloadSize_ms != 40 &&
+        encControl->payloadSize_ms != 60 ) {
+        silk_assert( 0 );
+        return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+    }
+    if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) {
+        silk_assert( 0 );
+        return SILK_ENC_INVALID_LOSS_RATE;
+    }
+    if( encControl->useDTX < 0 || encControl->useDTX > 1 ) {
+        silk_assert( 0 );
+        return SILK_ENC_INVALID_DTX_SETTING;
+    }
+    if( encControl->useCBR < 0 || encControl->useCBR > 1 ) {
+        silk_assert( 0 );
+        return SILK_ENC_INVALID_CBR_SETTING;
+    }
+    if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) {
+        silk_assert( 0 );
+        return SILK_ENC_INVALID_INBAND_FEC_SETTING;
+    }
+    if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) {
+        silk_assert( 0 );
+        return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+    }
+    if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) {
+        silk_assert( 0 );
+        return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+    }
+    if( encControl->nChannelsInternal > encControl->nChannelsAPI ) {
+        silk_assert( 0 );
+        return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+    }
+    if( encControl->complexity < 0 || encControl->complexity > 10 ) {
+        silk_assert( 0 );
+        return SILK_ENC_INVALID_COMPLEXITY_SETTING;
+    }
+
+    return SILK_NO_ERROR;
+}
diff --git a/third_party/opus/src/silk/code_signs.c b/third_party/opus/src/silk/code_signs.c
new file mode 100644
index 0000000..dfd1dca
--- /dev/null
+++ b/third_party/opus/src/silk/code_signs.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/*#define silk_enc_map(a)                ((a) > 0 ? 1 : 0)*/
+/*#define silk_dec_map(a)                ((a) > 0 ? 1 : -1)*/
+/* shifting avoids if-statement */
+#define silk_enc_map(a)                  ( silk_RSHIFT( (a), 15 ) + 1 )
+#define silk_dec_map(a)                  ( silk_LSHIFT( (a),  1 ) - 1 )
+
+/* Encodes signs of excitation */
+void silk_encode_signs(
+    ec_enc                      *psRangeEnc,                        /* I/O  Compressor data structure                   */
+    const opus_int8             pulses[],                           /* I    pulse signal                                */
+    opus_int                    length,                             /* I    length of input                             */
+    const opus_int              signalType,                         /* I    Signal type                                 */
+    const opus_int              quantOffsetType,                    /* I    Quantization offset type                    */
+    const opus_int              sum_pulses[ MAX_NB_SHELL_BLOCKS ]   /* I    Sum of absolute pulses per block            */
+)
+{
+    opus_int         i, j, p;
+    opus_uint8       icdf[ 2 ];
+    const opus_int8  *q_ptr;
+    const opus_uint8 *icdf_ptr;
+
+    icdf[ 1 ] = 0;
+    q_ptr = pulses;
+    i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) );
+    icdf_ptr = &silk_sign_iCDF[ i ];
+    length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH );
+    for( i = 0; i < length; i++ ) {
+        p = sum_pulses[ i ];
+        if( p > 0 ) {
+            icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ];
+            for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) {
+                if( q_ptr[ j ] != 0 ) {
+                    ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 );
+                }
+            }
+        }
+        q_ptr += SHELL_CODEC_FRAME_LENGTH;
+    }
+}
+
+/* Decodes signs of excitation */
+void silk_decode_signs(
+    ec_dec                      *psRangeDec,                        /* I/O  Compressor data structure                   */
+    opus_int16                  pulses[],                           /* I/O  pulse signal                                */
+    opus_int                    length,                             /* I    length of input                             */
+    const opus_int              signalType,                         /* I    Signal type                                 */
+    const opus_int              quantOffsetType,                    /* I    Quantization offset type                    */
+    const opus_int              sum_pulses[ MAX_NB_SHELL_BLOCKS ]   /* I    Sum of absolute pulses per block            */
+)
+{
+    opus_int         i, j, p;
+    opus_uint8       icdf[ 2 ];
+    opus_int16       *q_ptr;
+    const opus_uint8 *icdf_ptr;
+
+    icdf[ 1 ] = 0;
+    q_ptr = pulses;
+    i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) );
+    icdf_ptr = &silk_sign_iCDF[ i ];
+    length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH );
+    for( i = 0; i < length; i++ ) {
+        p = sum_pulses[ i ];
+        if( p > 0 ) {
+            icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ];
+            for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) {
+                if( q_ptr[ j ] > 0 ) {
+                    /* attach sign */
+#if 0
+                    /* conditional implementation */
+                    if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) {
+                        q_ptr[ j ] = -q_ptr[ j ];
+                    }
+#else
+                    /* implementation with shift, subtraction, multiplication */
+                    q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) );
+#endif
+                }
+            }
+        }
+        q_ptr += SHELL_CODEC_FRAME_LENGTH;
+    }
+}
diff --git a/third_party/opus/src/silk/control.h b/third_party/opus/src/silk/control.h
new file mode 100644
index 0000000..747e542
--- /dev/null
+++ b/third_party/opus/src/silk/control.h
@@ -0,0 +1,142 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_CONTROL_H
+#define SILK_CONTROL_H
+
+#include "typedef.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Decoder API flags */
+#define FLAG_DECODE_NORMAL                      0
+#define FLAG_PACKET_LOST                        1
+#define FLAG_DECODE_LBRR                        2
+
+/***********************************************/
+/* Structure for controlling encoder operation */
+/***********************************************/
+typedef struct {
+    /* I:   Number of channels; 1/2                                                         */
+    opus_int32 nChannelsAPI;
+
+    /* I:   Number of channels; 1/2                                                         */
+    opus_int32 nChannelsInternal;
+
+    /* I:   Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000   */
+    opus_int32 API_sampleRate;
+
+    /* I:   Maximum internal sampling rate in Hertz; 8000/12000/16000                       */
+    opus_int32 maxInternalSampleRate;
+
+    /* I:   Minimum internal sampling rate in Hertz; 8000/12000/16000                       */
+    opus_int32 minInternalSampleRate;
+
+    /* I:   Soft request for internal sampling rate in Hertz; 8000/12000/16000              */
+    opus_int32 desiredInternalSampleRate;
+
+    /* I:   Number of samples per packet in milliseconds; 10/20/40/60                       */
+    opus_int payloadSize_ms;
+
+    /* I:   Bitrate during active speech in bits/second; internally limited                 */
+    opus_int32 bitRate;
+
+    /* I:   Uplink packet loss in percent (0-100)                                           */
+    opus_int packetLossPercentage;
+
+    /* I:   Complexity mode; 0 is lowest, 10 is highest complexity                          */
+    opus_int complexity;
+
+    /* I:   Flag to enable in-band Forward Error Correction (FEC); 0/1                      */
+    opus_int useInBandFEC;
+
+    /* I:   Flag to enable discontinuous transmission (DTX); 0/1                            */
+    opus_int useDTX;
+
+    /* I:   Flag to use constant bitrate                                                    */
+    opus_int useCBR;
+
+    /* I:   Maximum number of bits allowed for the frame                                    */
+    opus_int maxBits;
+
+    /* I:   Causes a smooth downmix to mono                                                 */
+    opus_int toMono;
+
+    /* I:   Opus encoder is allowing us to switch bandwidth                                 */
+    opus_int opusCanSwitch;
+
+    /* I: Make frames as independent as possible (but still use LPC)                        */
+    opus_int reducedDependency;
+
+    /* O:   Internal sampling rate used, in Hertz; 8000/12000/16000                         */
+    opus_int32 internalSampleRate;
+
+    /* O: Flag that bandwidth switching is allowed (because low voice activity)             */
+    opus_int allowBandwidthSwitch;
+
+    /* O:   Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */
+    opus_int inWBmodeWithoutVariableLP;
+
+    /* O:   Stereo width */
+    opus_int stereoWidth_Q14;
+
+    /* O:   Tells the Opus encoder we're ready to switch                                    */
+    opus_int switchReady;
+
+} silk_EncControlStruct;
+
+/**************************************************************************/
+/* Structure for controlling decoder operation and reading decoder status */
+/**************************************************************************/
+typedef struct {
+    /* I:   Number of channels; 1/2                                                         */
+    opus_int32 nChannelsAPI;
+
+    /* I:   Number of channels; 1/2                                                         */
+    opus_int32 nChannelsInternal;
+
+    /* I:   Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000  */
+    opus_int32 API_sampleRate;
+
+    /* I:   Internal sampling rate used, in Hertz; 8000/12000/16000                         */
+    opus_int32 internalSampleRate;
+
+    /* I:   Number of samples per packet in milliseconds; 10/20/40/60                       */
+    opus_int payloadSize_ms;
+
+    /* O:   Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz      */
+    opus_int prevPitchLag;
+} silk_DecControlStruct;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/control_SNR.c b/third_party/opus/src/silk/control_SNR.c
new file mode 100644
index 0000000..cee87eb
--- /dev/null
+++ b/third_party/opus/src/silk/control_SNR.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+/* Control SNR of redidual quantizer */
+opus_int silk_control_SNR(
+    silk_encoder_state          *psEncC,                        /* I/O  Pointer to Silk encoder state               */
+    opus_int32                  TargetRate_bps                  /* I    Target max bitrate (bps)                    */
+)
+{
+    opus_int k, ret = SILK_NO_ERROR;
+    opus_int32 frac_Q6;
+    const opus_int32 *rateTable;
+
+    /* Set bitrate/coding quality */
+    TargetRate_bps = silk_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS );
+    if( TargetRate_bps != psEncC->TargetRate_bps ) {
+        psEncC->TargetRate_bps = TargetRate_bps;
+
+        /* If new TargetRate_bps, translate to SNR_dB value */
+        if( psEncC->fs_kHz == 8 ) {
+            rateTable = silk_TargetRate_table_NB;
+        } else if( psEncC->fs_kHz == 12 ) {
+            rateTable = silk_TargetRate_table_MB;
+        } else {
+            rateTable = silk_TargetRate_table_WB;
+        }
+
+        /* Reduce bitrate for 10 ms modes in these calculations */
+        if( psEncC->nb_subfr == 2 ) {
+            TargetRate_bps -= REDUCE_BITRATE_10_MS_BPS;
+        }
+
+        /* Find bitrate interval in table and interpolate */
+        for( k = 1; k < TARGET_RATE_TAB_SZ; k++ ) {
+            if( TargetRate_bps <= rateTable[ k ] ) {
+                frac_Q6 = silk_DIV32( silk_LSHIFT( TargetRate_bps - rateTable[ k - 1 ], 6 ),
+                                                 rateTable[ k ] - rateTable[ k - 1 ] );
+                psEncC->SNR_dB_Q7 = silk_LSHIFT( silk_SNR_table_Q1[ k - 1 ], 6 ) + silk_MUL( frac_Q6, silk_SNR_table_Q1[ k ] - silk_SNR_table_Q1[ k - 1 ] );
+                break;
+            }
+        }
+    }
+
+    return ret;
+}
diff --git a/third_party/opus/src/silk/control_audio_bandwidth.c b/third_party/opus/src/silk/control_audio_bandwidth.c
new file mode 100644
index 0000000..4f9bc5cb
--- /dev/null
+++ b/third_party/opus/src/silk/control_audio_bandwidth.c
@@ -0,0 +1,126 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+/* Control internal sampling rate */
+opus_int silk_control_audio_bandwidth(
+    silk_encoder_state          *psEncC,                        /* I/O  Pointer to Silk encoder state               */
+    silk_EncControlStruct       *encControl                     /* I    Control structure                           */
+)
+{
+    opus_int   fs_kHz;
+    opus_int32 fs_Hz;
+
+    fs_kHz = psEncC->fs_kHz;
+    fs_Hz = silk_SMULBB( fs_kHz, 1000 );
+    if( fs_Hz == 0 ) {
+        /* Encoder has just been initialized */
+        fs_Hz  = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz );
+        fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
+    } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) {
+        /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */
+        fs_Hz  = psEncC->API_fs_Hz;
+        fs_Hz  = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz );
+        fs_Hz  = silk_max( fs_Hz, psEncC->minInternal_fs_Hz );
+        fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
+    } else {
+        /* State machine for the internal sampling rate switching */
+        if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) {
+            /* Stop transition phase */
+            psEncC->sLP.mode = 0;
+        }
+        if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) {
+            /* Check if we should switch down */
+            if( silk_SMULBB( psEncC->fs_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz )
+            {
+                /* Switch down */
+                if( psEncC->sLP.mode == 0 ) {
+                    /* New transition */
+                    psEncC->sLP.transition_frame_no = TRANSITION_FRAMES;
+
+                    /* Reset transition filter state */
+                    silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
+                }
+                if( encControl->opusCanSwitch ) {
+                    /* Stop transition phase */
+                    psEncC->sLP.mode = 0;
+
+                    /* Switch to a lower sample frequency */
+                    fs_kHz = psEncC->fs_kHz == 16 ? 12 : 8;
+                } else {
+                   if( psEncC->sLP.transition_frame_no <= 0 ) {
+                       encControl->switchReady = 1;
+                       /* Make room for redundancy */
+                       encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
+                   } else {
+                       /* Direction: down (at double speed) */
+                       psEncC->sLP.mode = -2;
+                   }
+                }
+            }
+            else
+            /* Check if we should switch up */
+            if( silk_SMULBB( psEncC->fs_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz )
+            {
+                /* Switch up */
+                if( encControl->opusCanSwitch ) {
+                    /* Switch to a higher sample frequency */
+                    fs_kHz = psEncC->fs_kHz == 8 ? 12 : 16;
+
+                    /* New transition */
+                    psEncC->sLP.transition_frame_no = 0;
+
+                    /* Reset transition filter state */
+                    silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
+
+                    /* Direction: up */
+                    psEncC->sLP.mode = 1;
+                } else {
+                   if( psEncC->sLP.mode == 0 ) {
+                       encControl->switchReady = 1;
+                       /* Make room for redundancy */
+                       encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
+                   } else {
+                       /* Direction: up */
+                       psEncC->sLP.mode = 1;
+                   }
+                }
+            } else {
+               if (psEncC->sLP.mode<0)
+                  psEncC->sLP.mode = 1;
+            }
+        }
+    }
+
+    return fs_kHz;
+}
diff --git a/third_party/opus/src/silk/control_codec.c b/third_party/opus/src/silk/control_codec.c
new file mode 100644
index 0000000..044eea3
--- /dev/null
+++ b/third_party/opus/src/silk/control_codec.c
@@ -0,0 +1,428 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#define silk_encoder_state_Fxx      silk_encoder_state_FIX
+#else
+#include "main_FLP.h"
+#define silk_encoder_state_Fxx      silk_encoder_state_FLP
+#endif
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+#include "pitch_est_defines.h"
+
+static opus_int silk_setup_resamplers(
+    silk_encoder_state_Fxx          *psEnc,             /* I/O                      */
+    opus_int                        fs_kHz              /* I                        */
+);
+
+static opus_int silk_setup_fs(
+    silk_encoder_state_Fxx          *psEnc,             /* I/O                      */
+    opus_int                        fs_kHz,             /* I                        */
+    opus_int                        PacketSize_ms       /* I                        */
+);
+
+static opus_int silk_setup_complexity(
+    silk_encoder_state              *psEncC,            /* I/O                      */
+    opus_int                        Complexity          /* I                        */
+);
+
+static OPUS_INLINE opus_int silk_setup_LBRR(
+    silk_encoder_state              *psEncC,            /* I/O                      */
+    const opus_int32                TargetRate_bps      /* I                        */
+);
+
+
+/* Control encoder */
+opus_int silk_control_encoder(
+    silk_encoder_state_Fxx          *psEnc,                                 /* I/O  Pointer to Silk encoder state                                               */
+    silk_EncControlStruct           *encControl,                            /* I    Control structure                                                           */
+    const opus_int32                TargetRate_bps,                         /* I    Target max bitrate (bps)                                                    */
+    const opus_int                  allow_bw_switch,                        /* I    Flag to allow switching audio bandwidth                                     */
+    const opus_int                  channelNb,                              /* I    Channel number                                                              */
+    const opus_int                  force_fs_kHz
+)
+{
+    opus_int   fs_kHz, ret = 0;
+
+    psEnc->sCmn.useDTX                 = encControl->useDTX;
+    psEnc->sCmn.useCBR                 = encControl->useCBR;
+    psEnc->sCmn.API_fs_Hz              = encControl->API_sampleRate;
+    psEnc->sCmn.maxInternal_fs_Hz      = encControl->maxInternalSampleRate;
+    psEnc->sCmn.minInternal_fs_Hz      = encControl->minInternalSampleRate;
+    psEnc->sCmn.desiredInternal_fs_Hz  = encControl->desiredInternalSampleRate;
+    psEnc->sCmn.useInBandFEC           = encControl->useInBandFEC;
+    psEnc->sCmn.nChannelsAPI           = encControl->nChannelsAPI;
+    psEnc->sCmn.nChannelsInternal      = encControl->nChannelsInternal;
+    psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch;
+    psEnc->sCmn.channelNb              = channelNb;
+
+    if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) {
+        if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) {
+            /* Change in API sampling rate in the middle of encoding a packet */
+            ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz );
+        }
+        return ret;
+    }
+
+    /* Beyond this point we know that there are no previously coded frames in the payload buffer */
+
+    /********************************************/
+    /* Determine internal sampling rate         */
+    /********************************************/
+    fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl );
+    if( force_fs_kHz ) {
+       fs_kHz = force_fs_kHz;
+    }
+    /********************************************/
+    /* Prepare resampler and buffered data      */
+    /********************************************/
+    ret += silk_setup_resamplers( psEnc, fs_kHz );
+
+    /********************************************/
+    /* Set internal sampling frequency          */
+    /********************************************/
+    ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms );
+
+    /********************************************/
+    /* Set encoding complexity                  */
+    /********************************************/
+    ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity  );
+
+    /********************************************/
+    /* Set packet loss rate measured by farend  */
+    /********************************************/
+    psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage;
+
+    /********************************************/
+    /* Set LBRR usage                           */
+    /********************************************/
+    ret += silk_setup_LBRR( &psEnc->sCmn, TargetRate_bps );
+
+    psEnc->sCmn.controlled_since_last_payload = 1;
+
+    return ret;
+}
+
+static opus_int silk_setup_resamplers(
+    silk_encoder_state_Fxx          *psEnc,             /* I/O                      */
+    opus_int                         fs_kHz              /* I                        */
+)
+{
+    opus_int   ret = SILK_NO_ERROR;
+    SAVE_STACK;
+
+    if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz )
+    {
+        if( psEnc->sCmn.fs_kHz == 0 ) {
+            /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+            ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 );
+        } else {
+            VARDECL( opus_int16, x_buf_API_fs_Hz );
+            VARDECL( silk_resampler_state_struct, temp_resampler_state );
+#ifdef FIXED_POINT
+            opus_int16 *x_bufFIX = psEnc->x_buf;
+#else
+            VARDECL( opus_int16, x_bufFIX );
+            opus_int32 new_buf_samples;
+#endif
+            opus_int32 api_buf_samples;
+            opus_int32 old_buf_samples;
+            opus_int32 buf_length_ms;
+
+            buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS;
+            old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz;
+
+#ifndef FIXED_POINT
+            new_buf_samples = buf_length_ms * fs_kHz;
+            ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ),
+                   opus_int16 );
+            silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples );
+#endif
+
+            /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */
+            ALLOC( temp_resampler_state, 1, silk_resampler_state_struct );
+            ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 );
+
+            /* Calculate number of samples to temporarily upsample */
+            api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 );
+
+            /* Temporary resampling of x_buf data to API_fs_Hz */
+            ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 );
+            ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples );
+
+            /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+            ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 );
+
+            /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */
+            ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples );
+
+#ifndef FIXED_POINT
+            silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples);
+#endif
+        }
+    }
+
+    psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz;
+
+    RESTORE_STACK;
+    return ret;
+}
+
+static opus_int silk_setup_fs(
+    silk_encoder_state_Fxx          *psEnc,             /* I/O                      */
+    opus_int                        fs_kHz,             /* I                        */
+    opus_int                        PacketSize_ms       /* I                        */
+)
+{
+    opus_int ret = SILK_NO_ERROR;
+
+    /* Set packet size */
+    if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) {
+        if( ( PacketSize_ms !=  10 ) &&
+            ( PacketSize_ms !=  20 ) &&
+            ( PacketSize_ms !=  40 ) &&
+            ( PacketSize_ms !=  60 ) ) {
+            ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+        }
+        if( PacketSize_ms <= 10 ) {
+            psEnc->sCmn.nFramesPerPacket = 1;
+            psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1;
+            psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz );
+            psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
+            if( psEnc->sCmn.fs_kHz == 8 ) {
+                psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+            } else {
+                psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+            }
+        } else {
+            psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS );
+            psEnc->sCmn.nb_subfr = MAX_NB_SUBFR;
+            psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz );
+            psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
+            if( psEnc->sCmn.fs_kHz == 8 ) {
+                psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+            } else {
+                psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
+            }
+        }
+        psEnc->sCmn.PacketSize_ms  = PacketSize_ms;
+        psEnc->sCmn.TargetRate_bps = 0;         /* trigger new SNR computation */
+    }
+
+    /* Set internal sampling frequency */
+    silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
+    silk_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 );
+    if( psEnc->sCmn.fs_kHz != fs_kHz ) {
+        /* reset part of the state */
+        silk_memset( &psEnc->sShape,               0, sizeof( psEnc->sShape ) );
+        silk_memset( &psEnc->sPrefilt,             0, sizeof( psEnc->sPrefilt ) );
+        silk_memset( &psEnc->sCmn.sNSQ,            0, sizeof( psEnc->sCmn.sNSQ ) );
+        silk_memset( psEnc->sCmn.prev_NLSFq_Q15,   0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+        silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) );
+        psEnc->sCmn.inputBufIx                  = 0;
+        psEnc->sCmn.nFramesEncoded              = 0;
+        psEnc->sCmn.TargetRate_bps              = 0;     /* trigger new SNR computation */
+
+        /* Initialize non-zero parameters */
+        psEnc->sCmn.prevLag                     = 100;
+        psEnc->sCmn.first_frame_after_reset     = 1;
+        psEnc->sPrefilt.lagPrev                 = 100;
+        psEnc->sShape.LastGainIndex             = 10;
+        psEnc->sCmn.sNSQ.lagPrev                = 100;
+        psEnc->sCmn.sNSQ.prev_gain_Q16          = 65536;
+        psEnc->sCmn.prevSignalType              = TYPE_NO_VOICE_ACTIVITY;
+
+        psEnc->sCmn.fs_kHz = fs_kHz;
+        if( psEnc->sCmn.fs_kHz == 8 ) {
+            if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+                psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+            } else {
+                psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+            }
+        } else {
+            if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+                psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
+            } else {
+                psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+            }
+        }
+        if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) {
+            psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER;
+            psEnc->sCmn.psNLSF_CB  = &silk_NLSF_CB_NB_MB;
+        } else {
+            psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER;
+            psEnc->sCmn.psNLSF_CB  = &silk_NLSF_CB_WB;
+        }
+        psEnc->sCmn.subfr_length   = SUB_FRAME_LENGTH_MS * fs_kHz;
+        psEnc->sCmn.frame_length   = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr );
+        psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz );
+        psEnc->sCmn.la_pitch       = silk_SMULBB( LA_PITCH_MS, fs_kHz );
+        psEnc->sCmn.max_pitch_lag  = silk_SMULBB( 18, fs_kHz );
+        if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+            psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
+        } else {
+            psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
+        }
+        if( psEnc->sCmn.fs_kHz == 16 ) {
+            psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_WB, 9 );
+            psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF;
+        } else if( psEnc->sCmn.fs_kHz == 12 ) {
+            psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_MB, 9 );
+            psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF;
+        } else {
+            psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_NB, 9 );
+            psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
+        }
+    }
+
+    /* Check that settings are valid */
+    silk_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length );
+
+    return ret;
+}
+
+static opus_int silk_setup_complexity(
+    silk_encoder_state              *psEncC,            /* I/O                      */
+    opus_int                        Complexity          /* I                        */
+)
+{
+    opus_int ret = 0;
+
+    /* Set encoding complexity */
+    silk_assert( Complexity >= 0 && Complexity <= 10 );
+    if( Complexity < 2 ) {
+        psEncC->pitchEstimationComplexity       = SILK_PE_MIN_COMPLEX;
+        psEncC->pitchEstimationThreshold_Q16    = SILK_FIX_CONST( 0.8, 16 );
+        psEncC->pitchEstimationLPCOrder         = 6;
+        psEncC->shapingLPCOrder                 = 8;
+        psEncC->la_shape                        = 3 * psEncC->fs_kHz;
+        psEncC->nStatesDelayedDecision          = 1;
+        psEncC->useInterpolatedNLSFs            = 0;
+        psEncC->LTPQuantLowComplexity           = 1;
+        psEncC->NLSF_MSVQ_Survivors             = 2;
+        psEncC->warping_Q16                     = 0;
+    } else if( Complexity < 4 ) {
+        psEncC->pitchEstimationComplexity       = SILK_PE_MID_COMPLEX;
+        psEncC->pitchEstimationThreshold_Q16    = SILK_FIX_CONST( 0.76, 16 );
+        psEncC->pitchEstimationLPCOrder         = 8;
+        psEncC->shapingLPCOrder                 = 10;
+        psEncC->la_shape                        = 5 * psEncC->fs_kHz;
+        psEncC->nStatesDelayedDecision          = 1;
+        psEncC->useInterpolatedNLSFs            = 0;
+        psEncC->LTPQuantLowComplexity           = 0;
+        psEncC->NLSF_MSVQ_Survivors             = 4;
+        psEncC->warping_Q16                     = 0;
+    } else if( Complexity < 6 ) {
+        psEncC->pitchEstimationComplexity       = SILK_PE_MID_COMPLEX;
+        psEncC->pitchEstimationThreshold_Q16    = SILK_FIX_CONST( 0.74, 16 );
+        psEncC->pitchEstimationLPCOrder         = 10;
+        psEncC->shapingLPCOrder                 = 12;
+        psEncC->la_shape                        = 5 * psEncC->fs_kHz;
+        psEncC->nStatesDelayedDecision          = 2;
+        psEncC->useInterpolatedNLSFs            = 1;
+        psEncC->LTPQuantLowComplexity           = 0;
+        psEncC->NLSF_MSVQ_Survivors             = 8;
+        psEncC->warping_Q16                     = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+    } else if( Complexity < 8 ) {
+        psEncC->pitchEstimationComplexity       = SILK_PE_MID_COMPLEX;
+        psEncC->pitchEstimationThreshold_Q16    = SILK_FIX_CONST( 0.72, 16 );
+        psEncC->pitchEstimationLPCOrder         = 12;
+        psEncC->shapingLPCOrder                 = 14;
+        psEncC->la_shape                        = 5 * psEncC->fs_kHz;
+        psEncC->nStatesDelayedDecision          = 3;
+        psEncC->useInterpolatedNLSFs            = 1;
+        psEncC->LTPQuantLowComplexity           = 0;
+        psEncC->NLSF_MSVQ_Survivors             = 16;
+        psEncC->warping_Q16                     = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+    } else {
+        psEncC->pitchEstimationComplexity       = SILK_PE_MAX_COMPLEX;
+        psEncC->pitchEstimationThreshold_Q16    = SILK_FIX_CONST( 0.7, 16 );
+        psEncC->pitchEstimationLPCOrder         = 16;
+        psEncC->shapingLPCOrder                 = 16;
+        psEncC->la_shape                        = 5 * psEncC->fs_kHz;
+        psEncC->nStatesDelayedDecision          = MAX_DEL_DEC_STATES;
+        psEncC->useInterpolatedNLSFs            = 1;
+        psEncC->LTPQuantLowComplexity           = 0;
+        psEncC->NLSF_MSVQ_Survivors             = 32;
+        psEncC->warping_Q16                     = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+    }
+
+    /* Do not allow higher pitch estimation LPC order than predict LPC order */
+    psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder );
+    psEncC->shapeWinLength          = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape;
+    psEncC->Complexity              = Complexity;
+
+    silk_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER );
+    silk_assert( psEncC->shapingLPCOrder         <= MAX_SHAPE_LPC_ORDER      );
+    silk_assert( psEncC->nStatesDelayedDecision  <= MAX_DEL_DEC_STATES       );
+    silk_assert( psEncC->warping_Q16             <= 32767                    );
+    silk_assert( psEncC->la_shape                <= LA_SHAPE_MAX             );
+    silk_assert( psEncC->shapeWinLength          <= SHAPE_LPC_WIN_MAX        );
+    silk_assert( psEncC->NLSF_MSVQ_Survivors     <= NLSF_VQ_MAX_SURVIVORS    );
+
+    return ret;
+}
+
+static OPUS_INLINE opus_int silk_setup_LBRR(
+    silk_encoder_state          *psEncC,            /* I/O                      */
+    const opus_int32            TargetRate_bps      /* I                        */
+)
+{
+    opus_int   LBRR_in_previous_packet, ret = SILK_NO_ERROR;
+    opus_int32 LBRR_rate_thres_bps;
+
+    LBRR_in_previous_packet = psEncC->LBRR_enabled;
+    psEncC->LBRR_enabled = 0;
+    if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) {
+        if( psEncC->fs_kHz == 8 ) {
+            LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS;
+        } else if( psEncC->fs_kHz == 12 ) {
+            LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS;
+        } else {
+            LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS;
+        }
+        LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) );
+
+        if( TargetRate_bps > LBRR_rate_thres_bps ) {
+            /* Set gain increase for coding LBRR excitation */
+            if( LBRR_in_previous_packet == 0 ) {
+                /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
+                psEncC->LBRR_GainIncreases = 7;
+            } else {
+                psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 );
+            }
+            psEncC->LBRR_enabled = 1;
+        }
+    }
+
+    return ret;
+}
diff --git a/third_party/opus/src/silk/debug.c b/third_party/opus/src/silk/debug.c
new file mode 100644
index 0000000..9253faf
--- /dev/null
+++ b/third_party/opus/src/silk/debug.c
@@ -0,0 +1,170 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "debug.h"
+#include "SigProc_FIX.h"
+
+#if SILK_TIC_TOC
+
+#ifdef _WIN32
+
+#if (defined(_WIN32) || defined(_WINCE))
+#include <windows.h>    /* timer */
+#else   /* Linux or Mac*/
+#include <sys/time.h>
+#endif
+
+unsigned long silk_GetHighResolutionTime(void) /* O  time in usec*/
+{
+    /* Returns a time counter in microsec   */
+    /* the resolution is platform dependent */
+    /* but is typically 1.62 us resolution  */
+    LARGE_INTEGER lpPerformanceCount;
+    LARGE_INTEGER lpFrequency;
+    QueryPerformanceCounter(&lpPerformanceCount);
+    QueryPerformanceFrequency(&lpFrequency);
+    return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart);
+}
+#else   /* Linux or Mac*/
+unsigned long GetHighResolutionTime(void) /* O  time in usec*/
+{
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    return((tv.tv_sec*1000000)+(tv.tv_usec));
+}
+#endif
+
+int           silk_Timer_nTimers = 0;
+int           silk_Timer_depth_ctr = 0;
+char          silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN];
+#ifdef WIN32
+LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX];
+#else
+unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX];
+#endif
+unsigned int  silk_Timer_cnt[silk_NUM_TIMERS_MAX];
+opus_int64     silk_Timer_min[silk_NUM_TIMERS_MAX];
+opus_int64     silk_Timer_sum[silk_NUM_TIMERS_MAX];
+opus_int64     silk_Timer_max[silk_NUM_TIMERS_MAX];
+opus_int64     silk_Timer_depth[silk_NUM_TIMERS_MAX];
+
+#ifdef WIN32
+void silk_TimerSave(char *file_name)
+{
+    if( silk_Timer_nTimers > 0 )
+    {
+        int k;
+        FILE *fp;
+        LARGE_INTEGER lpFrequency;
+        LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2;
+        int del = 0x7FFFFFFF;
+        double avg, sum_avg;
+        /* estimate overhead of calling performance counters */
+        for( k = 0; k < 1000; k++ ) {
+            QueryPerformanceCounter(&lpPerformanceCount1);
+            QueryPerformanceCounter(&lpPerformanceCount2);
+            lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart;
+            if( (int)lpPerformanceCount2.LowPart < del )
+                del = lpPerformanceCount2.LowPart;
+        }
+        QueryPerformanceFrequency(&lpFrequency);
+        /* print results to file */
+        sum_avg = 0.0f;
+        for( k = 0; k < silk_Timer_nTimers; k++ ) {
+            if (silk_Timer_depth[k] == 0) {
+                sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k];
+            }
+        }
+        fp = fopen(file_name, "w");
+        fprintf(fp, "                                min         avg     %%         max      count\n");
+        for( k = 0; k < silk_Timer_nTimers; k++ ) {
+            if (silk_Timer_depth[k] == 0) {
+                fprintf(fp, "%-28s", silk_Timer_tags[k]);
+            } else if (silk_Timer_depth[k] == 1) {
+                fprintf(fp, " %-27s", silk_Timer_tags[k]);
+            } else if (silk_Timer_depth[k] == 2) {
+                fprintf(fp, "  %-26s", silk_Timer_tags[k]);
+            } else if (silk_Timer_depth[k] == 3) {
+                fprintf(fp, "   %-25s", silk_Timer_tags[k]);
+            } else {
+                fprintf(fp, "    %-24s", silk_Timer_tags[k]);
+            }
+            avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart;
+            fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart);
+            fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]);
+            fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart);
+            fprintf(fp, "%10d\n", silk_Timer_cnt[k]);
+        }
+        fprintf(fp, "                                microseconds\n");
+        fclose(fp);
+    }
+}
+#else
+void silk_TimerSave(char *file_name)
+{
+    if( silk_Timer_nTimers > 0 )
+    {
+        int k;
+        FILE *fp;
+        /* print results to file */
+        fp = fopen(file_name, "w");
+        fprintf(fp, "                                min         avg         max      count\n");
+        for( k = 0; k < silk_Timer_nTimers; k++ )
+        {
+            if (silk_Timer_depth[k] == 0) {
+                fprintf(fp, "%-28s", silk_Timer_tags[k]);
+            } else if (silk_Timer_depth[k] == 1) {
+                fprintf(fp, " %-27s", silk_Timer_tags[k]);
+            } else if (silk_Timer_depth[k] == 2) {
+                fprintf(fp, "  %-26s", silk_Timer_tags[k]);
+            } else if (silk_Timer_depth[k] == 3) {
+                fprintf(fp, "   %-25s", silk_Timer_tags[k]);
+            } else {
+                fprintf(fp, "    %-24s", silk_Timer_tags[k]);
+            }
+            fprintf(fp, "%d ", silk_Timer_min[k]);
+            fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]);
+            fprintf(fp, "%d ", silk_Timer_max[k]);
+            fprintf(fp, "%10d\n", silk_Timer_cnt[k]);
+        }
+        fprintf(fp, "                                microseconds\n");
+        fclose(fp);
+    }
+}
+#endif
+
+#endif /* SILK_TIC_TOC */
+
+#if SILK_DEBUG
+FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ];
+int silk_debug_store_count = 0;
+#endif /* SILK_DEBUG */
+
diff --git a/third_party/opus/src/silk/debug.h b/third_party/opus/src/silk/debug.h
new file mode 100644
index 0000000..efb6d3e
--- /dev/null
+++ b/third_party/opus/src/silk/debug.h
@@ -0,0 +1,279 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_DEBUG_H
+#define SILK_DEBUG_H
+
+#include "typedef.h"
+#include <stdio.h>      /* file writing */
+#include <string.h>     /* strcpy, strcmp */
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+unsigned long GetHighResolutionTime(void); /* O  time in usec*/
+
+/* make SILK_DEBUG dependent on compiler's _DEBUG */
+#if defined _WIN32
+    #ifdef _DEBUG
+        #define SILK_DEBUG  1
+    #else
+        #define SILK_DEBUG  0
+    #endif
+
+    /* overrule the above */
+    #if 0
+    /*  #define NO_ASSERTS*/
+    #undef  SILK_DEBUG
+    #define SILK_DEBUG  1
+    #endif
+#else
+    #define SILK_DEBUG  0
+#endif
+
+/* Flag for using timers */
+#define SILK_TIC_TOC    0
+
+
+#if SILK_TIC_TOC
+
+#if (defined(_WIN32) || defined(_WINCE))
+#include <windows.h>    /* timer */
+#else   /* Linux or Mac*/
+#include <sys/time.h>
+#endif
+
+/*********************************/
+/* timer functions for profiling */
+/*********************************/
+/* example:                                                         */
+/*                                                                  */
+/* TIC(LPC)                                                         */
+/* do_LPC(in_vec, order, acoef);    // do LPC analysis              */
+/* TOC(LPC)                                                         */
+/*                                                                  */
+/* and call the following just before exiting (from main)           */
+/*                                                                  */
+/* silk_TimerSave("silk_TimingData.txt");                           */
+/*                                                                  */
+/* results are now in silk_TimingData.txt                           */
+
+void silk_TimerSave(char *file_name);
+
+/* max number of timers (in different locations) */
+#define silk_NUM_TIMERS_MAX                  50
+/* max length of name tags in TIC(..), TOC(..) */
+#define silk_NUM_TIMERS_MAX_TAG_LEN          30
+
+extern int           silk_Timer_nTimers;
+extern int           silk_Timer_depth_ctr;
+extern char          silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN];
+#ifdef _WIN32
+extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX];
+#else
+extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX];
+#endif
+extern unsigned int  silk_Timer_cnt[silk_NUM_TIMERS_MAX];
+extern opus_int64    silk_Timer_sum[silk_NUM_TIMERS_MAX];
+extern opus_int64    silk_Timer_max[silk_NUM_TIMERS_MAX];
+extern opus_int64    silk_Timer_min[silk_NUM_TIMERS_MAX];
+extern opus_int64    silk_Timer_depth[silk_NUM_TIMERS_MAX];
+
+/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */
+#ifdef _WIN32
+#define TIC(TAG_NAME) {                                     \
+    static int init = 0;                                    \
+    static int ID = -1;                                     \
+    if( init == 0 )                                         \
+    {                                                       \
+        int k;                                              \
+        init = 1;                                           \
+        for( k = 0; k < silk_Timer_nTimers; k++ ) {         \
+            if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+                ID = k;                                     \
+                break;                                      \
+            }                                               \
+        }                                                   \
+        if (ID == -1) {                                     \
+            ID = silk_Timer_nTimers;                        \
+            silk_Timer_nTimers++;                           \
+            silk_Timer_depth[ID] = silk_Timer_depth_ctr;    \
+            strcpy(silk_Timer_tags[ID], #TAG_NAME);         \
+            silk_Timer_cnt[ID] = 0;                         \
+            silk_Timer_sum[ID] = 0;                         \
+            silk_Timer_min[ID] = 0xFFFFFFFF;                \
+            silk_Timer_max[ID] = 0;                         \
+        }                                                   \
+    }                                                       \
+    silk_Timer_depth_ctr++;                                 \
+    QueryPerformanceCounter(&silk_Timer_start[ID]);         \
+}
+#else
+#define TIC(TAG_NAME) {                                     \
+    static int init = 0;                                    \
+    static int ID = -1;                                     \
+    if( init == 0 )                                         \
+    {                                                       \
+        int k;                                              \
+        init = 1;                                           \
+        for( k = 0; k < silk_Timer_nTimers; k++ ) {         \
+        if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) {  \
+                ID = k;                                     \
+                break;                                      \
+            }                                               \
+        }                                                   \
+        if (ID == -1) {                                     \
+            ID = silk_Timer_nTimers;                        \
+            silk_Timer_nTimers++;                           \
+            silk_Timer_depth[ID] = silk_Timer_depth_ctr;    \
+            strcpy(silk_Timer_tags[ID], #TAG_NAME);         \
+            silk_Timer_cnt[ID] = 0;                         \
+            silk_Timer_sum[ID] = 0;                         \
+            silk_Timer_min[ID] = 0xFFFFFFFF;                \
+            silk_Timer_max[ID] = 0;                         \
+        }                                                   \
+    }                                                       \
+    silk_Timer_depth_ctr++;                                 \
+    silk_Timer_start[ID] = GetHighResolutionTime();         \
+}
+#endif
+
+#ifdef _WIN32
+#define TOC(TAG_NAME) {                                             \
+    LARGE_INTEGER lpPerformanceCount;                               \
+    static int init = 0;                                            \
+    static int ID = 0;                                              \
+    if( init == 0 )                                                 \
+    {                                                               \
+        int k;                                                      \
+        init = 1;                                                   \
+        for( k = 0; k < silk_Timer_nTimers; k++ ) {                 \
+            if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) {      \
+                ID = k;                                             \
+                break;                                              \
+            }                                                       \
+        }                                                           \
+    }                                                               \
+    QueryPerformanceCounter(&lpPerformanceCount);                   \
+    lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart;   \
+    if((lpPerformanceCount.QuadPart < 100000000) &&                 \
+        (lpPerformanceCount.QuadPart >= 0)) {                       \
+        silk_Timer_cnt[ID]++;                                       \
+        silk_Timer_sum[ID] += lpPerformanceCount.QuadPart;          \
+        if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] )      \
+            silk_Timer_max[ID] = lpPerformanceCount.QuadPart;       \
+        if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] )      \
+            silk_Timer_min[ID] = lpPerformanceCount.QuadPart;       \
+    }                                                               \
+    silk_Timer_depth_ctr--;                                         \
+}
+#else
+#define TOC(TAG_NAME) {                                             \
+    unsigned long endTime;                                          \
+    static int init = 0;                                            \
+    static int ID = 0;                                              \
+    if( init == 0 )                                                 \
+    {                                                               \
+        int k;                                                      \
+        init = 1;                                                   \
+        for( k = 0; k < silk_Timer_nTimers; k++ ) {                 \
+            if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) {      \
+                ID = k;                                             \
+                break;                                              \
+            }                                                       \
+        }                                                           \
+    }                                                               \
+    endTime = GetHighResolutionTime();                              \
+    endTime -= silk_Timer_start[ID];                                \
+    if((endTime < 100000000) &&                                     \
+        (endTime >= 0)) {                                           \
+        silk_Timer_cnt[ID]++;                                       \
+        silk_Timer_sum[ID] += endTime;                              \
+        if( endTime > silk_Timer_max[ID] )                          \
+            silk_Timer_max[ID] = endTime;                           \
+        if( endTime < silk_Timer_min[ID] )                          \
+            silk_Timer_min[ID] = endTime;                           \
+    }                                                               \
+        silk_Timer_depth_ctr--;                                     \
+}
+#endif
+
+#else /* SILK_TIC_TOC */
+
+/* define macros as empty strings */
+#define TIC(TAG_NAME)
+#define TOC(TAG_NAME)
+#define silk_TimerSave(FILE_NAME)
+
+#endif /* SILK_TIC_TOC */
+
+
+#if SILK_DEBUG
+/************************************/
+/* write data to file for debugging */
+/************************************/
+/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */
+
+#define silk_NUM_STORES_MAX                                  100
+extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ];
+extern int silk_debug_store_count;
+
+/* Faster way of storing the data */
+#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) {          \
+    static opus_int init = 0, cnt = 0;                              \
+    static FILE **fp;                                               \
+    if (init == 0) {                                                \
+        init = 1;                                                   \
+        cnt = silk_debug_store_count++;                             \
+        silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb");       \
+    }                                                               \
+    fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]);   \
+}
+
+/* Call this at the end of main() */
+#define SILK_DEBUG_STORE_CLOSE_FILES {                              \
+    opus_int i;                                                     \
+    for( i = 0; i < silk_debug_store_count; i++ ) {                 \
+        fclose( silk_debug_store_fp[ i ] );                         \
+    }                                                               \
+}
+
+#else /* SILK_DEBUG */
+
+/* define macros as empty strings */
+#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES)
+#define SILK_DEBUG_STORE_CLOSE_FILES
+
+#endif /* SILK_DEBUG */
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* SILK_DEBUG_H */
diff --git a/third_party/opus/src/silk/dec_API.c b/third_party/opus/src/silk/dec_API.c
new file mode 100644
index 0000000..b7d8ed4
--- /dev/null
+++ b/third_party/opus/src/silk/dec_API.c
@@ -0,0 +1,419 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "API.h"
+#include "main.h"
+#include "stack_alloc.h"
+#include "os_support.h"
+
+/************************/
+/* Decoder Super Struct */
+/************************/
+typedef struct {
+    silk_decoder_state          channel_state[ DECODER_NUM_CHANNELS ];
+    stereo_dec_state                sStereo;
+    opus_int                         nChannelsAPI;
+    opus_int                         nChannelsInternal;
+    opus_int                         prev_decode_only_middle;
+} silk_decoder;
+
+/*********************/
+/* Decoder functions */
+/*********************/
+
+opus_int silk_Get_Decoder_Size(                         /* O    Returns error code                              */
+    opus_int                        *decSizeBytes       /* O    Number of bytes in SILK decoder state           */
+)
+{
+    opus_int ret = SILK_NO_ERROR;
+
+    *decSizeBytes = sizeof( silk_decoder );
+
+    return ret;
+}
+
+/* Reset decoder state */
+opus_int silk_InitDecoder(                              /* O    Returns error code                              */
+    void                            *decState           /* I/O  State                                           */
+)
+{
+    opus_int n, ret = SILK_NO_ERROR;
+    silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state;
+
+    for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) {
+        ret  = silk_init_decoder( &channel_state[ n ] );
+    }
+    silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo));
+    /* Not strictly needed, but it's cleaner that way */
+    ((silk_decoder *)decState)->prev_decode_only_middle = 0;
+
+    return ret;
+}
+
+/* Decode a frame */
+opus_int silk_Decode(                                   /* O    Returns error code                              */
+    void*                           decState,           /* I/O  State                                           */
+    silk_DecControlStruct*          decControl,         /* I/O  Control Structure                               */
+    opus_int                        lostFlag,           /* I    0: no loss, 1 loss, 2 decode fec                */
+    opus_int                        newPacketFlag,      /* I    Indicates first decoder call for this packet    */
+    ec_dec                          *psRangeDec,        /* I/O  Compressor data structure                       */
+    opus_int16                      *samplesOut,        /* O    Decoded output speech vector                    */
+    opus_int32                      *nSamplesOut,       /* O    Number of samples decoded                       */
+    int                             arch                /* I    Run-time architecture                           */
+)
+{
+    opus_int   i, n, decode_only_middle = 0, ret = SILK_NO_ERROR;
+    opus_int32 nSamplesOutDec, LBRR_symbol;
+    opus_int16 *samplesOut1_tmp[ 2 ];
+    VARDECL( opus_int16, samplesOut1_tmp_storage1 );
+    VARDECL( opus_int16, samplesOut1_tmp_storage2 );
+    VARDECL( opus_int16, samplesOut2_tmp );
+    opus_int32 MS_pred_Q13[ 2 ] = { 0 };
+    opus_int16 *resample_out_ptr;
+    silk_decoder *psDec = ( silk_decoder * )decState;
+    silk_decoder_state *channel_state = psDec->channel_state;
+    opus_int has_side;
+    opus_int stereo_to_mono;
+    int delay_stack_alloc;
+    SAVE_STACK;
+
+    silk_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 );
+
+    /**********************************/
+    /* Test if first frame in payload */
+    /**********************************/
+    if( newPacketFlag ) {
+        for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+            channel_state[ n ].nFramesDecoded = 0;  /* Used to count frames in packet */
+        }
+    }
+
+    /* If Mono -> Stereo transition in bitstream: init state of second channel */
+    if( decControl->nChannelsInternal > psDec->nChannelsInternal ) {
+        ret += silk_init_decoder( &channel_state[ 1 ] );
+    }
+
+    stereo_to_mono = decControl->nChannelsInternal == 1 && psDec->nChannelsInternal == 2 &&
+                     ( decControl->internalSampleRate == 1000*channel_state[ 0 ].fs_kHz );
+
+    if( channel_state[ 0 ].nFramesDecoded == 0 ) {
+        for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+            opus_int fs_kHz_dec;
+            if( decControl->payloadSize_ms == 0 ) {
+                /* Assuming packet loss, use 10 ms */
+                channel_state[ n ].nFramesPerPacket = 1;
+                channel_state[ n ].nb_subfr = 2;
+            } else if( decControl->payloadSize_ms == 10 ) {
+                channel_state[ n ].nFramesPerPacket = 1;
+                channel_state[ n ].nb_subfr = 2;
+            } else if( decControl->payloadSize_ms == 20 ) {
+                channel_state[ n ].nFramesPerPacket = 1;
+                channel_state[ n ].nb_subfr = 4;
+            } else if( decControl->payloadSize_ms == 40 ) {
+                channel_state[ n ].nFramesPerPacket = 2;
+                channel_state[ n ].nb_subfr = 4;
+            } else if( decControl->payloadSize_ms == 60 ) {
+                channel_state[ n ].nFramesPerPacket = 3;
+                channel_state[ n ].nb_subfr = 4;
+            } else {
+                silk_assert( 0 );
+                RESTORE_STACK;
+                return SILK_DEC_INVALID_FRAME_SIZE;
+            }
+            fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1;
+            if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) {
+                silk_assert( 0 );
+                RESTORE_STACK;
+                return SILK_DEC_INVALID_SAMPLING_FREQUENCY;
+            }
+            ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate );
+        }
+    }
+
+    if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) {
+        silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) );
+        silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) );
+        silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) );
+    }
+    psDec->nChannelsAPI      = decControl->nChannelsAPI;
+    psDec->nChannelsInternal = decControl->nChannelsInternal;
+
+    if( decControl->API_sampleRate > (opus_int32)MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) {
+        ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY;
+        RESTORE_STACK;
+        return( ret );
+    }
+
+    if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) {
+        /* First decoder call for this payload */
+        /* Decode VAD flags and LBRR flag */
+        for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+            for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) {
+                channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1);
+            }
+            channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1);
+        }
+        /* Decode LBRR flags */
+        for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+            silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) );
+            if( channel_state[ n ].LBRR_flag ) {
+                if( channel_state[ n ].nFramesPerPacket == 1 ) {
+                    channel_state[ n ].LBRR_flags[ 0 ] = 1;
+                } else {
+                    LBRR_symbol = ec_dec_icdf( psRangeDec, silk_LBRR_flags_iCDF_ptr[ channel_state[ n ].nFramesPerPacket - 2 ], 8 ) + 1;
+                    for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) {
+                        channel_state[ n ].LBRR_flags[ i ] = silk_RSHIFT( LBRR_symbol, i ) & 1;
+                    }
+                }
+            }
+        }
+
+        if( lostFlag == FLAG_DECODE_NORMAL ) {
+            /* Regular decoding: skip all LBRR data */
+            for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) {
+                for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+                    if( channel_state[ n ].LBRR_flags[ i ] ) {
+                        opus_int16 pulses[ MAX_FRAME_LENGTH ];
+                        opus_int condCoding;
+
+                        if( decControl->nChannelsInternal == 2 && n == 0 ) {
+                            silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 );
+                            if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) {
+                                silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle );
+                            }
+                        }
+                        /* Use conditional coding if previous frame available */
+                        if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) {
+                            condCoding = CODE_CONDITIONALLY;
+                        } else {
+                            condCoding = CODE_INDEPENDENTLY;
+                        }
+                        silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding );
+                        silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType,
+                            channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length );
+                    }
+                }
+            }
+        }
+    }
+
+    /* Get MS predictor index */
+    if( decControl->nChannelsInternal == 2 ) {
+        if(   lostFlag == FLAG_DECODE_NORMAL ||
+            ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) )
+        {
+            silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 );
+            /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */
+            if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ||
+                ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) )
+            {
+                silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle );
+            } else {
+                decode_only_middle = 0;
+            }
+        } else {
+            for( n = 0; n < 2; n++ ) {
+                MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ];
+            }
+        }
+    }
+
+    /* Reset side channel decoder prediction memory for first frame with side coding */
+    if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) {
+        silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) );
+        silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) );
+        psDec->channel_state[ 1 ].lagPrev        = 100;
+        psDec->channel_state[ 1 ].LastGainIndex  = 10;
+        psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+        psDec->channel_state[ 1 ].first_frame_after_reset = 1;
+    }
+
+    /* Check if the temp buffer fits into the output PCM buffer. If it fits,
+       we can delay allocating the temp buffer until after the SILK peak stack
+       usage. We need to use a < and not a <= because of the two extra samples. */
+    delay_stack_alloc = decControl->internalSampleRate*decControl->nChannelsInternal
+          < decControl->API_sampleRate*decControl->nChannelsAPI;
+    ALLOC( samplesOut1_tmp_storage1, delay_stack_alloc ? ALLOC_NONE
+           : decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ),
+           opus_int16 );
+    if ( delay_stack_alloc )
+    {
+       samplesOut1_tmp[ 0 ] = samplesOut;
+       samplesOut1_tmp[ 1 ] = samplesOut + channel_state[ 0 ].frame_length + 2;
+    } else {
+       samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage1;
+       samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage1 + channel_state[ 0 ].frame_length + 2;
+    }
+
+    if( lostFlag == FLAG_DECODE_NORMAL ) {
+        has_side = !decode_only_middle;
+    } else {
+        has_side = !psDec->prev_decode_only_middle
+              || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 );
+    }
+    /* Call decoder for one frame */
+    for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+        if( n == 0 || has_side ) {
+            opus_int FrameIndex;
+            opus_int condCoding;
+
+            FrameIndex = channel_state[ 0 ].nFramesDecoded - n;
+            /* Use independent coding if no previous frame available */
+            if( FrameIndex <= 0 ) {
+                condCoding = CODE_INDEPENDENTLY;
+            } else if( lostFlag == FLAG_DECODE_LBRR ) {
+                condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY;
+            } else if( n > 0 && psDec->prev_decode_only_middle ) {
+                /* If we skipped a side frame in this packet, we don't
+                   need LTP scaling; the LTP state is well-defined. */
+                condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING;
+            } else {
+                condCoding = CODE_CONDITIONALLY;
+            }
+            ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding, arch);
+        } else {
+            silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) );
+        }
+        channel_state[ n ].nFramesDecoded++;
+    }
+
+    if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) {
+        /* Convert Mid/Side to Left/Right */
+        silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec );
+    } else {
+        /* Buffering */
+        silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) );
+        silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) );
+    }
+
+    /* Number of output samples */
+    *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) );
+
+    /* Set up pointers to temp buffers */
+    ALLOC( samplesOut2_tmp,
+           decControl->nChannelsAPI == 2 ? *nSamplesOut : ALLOC_NONE, opus_int16 );
+    if( decControl->nChannelsAPI == 2 ) {
+        resample_out_ptr = samplesOut2_tmp;
+    } else {
+        resample_out_ptr = samplesOut;
+    }
+
+    ALLOC( samplesOut1_tmp_storage2, delay_stack_alloc
+           ? decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 )
+           : ALLOC_NONE,
+           opus_int16 );
+    if ( delay_stack_alloc ) {
+       OPUS_COPY(samplesOut1_tmp_storage2, samplesOut, decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2));
+       samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage2;
+       samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage2 + channel_state[ 0 ].frame_length + 2;
+    }
+    for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) {
+
+        /* Resample decoded signal to API_sampleRate */
+        ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec );
+
+        /* Interleave if stereo output and stereo stream */
+        if( decControl->nChannelsAPI == 2 ) {
+            for( i = 0; i < *nSamplesOut; i++ ) {
+                samplesOut[ n + 2 * i ] = resample_out_ptr[ i ];
+            }
+        }
+    }
+
+    /* Create two channel output from mono stream */
+    if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) {
+        if ( stereo_to_mono ){
+            /* Resample right channel for newly collapsed stereo just in case
+               we weren't doing collapsing when switching to mono */
+            ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec );
+
+            for( i = 0; i < *nSamplesOut; i++ ) {
+                samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ];
+            }
+        } else {
+            for( i = 0; i < *nSamplesOut; i++ ) {
+                samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ];
+            }
+        }
+    }
+
+    /* Export pitch lag, measured at 48 kHz sampling rate */
+    if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) {
+        int mult_tab[ 3 ] = { 6, 4, 3 };
+        decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ];
+    } else {
+        decControl->prevPitchLag = 0;
+    }
+
+    if( lostFlag == FLAG_PACKET_LOST ) {
+       /* On packet loss, remove the gain clamping to prevent having the energy "bounce back"
+          if we lose packets when the energy is going down */
+       for ( i = 0; i < psDec->nChannelsInternal; i++ )
+          psDec->channel_state[ i ].LastGainIndex = 10;
+    } else {
+       psDec->prev_decode_only_middle = decode_only_middle;
+    }
+    RESTORE_STACK;
+    return ret;
+}
+
+#if 0
+/* Getting table of contents for a packet */
+opus_int silk_get_TOC(
+    const opus_uint8                *payload,           /* I    Payload data                                */
+    const opus_int                  nBytesIn,           /* I    Number of input bytes                       */
+    const opus_int                  nFramesPerPayload,  /* I    Number of SILK frames per payload           */
+    silk_TOC_struct                 *Silk_TOC           /* O    Type of content                             */
+)
+{
+    opus_int i, flags, ret = SILK_NO_ERROR;
+
+    if( nBytesIn < 1 ) {
+        return -1;
+    }
+    if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) {
+        return -1;
+    }
+
+    silk_memset( Silk_TOC, 0, sizeof( *Silk_TOC ) );
+
+    /* For stereo, extract the flags for the mid channel */
+    flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 );
+
+    Silk_TOC->inbandFECFlag = flags & 1;
+    for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) {
+        flags = silk_RSHIFT( flags, 1 );
+        Silk_TOC->VADFlags[ i ] = flags & 1;
+        Silk_TOC->VADFlag |= flags & 1;
+    }
+
+    return ret;
+}
+#endif
diff --git a/third_party/opus/src/silk/decode_core.c b/third_party/opus/src/silk/decode_core.c
new file mode 100644
index 0000000..e569c0e
--- /dev/null
+++ b/third_party/opus/src/silk/decode_core.c
@@ -0,0 +1,239 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/**********************************************************/
+/* Core decoder. Performs inverse NSQ operation LTP + LPC */
+/**********************************************************/
+void silk_decode_core(
+    silk_decoder_state          *psDec,                         /* I/O  Decoder state                               */
+    silk_decoder_control        *psDecCtrl,                     /* I    Decoder control                             */
+    opus_int16                  xq[],                           /* O    Decoded speech                              */
+    const opus_int16            pulses[ MAX_FRAME_LENGTH ],     /* I    Pulse signal                                */
+    int                         arch                            /* I    Run-time architecture                       */
+)
+{
+    opus_int   i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType;
+    opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ];
+    VARDECL( opus_int16, sLTP );
+    VARDECL( opus_int32, sLTP_Q15 );
+    opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10;
+    opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14;
+    VARDECL( opus_int32, res_Q14 );
+    VARDECL( opus_int32, sLPC_Q14 );
+    SAVE_STACK;
+
+    silk_assert( psDec->prev_gain_Q16 != 0 );
+
+    ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
+    ALLOC( sLTP_Q15, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
+    ALLOC( res_Q14, psDec->subfr_length, opus_int32 );
+    ALLOC( sLPC_Q14, psDec->subfr_length + MAX_LPC_ORDER, opus_int32 );
+
+    offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ];
+
+    if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) {
+        NLSF_interpolation_flag = 1;
+    } else {
+        NLSF_interpolation_flag = 0;
+    }
+
+    /* Decode excitation */
+    rand_seed = psDec->indices.Seed;
+    for( i = 0; i < psDec->frame_length; i++ ) {
+        rand_seed = silk_RAND( rand_seed );
+        psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 );
+        if( psDec->exc_Q14[ i ] > 0 ) {
+            psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4;
+        } else
+        if( psDec->exc_Q14[ i ] < 0 ) {
+            psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4;
+        }
+        psDec->exc_Q14[ i ] += offset_Q10 << 4;
+        if( rand_seed < 0 ) {
+           psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ];
+        }
+
+        rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] );
+    }
+
+    /* Copy LPC state */
+    silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+    pexc_Q14 = psDec->exc_Q14;
+    pxq      = xq;
+    sLTP_buf_idx = psDec->ltp_mem_length;
+    /* Loop over subframes */
+    for( k = 0; k < psDec->nb_subfr; k++ ) {
+        pres_Q14 = res_Q14;
+        A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ];
+
+        /* Preload LPC coeficients to array on stack. Gives small performance gain */
+        silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
+        B_Q14        = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ];
+        signalType   = psDec->indices.signalType;
+
+        Gain_Q10     = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 );
+        inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 );
+
+        /* Calculate gain adjustment factor */
+        if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) {
+            gain_adj_Q16 =  silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 );
+
+            /* Scale short term state */
+            for( i = 0; i < MAX_LPC_ORDER; i++ ) {
+                sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] );
+            }
+        } else {
+            gain_adj_Q16 = (opus_int32)1 << 16;
+        }
+
+        /* Save inv_gain */
+        silk_assert( inv_gain_Q31 != 0 );
+        psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ];
+
+        /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */
+        if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED &&
+            psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) {
+
+            silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
+            B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 );
+
+            signalType = TYPE_VOICED;
+            psDecCtrl->pitchL[ k ] = psDec->lagPrev;
+        }
+
+        if( signalType == TYPE_VOICED ) {
+            /* Voiced */
+            lag = psDecCtrl->pitchL[ k ];
+
+            /* Re-whitening */
+            if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) {
+                /* Rewhiten with new A coefs */
+                start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
+                silk_assert( start_idx > 0 );
+
+                if( k == 2 ) {
+                    silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) );
+                }
+
+                silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ],
+                    A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order, arch );
+
+                /* After rewhitening the LTP state is unscaled */
+                if( k == 0 ) {
+                    /* Do LTP downscaling to reduce inter-packet dependency */
+                    inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 );
+                }
+                for( i = 0; i < lag + LTP_ORDER/2; i++ ) {
+                    sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] );
+                }
+            } else {
+                /* Update LTP state when Gain changes */
+                if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+                    for( i = 0; i < lag + LTP_ORDER/2; i++ ) {
+                        sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] );
+                    }
+                }
+            }
+        }
+
+        /* Long-term prediction */
+        if( signalType == TYPE_VOICED ) {
+            /* Set up pointer */
+            pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+            for( i = 0; i < psDec->subfr_length; i++ ) {
+                /* Unrolled loop */
+                /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+                LTP_pred_Q13 = 2;
+                LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[  0 ], B_Q14[ 0 ] );
+                LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
+                LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
+                LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
+                LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
+                pred_lag_ptr++;
+
+                /* Generate LPC excitation */
+                pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 );
+
+                /* Update states */
+                sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 );
+                sLTP_buf_idx++;
+            }
+        } else {
+            pres_Q14 = pexc_Q14;
+        }
+
+        for( i = 0; i < psDec->subfr_length; i++ ) {
+            /* Short-term prediction */
+            silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
+            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+            LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  1 ], A_Q12_tmp[ 0 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  2 ], A_Q12_tmp[ 1 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  3 ], A_Q12_tmp[ 2 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  4 ], A_Q12_tmp[ 3 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  5 ], A_Q12_tmp[ 4 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  6 ], A_Q12_tmp[ 5 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  7 ], A_Q12_tmp[ 6 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  8 ], A_Q12_tmp[ 7 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i -  9 ], A_Q12_tmp[ 8 ] );
+            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] );
+            if( psDec->LPC_order == 16 ) {
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] );
+                LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] );
+            }
+
+            /* Add prediction to LPC excitation */
+            sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( pres_Q14[ i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) );
+
+            /* Scale with gain */
+            pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) );
+        }
+
+        /* DEBUG_STORE_DATA( dec.pcm, pxq, psDec->subfr_length * sizeof( opus_int16 ) ) */
+
+        /* Update LPC filter state */
+        silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+        pexc_Q14 += psDec->subfr_length;
+        pxq      += psDec->subfr_length;
+    }
+
+    /* Save LPC state */
+    silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/decode_frame.c b/third_party/opus/src/silk/decode_frame.c
new file mode 100644
index 0000000..a605d95
--- /dev/null
+++ b/third_party/opus/src/silk/decode_frame.c
@@ -0,0 +1,129 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "PLC.h"
+
+/****************/
+/* Decode frame */
+/****************/
+opus_int silk_decode_frame(
+    silk_decoder_state          *psDec,                         /* I/O  Pointer to Silk decoder state               */
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int16                  pOut[],                         /* O    Pointer to output speech frame              */
+    opus_int32                  *pN,                            /* O    Pointer to size of output frame             */
+    opus_int                    lostFlag,                       /* I    0: no loss, 1 loss, 2 decode fec            */
+    opus_int                    condCoding,                     /* I    The type of conditional coding to use       */
+    int                         arch                            /* I    Run-time architecture                       */
+)
+{
+    VARDECL( silk_decoder_control, psDecCtrl );
+    opus_int         L, mv_len, ret = 0;
+    SAVE_STACK;
+
+    L = psDec->frame_length;
+    ALLOC( psDecCtrl, 1, silk_decoder_control );
+    psDecCtrl->LTP_scale_Q14 = 0;
+
+    /* Safety checks */
+    silk_assert( L > 0 && L <= MAX_FRAME_LENGTH );
+
+    if(   lostFlag == FLAG_DECODE_NORMAL ||
+        ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) )
+    {
+        VARDECL( opus_int16, pulses );
+        ALLOC( pulses, (L + SHELL_CODEC_FRAME_LENGTH - 1) &
+                       ~(SHELL_CODEC_FRAME_LENGTH - 1), opus_int16 );
+        /*********************************************/
+        /* Decode quantization indices of side info  */
+        /*********************************************/
+        silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding );
+
+        /*********************************************/
+        /* Decode quantization indices of excitation */
+        /*********************************************/
+        silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType,
+                psDec->indices.quantOffsetType, psDec->frame_length );
+
+        /********************************************/
+        /* Decode parameters and pulse signal       */
+        /********************************************/
+        silk_decode_parameters( psDec, psDecCtrl, condCoding );
+
+        /********************************************************/
+        /* Run inverse NSQ                                      */
+        /********************************************************/
+        silk_decode_core( psDec, psDecCtrl, pOut, pulses, arch );
+
+        /********************************************************/
+        /* Update PLC state                                     */
+        /********************************************************/
+        silk_PLC( psDec, psDecCtrl, pOut, 0, arch );
+
+        psDec->lossCnt = 0;
+        psDec->prevSignalType = psDec->indices.signalType;
+        silk_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 );
+
+        /* A frame has been decoded without errors */
+        psDec->first_frame_after_reset = 0;
+    } else {
+        /* Handle packet loss by extrapolation */
+        silk_PLC( psDec, psDecCtrl, pOut, 1, arch );
+    }
+
+    /*************************/
+    /* Update output buffer. */
+    /*************************/
+    silk_assert( psDec->ltp_mem_length >= psDec->frame_length );
+    mv_len = psDec->ltp_mem_length - psDec->frame_length;
+    silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) );
+    silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) );
+
+    /************************************************/
+    /* Comfort noise generation / estimation        */
+    /************************************************/
+    silk_CNG( psDec, psDecCtrl, pOut, L );
+
+    /****************************************************************/
+    /* Ensure smooth connection of extrapolated and good frames     */
+    /****************************************************************/
+    silk_PLC_glue_frames( psDec, pOut, L );
+
+    /* Update some decoder state variables */
+    psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ];
+
+    /* Set output frame length */
+    *pN = L;
+
+    RESTORE_STACK;
+    return ret;
+}
diff --git a/third_party/opus/src/silk/decode_indices.c b/third_party/opus/src/silk/decode_indices.c
new file mode 100644
index 0000000..7afe5c26
--- /dev/null
+++ b/third_party/opus/src/silk/decode_indices.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Decode side-information parameters from payload */
+void silk_decode_indices(
+    silk_decoder_state          *psDec,                         /* I/O  State                                       */
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int                    FrameIndex,                     /* I    Frame number                                */
+    opus_int                    decode_LBRR,                    /* I    Flag indicating LBRR data is being decoded  */
+    opus_int                    condCoding                      /* I    The type of conditional coding to use       */
+)
+{
+    opus_int   i, k, Ix;
+    opus_int   decode_absolute_lagIndex, delta_lagIndex;
+    opus_int16 ec_ix[ MAX_LPC_ORDER ];
+    opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+
+    /*******************************************/
+    /* Decode signal type and quantizer offset */
+    /*******************************************/
+    if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) {
+        Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2;
+    } else {
+        Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 );
+    }
+    psDec->indices.signalType      = (opus_int8)silk_RSHIFT( Ix, 1 );
+    psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 );
+
+    /****************/
+    /* Decode gains */
+    /****************/
+    /* First subframe */
+    if( condCoding == CODE_CONDITIONALLY ) {
+        /* Conditional coding */
+        psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 );
+    } else {
+        /* Independent coding, in two stages: MSB bits followed by 3 LSBs */
+        psDec->indices.GainsIndices[ 0 ]  = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 );
+        psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 );
+    }
+
+    /* Remaining subframes */
+    for( i = 1; i < psDec->nb_subfr; i++ ) {
+        psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 );
+    }
+
+    /**********************/
+    /* Decode LSF Indices */
+    /**********************/
+    psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 );
+    silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] );
+    silk_assert( psDec->psNLSF_CB->order == psDec->LPC_order );
+    for( i = 0; i < psDec->psNLSF_CB->order; i++ ) {
+        Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+        if( Ix == 0 ) {
+            Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 );
+        } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) {
+            Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 );
+        }
+        psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE );
+    }
+
+    /* Decode LSF interpolation factor */
+    if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+        psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 );
+    } else {
+        psDec->indices.NLSFInterpCoef_Q2 = 4;
+    }
+
+    if( psDec->indices.signalType == TYPE_VOICED )
+    {
+        /*********************/
+        /* Decode pitch lags */
+        /*********************/
+        /* Get lag index */
+        decode_absolute_lagIndex = 1;
+        if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) {
+            /* Decode Delta index */
+            delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 );
+            if( delta_lagIndex > 0 ) {
+                delta_lagIndex = delta_lagIndex - 9;
+                psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex );
+                decode_absolute_lagIndex = 0;
+            }
+        }
+        if( decode_absolute_lagIndex ) {
+            /* Absolute decoding */
+            psDec->indices.lagIndex  = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 );
+            psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 );
+        }
+        psDec->ec_prevLagIndex = psDec->indices.lagIndex;
+
+        /* Get countour index */
+        psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 );
+
+        /********************/
+        /* Decode LTP gains */
+        /********************/
+        /* Decode PERIndex value */
+        psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 );
+
+        for( k = 0; k < psDec->nb_subfr; k++ ) {
+            psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 );
+        }
+
+        /**********************/
+        /* Decode LTP scaling */
+        /**********************/
+        if( condCoding == CODE_INDEPENDENTLY ) {
+            psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 );
+        } else {
+            psDec->indices.LTP_scaleIndex = 0;
+        }
+    }
+    psDec->ec_prevSignalType = psDec->indices.signalType;
+
+    /***************/
+    /* Decode seed */
+    /***************/
+    psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 );
+}
diff --git a/third_party/opus/src/silk/decode_parameters.c b/third_party/opus/src/silk/decode_parameters.c
new file mode 100644
index 0000000..e345b1dc
--- /dev/null
+++ b/third_party/opus/src/silk/decode_parameters.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Decode parameters from payload */
+void silk_decode_parameters(
+    silk_decoder_state          *psDec,                         /* I/O  State                                       */
+    silk_decoder_control        *psDecCtrl,                     /* I/O  Decoder control                             */
+    opus_int                    condCoding                      /* I    The type of conditional coding to use       */
+)
+{
+    opus_int   i, k, Ix;
+    opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ];
+    const opus_int8 *cbk_ptr_Q7;
+
+    /* Dequant Gains */
+    silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices,
+        &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr );
+
+    /****************/
+    /* Decode NLSFs */
+    /****************/
+    silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB );
+
+    /* Convert NLSF parameters to AR prediction filter coefficients */
+    silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order );
+
+    /* If just reset, e.g., because internal Fs changed, do not allow interpolation */
+    /* improves the case of packet loss in the first frame after a switch           */
+    if( psDec->first_frame_after_reset == 1 ) {
+        psDec->indices.NLSFInterpCoef_Q2 = 4;
+    }
+
+    if( psDec->indices.NLSFInterpCoef_Q2 < 4 ) {
+        /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */
+        /* the previous NLSF1, and the current NLSF1                                   */
+        for( i = 0; i < psDec->LPC_order; i++ ) {
+            pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2,
+                pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 );
+        }
+
+        /* Convert NLSF parameters to AR prediction filter coefficients */
+        silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order );
+    } else {
+        /* Copy LPC coefficients for first half from second half */
+        silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
+    }
+
+    silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) );
+
+    /* After a packet loss do BWE of LPC coefs */
+    if( psDec->lossCnt ) {
+        silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 );
+        silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 );
+    }
+
+    if( psDec->indices.signalType == TYPE_VOICED ) {
+        /*********************/
+        /* Decode pitch lags */
+        /*********************/
+
+        /* Decode pitch values */
+        silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr );
+
+        /* Decode Codebook Index */
+        cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */
+
+        for( k = 0; k < psDec->nb_subfr; k++ ) {
+            Ix = psDec->indices.LTPIndex[ k ];
+            for( i = 0; i < LTP_ORDER; i++ ) {
+                psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 );
+            }
+        }
+
+        /**********************/
+        /* Decode LTP scaling */
+        /**********************/
+        Ix = psDec->indices.LTP_scaleIndex;
+        psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ];
+    } else {
+        silk_memset( psDecCtrl->pitchL,      0,             psDec->nb_subfr * sizeof( opus_int   ) );
+        silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) );
+        psDec->indices.PERIndex  = 0;
+        psDecCtrl->LTP_scale_Q14 = 0;
+    }
+}
diff --git a/third_party/opus/src/silk/decode_pitch.c b/third_party/opus/src/silk/decode_pitch.c
new file mode 100644
index 0000000..fedbc6a
--- /dev/null
+++ b/third_party/opus/src/silk/decode_pitch.c
@@ -0,0 +1,77 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/***********************************************************
+* Pitch analyser function
+********************************************************** */
+#include "SigProc_FIX.h"
+#include "pitch_est_defines.h"
+
+void silk_decode_pitch(
+    opus_int16                  lagIndex,           /* I                                                                */
+    opus_int8                   contourIndex,       /* O                                                                */
+    opus_int                    pitch_lags[],       /* O    4 pitch values                                              */
+    const opus_int              Fs_kHz,             /* I    sampling frequency (kHz)                                    */
+    const opus_int              nb_subfr            /* I    number of sub frames                                        */
+)
+{
+    opus_int   lag, k, min_lag, max_lag, cbk_size;
+    const opus_int8 *Lag_CB_ptr;
+
+    if( Fs_kHz == 8 ) {
+        if( nb_subfr == PE_MAX_NB_SUBFR ) {
+            Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+            cbk_size   = PE_NB_CBKS_STAGE2_EXT;
+        } else {
+            silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
+            Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+            cbk_size   = PE_NB_CBKS_STAGE2_10MS;
+        }
+    } else {
+        if( nb_subfr == PE_MAX_NB_SUBFR ) {
+            Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+            cbk_size   = PE_NB_CBKS_STAGE3_MAX;
+        } else {
+            silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
+            Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+            cbk_size   = PE_NB_CBKS_STAGE3_10MS;
+        }
+    }
+
+    min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz );
+    max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz );
+    lag = min_lag + lagIndex;
+
+    for( k = 0; k < nb_subfr; k++ ) {
+        pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size );
+        pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag );
+    }
+}
diff --git a/third_party/opus/src/silk/decode_pulses.c b/third_party/opus/src/silk/decode_pulses.c
new file mode 100644
index 0000000..d6bbec9
--- /dev/null
+++ b/third_party/opus/src/silk/decode_pulses.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/*********************************************/
+/* Decode quantization indices of excitation */
+/*********************************************/
+void silk_decode_pulses(
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int16                  pulses[],                       /* O    Excitation signal                           */
+    const opus_int              signalType,                     /* I    Sigtype                                     */
+    const opus_int              quantOffsetType,                /* I    quantOffsetType                             */
+    const opus_int              frame_length                    /* I    Frame length                                */
+)
+{
+    opus_int   i, j, k, iter, abs_q, nLS, RateLevelIndex;
+    opus_int   sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ];
+    opus_int16 *pulses_ptr;
+    const opus_uint8 *cdf_ptr;
+
+    /*********************/
+    /* Decode rate level */
+    /*********************/
+    RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 );
+
+    /* Calculate number of shell blocks */
+    silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
+    iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
+    if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
+        silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
+        iter++;
+    }
+
+    /***************************************************/
+    /* Sum-Weighted-Pulses Decoding                    */
+    /***************************************************/
+    cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ];
+    for( i = 0; i < iter; i++ ) {
+        nLshifts[ i ] = 0;
+        sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 );
+
+        /* LSB indication */
+        while( sum_pulses[ i ] == SILK_MAX_PULSES + 1 ) {
+            nLshifts[ i ]++;
+            /* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */
+            sum_pulses[ i ] = ec_dec_icdf( psRangeDec,
+                    silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 );
+        }
+    }
+
+    /***************************************************/
+    /* Shell decoding                                  */
+    /***************************************************/
+    for( i = 0; i < iter; i++ ) {
+        if( sum_pulses[ i ] > 0 ) {
+            silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] );
+        } else {
+            silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( pulses[0] ) );
+        }
+    }
+
+    /***************************************************/
+    /* LSB Decoding                                    */
+    /***************************************************/
+    for( i = 0; i < iter; i++ ) {
+        if( nLshifts[ i ] > 0 ) {
+            nLS = nLshifts[ i ];
+            pulses_ptr = &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ];
+            for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+                abs_q = pulses_ptr[ k ];
+                for( j = 0; j < nLS; j++ ) {
+                    abs_q = silk_LSHIFT( abs_q, 1 );
+                    abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 );
+                }
+                pulses_ptr[ k ] = abs_q;
+            }
+            /* Mark the number of pulses non-zero for sign decoding. */
+            sum_pulses[ i ] |= nLS << 5;
+        }
+    }
+
+    /****************************************/
+    /* Decode and add signs to pulse signal */
+    /****************************************/
+    silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses );
+}
diff --git a/third_party/opus/src/silk/decoder_set_fs.c b/third_party/opus/src/silk/decoder_set_fs.c
new file mode 100644
index 0000000..eef0fd2
--- /dev/null
+++ b/third_party/opus/src/silk/decoder_set_fs.c
@@ -0,0 +1,108 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Set decoder sampling rate */
+opus_int silk_decoder_set_fs(
+    silk_decoder_state          *psDec,                         /* I/O  Decoder state pointer                       */
+    opus_int                    fs_kHz,                         /* I    Sampling frequency (kHz)                    */
+    opus_int32                  fs_API_Hz                       /* I    API Sampling frequency (Hz)                 */
+)
+{
+    opus_int frame_length, ret = 0;
+
+    silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
+    silk_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 );
+
+    /* New (sub)frame length */
+    psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz );
+    frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length );
+
+    /* Initialize resampler when switching internal or external sampling frequency */
+    if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) {
+        /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */
+        ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 );
+
+        psDec->fs_API_hz = fs_API_Hz;
+    }
+
+    if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) {
+        if( fs_kHz == 8 ) {
+            if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+                psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+            } else {
+                psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+            }
+        } else {
+            if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+                psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF;
+            } else {
+                psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+            }
+        }
+        if( psDec->fs_kHz != fs_kHz ) {
+            psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz );
+            if( fs_kHz == 8 || fs_kHz == 12 ) {
+                psDec->LPC_order = MIN_LPC_ORDER;
+                psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB;
+            } else {
+                psDec->LPC_order = MAX_LPC_ORDER;
+                psDec->psNLSF_CB = &silk_NLSF_CB_WB;
+            }
+            if( fs_kHz == 16 ) {
+                psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF;
+            } else if( fs_kHz == 12 ) {
+                psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF;
+            } else if( fs_kHz == 8 ) {
+                psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
+            } else {
+                /* unsupported sampling rate */
+                silk_assert( 0 );
+            }
+            psDec->first_frame_after_reset = 1;
+            psDec->lagPrev                 = 100;
+            psDec->LastGainIndex           = 10;
+            psDec->prevSignalType          = TYPE_NO_VOICE_ACTIVITY;
+            silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf));
+            silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) );
+        }
+
+        psDec->fs_kHz       = fs_kHz;
+        psDec->frame_length = frame_length;
+    }
+
+    /* Check that settings are valid */
+    silk_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH );
+
+    return ret;
+}
+
diff --git a/third_party/opus/src/silk/define.h b/third_party/opus/src/silk/define.h
new file mode 100644
index 0000000..19c9b00e
--- /dev/null
+++ b/third_party/opus/src/silk/define.h
@@ -0,0 +1,235 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_DEFINE_H
+#define SILK_DEFINE_H
+
+#include "errors.h"
+#include "typedef.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Max number of encoder channels (1/2) */
+#define ENCODER_NUM_CHANNELS                    2
+/* Number of decoder channels (1/2) */
+#define DECODER_NUM_CHANNELS                    2
+
+#define MAX_FRAMES_PER_PACKET                   3
+
+/* Limits on bitrate */
+#define MIN_TARGET_RATE_BPS                     5000
+#define MAX_TARGET_RATE_BPS                     80000
+#define TARGET_RATE_TAB_SZ                      8
+
+/* LBRR thresholds */
+#define LBRR_NB_MIN_RATE_BPS                    12000
+#define LBRR_MB_MIN_RATE_BPS                    14000
+#define LBRR_WB_MIN_RATE_BPS                    16000
+
+/* DTX settings */
+#define NB_SPEECH_FRAMES_BEFORE_DTX             10      /* eq 200 ms */
+#define MAX_CONSECUTIVE_DTX                     20      /* eq 400 ms */
+
+/* Maximum sampling frequency */
+#define MAX_FS_KHZ                              16
+#define MAX_API_FS_KHZ                          48
+
+/* Signal types */
+#define TYPE_NO_VOICE_ACTIVITY                  0
+#define TYPE_UNVOICED                           1
+#define TYPE_VOICED                             2
+
+/* Conditional coding types */
+#define CODE_INDEPENDENTLY                      0
+#define CODE_INDEPENDENTLY_NO_LTP_SCALING       1
+#define CODE_CONDITIONALLY                      2
+
+/* Settings for stereo processing */
+#define STEREO_QUANT_TAB_SIZE                   16
+#define STEREO_QUANT_SUB_STEPS                  5
+#define STEREO_INTERP_LEN_MS                    8       /* must be even */
+#define STEREO_RATIO_SMOOTH_COEF                0.01    /* smoothing coef for signal norms and stereo width */
+
+/* Range of pitch lag estimates */
+#define PITCH_EST_MIN_LAG_MS                    2       /* 2 ms -> 500 Hz */
+#define PITCH_EST_MAX_LAG_MS                    18      /* 18 ms -> 56 Hz */
+
+/* Maximum number of subframes */
+#define MAX_NB_SUBFR                            4
+
+/* Number of samples per frame */
+#define LTP_MEM_LENGTH_MS                       20
+#define SUB_FRAME_LENGTH_MS                     5
+#define MAX_SUB_FRAME_LENGTH                    ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ )
+#define MAX_FRAME_LENGTH_MS                     ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR )
+#define MAX_FRAME_LENGTH                        ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ )
+
+/* Milliseconds of lookahead for pitch analysis */
+#define LA_PITCH_MS                             2
+#define LA_PITCH_MAX                            ( LA_PITCH_MS * MAX_FS_KHZ )
+
+/* Order of LPC used in find pitch */
+#define MAX_FIND_PITCH_LPC_ORDER                16
+
+/* Length of LPC window used in find pitch */
+#define FIND_PITCH_LPC_WIN_MS                   ( 20 + (LA_PITCH_MS << 1) )
+#define FIND_PITCH_LPC_WIN_MS_2_SF              ( 10 + (LA_PITCH_MS << 1) )
+#define FIND_PITCH_LPC_WIN_MAX                  ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ )
+
+/* Milliseconds of lookahead for noise shape analysis */
+#define LA_SHAPE_MS                             5
+#define LA_SHAPE_MAX                            ( LA_SHAPE_MS * MAX_FS_KHZ )
+
+/* Maximum length of LPC window used in noise shape analysis */
+#define SHAPE_LPC_WIN_MAX                       ( 15 * MAX_FS_KHZ )
+
+/* dB level of lowest gain quantization level */
+#define MIN_QGAIN_DB                            2
+/* dB level of highest gain quantization level */
+#define MAX_QGAIN_DB                            88
+/* Number of gain quantization levels */
+#define N_LEVELS_QGAIN                          64
+/* Max increase in gain quantization index */
+#define MAX_DELTA_GAIN_QUANT                    36
+/* Max decrease in gain quantization index */
+#define MIN_DELTA_GAIN_QUANT                    -4
+
+/* Quantization offsets (multiples of 4) */
+#define OFFSET_VL_Q10                           32
+#define OFFSET_VH_Q10                           100
+#define OFFSET_UVL_Q10                          100
+#define OFFSET_UVH_Q10                          240
+
+#define QUANT_LEVEL_ADJUST_Q10                  80
+
+/* Maximum numbers of iterations used to stabilize an LPC vector */
+#define MAX_LPC_STABILIZE_ITERATIONS            16
+#define MAX_PREDICTION_POWER_GAIN               1e4f
+#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET   1e2f
+
+#define MAX_LPC_ORDER                           16
+#define MIN_LPC_ORDER                           10
+
+/* Find Pred Coef defines */
+#define LTP_ORDER                               5
+
+/* LTP quantization settings */
+#define NB_LTP_CBKS                             3
+
+/* Flag to use harmonic noise shaping */
+#define USE_HARM_SHAPING                        1
+
+/* Max LPC order of noise shaping filters */
+#define MAX_SHAPE_LPC_ORDER                     16
+
+#define HARM_SHAPE_FIR_TAPS                     3
+
+/* Maximum number of delayed decision states */
+#define MAX_DEL_DEC_STATES                      4
+
+#define LTP_BUF_LENGTH                          512
+#define LTP_MASK                                ( LTP_BUF_LENGTH - 1 )
+
+#define DECISION_DELAY                          32
+#define DECISION_DELAY_MASK                     ( DECISION_DELAY - 1 )
+
+/* Number of subframes for excitation entropy coding */
+#define SHELL_CODEC_FRAME_LENGTH                16
+#define LOG2_SHELL_CODEC_FRAME_LENGTH           4
+#define MAX_NB_SHELL_BLOCKS                     ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH )
+
+/* Number of rate levels, for entropy coding of excitation */
+#define N_RATE_LEVELS                           10
+
+/* Maximum sum of pulses per shell coding frame */
+#define SILK_MAX_PULSES                         16
+
+#define MAX_MATRIX_SIZE                         MAX_LPC_ORDER /* Max of LPC Order and LTP order */
+
+#if( MAX_LPC_ORDER > DECISION_DELAY )
+# define NSQ_LPC_BUF_LENGTH                     MAX_LPC_ORDER
+#else
+# define NSQ_LPC_BUF_LENGTH                     DECISION_DELAY
+#endif
+
+/***************************/
+/* Voice activity detector */
+/***************************/
+#define VAD_N_BANDS                             4
+
+#define VAD_INTERNAL_SUBFRAMES_LOG2             2
+#define VAD_INTERNAL_SUBFRAMES                  ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 )
+
+#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16         1024    /* Must be <  4096 */
+#define VAD_NOISE_LEVELS_BIAS                   50
+
+/* Sigmoid settings */
+#define VAD_NEGATIVE_OFFSET_Q5                  128     /* sigmoid is 0 at -128 */
+#define VAD_SNR_FACTOR_Q16                      45000
+
+/* smoothing for SNR measurement */
+#define VAD_SNR_SMOOTH_COEF_Q18                 4096
+
+/* Size of the piecewise linear cosine approximation table for the LSFs */
+#define LSF_COS_TAB_SZ_FIX                      128
+
+/******************/
+/* NLSF quantizer */
+/******************/
+#define NLSF_W_Q                                2
+#define NLSF_VQ_MAX_VECTORS                     32
+#define NLSF_VQ_MAX_SURVIVORS                   32
+#define NLSF_QUANT_MAX_AMPLITUDE                4
+#define NLSF_QUANT_MAX_AMPLITUDE_EXT            10
+#define NLSF_QUANT_LEVEL_ADJ                    0.1
+#define NLSF_QUANT_DEL_DEC_STATES_LOG2          2
+#define NLSF_QUANT_DEL_DEC_STATES               ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 )
+
+/* Transition filtering for mode switching */
+#define TRANSITION_TIME_MS                      5120    /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/
+#define TRANSITION_NB                           3       /* Hardcoded in tables */
+#define TRANSITION_NA                           2       /* Hardcoded in tables */
+#define TRANSITION_INT_NUM                      5       /* Hardcoded in tables */
+#define TRANSITION_FRAMES                       ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS )
+#define TRANSITION_INT_STEPS                    ( TRANSITION_FRAMES  / ( TRANSITION_INT_NUM - 1 ) )
+
+/* BWE factors to apply after packet loss */
+#define BWE_AFTER_LOSS_Q16                      63570
+
+/* Defines for CN generation */
+#define CNG_BUF_MASK_MAX                        255     /* 2^floor(log2(MAX_FRAME_LENGTH))-1    */
+#define CNG_GAIN_SMTH_Q16                       4634    /* 0.25^(1/4)                           */
+#define CNG_NLSF_SMTH_Q16                       16348   /* 0.25                                 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/enc_API.c b/third_party/opus/src/silk/enc_API.c
new file mode 100644
index 0000000..f8060286
--- /dev/null
+++ b/third_party/opus/src/silk/enc_API.c
@@ -0,0 +1,563 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "define.h"
+#include "API.h"
+#include "control.h"
+#include "typedef.h"
+#include "stack_alloc.h"
+#include "structs.h"
+#include "tuning_parameters.h"
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#else
+#include "main_FLP.h"
+#endif
+
+/***************************************/
+/* Read control structure from encoder */
+/***************************************/
+static opus_int silk_QueryEncoder(                      /* O    Returns error code                              */
+    const void                      *encState,          /* I    State                                           */
+    silk_EncControlStruct           *encStatus          /* O    Encoder Status                                  */
+);
+
+/****************************************/
+/* Encoder functions                    */
+/****************************************/
+
+opus_int silk_Get_Encoder_Size(                         /* O    Returns error code                              */
+    opus_int                        *encSizeBytes       /* O    Number of bytes in SILK encoder state           */
+)
+{
+    opus_int ret = SILK_NO_ERROR;
+
+    *encSizeBytes = sizeof( silk_encoder );
+
+    return ret;
+}
+
+/*************************/
+/* Init or Reset encoder */
+/*************************/
+opus_int silk_InitEncoder(                              /* O    Returns error code                              */
+    void                            *encState,          /* I/O  State                                           */
+    int                              arch,              /* I    Run-time architecture                           */
+    silk_EncControlStruct           *encStatus          /* O    Encoder Status                                  */
+)
+{
+    silk_encoder *psEnc;
+    opus_int n, ret = SILK_NO_ERROR;
+
+    psEnc = (silk_encoder *)encState;
+
+    /* Reset encoder */
+    silk_memset( psEnc, 0, sizeof( silk_encoder ) );
+    for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) {
+        if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) {
+            silk_assert( 0 );
+        }
+    }
+
+    psEnc->nChannelsAPI = 1;
+    psEnc->nChannelsInternal = 1;
+
+    /* Read control structure */
+    if( ret += silk_QueryEncoder( encState, encStatus ) ) {
+        silk_assert( 0 );
+    }
+
+    return ret;
+}
+
+/***************************************/
+/* Read control structure from encoder */
+/***************************************/
+static opus_int silk_QueryEncoder(                      /* O    Returns error code                              */
+    const void                      *encState,          /* I    State                                           */
+    silk_EncControlStruct           *encStatus          /* O    Encoder Status                                  */
+)
+{
+    opus_int ret = SILK_NO_ERROR;
+    silk_encoder_state_Fxx *state_Fxx;
+    silk_encoder *psEnc = (silk_encoder *)encState;
+
+    state_Fxx = psEnc->state_Fxx;
+
+    encStatus->nChannelsAPI              = psEnc->nChannelsAPI;
+    encStatus->nChannelsInternal         = psEnc->nChannelsInternal;
+    encStatus->API_sampleRate            = state_Fxx[ 0 ].sCmn.API_fs_Hz;
+    encStatus->maxInternalSampleRate     = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz;
+    encStatus->minInternalSampleRate     = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz;
+    encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz;
+    encStatus->payloadSize_ms            = state_Fxx[ 0 ].sCmn.PacketSize_ms;
+    encStatus->bitRate                   = state_Fxx[ 0 ].sCmn.TargetRate_bps;
+    encStatus->packetLossPercentage      = state_Fxx[ 0 ].sCmn.PacketLoss_perc;
+    encStatus->complexity                = state_Fxx[ 0 ].sCmn.Complexity;
+    encStatus->useInBandFEC              = state_Fxx[ 0 ].sCmn.useInBandFEC;
+    encStatus->useDTX                    = state_Fxx[ 0 ].sCmn.useDTX;
+    encStatus->useCBR                    = state_Fxx[ 0 ].sCmn.useCBR;
+    encStatus->internalSampleRate        = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
+    encStatus->allowBandwidthSwitch      = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch;
+    encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0;
+
+    return ret;
+}
+
+
+/**************************/
+/* Encode frame with Silk */
+/**************************/
+/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what                     */
+/* encControl->payloadSize_ms is set to                                                                         */
+opus_int silk_Encode(                                   /* O    Returns error code                              */
+    void                            *encState,          /* I/O  State                                           */
+    silk_EncControlStruct           *encControl,        /* I    Control status                                  */
+    const opus_int16                *samplesIn,         /* I    Speech sample input vector                      */
+    opus_int                        nSamplesIn,         /* I    Number of samples in input vector               */
+    ec_enc                          *psRangeEnc,        /* I/O  Compressor data structure                       */
+    opus_int32                      *nBytesOut,         /* I/O  Number of bytes in payload (input: Max bytes)   */
+    const opus_int                  prefillFlag         /* I    Flag to indicate prefilling buffers no coding   */
+)
+{
+    opus_int   n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0;
+    opus_int   nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms;
+    opus_int   nSamplesFromInput = 0, nSamplesFromInputMax;
+    opus_int   speech_act_thr_for_switch_Q8;
+    opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum;
+    silk_encoder *psEnc = ( silk_encoder * )encState;
+    VARDECL( opus_int16, buf );
+    opus_int transition, curr_block, tot_blocks;
+    SAVE_STACK;
+
+    if (encControl->reducedDependency)
+    {
+       psEnc->state_Fxx[0].sCmn.first_frame_after_reset = 1;
+       psEnc->state_Fxx[1].sCmn.first_frame_after_reset = 1;
+    }
+    psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0;
+
+    /* Check values in encoder control structure */
+    if( ( ret = check_control_input( encControl ) ) != 0 ) {
+        silk_assert( 0 );
+        RESTORE_STACK;
+        return ret;
+    }
+
+    encControl->switchReady = 0;
+
+    if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) {
+        /* Mono -> Stereo transition: init state of second channel and stereo state */
+        ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch );
+        silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) );
+        silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) );
+        psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0;
+        psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1;
+        psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0;
+        psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1;
+        psEnc->sStereo.width_prev_Q14 = 0;
+        psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 );
+        if( psEnc->nChannelsAPI == 2 ) {
+            silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) );
+            silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State,     &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State,     sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) );
+        }
+    }
+
+    transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal);
+
+    psEnc->nChannelsAPI = encControl->nChannelsAPI;
+    psEnc->nChannelsInternal = encControl->nChannelsInternal;
+
+    nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate );
+    tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1;
+    curr_block = 0;
+    if( prefillFlag ) {
+        /* Only accept input length of 10 ms */
+        if( nBlocksOf10ms != 1 ) {
+            silk_assert( 0 );
+            RESTORE_STACK;
+            return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+        }
+        /* Reset Encoder */
+        for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+            ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch );
+            silk_assert( !ret );
+        }
+        tmp_payloadSize_ms = encControl->payloadSize_ms;
+        encControl->payloadSize_ms = 10;
+        tmp_complexity = encControl->complexity;
+        encControl->complexity = 0;
+        for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+            psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+            psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1;
+        }
+    } else {
+        /* Only accept input lengths that are a multiple of 10 ms */
+        if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) {
+            silk_assert( 0 );
+            RESTORE_STACK;
+            return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+        }
+        /* Make sure no more than one packet can be produced */
+        if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) {
+            silk_assert( 0 );
+            RESTORE_STACK;
+            return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+        }
+    }
+
+    TargetRate_bps = silk_RSHIFT32( encControl->bitRate, encControl->nChannelsInternal - 1 );
+    for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+        /* Force the side channel to the same rate as the mid */
+        opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
+        if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, TargetRate_bps, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
+            silk_assert( 0 );
+            RESTORE_STACK;
+            return ret;
+        }
+        if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) {
+            for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
+                psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0;
+            }
+        }
+        psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX;
+    }
+    silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
+
+    /* Input buffering/resampling and encoding */
+    nSamplesToBufferMax =
+        10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz;
+    nSamplesFromInputMax =
+        silk_DIV32_16( nSamplesToBufferMax *
+                           psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz,
+                       psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
+    ALLOC( buf, nSamplesFromInputMax, opus_int16 );
+    while( 1 ) {
+        nSamplesToBuffer  = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx;
+        nSamplesToBuffer  = silk_min( nSamplesToBuffer, nSamplesToBufferMax );
+        nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
+        /* Resample and write to buffer */
+        if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) {
+            opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
+            for( n = 0; n < nSamplesFromInput; n++ ) {
+                buf[ n ] = samplesIn[ 2 * n ];
+            }
+            /* Making sure to start both resamplers from the same state when switching from mono to stereo */
+            if( psEnc->nPrevChannelsInternal == 1 && id==0 ) {
+               silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state));
+            }
+
+            ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+                &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+            psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+
+            nSamplesToBuffer  = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx;
+            nSamplesToBuffer  = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
+            for( n = 0; n < nSamplesFromInput; n++ ) {
+                buf[ n ] = samplesIn[ 2 * n + 1 ];
+            }
+            ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
+                &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+
+            psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer;
+        } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) {
+            /* Combine left and right channels before resampling */
+            for( n = 0; n < nSamplesFromInput; n++ ) {
+                sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ];
+                buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum,  1 );
+            }
+            ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+                &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+            /* On the first mono frame, average the results for the two resampler states  */
+            if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) {
+               ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
+                   &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+               for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) {
+                  psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] =
+                        silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ]
+                                  + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1);
+               }
+            }
+            psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+        } else {
+            silk_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 );
+            silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16));
+            ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+                &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+            psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+        }
+
+        samplesIn  += nSamplesFromInput * encControl->nChannelsAPI;
+        nSamplesIn -= nSamplesFromInput;
+
+        /* Default */
+        psEnc->allowBandwidthSwitch = 0;
+
+        /* Silk encoder */
+        if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) {
+            /* Enough data in input buffer, so encode */
+            silk_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length );
+            silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length );
+
+            /* Deal with LBRR data */
+            if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) {
+                /* Create space at start of payload for VAD and FEC flags */
+                opus_uint8 iCDF[ 2 ] = { 0, 0 };
+                iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
+                ec_enc_icdf( psRangeEnc, 0, iCDF, 8 );
+
+                /* Encode any LBRR data from previous packet */
+                /* Encode LBRR flags */
+                for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+                    LBRR_symbol = 0;
+                    for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
+                        LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i );
+                    }
+                    psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0;
+                    if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) {
+                        ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 );
+                    }
+                }
+
+                /* Code LBRR indices and excitation signals */
+                for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
+                    for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+                        if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) {
+                            opus_int condCoding;
+
+                            if( encControl->nChannelsInternal == 2 && n == 0 ) {
+                                silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] );
+                                /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */
+                                if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) {
+                                    silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] );
+                                }
+                            }
+                            /* Use conditional coding if previous frame available */
+                            if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) {
+                                condCoding = CODE_CONDITIONALLY;
+                            } else {
+                                condCoding = CODE_INDEPENDENTLY;
+                            }
+                            silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding );
+                            silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType,
+                                psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length );
+                        }
+                    }
+                }
+
+                /* Reset LBRR flags */
+                for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+                    silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) );
+                }
+
+                psEnc->nBitsUsedLBRR = ec_tell( psRangeEnc );
+            }
+
+            silk_HP_variable_cutoff( psEnc->state_Fxx );
+
+            /* Total target bits for packet */
+            nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
+            /* Subtract bits used for LBRR */
+            if( !prefillFlag ) {
+                nBits -= psEnc->nBitsUsedLBRR;
+            }
+            /* Divide by number of uncoded frames left in packet */
+            nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket );
+            /* Convert to bits/second */
+            if( encControl->payloadSize_ms == 10 ) {
+                TargetRate_bps = silk_SMULBB( nBits, 100 );
+            } else {
+                TargetRate_bps = silk_SMULBB( nBits, 50 );
+            }
+            /* Subtract fraction of bits in excess of target in previous frames and packets */
+            TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
+            if( !prefillFlag && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded > 0 ) {
+                /* Compare actual vs target bits so far in this packet */
+                opus_int32 bitsBalance = ec_tell( psRangeEnc ) - psEnc->nBitsUsedLBRR - nBits * psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
+                TargetRate_bps -= silk_DIV32_16( silk_MUL( bitsBalance, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
+            }
+            /* Never exceed input bitrate */
+            TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 );
+
+            /* Convert Left/Right to Mid/Side */
+            if( encControl->nChannelsInternal == 2 ) {
+                silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ],
+                    psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ],
+                    MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono,
+                    psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length );
+                if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
+                    /* Reset side channel encoder memory for first frame with side coding */
+                    if( psEnc->prev_decode_only_middle == 1 ) {
+                        silk_memset( &psEnc->state_Fxx[ 1 ].sShape,               0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) );
+                        silk_memset( &psEnc->state_Fxx[ 1 ].sPrefilt,             0, sizeof( psEnc->state_Fxx[ 1 ].sPrefilt ) );
+                        silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ,            0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) );
+                        silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15,   0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) );
+                        silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) );
+                        psEnc->state_Fxx[ 1 ].sCmn.prevLag                 = 100;
+                        psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev            = 100;
+                        psEnc->state_Fxx[ 1 ].sShape.LastGainIndex         = 10;
+                        psEnc->state_Fxx[ 1 ].sCmn.prevSignalType          = TYPE_NO_VOICE_ACTIVITY;
+                        psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16      = 65536;
+                        psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1;
+                    }
+                    silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] );
+                } else {
+                    psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0;
+                }
+                if( !prefillFlag ) {
+                    silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
+                    if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
+                        silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
+                    }
+                }
+            } else {
+                /* Buffering */
+                silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) );
+                silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) );
+            }
+            silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] );
+
+            /* Encode */
+            for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+                opus_int maxBits, useCBR;
+
+                /* Handling rate constraints */
+                maxBits = encControl->maxBits;
+                if( tot_blocks == 2 && curr_block == 0 ) {
+                    maxBits = maxBits * 3 / 5;
+                } else if( tot_blocks == 3 ) {
+                    if( curr_block == 0 ) {
+                        maxBits = maxBits * 2 / 5;
+                    } else if( curr_block == 1 ) {
+                        maxBits = maxBits * 3 / 4;
+                    }
+                }
+                useCBR = encControl->useCBR && curr_block == tot_blocks - 1;
+
+                if( encControl->nChannelsInternal == 1 ) {
+                    channelRate_bps = TargetRate_bps;
+                } else {
+                    channelRate_bps = MStargetRates_bps[ n ];
+                    if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) {
+                        useCBR = 0;
+                        /* Give mid up to 1/2 of the max bits for that frame */
+                        maxBits -= encControl->maxBits / ( tot_blocks * 2 );
+                    }
+                }
+
+                if( channelRate_bps > 0 ) {
+                    opus_int condCoding;
+
+                    silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps );
+
+                    /* Use independent coding if no previous frame available */
+                    if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) {
+                        condCoding = CODE_INDEPENDENTLY;
+                    } else if( n > 0 && psEnc->prev_decode_only_middle ) {
+                        /* If we skipped a side frame in this packet, we don't
+                           need LTP scaling; the LTP state is well-defined. */
+                        condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING;
+                    } else {
+                        condCoding = CODE_CONDITIONALLY;
+                    }
+                    if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) {
+                        silk_assert( 0 );
+                    }
+                }
+                psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+                psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0;
+                psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++;
+            }
+            psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ];
+
+            /* Insert VAD and FEC flags at beginning of bitstream */
+            if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) {
+                flags = 0;
+                for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+                    for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
+                        flags  = silk_LSHIFT( flags, 1 );
+                        flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ];
+                    }
+                    flags  = silk_LSHIFT( flags, 1 );
+                    flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag;
+                }
+                if( !prefillFlag ) {
+                    ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
+                }
+
+                /* Return zero bytes if all channels DTXed */
+                if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) {
+                    *nBytesOut = 0;
+                }
+
+                psEnc->nBitsExceeded += *nBytesOut * 8;
+                psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
+                psEnc->nBitsExceeded  = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 );
+
+                /* Update flag indicating if bandwidth switching is allowed */
+                speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ),
+                    SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms );
+                if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) {
+                    psEnc->allowBandwidthSwitch = 1;
+                    psEnc->timeSinceSwitchAllowed_ms = 0;
+                } else {
+                    psEnc->allowBandwidthSwitch = 0;
+                    psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms;
+                }
+            }
+
+            if( nSamplesIn == 0 ) {
+                break;
+            }
+        } else {
+            break;
+        }
+        curr_block++;
+    }
+
+    psEnc->nPrevChannelsInternal = encControl->nChannelsInternal;
+
+    encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch;
+    encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0;
+    encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
+    encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14;
+    if( prefillFlag ) {
+        encControl->payloadSize_ms = tmp_payloadSize_ms;
+        encControl->complexity = tmp_complexity;
+        for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+            psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+            psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0;
+        }
+    }
+
+    RESTORE_STACK;
+    return ret;
+}
+
diff --git a/third_party/opus/src/silk/encode_indices.c b/third_party/opus/src/silk/encode_indices.c
new file mode 100644
index 0000000..666c8c0
--- /dev/null
+++ b/third_party/opus/src/silk/encode_indices.c
@@ -0,0 +1,181 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Encode side-information parameters to payload */
+void silk_encode_indices(
+    silk_encoder_state          *psEncC,                        /* I/O  Encoder state                               */
+    ec_enc                      *psRangeEnc,                    /* I/O  Compressor data structure                   */
+    opus_int                    FrameIndex,                     /* I    Frame number                                */
+    opus_int                    encode_LBRR,                    /* I    Flag indicating LBRR data is being encoded  */
+    opus_int                    condCoding                      /* I    The type of conditional coding to use       */
+)
+{
+    opus_int   i, k, typeOffset;
+    opus_int   encode_absolute_lagIndex, delta_lagIndex;
+    opus_int16 ec_ix[ MAX_LPC_ORDER ];
+    opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+    const SideInfoIndices *psIndices;
+
+    if( encode_LBRR ) {
+         psIndices = &psEncC->indices_LBRR[ FrameIndex ];
+    } else {
+         psIndices = &psEncC->indices;
+    }
+
+    /*******************************************/
+    /* Encode signal type and quantizer offset */
+    /*******************************************/
+    typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType;
+    silk_assert( typeOffset >= 0 && typeOffset < 6 );
+    silk_assert( encode_LBRR == 0 || typeOffset >= 2 );
+    if( encode_LBRR || typeOffset >= 2 ) {
+        ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 );
+    } else {
+        ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 );
+    }
+
+    /****************/
+    /* Encode gains */
+    /****************/
+    /* first subframe */
+    if( condCoding == CODE_CONDITIONALLY ) {
+        /* conditional coding */
+        silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
+        ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 );
+    } else {
+        /* independent coding, in two stages: MSB bits followed by 3 LSBs */
+        silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN );
+        ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 );
+        ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 );
+    }
+
+    /* remaining subframes */
+    for( i = 1; i < psEncC->nb_subfr; i++ ) {
+        silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
+        ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 );
+    }
+
+    /****************/
+    /* Encode NLSFs */
+    /****************/
+    ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 );
+    silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] );
+    silk_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder );
+    for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) {
+        if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) {
+            ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+            ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
+        } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) {
+            ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+            ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
+        } else {
+            ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+        }
+    }
+
+    /* Encode NLSF interpolation factor */
+    if( psEncC->nb_subfr == MAX_NB_SUBFR ) {
+        silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 );
+        ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 );
+    }
+
+    if( psIndices->signalType == TYPE_VOICED )
+    {
+        /*********************/
+        /* Encode pitch lags */
+        /*********************/
+        /* lag index */
+        encode_absolute_lagIndex = 1;
+        if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) {
+            /* Delta Encoding */
+            delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex;
+            if( delta_lagIndex < -8 || delta_lagIndex > 11 ) {
+                delta_lagIndex = 0;
+            } else {
+                delta_lagIndex = delta_lagIndex + 9;
+                encode_absolute_lagIndex = 0; /* Only use delta */
+            }
+            silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 );
+            ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 );
+        }
+        if( encode_absolute_lagIndex ) {
+            /* Absolute encoding */
+            opus_int32 pitch_high_bits, pitch_low_bits;
+            pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
+            pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
+            silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 );
+            silk_assert( pitch_high_bits < 32 );
+            ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 );
+            ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 );
+        }
+        psEncC->ec_prevLagIndex = psIndices->lagIndex;
+
+        /* Countour index */
+        silk_assert(   psIndices->contourIndex  >= 0 );
+        silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz  > 8 && psEncC->nb_subfr == 4 ) ||
+                    ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) ||
+                    ( psIndices->contourIndex < 12 && psEncC->fs_kHz  > 8 && psEncC->nb_subfr == 2 ) ||
+                    ( psIndices->contourIndex <  3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) );
+        ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 );
+
+        /********************/
+        /* Encode LTP gains */
+        /********************/
+        /* PERIndex value */
+        silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 );
+        ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 );
+
+        /* Codebook Indices */
+        for( k = 0; k < psEncC->nb_subfr; k++ ) {
+            silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) );
+            ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 );
+        }
+
+        /**********************/
+        /* Encode LTP scaling */
+        /**********************/
+        if( condCoding == CODE_INDEPENDENTLY ) {
+            silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 );
+            ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 );
+        }
+        silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 );
+    }
+
+    psEncC->ec_prevSignalType = psIndices->signalType;
+
+    /***************/
+    /* Encode seed */
+    /***************/
+    silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 );
+    ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 );
+}
diff --git a/third_party/opus/src/silk/encode_pulses.c b/third_party/opus/src/silk/encode_pulses.c
new file mode 100644
index 0000000..ab00264
--- /dev/null
+++ b/third_party/opus/src/silk/encode_pulses.c
@@ -0,0 +1,206 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/*********************************************/
+/* Encode quantization indices of excitation */
+/*********************************************/
+
+static OPUS_INLINE opus_int combine_and_check(    /* return ok                           */
+    opus_int         *pulses_comb,           /* O                                   */
+    const opus_int   *pulses_in,             /* I                                   */
+    opus_int         max_pulses,             /* I    max value for sum of pulses    */
+    opus_int         len                     /* I    number of output values        */
+)
+{
+    opus_int k, sum;
+
+    for( k = 0; k < len; k++ ) {
+        sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ];
+        if( sum > max_pulses ) {
+            return 1;
+        }
+        pulses_comb[ k ] = sum;
+    }
+
+    return 0;
+}
+
+/* Encode quantization indices of excitation */
+void silk_encode_pulses(
+    ec_enc                      *psRangeEnc,                    /* I/O  compressor data structure                   */
+    const opus_int              signalType,                     /* I    Signal type                                 */
+    const opus_int              quantOffsetType,                /* I    quantOffsetType                             */
+    opus_int8                   pulses[],                       /* I    quantization indices                        */
+    const opus_int              frame_length                    /* I    Frame length                                */
+)
+{
+    opus_int   i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0;
+    opus_int32 abs_q, minSumBits_Q5, sumBits_Q5;
+    VARDECL( opus_int, abs_pulses );
+    VARDECL( opus_int, sum_pulses );
+    VARDECL( opus_int, nRshifts );
+    opus_int   pulses_comb[ 8 ];
+    opus_int   *abs_pulses_ptr;
+    const opus_int8 *pulses_ptr;
+    const opus_uint8 *cdf_ptr;
+    const opus_uint8 *nBits_ptr;
+    SAVE_STACK;
+
+    silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/
+
+    /****************************/
+    /* Prepare for shell coding */
+    /****************************/
+    /* Calculate number of shell blocks */
+    silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
+    iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
+    if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
+        silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
+        iter++;
+        silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8));
+    }
+
+    /* Take the absolute value of the pulses */
+    ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int );
+    silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) );
+    for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) {
+        abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] );
+        abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] );
+        abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] );
+        abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] );
+    }
+
+    /* Calc sum pulses per shell code frame */
+    ALLOC( sum_pulses, iter, opus_int );
+    ALLOC( nRshifts, iter, opus_int );
+    abs_pulses_ptr = abs_pulses;
+    for( i = 0; i < iter; i++ ) {
+        nRshifts[ i ] = 0;
+
+        while( 1 ) {
+            /* 1+1 -> 2 */
+            scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 );
+            /* 2+2 -> 4 */
+            scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 );
+            /* 4+4 -> 8 */
+            scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 );
+            /* 8+8 -> 16 */
+            scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 );
+
+            if( scale_down ) {
+                /* We need to downscale the quantization signal */
+                nRshifts[ i ]++;
+                for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+                    abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 );
+                }
+            } else {
+                /* Jump out of while(1) loop and go to next shell coding frame */
+                break;
+            }
+        }
+        abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH;
+    }
+
+    /**************/
+    /* Rate level */
+    /**************/
+    /* find rate level that leads to fewest bits for coding of pulses per block info */
+    minSumBits_Q5 = silk_int32_MAX;
+    for( k = 0; k < N_RATE_LEVELS - 1; k++ ) {
+        nBits_ptr  = silk_pulses_per_block_BITS_Q5[ k ];
+        sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ];
+        for( i = 0; i < iter; i++ ) {
+            if( nRshifts[ i ] > 0 ) {
+                sumBits_Q5 += nBits_ptr[ SILK_MAX_PULSES + 1 ];
+            } else {
+                sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ];
+            }
+        }
+        if( sumBits_Q5 < minSumBits_Q5 ) {
+            minSumBits_Q5 = sumBits_Q5;
+            RateLevelIndex = k;
+        }
+    }
+    ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 );
+
+    /***************************************************/
+    /* Sum-Weighted-Pulses Encoding                    */
+    /***************************************************/
+    cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ];
+    for( i = 0; i < iter; i++ ) {
+        if( nRshifts[ i ] == 0 ) {
+            ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 );
+        } else {
+            ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, cdf_ptr, 8 );
+            for( k = 0; k < nRshifts[ i ] - 1; k++ ) {
+                ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
+            }
+            ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
+        }
+    }
+
+    /******************/
+    /* Shell Encoding */
+    /******************/
+    for( i = 0; i < iter; i++ ) {
+        if( sum_pulses[ i ] > 0 ) {
+            silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] );
+        }
+    }
+
+    /****************/
+    /* LSB Encoding */
+    /****************/
+    for( i = 0; i < iter; i++ ) {
+        if( nRshifts[ i ] > 0 ) {
+            pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ];
+            nLS = nRshifts[ i ] - 1;
+            for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+                abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] );
+                for( j = nLS; j > 0; j-- ) {
+                    bit = silk_RSHIFT( abs_q, j ) & 1;
+                    ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
+                }
+                bit = abs_q & 1;
+                ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
+            }
+        }
+    }
+
+    /****************/
+    /* Encode signs */
+    /****************/
+    silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses );
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/errors.h b/third_party/opus/src/silk/errors.h
new file mode 100644
index 0000000..4507080
--- /dev/null
+++ b/third_party/opus/src/silk/errors.h
@@ -0,0 +1,98 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_ERRORS_H
+#define SILK_ERRORS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************/
+/* Error messages */
+/******************/
+#define SILK_NO_ERROR                               0
+
+/**************************/
+/* Encoder error messages */
+/**************************/
+
+/* Input length is not a multiple of 10 ms, or length is longer than the packet length */
+#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES        -101
+
+/* Sampling frequency not 8000, 12000 or 16000 Hertz */
+#define SILK_ENC_FS_NOT_SUPPORTED                   -102
+
+/* Packet size not 10, 20, 40, or 60 ms */
+#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED          -103
+
+/* Allocated payload buffer too short */
+#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT              -104
+
+/* Loss rate not between 0 and 100 percent */
+#define SILK_ENC_INVALID_LOSS_RATE                  -105
+
+/* Complexity setting not valid, use 0...10 */
+#define SILK_ENC_INVALID_COMPLEXITY_SETTING         -106
+
+/* Inband FEC setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_INBAND_FEC_SETTING         -107
+
+/* DTX setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_DTX_SETTING                -108
+
+/* CBR setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_CBR_SETTING                -109
+
+/* Internal encoder error */
+#define SILK_ENC_INTERNAL_ERROR                     -110
+
+/* Internal encoder error */
+#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR   -111
+
+/**************************/
+/* Decoder error messages */
+/**************************/
+
+/* Output sampling frequency lower than internal decoded sampling frequency */
+#define SILK_DEC_INVALID_SAMPLING_FREQUENCY         -200
+
+/* Payload size exceeded the maximum allowed 1024 bytes */
+#define SILK_DEC_PAYLOAD_TOO_LARGE                  -201
+
+/* Payload has bit errors */
+#define SILK_DEC_PAYLOAD_ERROR                      -202
+
+/* Payload has bit errors */
+#define SILK_DEC_INVALID_FRAME_SIZE                 -203
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/fixed/LTP_analysis_filter_FIX.c b/third_party/opus/src/silk/fixed/LTP_analysis_filter_FIX.c
new file mode 100644
index 0000000..5574e70
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/LTP_analysis_filter_FIX.c
@@ -0,0 +1,90 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+void silk_LTP_analysis_filter_FIX(
+    opus_int16                      *LTP_res,                               /* O    LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length )  */
+    const opus_int16                *x,                                     /* I    Pointer to input signal with at least max( pitchL ) preceding samples       */
+    const opus_int16                LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I    LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe                   */
+    const opus_int                  pitchL[ MAX_NB_SUBFR ],                 /* I    Pitch lag, one for each subframe                                            */
+    const opus_int32                invGains_Q16[ MAX_NB_SUBFR ],           /* I    Inverse quantization gains, one for each subframe                           */
+    const opus_int                  subfr_length,                           /* I    Length of each subframe                                                     */
+    const opus_int                  nb_subfr,                               /* I    Number of subframes                                                         */
+    const opus_int                  pre_length                              /* I    Length of the preceding samples starting at &x[0] for each subframe         */
+)
+{
+    const opus_int16 *x_ptr, *x_lag_ptr;
+    opus_int16   Btmp_Q14[ LTP_ORDER ];
+    opus_int16   *LTP_res_ptr;
+    opus_int     k, i;
+    opus_int32   LTP_est;
+
+    x_ptr = x;
+    LTP_res_ptr = LTP_res;
+    for( k = 0; k < nb_subfr; k++ ) {
+
+        x_lag_ptr = x_ptr - pitchL[ k ];
+
+        Btmp_Q14[ 0 ] = LTPCoef_Q14[ k * LTP_ORDER ];
+        Btmp_Q14[ 1 ] = LTPCoef_Q14[ k * LTP_ORDER + 1 ];
+        Btmp_Q14[ 2 ] = LTPCoef_Q14[ k * LTP_ORDER + 2 ];
+        Btmp_Q14[ 3 ] = LTPCoef_Q14[ k * LTP_ORDER + 3 ];
+        Btmp_Q14[ 4 ] = LTPCoef_Q14[ k * LTP_ORDER + 4 ];
+
+        /* LTP analysis FIR filter */
+        for( i = 0; i < subfr_length + pre_length; i++ ) {
+            LTP_res_ptr[ i ] = x_ptr[ i ];
+
+            /* Long-term prediction */
+            LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] );
+            LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 1 ], Btmp_Q14[ 1 ] );
+            LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 0 ], Btmp_Q14[ 2 ] );
+            LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -1 ], Btmp_Q14[ 3 ] );
+            LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -2 ], Btmp_Q14[ 4 ] );
+
+            LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/
+
+            /* Subtract long-term prediction */
+            LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est );
+
+            /* Scale residual */
+            LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] );
+
+            x_lag_ptr++;
+        }
+
+        /* Update pointers */
+        LTP_res_ptr += subfr_length + pre_length;
+        x_ptr       += subfr_length;
+    }
+}
+
diff --git a/third_party/opus/src/silk/fixed/LTP_scale_ctrl_FIX.c b/third_party/opus/src/silk/fixed/LTP_scale_ctrl_FIX.c
new file mode 100644
index 0000000..3dcedef
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/LTP_scale_ctrl_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  encoder state                                                               */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  encoder control                                                             */
+    opus_int                        condCoding                              /* I    The type of conditional coding to use                                       */
+)
+{
+    opus_int round_loss;
+
+    if( condCoding == CODE_INDEPENDENTLY ) {
+        /* Only scale if first frame in packet */
+        round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket;
+        psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT(
+            silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 );
+    } else {
+        /* Default is minimum scaling */
+        psEnc->sCmn.indices.LTP_scaleIndex = 0;
+    }
+    psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ];
+}
diff --git a/third_party/opus/src/silk/fixed/apply_sine_window_FIX.c b/third_party/opus/src/silk/fixed/apply_sine_window_FIX.c
new file mode 100644
index 0000000..4502b71
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/apply_sine_window_FIX.c
@@ -0,0 +1,101 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Apply sine window to signal vector.                                      */
+/* Window types:                                                            */
+/*    1 -> sine window from 0 to pi/2                                       */
+/*    2 -> sine window from pi/2 to pi                                      */
+/* Every other sample is linearly interpolated, for speed.                  */
+/* Window length must be between 16 and 120 (incl) and a multiple of 4.     */
+
+/* Matlab code for table:
+   for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end
+*/
+static const opus_int16 freq_table_Q16[ 27 ] = {
+   12111,    9804,    8235,    7100,    6239,    5565,    5022,    4575,    4202,
+    3885,    3612,    3375,    3167,    2984,    2820,    2674,    2542,    2422,
+    2313,    2214,    2123,    2038,    1961,    1889,    1822,    1760,    1702,
+};
+
+void silk_apply_sine_window(
+    opus_int16                  px_win[],           /* O    Pointer to windowed signal                                  */
+    const opus_int16            px[],               /* I    Pointer to input signal                                     */
+    const opus_int              win_type,           /* I    Selects a window type                                       */
+    const opus_int              length              /* I    Window length, multiple of 4                                */
+)
+{
+    opus_int   k, f_Q16, c_Q16;
+    opus_int32 S0_Q16, S1_Q16;
+
+    silk_assert( win_type == 1 || win_type == 2 );
+
+    /* Length must be in a range from 16 to 120 and a multiple of 4 */
+    silk_assert( length >= 16 && length <= 120 );
+    silk_assert( ( length & 3 ) == 0 );
+
+    /* Frequency */
+    k = ( length >> 2 ) - 4;
+    silk_assert( k >= 0 && k <= 26 );
+    f_Q16 = (opus_int)freq_table_Q16[ k ];
+
+    /* Factor used for cosine approximation */
+    c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 );
+    silk_assert( c_Q16 >= -32768 );
+
+    /* initialize state */
+    if( win_type == 1 ) {
+        /* start from 0 */
+        S0_Q16 = 0;
+        /* approximation of sin(f) */
+        S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 );
+    } else {
+        /* start from 1 */
+        S0_Q16 = ( (opus_int32)1 << 16 );
+        /* approximation of cos(f) */
+        S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 );
+    }
+
+    /* Uses the recursive equation:   sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f)    */
+    /* 4 samples at a time */
+    for( k = 0; k < length; k += 4 ) {
+        px_win[ k ]     = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] );
+        px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] );
+        S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1;
+        S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) );
+
+        px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] );
+        px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] );
+        S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16;
+        S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) );
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/autocorr_FIX.c b/third_party/opus/src/silk/fixed/autocorr_FIX.c
new file mode 100644
index 0000000..de95c98
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/autocorr_FIX.c
@@ -0,0 +1,48 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "celt_lpc.h"
+
+/* Compute autocorrelation */
+void silk_autocorr(
+    opus_int32                  *results,           /* O    Result (length correlationCount)                            */
+    opus_int                    *scale,             /* O    Scaling of the correlation vector                           */
+    const opus_int16            *inputData,         /* I    Input data to correlate                                     */
+    const opus_int              inputDataSize,      /* I    Length of input                                             */
+    const opus_int              correlationCount,   /* I    Number of correlation taps to compute                       */
+    int                         arch                /* I    Run-time architecture                                       */
+)
+{
+    opus_int   corrCount;
+    corrCount = silk_min_int( inputDataSize, correlationCount );
+    *scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch);
+}
diff --git a/third_party/opus/src/silk/fixed/burg_modified_FIX.c b/third_party/opus/src/silk/fixed/burg_modified_FIX.c
new file mode 100644
index 0000000..17d0e09
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/burg_modified_FIX.c
@@ -0,0 +1,280 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "define.h"
+#include "tuning_parameters.h"
+#include "pitch.h"
+
+#define MAX_FRAME_SIZE              384             /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
+
+#define QA                          25
+#define N_BITS_HEAD_ROOM            2
+#define MIN_RSHIFTS                 -16
+#define MAX_RSHIFTS                 (32 - QA)
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified_c(
+    opus_int32                  *res_nrg,           /* O    Residual energy                                             */
+    opus_int                    *res_nrg_Q,         /* O    Residual energy Q value                                     */
+    opus_int32                  A_Q16[],            /* O    Prediction coefficients (length order)                      */
+    const opus_int16            x[],                /* I    Input signal, length: nb_subfr * ( D + subfr_length )       */
+    const opus_int32            minInvGain_Q30,     /* I    Inverse of max prediction gain                              */
+    const opus_int              subfr_length,       /* I    Input signal subframe length (incl. D preceding samples)    */
+    const opus_int              nb_subfr,           /* I    Number of subframes stacked in x                            */
+    const opus_int              D,                  /* I    Order                                                       */
+    int                         arch                /* I    Run-time architecture                                       */
+)
+{
+    opus_int         k, n, s, lz, rshifts, reached_max_gain;
+    opus_int32       C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
+    const opus_int16 *x_ptr;
+    opus_int32       C_first_row[ SILK_MAX_ORDER_LPC ];
+    opus_int32       C_last_row[  SILK_MAX_ORDER_LPC ];
+    opus_int32       Af_QA[       SILK_MAX_ORDER_LPC ];
+    opus_int32       CAf[ SILK_MAX_ORDER_LPC + 1 ];
+    opus_int32       CAb[ SILK_MAX_ORDER_LPC + 1 ];
+    opus_int32       xcorr[ SILK_MAX_ORDER_LPC ];
+    opus_int64       C0_64;
+
+    silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+    /* Compute autocorrelations, added over subframes */
+    C0_64 = silk_inner_prod16_aligned_64( x, x, subfr_length*nb_subfr, arch );
+    lz = silk_CLZ64(C0_64);
+    rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz;
+    if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS;
+    if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS;
+
+    if (rshifts > 0) {
+        C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts );
+    } else {
+        C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts );
+    }
+
+    CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1;                                /* Q(-rshifts) */
+    silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+    if( rshifts > 0 ) {
+        for( s = 0; s < nb_subfr; s++ ) {
+            x_ptr = x + s * subfr_length;
+            for( n = 1; n < D + 1; n++ ) {
+                C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64(
+                    silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts );
+            }
+        }
+    } else {
+        for( s = 0; s < nb_subfr; s++ ) {
+            int i;
+            opus_int32 d;
+            x_ptr = x + s * subfr_length;
+            celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch );
+            for( n = 1; n < D + 1; n++ ) {
+               for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ )
+                  d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] );
+               xcorr[ n - 1 ] += d;
+            }
+            for( n = 1; n < D + 1; n++ ) {
+                C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts );
+            }
+        }
+    }
+    silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+
+    /* Initialize */
+    CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1;                                /* Q(-rshifts) */
+
+    invGain_Q30 = (opus_int32)1 << 30;
+    reached_max_gain = 0;
+    for( n = 0; n < D; n++ ) {
+        /* Update first row of correlation matrix (without first element) */
+        /* Update last row of correlation matrix (without last element, stored in reversed order) */
+        /* Update C * Af */
+        /* Update C * flipud(Af) (stored in reversed order) */
+        if( rshifts > -2 ) {
+            for( s = 0; s < nb_subfr; s++ ) {
+                x_ptr = x + s * subfr_length;
+                x1  = -silk_LSHIFT32( (opus_int32)x_ptr[ n ],                    16 - rshifts );        /* Q(16-rshifts) */
+                x2  = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts );        /* Q(16-rshifts) */
+                tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ],                    QA - 16 );             /* Q(QA-16) */
+                tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 );             /* Q(QA-16) */
+                for( k = 0; k < n; k++ ) {
+                    C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ]            ); /* Q( -rshifts ) */
+                    C_last_row[ k ]  = silk_SMLAWB( C_last_row[ k ],  x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+                    Atmp_QA = Af_QA[ k ];
+                    tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ]            );                 /* Q(QA-16) */
+                    tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] );                 /* Q(QA-16) */
+                }
+                tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts );                                       /* Q(16-rshifts) */
+                tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts );                                       /* Q(16-rshifts) */
+                for( k = 0; k <= n; k++ ) {
+                    CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ]                    );        /* Q( -rshift ) */
+                    CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] );        /* Q( -rshift ) */
+                }
+            }
+        } else {
+            for( s = 0; s < nb_subfr; s++ ) {
+                x_ptr = x + s * subfr_length;
+                x1  = -silk_LSHIFT32( (opus_int32)x_ptr[ n ],                    -rshifts );            /* Q( -rshifts ) */
+                x2  = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts );            /* Q( -rshifts ) */
+                tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ],                    17 );                  /* Q17 */
+                tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 );                  /* Q17 */
+                for( k = 0; k < n; k++ ) {
+                    C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ]            ); /* Q( -rshifts ) */
+                    C_last_row[ k ]  = silk_MLA( C_last_row[ k ],  x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+                    Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 );                                   /* Q17 */
+                    /* We sometimes have get overflows in the multiplications (even beyond +/- 2^32),
+                       but they cancel each other and the real result seems to always fit in a 32-bit
+                       signed integer. This was determined experimentally, not theoretically (unfortunately). */
+                    tmp1 = silk_MLA_ovflw( tmp1, x_ptr[ n - k - 1 ],            Atmp1 );                      /* Q17 */
+                    tmp2 = silk_MLA_ovflw( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 );                      /* Q17 */
+                }
+                tmp1 = -tmp1;                                                                           /* Q17 */
+                tmp2 = -tmp2;                                                                           /* Q17 */
+                for( k = 0; k <= n; k++ ) {
+                    CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1,
+                        silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) );                    /* Q( -rshift ) */
+                    CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2,
+                        silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */
+                }
+            }
+        }
+
+        /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+        tmp1 = C_first_row[ n ];                                                                        /* Q( -rshifts ) */
+        tmp2 = C_last_row[ n ];                                                                         /* Q( -rshifts ) */
+        num  = 0;                                                                                       /* Q( -rshifts ) */
+        nrg  = silk_ADD32( CAb[ 0 ], CAf[ 0 ] );                                                        /* Q( 1-rshifts ) */
+        for( k = 0; k < n; k++ ) {
+            Atmp_QA = Af_QA[ k ];
+            lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1;
+            lz = silk_min( 32 - QA, lz );
+            Atmp1 = silk_LSHIFT32( Atmp_QA, lz );                                                       /* Q( QA + lz ) */
+
+            tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[  n - k - 1 ], Atmp1 ), 32 - QA - lz );  /* Q( -rshifts ) */
+            tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz );  /* Q( -rshifts ) */
+            num  = silk_ADD_LSHIFT32( num,  silk_SMMUL( CAb[ n - k ],             Atmp1 ), 32 - QA - lz );  /* Q( -rshifts ) */
+            nrg  = silk_ADD_LSHIFT32( nrg,  silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ),
+                                                                                Atmp1 ), 32 - QA - lz );    /* Q( 1-rshifts ) */
+        }
+        CAf[ n + 1 ] = tmp1;                                                                            /* Q( -rshifts ) */
+        CAb[ n + 1 ] = tmp2;                                                                            /* Q( -rshifts ) */
+        num = silk_ADD32( num, tmp2 );                                                                  /* Q( -rshifts ) */
+        num = silk_LSHIFT32( -num, 1 );                                                                 /* Q( 1-rshifts ) */
+
+        /* Calculate the next order reflection (parcor) coefficient */
+        if( silk_abs( num ) < nrg ) {
+            rc_Q31 = silk_DIV32_varQ( num, nrg, 31 );
+        } else {
+            rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN;
+        }
+
+        /* Update inverse prediction gain */
+        tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+        tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 );
+        if( tmp1 <= minInvGain_Q30 ) {
+            /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+            tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 );            /* Q30 */
+            rc_Q31 = silk_SQRT_APPROX( tmp2 );                                                  /* Q15 */
+            if( rc_Q31 > 0 ) {
+                /* Newton-Raphson iteration */
+                rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 );                       /* Q15 */
+                rc_Q31 = silk_LSHIFT32( rc_Q31, 16 );                                                   /* Q31 */
+                if( num < 0 ) {
+                    /* Ensure adjusted reflection coefficients has the original sign */
+                    rc_Q31 = -rc_Q31;
+                }
+            }
+            invGain_Q30 = minInvGain_Q30;
+            reached_max_gain = 1;
+        } else {
+            invGain_Q30 = tmp1;
+        }
+
+        /* Update the AR coefficients */
+        for( k = 0; k < (n + 1) >> 1; k++ ) {
+            tmp1 = Af_QA[ k ];                                                                  /* QA */
+            tmp2 = Af_QA[ n - k - 1 ];                                                          /* QA */
+            Af_QA[ k ]         = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 );      /* QA */
+            Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 );      /* QA */
+        }
+        Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA );                                          /* QA */
+
+        if( reached_max_gain ) {
+            /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+            for( k = n + 1; k < D; k++ ) {
+                Af_QA[ k ] = 0;
+            }
+            break;
+        }
+
+        /* Update C * Af and C * Ab */
+        for( k = 0; k <= n + 1; k++ ) {
+            tmp1 = CAf[ k ];                                                                    /* Q( -rshifts ) */
+            tmp2 = CAb[ n - k + 1 ];                                                            /* Q( -rshifts ) */
+            CAf[ k ]         = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 );        /* Q( -rshifts ) */
+            CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 );        /* Q( -rshifts ) */
+        }
+    }
+
+    if( reached_max_gain ) {
+        for( k = 0; k < D; k++ ) {
+            /* Scale coefficients */
+            A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );
+        }
+        /* Subtract energy of preceding samples from C0 */
+        if( rshifts > 0 ) {
+            for( s = 0; s < nb_subfr; s++ ) {
+                x_ptr = x + s * subfr_length;
+                C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts );
+            }
+        } else {
+            for( s = 0; s < nb_subfr; s++ ) {
+                x_ptr = x + s * subfr_length;
+                C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch), -rshifts);
+            }
+        }
+        /* Approximate residual energy */
+        *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 );
+        *res_nrg_Q = -rshifts;
+    } else {
+        /* Return residual energy */
+        nrg  = CAf[ 0 ];                                                                            /* Q( -rshifts ) */
+        tmp1 = (opus_int32)1 << 16;                                                                             /* Q16 */
+        for( k = 0; k < D; k++ ) {
+            Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );                                       /* Q16 */
+            nrg  = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 );                                         /* Q( -rshifts ) */
+            tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 );                                               /* Q16 */
+            A_Q16[ k ] = -Atmp1;
+        }
+        *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
+        *res_nrg_Q = -rshifts;
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/corrMatrix_FIX.c b/third_party/opus/src/silk/fixed/corrMatrix_FIX.c
new file mode 100644
index 0000000..c1d437c
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/corrMatrix_FIX.c
@@ -0,0 +1,158 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/**********************************************************************
+ * Correlation Matrix Computations for LS estimate.
+ **********************************************************************/
+
+#include "main_FIX.h"
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FIX(
+    const opus_int16                *x,                                     /* I    x vector [L + order - 1] used to form data matrix X                         */
+    const opus_int16                *t,                                     /* I    Target vector [L]                                                           */
+    const opus_int                  L,                                      /* I    Length of vectors                                                           */
+    const opus_int                  order,                                  /* I    Max lag for correlation                                                     */
+    opus_int32                      *Xt,                                    /* O    Pointer to X'*t correlation vector [order]                                  */
+    const opus_int                  rshifts,                                /* I    Right shifts of correlations                                                */
+    int                             arch                                    /* I    Run-time architecture                                                       */
+)
+{
+    opus_int         lag, i;
+    const opus_int16 *ptr1, *ptr2;
+    opus_int32       inner_prod;
+
+    ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */
+    ptr2 = t;
+    /* Calculate X'*t */
+    if( rshifts > 0 ) {
+        /* Right shifting used */
+        for( lag = 0; lag < order; lag++ ) {
+            inner_prod = 0;
+            for( i = 0; i < L; i++ ) {
+                inner_prod += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts );
+            }
+            Xt[ lag ] = inner_prod; /* X[:,lag]'*t */
+            ptr1--; /* Go to next column of X */
+        }
+    } else {
+        silk_assert( rshifts == 0 );
+        for( lag = 0; lag < order; lag++ ) {
+            Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); /* X[:,lag]'*t */
+            ptr1--; /* Go to next column of X */
+        }
+    }
+}
+
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FIX(
+    const opus_int16                *x,                                     /* I    x vector [L + order - 1] used to form data matrix X                         */
+    const opus_int                  L,                                      /* I    Length of vectors                                                           */
+    const opus_int                  order,                                  /* I    Max lag for correlation                                                     */
+    const opus_int                  head_room,                              /* I    Desired headroom                                                            */
+    opus_int32                      *XX,                                    /* O    Pointer to X'*X correlation matrix [ order x order ]                        */
+    opus_int                        *rshifts,                               /* I/O  Right shifts of correlations                                                */
+    int                             arch                                    /* I    Run-time architecture                                                       */
+)
+{
+    opus_int         i, j, lag, rshifts_local, head_room_rshifts;
+    opus_int32       energy;
+    const opus_int16 *ptr1, *ptr2;
+
+    /* Calculate energy to find shift used to fit in 32 bits */
+    silk_sum_sqr_shift( &energy, &rshifts_local, x, L + order - 1 );
+    /* Add shifts to get the desired head room */
+    head_room_rshifts = silk_max( head_room - silk_CLZ32( energy ), 0 );
+
+    energy = silk_RSHIFT32( energy, head_room_rshifts );
+    rshifts_local += head_room_rshifts;
+
+    /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */
+    /* Remove contribution of first order - 1 samples */
+    for( i = 0; i < order - 1; i++ ) {
+        energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), rshifts_local );
+    }
+    if( rshifts_local < *rshifts ) {
+        /* Adjust energy */
+        energy = silk_RSHIFT32( energy, *rshifts - rshifts_local );
+        rshifts_local = *rshifts;
+    }
+
+    /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */
+    /* Fill out the diagonal of the correlation matrix */
+    matrix_ptr( XX, 0, 0, order ) = energy;
+    ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */
+    for( j = 1; j < order; j++ ) {
+        energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), rshifts_local ) );
+        energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), rshifts_local ) );
+        matrix_ptr( XX, j, j, order ) = energy;
+    }
+
+    ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */
+    /* Calculate the remaining elements of the correlation matrix */
+    if( rshifts_local > 0 ) {
+        /* Right shifting used */
+        for( lag = 1; lag < order; lag++ ) {
+            /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
+            energy = 0;
+            for( i = 0; i < L; i++ ) {
+                energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts_local );
+            }
+            /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
+            matrix_ptr( XX, lag, 0, order ) = energy;
+            matrix_ptr( XX, 0, lag, order ) = energy;
+            for( j = 1; j < ( order - lag ); j++ ) {
+                energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), rshifts_local ) );
+                energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), rshifts_local ) );
+                matrix_ptr( XX, lag + j, j, order ) = energy;
+                matrix_ptr( XX, j, lag + j, order ) = energy;
+            }
+            ptr2--; /* Update pointer to first sample of next column (lag) in X */
+        }
+    } else {
+        for( lag = 1; lag < order; lag++ ) {
+            /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
+            energy = silk_inner_prod_aligned( ptr1, ptr2, L, arch );
+            matrix_ptr( XX, lag, 0, order ) = energy;
+            matrix_ptr( XX, 0, lag, order ) = energy;
+            /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
+            for( j = 1; j < ( order - lag ); j++ ) {
+                energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) );
+                energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] );
+                matrix_ptr( XX, lag + j, j, order ) = energy;
+                matrix_ptr( XX, j, lag + j, order ) = energy;
+            }
+            ptr2--;/* Update pointer to first sample of next column (lag) in X */
+        }
+    }
+    *rshifts = rshifts_local;
+}
+
diff --git a/third_party/opus/src/silk/fixed/encode_frame_FIX.c b/third_party/opus/src/silk/fixed/encode_frame_FIX.c
new file mode 100644
index 0000000..5ef44b03
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/encode_frame_FIX.c
@@ -0,0 +1,387 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate           */
+static OPUS_INLINE void silk_LBRR_encode_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Pointer to Silk FIX encoder state                                           */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  Pointer to Silk FIX encoder control struct                                  */
+    const opus_int32                xfw_Q3[],                               /* I    Input signal                                                                */
+    opus_int                        condCoding                              /* I    The type of conditional coding used so far for this frame                   */
+);
+
+void silk_encode_do_VAD_FIX(
+    silk_encoder_state_FIX          *psEnc                                  /* I/O  Pointer to Silk FIX encoder state                                           */
+)
+{
+    /****************************/
+    /* Voice Activity Detection */
+    /****************************/
+    silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch );
+
+    /**************************************************/
+    /* Convert speech activity into VAD and DTX flags */
+    /**************************************************/
+    if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) {
+        psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
+        psEnc->sCmn.noSpeechCounter++;
+        if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) {
+            psEnc->sCmn.inDTX = 0;
+        } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
+            psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
+            psEnc->sCmn.inDTX           = 0;
+        }
+        psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
+    } else {
+        psEnc->sCmn.noSpeechCounter    = 0;
+        psEnc->sCmn.inDTX              = 0;
+        psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+        psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+    }
+}
+
+/****************/
+/* Encode frame */
+/****************/
+opus_int silk_encode_frame_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Pointer to Silk FIX encoder state                                           */
+    opus_int32                      *pnBytesOut,                            /* O    Pointer to number of payload bytes;                                         */
+    ec_enc                          *psRangeEnc,                            /* I/O  compressor data structure                                                   */
+    opus_int                        condCoding,                             /* I    The type of conditional coding to use                                       */
+    opus_int                        maxBits,                                /* I    If > 0: maximum number of output bits                                       */
+    opus_int                        useCBR                                  /* I    Flag to force constant-bitrate operation                                    */
+)
+{
+    silk_encoder_control_FIX sEncCtrl;
+    opus_int     i, iter, maxIter, found_upper, found_lower, ret = 0;
+    opus_int16   *x_frame;
+    ec_enc       sRangeEnc_copy, sRangeEnc_copy2;
+    silk_nsq_state sNSQ_copy, sNSQ_copy2;
+    opus_int32   seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+    opus_int32   gainsID, gainsID_lower, gainsID_upper;
+    opus_int16   gainMult_Q8;
+    opus_int16   ec_prevLagIndex_copy;
+    opus_int     ec_prevSignalType_copy;
+    opus_int8    LastGainIndex_copy2;
+    SAVE_STACK;
+
+    /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
+    LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
+    psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
+
+    /**************************************************************/
+    /* Set up Input Pointers, and insert frame in input buffer   */
+    /*************************************************************/
+    /* start of frame to encode */
+    x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length;
+
+    /***************************************/
+    /* Ensure smooth bandwidth transitions */
+    /***************************************/
+    silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+    /*******************************************/
+    /* Copy new frame to front of input buffer */
+    /*******************************************/
+    silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) );
+
+    if( !psEnc->sCmn.prefillFlag ) {
+        VARDECL( opus_int32, xfw_Q3 );
+        VARDECL( opus_int16, res_pitch );
+        VARDECL( opus_uint8, ec_buf_copy );
+        opus_int16 *res_pitch_frame;
+
+        ALLOC( res_pitch,
+               psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length
+                   + psEnc->sCmn.ltp_mem_length, opus_int16 );
+        /* start of pitch LPC residual frame */
+        res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length;
+
+        /*****************************************/
+        /* Find pitch lags, initial LPC analysis */
+        /*****************************************/
+        silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch );
+
+        /************************/
+        /* Noise shape analysis */
+        /************************/
+        silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch );
+
+        /***************************************************/
+        /* Find linear prediction coefficients (LPC + LTP) */
+        /***************************************************/
+        silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding );
+
+        /****************************************/
+        /* Process gains                        */
+        /****************************************/
+        silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding );
+
+        /*****************************************/
+        /* Prefiltering for noise shaper         */
+        /*****************************************/
+        ALLOC( xfw_Q3, psEnc->sCmn.frame_length, opus_int32 );
+        silk_prefilter_FIX( psEnc, &sEncCtrl, xfw_Q3, x_frame );
+
+        /****************************************/
+        /* Low Bitrate Redundant Encoding       */
+        /****************************************/
+        silk_LBRR_encode_FIX( psEnc, &sEncCtrl, xfw_Q3, condCoding );
+
+        /* Loop over quantizer and entropy coding to control bitrate */
+        maxIter = 6;
+        gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
+        found_lower = 0;
+        found_upper = 0;
+        gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+        gainsID_lower = -1;
+        gainsID_upper = -1;
+        /* Copy part of the input state */
+        silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+        silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+        seed_copy = psEnc->sCmn.indices.Seed;
+        ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+        ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
+        ALLOC( ec_buf_copy, 1275, opus_uint8 );
+        for( iter = 0; ; iter++ ) {
+            if( gainsID == gainsID_lower ) {
+                nBits = nBits_lower;
+            } else if( gainsID == gainsID_upper ) {
+                nBits = nBits_upper;
+            } else {
+                /* Restore part of the input state */
+                if( iter > 0 ) {
+                    silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+                    silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
+                    psEnc->sCmn.indices.Seed = seed_copy;
+                    psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+                    psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+                }
+
+                /*****************************************/
+                /* Noise shaping quantization            */
+                /*****************************************/
+                if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+                    silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses,
+                           sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
+                           sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14,
+                           psEnc->sCmn.arch );
+                } else {
+                    silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses,
+                            sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
+                            sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14,
+                            psEnc->sCmn.arch);
+                }
+
+                /****************************************/
+                /* Encode Parameters                    */
+                /****************************************/
+                silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+
+                /****************************************/
+                /* Encode Excitation Signal             */
+                /****************************************/
+                silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+                    psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+
+                nBits = ec_tell( psRangeEnc );
+
+                if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+                    break;
+                }
+            }
+
+            if( iter == maxIter ) {
+                if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
+                    /* Restore output state from earlier iteration that did meet the bitrate budget */
+                    silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+                    silk_assert( sRangeEnc_copy2.offs <= 1275 );
+                    silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
+                    silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
+                    psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
+                }
+                break;
+            }
+
+            if( nBits > maxBits ) {
+                if( found_lower == 0 && iter >= 2 ) {
+                    /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
+                    sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 );
+                    found_upper = 0;
+                    gainsID_upper = -1;
+                } else {
+                    found_upper = 1;
+                    nBits_upper = nBits;
+                    gainMult_upper = gainMult_Q8;
+                    gainsID_upper = gainsID;
+                }
+            } else if( nBits < maxBits - 5 ) {
+                found_lower = 1;
+                nBits_lower = nBits;
+                gainMult_lower = gainMult_Q8;
+                if( gainsID != gainsID_lower ) {
+                    gainsID_lower = gainsID;
+                    /* Copy part of the output state */
+                    silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+                    silk_assert( psRangeEnc->offs <= 1275 );
+                    silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+                    silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+                    LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+                }
+            } else {
+                /* Within 5 bits of budget: close enough */
+                break;
+            }
+
+            if( ( found_lower & found_upper ) == 0 ) {
+                /* Adjust gain according to high-rate rate/distortion curve */
+                opus_int32 gain_factor_Q16;
+                gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+                gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) );
+                if( nBits > maxBits ) {
+                    gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
+                }
+                gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 );
+            } else {
+                /* Adjust gain by interpolating */
+                gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower );
+                /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
+                if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
+                } else
+                if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+                }
+            }
+
+            for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+                sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 );
+            }
+
+            /* Quantize gains */
+            psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+            silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16,
+                  &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+            /* Unique identifier of gains vector */
+            gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+        }
+    }
+
+    /* Update input buffer */
+    silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
+        ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) );
+
+    /* Exit without entropy coding */
+    if( psEnc->sCmn.prefillFlag ) {
+        /* No payload */
+        *pnBytesOut = 0;
+        RESTORE_STACK;
+        return ret;
+    }
+
+    /* Parameters needed for next frame */
+    psEnc->sCmn.prevLag        = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+    psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
+
+    /****************************************/
+    /* Finalize payload                     */
+    /****************************************/
+    psEnc->sCmn.first_frame_after_reset = 0;
+    /* Payload size */
+    *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
+
+    RESTORE_STACK;
+    return ret;
+}
+
+/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate  */
+static OPUS_INLINE void silk_LBRR_encode_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Pointer to Silk FIX encoder state                                           */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  Pointer to Silk FIX encoder control struct                                  */
+    const opus_int32                xfw_Q3[],                               /* I    Input signal                                                                */
+    opus_int                        condCoding                              /* I    The type of conditional coding used so far for this frame                   */
+)
+{
+    opus_int32   TempGains_Q16[ MAX_NB_SUBFR ];
+    SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
+    silk_nsq_state sNSQ_LBRR;
+
+    /*******************************************/
+    /* Control use of inband LBRR              */
+    /*******************************************/
+    if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
+        psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+
+        /* Copy noise shaping quantizer state and quantization indices from regular encoding */
+        silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+        silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
+
+        /* Save original gains */
+        silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+
+        if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
+            /* First frame in packet or previous frame not LBRR coded */
+            psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
+
+            /* Increase Gains to get target LBRR rate */
+            psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases;
+            psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
+        }
+
+        /* Decode to get gains in sync with decoder         */
+        /* Overwrite unquantized gains with quantized gains */
+        silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices,
+            &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+        /*****************************************/
+        /* Noise shaping quantization            */
+        /*****************************************/
+        if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+            silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3,
+                psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
+                psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
+                psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch );
+        } else {
+            silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3,
+                psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
+                psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
+                psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch );
+        }
+
+        /* Restore original gains */
+        silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/find_LPC_FIX.c b/third_party/opus/src/silk/fixed/find_LPC_FIX.c
new file mode 100644
index 0000000..e11cdc86
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/find_LPC_FIX.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Finds LPC vector from correlations, and converts to NLSF */
+void silk_find_LPC_FIX(
+    silk_encoder_state              *psEncC,                                /* I/O  Encoder state                                                               */
+    opus_int16                      NLSF_Q15[],                             /* O    NLSFs                                                                       */
+    const opus_int16                x[],                                    /* I    Input signal                                                                */
+    const opus_int32                minInvGain_Q30                          /* I    Inverse of max prediction gain                                              */
+)
+{
+    opus_int     k, subfr_length;
+    opus_int32   a_Q16[ MAX_LPC_ORDER ];
+    opus_int     isInterpLower, shift;
+    opus_int32   res_nrg0, res_nrg1;
+    opus_int     rshift0, rshift1;
+
+    /* Used only for LSF interpolation */
+    opus_int32   a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg;
+    opus_int     res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q;
+    opus_int16   a_tmp_Q12[ MAX_LPC_ORDER ];
+    opus_int16   NLSF0_Q15[ MAX_LPC_ORDER ];
+    SAVE_STACK;
+
+    subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder;
+
+    /* Default: no interpolation */
+    psEncC->indices.NLSFInterpCoef_Q2 = 4;
+
+    /* Burg AR analysis for the full frame */
+    silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch );
+
+    if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) {
+        VARDECL( opus_int16, LPC_res );
+
+        /* Optimal solution for last 10 ms */
+        silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch );
+
+        /* subtract residual energy here, as that's easier than adding it to the    */
+        /* residual energy of the first 10 ms in each iteration of the search below */
+        shift = res_tmp_nrg_Q - res_nrg_Q;
+        if( shift >= 0 ) {
+            if( shift < 32 ) {
+                res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift );
+            }
+        } else {
+            silk_assert( shift > -32 );
+            res_nrg   = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg;
+            res_nrg_Q = res_tmp_nrg_Q;
+        }
+
+        /* Convert to NLSFs */
+        silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder );
+
+        ALLOC( LPC_res, 2 * subfr_length, opus_int16 );
+
+        /* Search over interpolation indices to find the one with lowest residual energy */
+        for( k = 3; k >= 0; k-- ) {
+            /* Interpolate NLSFs for first half */
+            silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder );
+
+            /* Convert to LPC for residual energy evaluation */
+            silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder );
+
+            /* Calculate residual energy with NLSF interpolation */
+            silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder, psEncC->arch );
+
+            silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder,                subfr_length - psEncC->predictLPCOrder );
+            silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder );
+
+            /* Add subframe energies from first half frame */
+            shift = rshift0 - rshift1;
+            if( shift >= 0 ) {
+                res_nrg1         = silk_RSHIFT( res_nrg1, shift );
+                res_nrg_interp_Q = -rshift0;
+            } else {
+                res_nrg0         = silk_RSHIFT( res_nrg0, -shift );
+                res_nrg_interp_Q = -rshift1;
+            }
+            res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 );
+
+            /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */
+            shift = res_nrg_interp_Q - res_nrg_Q;
+            if( shift >= 0 ) {
+                if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) {
+                    isInterpLower = silk_TRUE;
+                } else {
+                    isInterpLower = silk_FALSE;
+                }
+            } else {
+                if( -shift < 32 ) {
+                    if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) {
+                        isInterpLower = silk_TRUE;
+                    } else {
+                        isInterpLower = silk_FALSE;
+                    }
+                } else {
+                    isInterpLower = silk_FALSE;
+                }
+            }
+
+            /* Determine whether current interpolated NLSFs are best so far */
+            if( isInterpLower == silk_TRUE ) {
+                /* Interpolation has lower residual energy */
+                res_nrg   = res_nrg_interp;
+                res_nrg_Q = res_nrg_interp_Q;
+                psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k;
+            }
+        }
+    }
+
+    if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) {
+        /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
+        silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder );
+    }
+
+    silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) );
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/fixed/find_LTP_FIX.c b/third_party/opus/src/silk/fixed/find_LTP_FIX.c
new file mode 100644
index 0000000..1314a28
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/find_LTP_FIX.c
@@ -0,0 +1,245 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "tuning_parameters.h"
+
+/* Head room for correlations */
+#define LTP_CORRS_HEAD_ROOM                             2
+
+void silk_fit_LTP(
+    opus_int32 LTP_coefs_Q16[ LTP_ORDER ],
+    opus_int16 LTP_coefs_Q14[ LTP_ORDER ]
+);
+
+void silk_find_LTP_FIX(
+    opus_int16                      b_Q14[ MAX_NB_SUBFR * LTP_ORDER ],      /* O    LTP coefs                                                                   */
+    opus_int32                      WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O    Weight for LTP quantization                                           */
+    opus_int                        *LTPredCodGain_Q7,                      /* O    LTP coding gain                                                             */
+    const opus_int16                r_lpc[],                                /* I    residual signal after LPC signal + state for first 10 ms                    */
+    const opus_int                  lag[ MAX_NB_SUBFR ],                    /* I    LTP lags                                                                    */
+    const opus_int32                Wght_Q15[ MAX_NB_SUBFR ],               /* I    weights                                                                     */
+    const opus_int                  subfr_length,                           /* I    subframe length                                                             */
+    const opus_int                  nb_subfr,                               /* I    number of subframes                                                         */
+    const opus_int                  mem_offset,                             /* I    number of samples in LTP memory                                             */
+    opus_int                        corr_rshifts[ MAX_NB_SUBFR ],           /* O    right shifts applied to correlations                                        */
+    int                             arch                                    /* I    Run-time architecture                                                       */
+)
+{
+    opus_int   i, k, lshift;
+    const opus_int16 *r_ptr, *lag_ptr;
+    opus_int16 *b_Q14_ptr;
+
+    opus_int32 regu;
+    opus_int32 *WLTP_ptr;
+    opus_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], g_Q26;
+    opus_int32 w[ MAX_NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits;
+
+    opus_int32 temp32, denom32;
+    opus_int   extra_shifts;
+    opus_int   rr_shifts, maxRshifts, maxRshifts_wxtra, LZs;
+    opus_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16;
+    opus_int32 Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ];
+    opus_int32 wd, m_Q12;
+
+    b_Q14_ptr = b_Q14;
+    WLTP_ptr  = WLTP;
+    r_ptr     = &r_lpc[ mem_offset ];
+    for( k = 0; k < nb_subfr; k++ ) {
+        lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
+
+        silk_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */
+
+        /* Assure headroom */
+        LZs = silk_CLZ32( rr[k] );
+        if( LZs < LTP_CORRS_HEAD_ROOM ) {
+            rr[ k ] = silk_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs );
+            rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs );
+        }
+        corr_rshifts[ k ] = rr_shifts;
+        silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP_ptr, &corr_rshifts[ k ], arch );  /* WLTP_fix_ptr in Q( -corr_rshifts[ k ] ) */
+
+        /* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */
+        silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr, corr_rshifts[ k ], arch );  /* Rr_fix_ptr   in Q( -corr_rshifts[ k ] ) */
+        if( corr_rshifts[ k ] > rr_shifts ) {
+            rr[ k ] = silk_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */
+        }
+        silk_assert( rr[ k ] >= 0 );
+
+        regu = 1;
+        regu = silk_SMLAWB( regu, rr[ k ], SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+        regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+        regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+        silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER );
+
+        silk_solve_LDL_FIX( WLTP_ptr, LTP_ORDER, Rr, b_Q16 ); /* WLTP_fix_ptr and Rr_fix_ptr both in Q(-corr_rshifts[k]) */
+
+        /* Limit and store in Q14 */
+        silk_fit_LTP( b_Q16, b_Q14_ptr );
+
+        /* Calculate residual energy */
+        nrg[ k ] = silk_residual_energy16_covar_FIX( b_Q14_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER, 14 ); /* nrg_fix in Q( -corr_rshifts[ k ] ) */
+
+        /* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */
+        extra_shifts = silk_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM );
+        denom32 = silk_LSHIFT_SAT32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */
+            silk_RSHIFT( silk_SMULWB( (opus_int32)subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts );    /* Q( -corr_rshifts[ k ] + extra_shifts ) */
+        denom32 = silk_max( denom32, 1 );
+        silk_assert( ((opus_int64)Wght_Q15[ k ] << 16 ) < silk_int32_MAX );                       /* Wght always < 0.5 in Q0 */
+        temp32 = silk_DIV32( silk_LSHIFT( (opus_int32)Wght_Q15[ k ], 16 ), denom32 );             /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */
+        temp32 = silk_RSHIFT( temp32, 31 + corr_rshifts[ k ] - extra_shifts - 26 );               /* Q26 */
+
+        /* Limit temp such that the below scaling never wraps around */
+        WLTP_max = 0;
+        for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
+            WLTP_max = silk_max( WLTP_ptr[ i ], WLTP_max );
+        }
+        lshift = silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */
+        silk_assert( 26 - 18 + lshift >= 0 );
+        if( 26 - 18 + lshift < 31 ) {
+            temp32 = silk_min_32( temp32, silk_LSHIFT( (opus_int32)1, 26 - 18 + lshift ) );
+        }
+
+        silk_scale_vector32_Q26_lshift_18( WLTP_ptr, temp32, LTP_ORDER * LTP_ORDER ); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */
+
+        w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER/2, LTP_ORDER/2, LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */
+        silk_assert( w[k] >= 0 );
+
+        r_ptr     += subfr_length;
+        b_Q14_ptr += LTP_ORDER;
+        WLTP_ptr  += LTP_ORDER * LTP_ORDER;
+    }
+
+    maxRshifts = 0;
+    for( k = 0; k < nb_subfr; k++ ) {
+        maxRshifts = silk_max_int( corr_rshifts[ k ], maxRshifts );
+    }
+
+    /* Compute LTP coding gain */
+    if( LTPredCodGain_Q7 != NULL ) {
+        LPC_LTP_res_nrg = 0;
+        LPC_res_nrg     = 0;
+        silk_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */
+        for( k = 0; k < nb_subfr; k++ ) {
+            LPC_res_nrg     = silk_ADD32( LPC_res_nrg,     silk_RSHIFT( silk_ADD32( silk_SMULWB(  rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */
+            LPC_LTP_res_nrg = silk_ADD32( LPC_LTP_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */
+        }
+        LPC_LTP_res_nrg = silk_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */
+
+        div_Q16 = silk_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 );
+        *LTPredCodGain_Q7 = ( opus_int )silk_SMULBB( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) );
+
+        silk_assert( *LTPredCodGain_Q7 == ( opus_int )silk_SAT16( silk_MUL( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ) ) );
+    }
+
+    /* smoothing */
+    /* d = sum( B, 1 ); */
+    b_Q14_ptr = b_Q14;
+    for( k = 0; k < nb_subfr; k++ ) {
+        d_Q14[ k ] = 0;
+        for( i = 0; i < LTP_ORDER; i++ ) {
+            d_Q14[ k ] += b_Q14_ptr[ i ];
+        }
+        b_Q14_ptr += LTP_ORDER;
+    }
+
+    /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
+
+    /* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */
+    max_abs_d_Q14 = 0;
+    max_w_bits    = 0;
+    for( k = 0; k < nb_subfr; k++ ) {
+        max_abs_d_Q14 = silk_max_32( max_abs_d_Q14, silk_abs( d_Q14[ k ] ) );
+        /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */
+        /* Find bits needed in Q( 18 - maxRshifts ) */
+        max_w_bits = silk_max_32( max_w_bits, 32 - silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts );
+    }
+
+    /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -silk_int16_MIN */
+    silk_assert( max_abs_d_Q14 <= ( 5 << 15 ) );
+
+    /* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */
+    extra_shifts = max_w_bits + 32 - silk_CLZ32( max_abs_d_Q14 ) - 14;
+
+    /* Subtract what we got available; bits in output var plus maxRshifts */
+    extra_shifts -= ( 32 - 1 - 2 + maxRshifts ); /* Keep sign bit free as well as 2 bits for accumulation */
+    extra_shifts = silk_max_int( extra_shifts, 0 );
+
+    maxRshifts_wxtra = maxRshifts + extra_shifts;
+
+    temp32 = silk_RSHIFT( 262, maxRshifts + extra_shifts ) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */
+    wd = 0;
+    for( k = 0; k < nb_subfr; k++ ) {
+        /* w has at least 2 bits of headroom so no overflow should happen */
+        temp32 = silk_ADD32( temp32,                     silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) );                      /* Q( 18 - maxRshifts_wxtra ) */
+        wd     = silk_ADD32( wd, silk_LSHIFT( silk_SMULWW( silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */
+    }
+    m_Q12 = silk_DIV32_varQ( wd, temp32, 12 );
+
+    b_Q14_ptr = b_Q14;
+    for( k = 0; k < nb_subfr; k++ ) {
+        /* w_fix[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */
+        if( 2 - corr_rshifts[k] > 0 ) {
+            temp32 = silk_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] );
+        } else {
+            temp32 = silk_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 );
+        }
+
+        g_Q26 = silk_MUL(
+            silk_DIV32(
+                SILK_FIX_CONST( LTP_SMOOTHING, 26 ),
+                silk_RSHIFT( SILK_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ),                          /* Q10 */
+            silk_LSHIFT_SAT32( silk_SUB_SAT32( (opus_int32)m_Q12, silk_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) );    /* Q16 */
+
+        temp32 = 0;
+        for( i = 0; i < LTP_ORDER; i++ ) {
+            delta_b_Q14[ i ] = silk_max_16( b_Q14_ptr[ i ], 1638 );     /* 1638_Q14 = 0.1_Q0 */
+            temp32 += delta_b_Q14[ i ];                                 /* Q14 */
+        }
+        temp32 = silk_DIV32( g_Q26, temp32 );                           /* Q14 -> Q12 */
+        for( i = 0; i < LTP_ORDER; i++ ) {
+            b_Q14_ptr[ i ] = silk_LIMIT_32( (opus_int32)b_Q14_ptr[ i ] + silk_SMULWB( silk_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 );
+        }
+        b_Q14_ptr += LTP_ORDER;
+    }
+}
+
+void silk_fit_LTP(
+    opus_int32 LTP_coefs_Q16[ LTP_ORDER ],
+    opus_int16 LTP_coefs_Q14[ LTP_ORDER ]
+)
+{
+    opus_int i;
+
+    for( i = 0; i < LTP_ORDER; i++ ) {
+        LTP_coefs_Q14[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( LTP_coefs_Q16[ i ], 2 ) );
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/find_pitch_lags_FIX.c b/third_party/opus/src/silk/fixed/find_pitch_lags_FIX.c
new file mode 100644
index 0000000..b8440a8
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/find_pitch_lags_FIX.c
@@ -0,0 +1,145 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Find pitch lags */
+void silk_find_pitch_lags_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  encoder state                                                               */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  encoder control                                                             */
+    opus_int16                      res[],                                  /* O    residual                                                                    */
+    const opus_int16                x[],                                    /* I    Speech signal                                                               */
+    int                             arch                                    /* I    Run-time architecture                                                       */
+)
+{
+    opus_int   buf_len, i, scale;
+    opus_int32 thrhld_Q13, res_nrg;
+    const opus_int16 *x_buf, *x_buf_ptr;
+    VARDECL( opus_int16, Wsig );
+    opus_int16 *Wsig_ptr;
+    opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ];
+    opus_int16 rc_Q15[    MAX_FIND_PITCH_LPC_ORDER ];
+    opus_int32 A_Q24[     MAX_FIND_PITCH_LPC_ORDER ];
+    opus_int16 A_Q12[     MAX_FIND_PITCH_LPC_ORDER ];
+    SAVE_STACK;
+
+    /******************************************/
+    /* Set up buffer lengths etc based on Fs  */
+    /******************************************/
+    buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length;
+
+    /* Safety check */
+    silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length );
+
+    x_buf = x - psEnc->sCmn.ltp_mem_length;
+
+    /*************************************/
+    /* Estimate LPC AR coefficients      */
+    /*************************************/
+
+    /* Calculate windowed signal */
+
+    ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 );
+
+    /* First LA_LTP samples */
+    x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length;
+    Wsig_ptr  = Wsig;
+    silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch );
+
+    /* Middle un - windowed samples */
+    Wsig_ptr  += psEnc->sCmn.la_pitch;
+    x_buf_ptr += psEnc->sCmn.la_pitch;
+    silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) );
+
+    /* Last LA_LTP samples */
+    Wsig_ptr  += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
+    x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
+    silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch );
+
+    /* Calculate autocorrelation sequence */
+    silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch );
+
+    /* Add white noise, as fraction of energy */
+    auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1;
+
+    /* Calculate the reflection coefficients using schur */
+    res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder );
+
+    /* Prediction gain */
+    psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 );
+
+    /* Convert reflection coefficients to prediction coefficients */
+    silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder );
+
+    /* Convert From 32 bit Q24 to 16 bit Q12 coefs */
+    for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) {
+        A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) );
+    }
+
+    /* Do BWE */
+    silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) );
+
+    /*****************************************/
+    /* LPC analysis filtering                */
+    /*****************************************/
+    silk_LPC_analysis_filter( res, x_buf, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder, psEnc->sCmn.arch );
+
+    if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) {
+        /* Threshold for pitch estimator */
+        thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 );
+        thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder );
+        thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1,   21  ), psEnc->sCmn.speech_activity_Q8 );
+        thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15,  13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) );
+        thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1,   14 ), psEnc->sCmn.input_tilt_Q15 );
+        thrhld_Q13 = silk_SAT16(  thrhld_Q13 );
+
+        /*****************************************/
+        /* Call pitch estimator                  */
+        /*****************************************/
+        if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex,
+                &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16,
+                (opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr,
+                psEnc->sCmn.arch) == 0 )
+        {
+            psEnc->sCmn.indices.signalType = TYPE_VOICED;
+        } else {
+            psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+        }
+    } else {
+        silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) );
+        psEnc->sCmn.indices.lagIndex = 0;
+        psEnc->sCmn.indices.contourIndex = 0;
+        psEnc->LTPCorr_Q15 = 0;
+    }
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/fixed/find_pred_coefs_FIX.c b/third_party/opus/src/silk/fixed/find_pred_coefs_FIX.c
new file mode 100644
index 0000000..d308e9cf
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/find_pred_coefs_FIX.c
@@ -0,0 +1,148 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+
+void silk_find_pred_coefs_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  encoder state                                                               */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  encoder control                                                             */
+    const opus_int16                res_pitch[],                            /* I    Residual from pitch analysis                                                */
+    const opus_int16                x[],                                    /* I    Speech signal                                                               */
+    opus_int                        condCoding                              /* I    The type of conditional coding to use                                       */
+)
+{
+    opus_int         i;
+    opus_int32       invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ], Wght_Q15[ MAX_NB_SUBFR ];
+    opus_int16       NLSF_Q15[ MAX_LPC_ORDER ];
+    const opus_int16 *x_ptr;
+    opus_int16       *x_pre_ptr;
+    VARDECL( opus_int16, LPC_in_pre );
+    opus_int32       tmp, min_gain_Q16, minInvGain_Q30;
+    opus_int         LTP_corrs_rshift[ MAX_NB_SUBFR ];
+    SAVE_STACK;
+
+    /* weighting for weighted least squares */
+    min_gain_Q16 = silk_int32_MAX >> 6;
+    for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+        min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] );
+    }
+    for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+        /* Divide to Q16 */
+        silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 );
+        /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */
+        invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 );
+
+        /* Ensure Wght_Q15 a minimum value 1 */
+        invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 363 );
+
+        /* Square the inverted gains */
+        silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) );
+        tmp = silk_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] );
+        Wght_Q15[ i ] = silk_RSHIFT( tmp, 1 );
+
+        /* Invert the inverted and normalized gains */
+        local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] );
+    }
+
+    ALLOC( LPC_in_pre,
+           psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder
+               + psEnc->sCmn.frame_length, opus_int16 );
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        VARDECL( opus_int32, WLTP );
+
+        /**********/
+        /* VOICED */
+        /**********/
+        silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 );
+
+        ALLOC( WLTP, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 );
+
+        /* LTP analysis */
+        silk_find_LTP_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7,
+            res_pitch, psEncCtrl->pitchL, Wght_Q15, psEnc->sCmn.subfr_length,
+            psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length, LTP_corrs_rshift, psEnc->sCmn.arch );
+
+        /* Quantize LTP gain parameters */
+        silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex,
+            &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr,
+            psEnc->sCmn.arch);
+
+        /* Control LTP scaling */
+        silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding );
+
+        /* Create LTP residual */
+        silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14,
+            psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+    } else {
+        /************/
+        /* UNVOICED */
+        /************/
+        /* Create signal with prepended subframes, scaled by inverse gains */
+        x_ptr     = x - psEnc->sCmn.predictLPCOrder;
+        x_pre_ptr = LPC_in_pre;
+        for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+            silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ],
+                psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder );
+            x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder;
+            x_ptr     += psEnc->sCmn.subfr_length;
+        }
+
+        silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) );
+        psEncCtrl->LTPredCodGain_Q7 = 0;
+        psEnc->sCmn.sum_log_gain_Q7 = 0;
+    }
+
+    /* Limit on total predictive coding gain */
+    if( psEnc->sCmn.first_frame_after_reset ) {
+        minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 );
+    } else {
+        minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) );      /* Q16 */
+        minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30,
+            silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ),
+                silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 );
+    }
+
+    /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
+    silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 );
+
+    /* Quantize LSFs */
+    silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 );
+
+    /* Calculate residual energy using quantized LPC coefficients */
+    silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains,
+        psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.arch );
+
+    /* Copy to prediction struct for use in next frame for interpolation */
+    silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/fixed/k2a_FIX.c b/third_party/opus/src/silk/fixed/k2a_FIX.c
new file mode 100644
index 0000000..5fee599b
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/k2a_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a(
+    opus_int32                  *A_Q24,             /* O    Prediction coefficients [order] Q24                         */
+    const opus_int16            *rc_Q15,            /* I    Reflection coefficients [order] Q15                         */
+    const opus_int32            order               /* I    Prediction order                                            */
+)
+{
+    opus_int   k, n;
+    opus_int32 Atmp[ SILK_MAX_ORDER_LPC ];
+
+    for( k = 0; k < order; k++ ) {
+        for( n = 0; n < k; n++ ) {
+            Atmp[ n ] = A_Q24[ n ];
+        }
+        for( n = 0; n < k; n++ ) {
+            A_Q24[ n ] = silk_SMLAWB( A_Q24[ n ], silk_LSHIFT( Atmp[ k - n - 1 ], 1 ), rc_Q15[ k ] );
+        }
+        A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 );
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/k2a_Q16_FIX.c b/third_party/opus/src/silk/fixed/k2a_Q16_FIX.c
new file mode 100644
index 0000000..3b03987
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/k2a_Q16_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_Q16(
+    opus_int32                  *A_Q24,             /* O    Prediction coefficients [order] Q24                         */
+    const opus_int32            *rc_Q16,            /* I    Reflection coefficients [order] Q16                         */
+    const opus_int32            order               /* I    Prediction order                                            */
+)
+{
+    opus_int   k, n;
+    opus_int32 Atmp[ SILK_MAX_ORDER_LPC ];
+
+    for( k = 0; k < order; k++ ) {
+        for( n = 0; n < k; n++ ) {
+            Atmp[ n ] = A_Q24[ n ];
+        }
+        for( n = 0; n < k; n++ ) {
+            A_Q24[ n ] = silk_SMLAWW( A_Q24[ n ], Atmp[ k - n - 1 ], rc_Q16[ k ] );
+        }
+        A_Q24[ k ] = -silk_LSHIFT( rc_Q16[ k ], 8 );
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/main_FIX.h b/third_party/opus/src/silk/fixed/main_FIX.h
new file mode 100644
index 0000000..375b5eb
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/main_FIX.h
@@ -0,0 +1,272 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MAIN_FIX_H
+#define SILK_MAIN_FIX_H
+
+#include "SigProc_FIX.h"
+#include "structs_FIX.h"
+#include "control.h"
+#include "main.h"
+#include "PLC.h"
+#include "debug.h"
+#include "entenc.h"
+
+#ifndef FORCE_CPP_BUILD
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#endif
+
+#define silk_encoder_state_Fxx      silk_encoder_state_FIX
+#define silk_encode_do_VAD_Fxx      silk_encode_do_VAD_FIX
+#define silk_encode_frame_Fxx       silk_encode_frame_FIX
+
+/*********************/
+/* Encoder Functions */
+/*********************/
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+    silk_encoder_state_Fxx          state_Fxx[]                             /* I/O  Encoder states                                                              */
+);
+
+/* Encoder main function */
+void silk_encode_do_VAD_FIX(
+    silk_encoder_state_FIX          *psEnc                                  /* I/O  Pointer to Silk FIX encoder state                                           */
+);
+
+/* Encoder main function */
+opus_int silk_encode_frame_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Pointer to Silk FIX encoder state                                           */
+    opus_int32                      *pnBytesOut,                            /* O    Pointer to number of payload bytes;                                         */
+    ec_enc                          *psRangeEnc,                            /* I/O  compressor data structure                                                   */
+    opus_int                        condCoding,                             /* I    The type of conditional coding to use                                       */
+    opus_int                        maxBits,                                /* I    If > 0: maximum number of output bits                                       */
+    opus_int                        useCBR                                  /* I    Flag to force constant-bitrate operation                                    */
+);
+
+/* Initializes the Silk encoder state */
+opus_int silk_init_encoder(
+    silk_encoder_state_Fxx          *psEnc,                                 /* I/O  Pointer to Silk FIX encoder state                                           */
+    int                              arch                                   /* I    Run-time architecture                                                       */
+);
+
+/* Control the Silk encoder */
+opus_int silk_control_encoder(
+    silk_encoder_state_Fxx          *psEnc,                                 /* I/O  Pointer to Silk encoder state                                               */
+    silk_EncControlStruct           *encControl,                            /* I    Control structure                                                           */
+    const opus_int32                TargetRate_bps,                         /* I    Target max bitrate (bps)                                                    */
+    const opus_int                  allow_bw_switch,                        /* I    Flag to allow switching audio bandwidth                                     */
+    const opus_int                  channelNb,                              /* I    Channel number                                                              */
+    const opus_int                  force_fs_kHz
+);
+
+/****************/
+/* Prefiltering */
+/****************/
+void silk_prefilter_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Encoder state                                                               */
+    const silk_encoder_control_FIX  *psEncCtrl,                             /* I    Encoder control                                                             */
+    opus_int32                      xw_Q10[],                               /* O    Weighted signal                                                             */
+    const opus_int16                x[]                                     /* I    Speech signal                                                               */
+);
+
+void silk_warped_LPC_analysis_filter_FIX_c(
+          opus_int32            state[],                    /* I/O  State [order + 1]                   */
+          opus_int32            res_Q2[],                   /* O    Residual signal [length]            */
+    const opus_int16            coef_Q13[],                 /* I    Coefficients [order]                */
+    const opus_int16            input[],                    /* I    Input signal [length]               */
+    const opus_int16            lambda_Q16,                 /* I    Warping factor                      */
+    const opus_int              length,                     /* I    Length of input signal              */
+    const opus_int              order                       /* I    Filter order (even)                 */
+);
+
+
+/**************************/
+/* Noise shaping analysis */
+/**************************/
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Encoder state FIX                                                           */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  Encoder control FIX                                                         */
+    const opus_int16                *pitch_res,                             /* I    LPC residual from pitch analysis                                            */
+    const opus_int16                *x,                                     /* I    Input signal [ frame_length + la_shape ]                                    */
+    int                              arch                                   /* I    Run-time architecture                                                       */
+);
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FIX(
+          opus_int32                *corr,                                  /* O    Result [order + 1]                                                          */
+          opus_int                  *scale,                                 /* O    Scaling of the correlation vector                                           */
+    const opus_int16                *input,                                 /* I    Input data to correlate                                                     */
+    const opus_int                  warping_Q16,                            /* I    Warping coefficient                                                         */
+    const opus_int                  length,                                 /* I    Length of input                                                             */
+    const opus_int                  order                                   /* I    Correlation order (even)                                                    */
+);
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  encoder state                                                               */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  encoder control                                                             */
+    opus_int                        condCoding                              /* I    The type of conditional coding to use                                       */
+);
+
+/**********************************************/
+/* Prediction Analysis                        */
+/**********************************************/
+/* Find pitch lags */
+void silk_find_pitch_lags_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  encoder state                                                               */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  encoder control                                                             */
+    opus_int16                      res[],                                  /* O    residual                                                                    */
+    const opus_int16                x[],                                    /* I    Speech signal                                                               */
+    int                             arch                                    /* I    Run-time architecture                                                       */
+);
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  encoder state                                                               */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  encoder control                                                             */
+    const opus_int16                res_pitch[],                            /* I    Residual from pitch analysis                                                */
+    const opus_int16                x[],                                    /* I    Speech signal                                                               */
+    opus_int                        condCoding                              /* I    The type of conditional coding to use                                       */
+);
+
+/* LPC analysis */
+void silk_find_LPC_FIX(
+    silk_encoder_state              *psEncC,                                /* I/O  Encoder state                                                               */
+    opus_int16                      NLSF_Q15[],                             /* O    NLSFs                                                                       */
+    const opus_int16                x[],                                    /* I    Input signal                                                                */
+    const opus_int32                minInvGain_Q30                          /* I    Inverse of max prediction gain                                              */
+);
+
+/* LTP analysis */
+void silk_find_LTP_FIX(
+    opus_int16                      b_Q14[ MAX_NB_SUBFR * LTP_ORDER ],      /* O    LTP coefs                                                                   */
+    opus_int32                      WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O    Weight for LTP quantization                                           */
+    opus_int                        *LTPredCodGain_Q7,                      /* O    LTP coding gain                                                             */
+    const opus_int16                r_lpc[],                                /* I    residual signal after LPC signal + state for first 10 ms                    */
+    const opus_int                  lag[ MAX_NB_SUBFR ],                    /* I    LTP lags                                                                    */
+    const opus_int32                Wght_Q15[ MAX_NB_SUBFR ],               /* I    weights                                                                     */
+    const opus_int                  subfr_length,                           /* I    subframe length                                                             */
+    const opus_int                  nb_subfr,                               /* I    number of subframes                                                         */
+    const opus_int                  mem_offset,                             /* I    number of samples in LTP memory                                             */
+    opus_int                        corr_rshifts[ MAX_NB_SUBFR ],           /* O    right shifts applied to correlations                                        */
+    int                             arch                                    /* I    Run-time architecture                                                       */
+);
+
+void silk_LTP_analysis_filter_FIX(
+    opus_int16                      *LTP_res,                               /* O    LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length )  */
+    const opus_int16                *x,                                     /* I    Pointer to input signal with at least max( pitchL ) preceding samples       */
+    const opus_int16                LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I    LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe                   */
+    const opus_int                  pitchL[ MAX_NB_SUBFR ],                 /* I    Pitch lag, one for each subframe                                            */
+    const opus_int32                invGains_Q16[ MAX_NB_SUBFR ],           /* I    Inverse quantization gains, one for each subframe                           */
+    const opus_int                  subfr_length,                           /* I    Length of each subframe                                                     */
+    const opus_int                  nb_subfr,                               /* I    Number of subframes                                                         */
+    const opus_int                  pre_length                              /* I    Length of the preceding samples starting at &x[0] for each subframe         */
+);
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order   */
+/* of preceding samples                                                                 */
+void silk_residual_energy_FIX(
+          opus_int32                nrgs[ MAX_NB_SUBFR ],                   /* O    Residual energy per subframe                                                */
+          opus_int                  nrgsQ[ MAX_NB_SUBFR ],                  /* O    Q value per subframe                                                        */
+    const opus_int16                x[],                                    /* I    Input signal                                                                */
+          opus_int16                a_Q12[ 2 ][ MAX_LPC_ORDER ],            /* I    AR coefs for each frame half                                                */
+    const opus_int32                gains[ MAX_NB_SUBFR ],                  /* I    Quantization gains                                                          */
+    const opus_int                  subfr_length,                           /* I    Subframe length                                                             */
+    const opus_int                  nb_subfr,                               /* I    Number of subframes                                                         */
+    const opus_int                  LPC_order,                              /* I    LPC order                                                                   */
+    int                             arch                                    /* I    Run-time architecture                                                       */
+);
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+opus_int32 silk_residual_energy16_covar_FIX(
+    const opus_int16                *c,                                     /* I    Prediction vector                                                           */
+    const opus_int32                *wXX,                                   /* I    Correlation matrix                                                          */
+    const opus_int32                *wXx,                                   /* I    Correlation vector                                                          */
+    opus_int32                      wxx,                                    /* I    Signal energy                                                               */
+    opus_int                        D,                                      /* I    Dimension                                                                   */
+    opus_int                        cQ                                      /* I    Q value for c vector 0 - 15                                                 */
+);
+
+/* Processing of gains */
+void silk_process_gains_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Encoder state                                                               */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  Encoder control                                                             */
+    opus_int                        condCoding                              /* I    The type of conditional coding to use                                       */
+);
+
+/******************/
+/* Linear Algebra */
+/******************/
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FIX(
+    const opus_int16                *x,                                     /* I    x vector [L + order - 1] used to form data matrix X                         */
+    const opus_int                  L,                                      /* I    Length of vectors                                                           */
+    const opus_int                  order,                                  /* I    Max lag for correlation                                                     */
+    const opus_int                  head_room,                              /* I    Desired headroom                                                            */
+    opus_int32                      *XX,                                    /* O    Pointer to X'*X correlation matrix [ order x order ]                        */
+    opus_int                        *rshifts,                               /* I/O  Right shifts of correlations                                                */
+    int                              arch                                   /* I    Run-time architecture                                                       */
+);
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FIX(
+    const opus_int16                *x,                                     /* I    x vector [L + order - 1] used to form data matrix X                         */
+    const opus_int16                *t,                                     /* I    Target vector [L]                                                           */
+    const opus_int                  L,                                      /* I    Length of vectors                                                           */
+    const opus_int                  order,                                  /* I    Max lag for correlation                                                     */
+    opus_int32                      *Xt,                                    /* O    Pointer to X'*t correlation vector [order]                                  */
+    const opus_int                  rshifts,                                /* I    Right shifts of correlations                                                */
+    int                             arch                                    /* I    Run-time architecture                                                       */
+);
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FIX(
+    opus_int32                      *XX,                                    /* I/O  Correlation matrices                                                        */
+    opus_int32                      *xx,                                    /* I/O  Correlation values                                                          */
+    opus_int32                      noise,                                  /* I    Noise to add                                                                */
+    opus_int                        D                                       /* I    Dimension of XX                                                             */
+);
+
+/* Solves Ax = b, assuming A is symmetric */
+void silk_solve_LDL_FIX(
+    opus_int32                      *A,                                     /* I    Pointer to symetric square matrix A                                         */
+    opus_int                        M,                                      /* I    Size of matrix                                                              */
+    const opus_int32                *b,                                     /* I    Pointer to b vector                                                         */
+    opus_int32                      *x_Q16                                  /* O    Pointer to x solution vector                                                */
+);
+
+#ifndef FORCE_CPP_BUILD
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* FORCE_CPP_BUILD */
+#endif /* SILK_MAIN_FIX_H */
diff --git a/third_party/opus/src/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h b/third_party/opus/src/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h
new file mode 100644
index 0000000..c30481e
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h
@@ -0,0 +1,336 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+
+/**************************************************************/
+/* Compute noise shaping coefficients and initial gain values */
+/**************************************************************/
+#define OVERRIDE_silk_noise_shape_analysis_FIX
+
+void silk_noise_shape_analysis_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Encoder state FIX                                                           */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  Encoder control FIX                                                         */
+    const opus_int16                *pitch_res,                             /* I    LPC residual from pitch analysis                                            */
+    const opus_int16                *x,                                     /* I    Input signal [ frame_length + la_shape ]                                    */
+    int                              arch                                   /* I    Run-time architecture                                                       */
+)
+{
+    silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+    opus_int     k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0;
+    opus_int32   SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32;
+    opus_int32   nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
+    opus_int32   delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
+    opus_int32   auto_corr[     MAX_SHAPE_LPC_ORDER + 1 ];
+    opus_int32   refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ];
+    opus_int32   AR1_Q24[       MAX_SHAPE_LPC_ORDER ];
+    opus_int32   AR2_Q24[       MAX_SHAPE_LPC_ORDER ];
+    VARDECL( opus_int16, x_windowed );
+    const opus_int16 *x_ptr, *pitch_res_ptr;
+    SAVE_STACK;
+
+    /* Point to start of first LPC analysis block */
+    x_ptr = x - psEnc->sCmn.la_shape;
+
+    /****************/
+    /* GAIN CONTROL */
+    /****************/
+    SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7;
+
+    /* Input quality is the average of the quality in the lowest two VAD bands */
+    psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ]
+        + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 );
+
+    /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
+    psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 -
+        SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 );
+
+    /* Reduce coding SNR during low speech activity */
+    if( psEnc->sCmn.useCBR == 0 ) {
+        b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8;
+        b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 );
+        SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+            silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ),                                       /* Q11*/
+            silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) );     /* Q12*/
+    }
+
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Reduce gains for periodic signals */
+        SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 );
+    } else {
+        /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
+        SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+            silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ),
+            SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 );
+    }
+
+    /*************************/
+    /* SPARSENESS PROCESSING */
+    /*************************/
+    /* Set quantizer offset */
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Initially set to 0; may be overruled in process_gains(..) */
+        psEnc->sCmn.indices.quantOffsetType = 0;
+        psEncCtrl->sparseness_Q8 = 0;
+    } else {
+        /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
+        nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 );
+        energy_variation_Q7 = 0;
+        log_energy_prev_Q7  = 0;
+        pitch_res_ptr = pitch_res;
+        for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) {
+            silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples );
+            nrg += silk_RSHIFT( nSamples, scale );           /* Q(-scale)*/
+
+            log_energy_Q7 = silk_lin2log( nrg );
+            if( k > 0 ) {
+                energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 );
+            }
+            log_energy_prev_Q7 = log_energy_Q7;
+            pitch_res_ptr += nSamples;
+        }
+
+        psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 -
+            SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 );
+
+        /* Set quantization offset depending on sparseness measure */
+        if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) {
+            psEnc->sCmn.indices.quantOffsetType = 0;
+        } else {
+            psEnc->sCmn.indices.quantOffsetType = 1;
+        }
+
+        /* Increase coding SNR for sparse signals */
+        SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) );
+    }
+
+    /*******************************/
+    /* Control bandwidth expansion */
+    /*******************************/
+    /* More BWE for signals with high prediction gain */
+    strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) );
+    BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ),
+        silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 );
+    delta_Q16  = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ),
+        SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) );
+    BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 );
+    BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 );
+    /* BWExp1 will be applied after BWExp2, so make it relative */
+    BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) );
+
+    if( psEnc->sCmn.warping_Q16 > 0 ) {
+        /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
+        warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) );
+    } else {
+        warping_Q16 = 0;
+    }
+
+    /********************************************/
+    /* Compute noise shaping AR coefs and gains */
+    /********************************************/
+    ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 );
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        /* Apply window: sine slope followed by flat part followed by cosine slope */
+        opus_int shift, slope_part, flat_part;
+        flat_part = psEnc->sCmn.fs_kHz * 3;
+        slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 );
+
+        silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part );
+        shift = slope_part;
+        silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) );
+        shift += flat_part;
+        silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part );
+
+        /* Update pointer: next LPC analysis block */
+        x_ptr += psEnc->sCmn.subfr_length;
+
+        if( psEnc->sCmn.warping_Q16 > 0 ) {
+            /* Calculate warped auto correlation */
+            silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder );
+        } else {
+            /* Calculate regular auto correlation */
+            silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch );
+        }
+
+        /* Add white noise, as a fraction of energy */
+        auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ),
+            SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) );
+
+        /* Calculate the reflection coefficients using schur */
+        nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder );
+        silk_assert( nrg >= 0 );
+
+        /* Convert reflection coefficients to prediction coefficients */
+        silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder );
+
+        Qnrg = -scale;          /* range: -12...30*/
+        silk_assert( Qnrg >= -12 );
+        silk_assert( Qnrg <=  30 );
+
+        /* Make sure that Qnrg is an even number */
+        if( Qnrg & 1 ) {
+            Qnrg -= 1;
+            nrg >>= 1;
+        }
+
+        tmp32 = silk_SQRT_APPROX( nrg );
+        Qnrg >>= 1;             /* range: -6...15*/
+
+        psEncCtrl->Gains_Q16[ k ] = (silk_LSHIFT32( silk_LIMIT( (tmp32), silk_RSHIFT32( silk_int32_MIN, (16 - Qnrg) ), \
+                            silk_RSHIFT32( silk_int32_MAX, (16 - Qnrg) ) ), (16 - Qnrg) ));
+
+        if( psEnc->sCmn.warping_Q16 > 0 ) {
+            /* Adjust gain for warping */
+            gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder );
+            silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+            if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) {
+               psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX;
+            } else {
+               psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+            }
+        }
+
+        /* Bandwidth expansion for synthesis filter shaping */
+        silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 );
+
+        /* Compute noise shaping filter coefficients */
+        silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) );
+
+        /* Bandwidth expansion for analysis filter shaping */
+        silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) );
+        silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 );
+
+        /* Ratio of prediction gains, in energy domain */
+        pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder );
+        nrg         = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder );
+
+        /*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/
+        pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 );
+        psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 );
+
+        /* Convert to monic warped prediction coefficients and limit absolute values */
+        limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder );
+
+        /* Convert from Q24 to Q13 and store in int16 */
+        for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) {
+            psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) );
+            psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) );
+        }
+    }
+
+    /*****************/
+    /* Gain tweaking */
+    /*****************/
+    /* Increase gains during low speech activity and put lower limit on gains */
+    gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) );
+    gain_add_Q16  = silk_log2lin(  silk_SMLAWB(  SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) );
+    silk_assert( gain_mult_Q16 > 0 );
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+        silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+        psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
+    }
+
+    gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ),
+        psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 );
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] );
+    }
+
+    /************************************************/
+    /* Control low-frequency shaping and noise tilt */
+    /************************************************/
+    /* Less low frequency shaping for noisy inputs */
+    strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ),
+        SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) );
+    strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 );
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
+        /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
+        opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz );
+        for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+            b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] );
+            /* Pack two coefficients in one int32 */
+            psEncCtrl->LF_shp_Q14[ k ]  = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 );
+            psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+        }
+        silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/
+        Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) -
+            silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ),
+                silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) );
+    } else {
+        b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/
+        /* Pack two coefficients in one int32 */
+        psEncCtrl->LF_shp_Q14[ 0 ]  = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 -
+            silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 );
+        psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+        for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
+            psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ];
+        }
+        Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 );
+    }
+
+    /****************************/
+    /* HARMONIC SHAPING CONTROL */
+    /****************************/
+    /* Control boosting of harmonic frequencies */
+    HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ),
+        psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) );
+
+    /* More harmonic boost for noisy input signals */
+    HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16,
+        SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) );
+
+    if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* More harmonic noise shaping for high bitrates or noisy input */
+        HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ),
+                SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ),
+                psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) );
+
+        /* Less harmonic noise shaping for less periodic signals */
+        HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ),
+            silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) );
+    } else {
+        HarmShapeGain_Q16 = 0;
+    }
+
+    /*************************/
+    /* Smooth over subframes */
+    /*************************/
+    for( k = 0; k < MAX_NB_SUBFR; k++ ) {
+        psShapeSt->HarmBoost_smth_Q16 =
+            silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16,     HarmBoost_Q16     - psShapeSt->HarmBoost_smth_Q16,     SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+        psShapeSt->HarmShapeGain_smth_Q16 =
+            silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+        psShapeSt->Tilt_smth_Q16 =
+            silk_SMLAWB( psShapeSt->Tilt_smth_Q16,          Tilt_Q16          - psShapeSt->Tilt_smth_Q16,          SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+
+        psEncCtrl->HarmBoost_Q14[ k ]     = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16,     2 );
+        psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 );
+        psEncCtrl->Tilt_Q14[ k ]          = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16,          2 );
+    }
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/fixed/mips/prefilter_FIX_mipsr1.h b/third_party/opus/src/silk/fixed/mips/prefilter_FIX_mipsr1.h
new file mode 100644
index 0000000..21b25688
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/mips/prefilter_FIX_mipsr1.h
@@ -0,0 +1,184 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+#ifndef __PREFILTER_FIX_MIPSR1_H__
+#define __PREFILTER_FIX_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+#define OVERRIDE_silk_warped_LPC_analysis_filter_FIX
+void silk_warped_LPC_analysis_filter_FIX(
+          opus_int32            state[],                    /* I/O  State [order + 1]                   */
+          opus_int32            res_Q2[],                   /* O    Residual signal [length]            */
+    const opus_int16            coef_Q13[],                 /* I    Coefficients [order]                */
+    const opus_int16            input[],                    /* I    Input signal [length]               */
+    const opus_int16            lambda_Q16,                 /* I    Warping factor                      */
+    const opus_int              length,                     /* I    Length of input signal              */
+    const opus_int              order,                      /* I    Filter order (even)                 */
+               int              arch
+)
+{
+    opus_int     n, i;
+    opus_int32   acc_Q11, acc_Q22, tmp1, tmp2, tmp3, tmp4;
+    opus_int32   state_cur, state_next;
+
+    (void)arch;
+
+    /* Order must be even */
+    /* Length must be even */
+
+    silk_assert( ( order & 1 ) == 0 );
+    silk_assert( ( length & 1 ) == 0 );
+
+    for( n = 0; n < length; n+=2 ) {
+        /* Output of lowpass section */
+        tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 );
+        state_cur = silk_LSHIFT( input[ n ], 14 );
+        /* Output of allpass section */
+        tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 );
+        state_next = tmp2;
+        acc_Q11 = silk_RSHIFT( order, 1 );
+        acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] );
+
+
+        /* Output of lowpass section */
+        tmp4 = silk_SMLAWB( state_cur, state_next, lambda_Q16 );
+        state[ 0 ] = silk_LSHIFT( input[ n+1 ], 14 );
+        /* Output of allpass section */
+        tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 );
+        state[ 1 ] = tmp4;
+        acc_Q22 = silk_RSHIFT( order, 1 );
+        acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ 0 ] );
+
+        /* Loop over allpass sections */
+        for( i = 2; i < order; i += 2 ) {
+            /* Output of allpass section */
+            tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 );
+            state_cur = tmp1;
+            acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] );
+            /* Output of allpass section */
+            tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 );
+            state_next = tmp2;
+            acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] );
+
+
+            /* Output of allpass section */
+            tmp4 = silk_SMLAWB( state_cur, state_next - tmp3, lambda_Q16 );
+            state[ i ] = tmp3;
+            acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ i - 1 ] );
+            /* Output of allpass section */
+            tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 );
+            state[ i + 1 ] = tmp4;
+            acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ i ] );
+        }
+        acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] );
+        res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 );
+
+        state[ order ] = tmp3;
+        acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ order - 1 ] );
+        res_Q2[ n+1 ] = silk_LSHIFT( (opus_int32)input[ n+1 ], 2 ) - silk_RSHIFT_ROUND( acc_Q22, 9 );
+    }
+}
+
+
+
+/* Prefilter for finding Quantizer input signal */
+#define OVERRIDE_silk_prefilt_FIX
+static inline void silk_prefilt_FIX(
+    silk_prefilter_state_FIX    *P,                         /* I/O  state                               */
+    opus_int32                  st_res_Q12[],               /* I    short term residual signal          */
+    opus_int32                  xw_Q3[],                    /* O    prefiltered signal                  */
+    opus_int32                  HarmShapeFIRPacked_Q12,     /* I    Harmonic shaping coeficients        */
+    opus_int                    Tilt_Q14,                   /* I    Tilt shaping coeficient             */
+    opus_int32                  LF_shp_Q14,                 /* I    Low-frequancy shaping coeficients   */
+    opus_int                    lag,                        /* I    Lag for harmonic shaping            */
+    opus_int                    length                      /* I    Length of signals                   */
+)
+{
+    opus_int   i, idx, LTP_shp_buf_idx;
+    opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10;
+    opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12;
+    opus_int16 *LTP_shp_buf;
+
+    /* To speed up use temp variables instead of using the struct */
+    LTP_shp_buf     = P->sLTP_shp;
+    LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
+    sLF_AR_shp_Q12  = P->sLF_AR_shp_Q12;
+    sLF_MA_shp_Q12  = P->sLF_MA_shp_Q12;
+
+    if( lag > 0 ) {
+        for( i = 0; i < length; i++ ) {
+            /* unrolled loop */
+            silk_assert( HARM_SHAPE_FIR_TAPS == 3 );
+            idx = lag + LTP_shp_buf_idx;
+            n_LTP_Q12 = silk_SMULBB(            LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+            n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2    ) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+            n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+
+            n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 );
+            n_LF_Q10   = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 );
+
+            sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) );
+            sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12,  silk_LSHIFT( n_LF_Q10,   2 ) );
+
+            LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
+            LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) );
+
+            xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 );
+        }
+    }
+    else
+    {
+        for( i = 0; i < length; i++ ) {
+
+            n_LTP_Q12 = 0;
+
+            n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 );
+            n_LF_Q10   = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 );
+
+            sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) );
+            sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12,  silk_LSHIFT( n_LF_Q10,   2 ) );
+
+            LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
+            LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) );
+
+            xw_Q3[i] = silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 9 );
+        }
+    }
+
+    /* Copy temp variable back to state */
+    P->sLF_AR_shp_Q12   = sLF_AR_shp_Q12;
+    P->sLF_MA_shp_Q12   = sLF_MA_shp_Q12;
+    P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
+}
+
+#endif /* __PREFILTER_FIX_MIPSR1_H__ */
diff --git a/third_party/opus/src/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h b/third_party/opus/src/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h
new file mode 100644
index 0000000..e803ef0f
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h
@@ -0,0 +1,165 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__
+#define __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+#undef QC
+#define QC  10
+
+#undef QS
+#define QS  14
+
+/* Autocorrelations for a warped frequency axis */
+#define OVERRIDE_silk_warped_autocorrelation_FIX
+void silk_warped_autocorrelation_FIX(
+          opus_int32                *corr,                                  /* O    Result [order + 1]                                                          */
+          opus_int                  *scale,                                 /* O    Scaling of the correlation vector                                           */
+    const opus_int16                *input,                                 /* I    Input data to correlate                                                     */
+    const opus_int                  warping_Q16,                            /* I    Warping coefficient                                                         */
+    const opus_int                  length,                                 /* I    Length of input                                                             */
+    const opus_int                  order                                   /* I    Correlation order (even)                                                    */
+)
+{
+    opus_int   n, i, lsh;
+    opus_int32 tmp1_QS=0, tmp2_QS=0, tmp3_QS=0, tmp4_QS=0, tmp5_QS=0, tmp6_QS=0, tmp7_QS=0, tmp8_QS=0, start_1=0, start_2=0, start_3=0;
+    opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+    opus_int64 corr_QC[  MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+    opus_int64 temp64;
+
+    opus_int32 val;
+    val = 2 * QS - QC;
+
+    /* Order must be even */
+    silk_assert( ( order & 1 ) == 0 );
+    silk_assert( 2 * QS - QC >= 0 );
+
+    /* Loop over samples */
+    for( n = 0; n < length; n=n+4 ) {
+
+        tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
+        start_1 = tmp1_QS;
+        tmp3_QS = silk_LSHIFT32( (opus_int32)input[ n+1], QS );
+        start_2 = tmp3_QS;
+        tmp5_QS = silk_LSHIFT32( (opus_int32)input[ n+2], QS );
+        start_3 = tmp5_QS;
+        tmp7_QS = silk_LSHIFT32( (opus_int32)input[ n+3], QS );
+
+        /* Loop over allpass sections */
+        for( i = 0; i < order; i += 2 ) {
+            /* Output of allpass section */
+            tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
+            corr_QC[  i ] = __builtin_mips_madd( corr_QC[  i ], tmp1_QS,  start_1);
+
+            tmp4_QS = silk_SMLAWB( tmp1_QS, tmp2_QS - tmp3_QS, warping_Q16 );
+            corr_QC[  i ] = __builtin_mips_madd( corr_QC[  i ], tmp3_QS,  start_2);
+
+            tmp6_QS = silk_SMLAWB( tmp3_QS, tmp4_QS - tmp5_QS, warping_Q16 );
+            corr_QC[  i ] = __builtin_mips_madd( corr_QC[  i ], tmp5_QS,  start_3);
+
+            tmp8_QS = silk_SMLAWB( tmp5_QS, tmp6_QS - tmp7_QS, warping_Q16 );
+            state_QS[ i ]  = tmp7_QS;
+            corr_QC[  i ] = __builtin_mips_madd( corr_QC[  i ], tmp7_QS, state_QS[0]);
+
+            /* Output of allpass section */
+            tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
+            corr_QC[  i+1 ] = __builtin_mips_madd( corr_QC[  i+1 ], tmp2_QS,  start_1);
+
+            tmp3_QS = silk_SMLAWB( tmp2_QS, tmp1_QS - tmp4_QS, warping_Q16 );
+            corr_QC[  i+1 ] = __builtin_mips_madd( corr_QC[  i+1 ], tmp4_QS,  start_2);
+
+            tmp5_QS = silk_SMLAWB( tmp4_QS, tmp3_QS - tmp6_QS, warping_Q16 );
+            corr_QC[  i+1 ] = __builtin_mips_madd( corr_QC[  i+1 ], tmp6_QS,  start_3);
+
+            tmp7_QS = silk_SMLAWB( tmp6_QS, tmp5_QS - tmp8_QS, warping_Q16 );
+            state_QS[ i + 1 ]  = tmp8_QS;
+            corr_QC[  i+1 ] = __builtin_mips_madd( corr_QC[  i+1 ], tmp8_QS,  state_QS[ 0 ]);
+
+        }
+        state_QS[ order ] = tmp7_QS;
+
+        corr_QC[  order ] = __builtin_mips_madd( corr_QC[  order ], tmp1_QS,  start_1);
+        corr_QC[  order ] = __builtin_mips_madd( corr_QC[  order ], tmp3_QS,  start_2);
+        corr_QC[  order ] = __builtin_mips_madd( corr_QC[  order ], tmp5_QS,  start_3);
+        corr_QC[  order ] = __builtin_mips_madd( corr_QC[  order ], tmp7_QS,  state_QS[ 0 ]);
+    }
+
+    for(;n< length; n++ ) {
+
+        tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
+
+        /* Loop over allpass sections */
+        for( i = 0; i < order; i += 2 ) {
+
+            /* Output of allpass section */
+            tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
+            state_QS[ i ] = tmp1_QS;
+            corr_QC[  i ] = __builtin_mips_madd( corr_QC[  i ], tmp1_QS,   state_QS[ 0 ]);
+
+            /* Output of allpass section */
+            tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
+            state_QS[ i + 1 ]  = tmp2_QS;
+            corr_QC[  i+1 ] = __builtin_mips_madd( corr_QC[  i+1 ], tmp2_QS,   state_QS[ 0 ]);
+        }
+        state_QS[ order ] = tmp1_QS;
+        corr_QC[  order ] = __builtin_mips_madd( corr_QC[  order ], tmp1_QS,   state_QS[ 0 ]);
+    }
+
+    temp64 =  corr_QC[ 0 ];
+    temp64 = __builtin_mips_shilo(temp64, val);
+
+    lsh = silk_CLZ64( temp64 ) - 35;
+    lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
+    *scale = -( QC + lsh );
+    silk_assert( *scale >= -30 && *scale <= 12 );
+    if( lsh >= 0 ) {
+        for( i = 0; i < order + 1; i++ ) {
+            temp64 = corr_QC[ i ];
+            //temp64 = __builtin_mips_shilo(temp64, val);
+            temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val);
+            corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) );
+        }
+    } else {
+        for( i = 0; i < order + 1; i++ ) {
+            temp64 = corr_QC[ i ];
+            //temp64 = __builtin_mips_shilo(temp64, val);
+            temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val);
+            corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) );
+        }
+    }
+
+     corr_QC[ 0 ] = __builtin_mips_shilo(corr_QC[ 0 ], val);
+
+     silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
+}
+#endif /* __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ */
diff --git a/third_party/opus/src/silk/fixed/noise_shape_analysis_FIX.c b/third_party/opus/src/silk/fixed/noise_shape_analysis_FIX.c
new file mode 100644
index 0000000..22a89f75ae
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/noise_shape_analysis_FIX.c
@@ -0,0 +1,451 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a   */
+/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
+/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
+/* coefficient in an array of coefficients, for monic filters.                                    */
+static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/
+    const opus_int32     *coefs_Q24,
+    opus_int             lambda_Q16,
+    opus_int             order
+) {
+    opus_int   i;
+    opus_int32 gain_Q24;
+
+    lambda_Q16 = -lambda_Q16;
+    gain_Q24 = coefs_Q24[ order - 1 ];
+    for( i = order - 2; i >= 0; i-- ) {
+        gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 );
+    }
+    gain_Q24  = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 );
+    return silk_INVERSE32_varQ( gain_Q24, 40 );
+}
+
+/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum     */
+/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
+static OPUS_INLINE void limit_warped_coefs(
+    opus_int32           *coefs_syn_Q24,
+    opus_int32           *coefs_ana_Q24,
+    opus_int             lambda_Q16,
+    opus_int32           limit_Q24,
+    opus_int             order
+) {
+    opus_int   i, iter, ind = 0;
+    opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16;
+    opus_int32 nom_Q16, den_Q24;
+
+    /* Convert to monic coefficients */
+    lambda_Q16 = -lambda_Q16;
+    for( i = order - 1; i > 0; i-- ) {
+        coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+        coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+    }
+    lambda_Q16 = -lambda_Q16;
+    nom_Q16  = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16,        lambda_Q16 );
+    den_Q24  = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 );
+    gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+    den_Q24  = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 );
+    gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+    for( i = 0; i < order; i++ ) {
+        coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+        coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+    }
+
+    for( iter = 0; iter < 10; iter++ ) {
+        /* Find maximum absolute value */
+        maxabs_Q24 = -1;
+        for( i = 0; i < order; i++ ) {
+            tmp = silk_max( silk_abs_int32( coefs_syn_Q24[ i ] ), silk_abs_int32( coefs_ana_Q24[ i ] ) );
+            if( tmp > maxabs_Q24 ) {
+                maxabs_Q24 = tmp;
+                ind = i;
+            }
+        }
+        if( maxabs_Q24 <= limit_Q24 ) {
+            /* Coefficients are within range - done */
+            return;
+        }
+
+        /* Convert back to true warped coefficients */
+        for( i = 1; i < order; i++ ) {
+            coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+            coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+        }
+        gain_syn_Q16 = silk_INVERSE32_varQ( gain_syn_Q16, 32 );
+        gain_ana_Q16 = silk_INVERSE32_varQ( gain_ana_Q16, 32 );
+        for( i = 0; i < order; i++ ) {
+            coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+            coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+        }
+
+        /* Apply bandwidth expansion */
+        chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ(
+            silk_SMULWB( maxabs_Q24 - limit_Q24, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ),
+            silk_MUL( maxabs_Q24, ind + 1 ), 22 );
+        silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 );
+        silk_bwexpander_32( coefs_ana_Q24, order, chirp_Q16 );
+
+        /* Convert to monic warped coefficients */
+        lambda_Q16 = -lambda_Q16;
+        for( i = order - 1; i > 0; i-- ) {
+            coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+            coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+        }
+        lambda_Q16 = -lambda_Q16;
+        nom_Q16  = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16,        lambda_Q16 );
+        den_Q24  = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 );
+        gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+        den_Q24  = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 );
+        gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+        for( i = 0; i < order; i++ ) {
+            coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+            coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+        }
+    }
+    silk_assert( 0 );
+}
+
+#if defined(MIPSr1_ASM)
+#include "mips/noise_shape_analysis_FIX_mipsr1.h"
+#endif
+
+/**************************************************************/
+/* Compute noise shaping coefficients and initial gain values */
+/**************************************************************/
+#ifndef OVERRIDE_silk_noise_shape_analysis_FIX
+void silk_noise_shape_analysis_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Encoder state FIX                                                           */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  Encoder control FIX                                                         */
+    const opus_int16                *pitch_res,                             /* I    LPC residual from pitch analysis                                            */
+    const opus_int16                *x,                                     /* I    Input signal [ frame_length + la_shape ]                                    */
+    int                              arch                                   /* I    Run-time architecture                                                       */
+)
+{
+    silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+    opus_int     k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0;
+    opus_int32   SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32;
+    opus_int32   nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
+    opus_int32   delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
+    opus_int32   auto_corr[     MAX_SHAPE_LPC_ORDER + 1 ];
+    opus_int32   refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ];
+    opus_int32   AR1_Q24[       MAX_SHAPE_LPC_ORDER ];
+    opus_int32   AR2_Q24[       MAX_SHAPE_LPC_ORDER ];
+    VARDECL( opus_int16, x_windowed );
+    const opus_int16 *x_ptr, *pitch_res_ptr;
+    SAVE_STACK;
+
+    /* Point to start of first LPC analysis block */
+    x_ptr = x - psEnc->sCmn.la_shape;
+
+    /****************/
+    /* GAIN CONTROL */
+    /****************/
+    SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7;
+
+    /* Input quality is the average of the quality in the lowest two VAD bands */
+    psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ]
+        + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 );
+
+    /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
+    psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 -
+        SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 );
+
+    /* Reduce coding SNR during low speech activity */
+    if( psEnc->sCmn.useCBR == 0 ) {
+        b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8;
+        b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 );
+        SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+            silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ),                                       /* Q11*/
+            silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) );     /* Q12*/
+    }
+
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Reduce gains for periodic signals */
+        SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 );
+    } else {
+        /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
+        SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+            silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ),
+            SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 );
+    }
+
+    /*************************/
+    /* SPARSENESS PROCESSING */
+    /*************************/
+    /* Set quantizer offset */
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Initially set to 0; may be overruled in process_gains(..) */
+        psEnc->sCmn.indices.quantOffsetType = 0;
+        psEncCtrl->sparseness_Q8 = 0;
+    } else {
+        /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
+        nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 );
+        energy_variation_Q7 = 0;
+        log_energy_prev_Q7  = 0;
+        pitch_res_ptr = pitch_res;
+        for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) {
+            silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples );
+            nrg += silk_RSHIFT( nSamples, scale );           /* Q(-scale)*/
+
+            log_energy_Q7 = silk_lin2log( nrg );
+            if( k > 0 ) {
+                energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 );
+            }
+            log_energy_prev_Q7 = log_energy_Q7;
+            pitch_res_ptr += nSamples;
+        }
+
+        psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 -
+            SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 );
+
+        /* Set quantization offset depending on sparseness measure */
+        if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) {
+            psEnc->sCmn.indices.quantOffsetType = 0;
+        } else {
+            psEnc->sCmn.indices.quantOffsetType = 1;
+        }
+
+        /* Increase coding SNR for sparse signals */
+        SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) );
+    }
+
+    /*******************************/
+    /* Control bandwidth expansion */
+    /*******************************/
+    /* More BWE for signals with high prediction gain */
+    strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) );
+    BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ),
+        silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 );
+    delta_Q16  = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ),
+        SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) );
+    BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 );
+    BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 );
+    /* BWExp1 will be applied after BWExp2, so make it relative */
+    BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) );
+
+    if( psEnc->sCmn.warping_Q16 > 0 ) {
+        /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
+        warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) );
+    } else {
+        warping_Q16 = 0;
+    }
+
+    /********************************************/
+    /* Compute noise shaping AR coefs and gains */
+    /********************************************/
+    ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 );
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        /* Apply window: sine slope followed by flat part followed by cosine slope */
+        opus_int shift, slope_part, flat_part;
+        flat_part = psEnc->sCmn.fs_kHz * 3;
+        slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 );
+
+        silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part );
+        shift = slope_part;
+        silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) );
+        shift += flat_part;
+        silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part );
+
+        /* Update pointer: next LPC analysis block */
+        x_ptr += psEnc->sCmn.subfr_length;
+
+        if( psEnc->sCmn.warping_Q16 > 0 ) {
+            /* Calculate warped auto correlation */
+            silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder );
+        } else {
+            /* Calculate regular auto correlation */
+            silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch );
+        }
+
+        /* Add white noise, as a fraction of energy */
+        auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ),
+            SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) );
+
+        /* Calculate the reflection coefficients using schur */
+        nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder );
+        silk_assert( nrg >= 0 );
+
+        /* Convert reflection coefficients to prediction coefficients */
+        silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder );
+
+        Qnrg = -scale;          /* range: -12...30*/
+        silk_assert( Qnrg >= -12 );
+        silk_assert( Qnrg <=  30 );
+
+        /* Make sure that Qnrg is an even number */
+        if( Qnrg & 1 ) {
+            Qnrg -= 1;
+            nrg >>= 1;
+        }
+
+        tmp32 = silk_SQRT_APPROX( nrg );
+        Qnrg >>= 1;             /* range: -6...15*/
+
+        psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg );
+
+        if( psEnc->sCmn.warping_Q16 > 0 ) {
+            /* Adjust gain for warping */
+            gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder );
+            silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+            if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) {
+               psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX;
+            } else {
+               psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+            }
+        }
+
+        /* Bandwidth expansion for synthesis filter shaping */
+        silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 );
+
+        /* Compute noise shaping filter coefficients */
+        silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) );
+
+        /* Bandwidth expansion for analysis filter shaping */
+        silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) );
+        silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 );
+
+        /* Ratio of prediction gains, in energy domain */
+        pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder );
+        nrg         = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder );
+
+        /*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/
+        pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 );
+        psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 );
+
+        /* Convert to monic warped prediction coefficients and limit absolute values */
+        limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder );
+
+        /* Convert from Q24 to Q13 and store in int16 */
+        for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) {
+            psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) );
+            psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) );
+        }
+    }
+
+    /*****************/
+    /* Gain tweaking */
+    /*****************/
+    /* Increase gains during low speech activity and put lower limit on gains */
+    gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) );
+    gain_add_Q16  = silk_log2lin(  silk_SMLAWB(  SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) );
+    silk_assert( gain_mult_Q16 > 0 );
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+        silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+        psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
+    }
+
+    gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ),
+        psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 );
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] );
+    }
+
+    /************************************************/
+    /* Control low-frequency shaping and noise tilt */
+    /************************************************/
+    /* Less low frequency shaping for noisy inputs */
+    strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ),
+        SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) );
+    strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 );
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
+        /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
+        opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz );
+        for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+            b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] );
+            /* Pack two coefficients in one int32 */
+            psEncCtrl->LF_shp_Q14[ k ]  = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 );
+            psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+        }
+        silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/
+        Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) -
+            silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ),
+                silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) );
+    } else {
+        b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/
+        /* Pack two coefficients in one int32 */
+        psEncCtrl->LF_shp_Q14[ 0 ]  = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 -
+            silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 );
+        psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+        for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
+            psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ];
+        }
+        Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 );
+    }
+
+    /****************************/
+    /* HARMONIC SHAPING CONTROL */
+    /****************************/
+    /* Control boosting of harmonic frequencies */
+    HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ),
+        psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) );
+
+    /* More harmonic boost for noisy input signals */
+    HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16,
+        SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) );
+
+    if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* More harmonic noise shaping for high bitrates or noisy input */
+        HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ),
+                SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ),
+                psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) );
+
+        /* Less harmonic noise shaping for less periodic signals */
+        HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ),
+            silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) );
+    } else {
+        HarmShapeGain_Q16 = 0;
+    }
+
+    /*************************/
+    /* Smooth over subframes */
+    /*************************/
+    for( k = 0; k < MAX_NB_SUBFR; k++ ) {
+        psShapeSt->HarmBoost_smth_Q16 =
+            silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16,     HarmBoost_Q16     - psShapeSt->HarmBoost_smth_Q16,     SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+        psShapeSt->HarmShapeGain_smth_Q16 =
+            silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+        psShapeSt->Tilt_smth_Q16 =
+            silk_SMLAWB( psShapeSt->Tilt_smth_Q16,          Tilt_Q16          - psShapeSt->Tilt_smth_Q16,          SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+
+        psEncCtrl->HarmBoost_Q14[ k ]     = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16,     2 );
+        psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 );
+        psEncCtrl->Tilt_Q14[ k ]          = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16,          2 );
+    }
+    RESTORE_STACK;
+}
+#endif /* OVERRIDE_silk_noise_shape_analysis_FIX */
diff --git a/third_party/opus/src/silk/fixed/pitch_analysis_core_FIX.c b/third_party/opus/src/silk/fixed/pitch_analysis_core_FIX.c
new file mode 100644
index 0000000..01bb9fc0
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/pitch_analysis_core_FIX.c
@@ -0,0 +1,746 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/***********************************************************
+* Pitch analyser function
+********************************************************** */
+#include "SigProc_FIX.h"
+#include "pitch_est_defines.h"
+#include "stack_alloc.h"
+#include "debug.h"
+#include "pitch.h"
+
+#define SCRATCH_SIZE    22
+#define SF_LENGTH_4KHZ  ( PE_SUBFR_LENGTH_MS * 4 )
+#define SF_LENGTH_8KHZ  ( PE_SUBFR_LENGTH_MS * 8 )
+#define MIN_LAG_4KHZ    ( PE_MIN_LAG_MS * 4 )
+#define MIN_LAG_8KHZ    ( PE_MIN_LAG_MS * 8 )
+#define MAX_LAG_4KHZ    ( PE_MAX_LAG_MS * 4 )
+#define MAX_LAG_8KHZ    ( PE_MAX_LAG_MS * 8 - 1 )
+#define CSTRIDE_4KHZ    ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ )
+#define CSTRIDE_8KHZ    ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) )
+#define D_COMP_MIN      ( MIN_LAG_8KHZ - 3 )
+#define D_COMP_MAX      ( MAX_LAG_8KHZ + 4 )
+#define D_COMP_STRIDE   ( D_COMP_MAX - D_COMP_MIN )
+
+typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ];
+
+/************************************************************/
+/* Internally used functions                                */
+/************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+    silk_pe_stage3_vals cross_corr_st3[],              /* O 3 DIM correlation array */
+    const opus_int16  frame[],                         /* I vector to correlate         */
+    opus_int          start_lag,                       /* I lag offset to search around */
+    opus_int          sf_length,                       /* I length of a 5 ms subframe   */
+    opus_int          nb_subfr,                        /* I number of subframes         */
+    opus_int          complexity,                      /* I Complexity setting          */
+    int               arch                             /* I Run-time architecture       */
+);
+
+static void silk_P_Ana_calc_energy_st3(
+    silk_pe_stage3_vals energies_st3[],                /* O 3 DIM energy array */
+    const opus_int16  frame[],                         /* I vector to calc energy in    */
+    opus_int          start_lag,                       /* I lag offset to search around */
+    opus_int          sf_length,                       /* I length of one 5 ms subframe */
+    opus_int          nb_subfr,                        /* I number of subframes         */
+    opus_int          complexity,                      /* I Complexity setting          */
+    int               arch                             /* I Run-time architecture       */
+);
+
+/*************************************************************/
+/*      FIXED POINT CORE PITCH ANALYSIS FUNCTION             */
+/*************************************************************/
+opus_int silk_pitch_analysis_core(                  /* O    Voicing estimate: 0 voiced, 1 unvoiced                      */
+    const opus_int16            *frame,             /* I    Signal of length PE_FRAME_LENGTH_MS*Fs_kHz                  */
+    opus_int                    *pitch_out,         /* O    4 pitch lag values                                          */
+    opus_int16                  *lagIndex,          /* O    Lag Index                                                   */
+    opus_int8                   *contourIndex,      /* O    Pitch contour Index                                         */
+    opus_int                    *LTPCorr_Q15,       /* I/O  Normalized correlation; input: value from previous frame    */
+    opus_int                    prevLag,            /* I    Last lag of previous frame; set to zero is unvoiced         */
+    const opus_int32            search_thres1_Q16,  /* I    First stage threshold for lag candidates 0 - 1              */
+    const opus_int              search_thres2_Q13,  /* I    Final threshold for lag candidates 0 - 1                    */
+    const opus_int              Fs_kHz,             /* I    Sample frequency (kHz)                                      */
+    const opus_int              complexity,         /* I    Complexity setting, 0-2, where 2 is highest                 */
+    const opus_int              nb_subfr,           /* I    number of 5 ms subframes                                    */
+    int                         arch                /* I    Run-time architecture                                       */
+)
+{
+    VARDECL( opus_int16, frame_8kHz );
+    VARDECL( opus_int16, frame_4kHz );
+    opus_int32 filt_state[ 6 ];
+    const opus_int16 *input_frame_ptr;
+    opus_int   i, k, d, j;
+    VARDECL( opus_int16, C );
+    VARDECL( opus_int32, xcorr32 );
+    const opus_int16 *target_ptr, *basis_ptr;
+    opus_int32 cross_corr, normalizer, energy, shift, energy_basis, energy_target;
+    opus_int   d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp;
+    VARDECL( opus_int16, d_comp );
+    opus_int32 sum, threshold, lag_counter;
+    opus_int   CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new;
+    opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new;
+    VARDECL( silk_pe_stage3_vals, energies_st3 );
+    VARDECL( silk_pe_stage3_vals, cross_corr_st3 );
+    opus_int   frame_length, frame_length_8kHz, frame_length_4kHz;
+    opus_int   sf_length;
+    opus_int   min_lag;
+    opus_int   max_lag;
+    opus_int32 contour_bias_Q15, diff;
+    opus_int   nb_cbk_search, cbk_size;
+    opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13;
+    const opus_int8 *Lag_CB_ptr;
+    SAVE_STACK;
+    /* Check for valid sampling frequency */
+    silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
+
+    /* Check for valid complexity setting */
+    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+    silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) );
+    silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) );
+
+    /* Set up frame lengths max / min lag for the sampling frequency */
+    frame_length      = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
+    frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
+    frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
+    sf_length         = PE_SUBFR_LENGTH_MS * Fs_kHz;
+    min_lag           = PE_MIN_LAG_MS * Fs_kHz;
+    max_lag           = PE_MAX_LAG_MS * Fs_kHz - 1;
+
+    /* Resample from input sampled at Fs_kHz to 8 kHz */
+    ALLOC( frame_8kHz, frame_length_8kHz, opus_int16 );
+    if( Fs_kHz == 16 ) {
+        silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+        silk_resampler_down2( filt_state, frame_8kHz, frame, frame_length );
+    } else if( Fs_kHz == 12 ) {
+        silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
+        silk_resampler_down2_3( filt_state, frame_8kHz, frame, frame_length );
+    } else {
+        silk_assert( Fs_kHz == 8 );
+        silk_memcpy( frame_8kHz, frame, frame_length_8kHz * sizeof(opus_int16) );
+    }
+
+    /* Decimate again to 4 kHz */
+    silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */
+    ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 );
+    silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz );
+
+    /* Low-pass filter */
+    for( i = frame_length_4kHz - 1; i > 0; i-- ) {
+        frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] );
+    }
+
+    /*******************************************************************************
+    ** Scale 4 kHz signal down to prevent correlations measures from overflowing
+    ** find scaling as max scaling for each 8kHz(?) subframe
+    *******************************************************************************/
+
+    /* Inner product is calculated with different lengths, so scale for the worst case */
+    silk_sum_sqr_shift( &energy, &shift, frame_4kHz, frame_length_4kHz );
+    if( shift > 0 ) {
+        shift = silk_RSHIFT( shift, 1 );
+        for( i = 0; i < frame_length_4kHz; i++ ) {
+            frame_4kHz[ i ] = silk_RSHIFT( frame_4kHz[ i ], shift );
+        }
+    }
+
+    /******************************************************************************
+    * FIRST STAGE, operating in 4 khz
+    ******************************************************************************/
+    ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 );
+    ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 );
+    silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) );
+    target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ];
+    for( k = 0; k < nb_subfr >> 1; k++ ) {
+        /* Check that we are within range of the array */
+        silk_assert( target_ptr >= frame_4kHz );
+        silk_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+        basis_ptr = target_ptr - MIN_LAG_4KHZ;
+
+        /* Check that we are within range of the array */
+        silk_assert( basis_ptr >= frame_4kHz );
+        silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+        celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch );
+
+        /* Calculate first vector products before loop */
+        cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ];
+        normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch );
+        normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr,  basis_ptr, SF_LENGTH_8KHZ, arch ) );
+        normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) );
+
+        matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) =
+            (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 );                      /* Q13 */
+
+        /* From now on normalizer is computed recursively */
+        for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) {
+            basis_ptr--;
+
+            /* Check that we are within range of the array */
+            silk_assert( basis_ptr >= frame_4kHz );
+            silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+            cross_corr = xcorr32[ MAX_LAG_4KHZ - d ];
+
+            /* Add contribution of new sample and remove contribution from oldest sample */
+            normalizer = silk_ADD32( normalizer,
+                silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) -
+                silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) );
+
+            matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) =
+                (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 );                  /* Q13 */
+        }
+        /* Update target pointer */
+        target_ptr += SF_LENGTH_8KHZ;
+    }
+
+    /* Combine two subframes into single correlation measure and apply short-lag bias */
+    if( nb_subfr == PE_MAX_NB_SUBFR ) {
+        for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
+            sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ )
+                + (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ );               /* Q14 */
+            sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) );                                /* Q14 */
+            C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum;                                            /* Q14 */
+        }
+    } else {
+        /* Only short-lag bias */
+        for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
+            sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 );                          /* Q14 */
+            sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) );                                /* Q14 */
+            C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum;                                            /* Q14 */
+        }
+    }
+
+    /* Sort */
+    length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 );
+    silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
+    silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ,
+                                          length_d_srch );
+
+    /* Escape if correlation is very low already here */
+    Cmax = (opus_int)C[ 0 ];                                                    /* Q14 */
+    if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) {
+        silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+        *LTPCorr_Q15  = 0;
+        *lagIndex     = 0;
+        *contourIndex = 0;
+        RESTORE_STACK;
+        return 1;
+    }
+
+    threshold = silk_SMULWB( search_thres1_Q16, Cmax );
+    for( i = 0; i < length_d_srch; i++ ) {
+        /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
+        if( C[ i ] > threshold ) {
+            d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 );
+        } else {
+            length_d_srch = i;
+            break;
+        }
+    }
+    silk_assert( length_d_srch > 0 );
+
+    ALLOC( d_comp, D_COMP_STRIDE, opus_int16 );
+    for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) {
+        d_comp[ i - D_COMP_MIN ] = 0;
+    }
+    for( i = 0; i < length_d_srch; i++ ) {
+        d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1;
+    }
+
+    /* Convolution */
+    for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
+        d_comp[ i - D_COMP_MIN ] +=
+            d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ];
+    }
+
+    length_d_srch = 0;
+    for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) {
+        if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) {
+            d_srch[ length_d_srch ] = i;
+            length_d_srch++;
+        }
+    }
+
+    /* Convolution */
+    for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
+        d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ]
+            + d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ];
+    }
+
+    length_d_comp = 0;
+    for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) {
+        if( d_comp[ i - D_COMP_MIN ] > 0 ) {
+            d_comp[ length_d_comp ] = i - 2;
+            length_d_comp++;
+        }
+    }
+
+    /**********************************************************************************
+    ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
+    *************************************************************************************/
+
+    /******************************************************************************
+    ** Scale signal down to avoid correlations measures from overflowing
+    *******************************************************************************/
+    /* find scaling as max scaling for each subframe */
+    silk_sum_sqr_shift( &energy, &shift, frame_8kHz, frame_length_8kHz );
+    if( shift > 0 ) {
+        shift = silk_RSHIFT( shift, 1 );
+        for( i = 0; i < frame_length_8kHz; i++ ) {
+            frame_8kHz[ i ] = silk_RSHIFT( frame_8kHz[ i ], shift );
+        }
+    }
+
+    /*********************************************************************************
+    * Find energy of each subframe projected onto its history, for a range of delays
+    *********************************************************************************/
+    silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) );
+
+    target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
+    for( k = 0; k < nb_subfr; k++ ) {
+
+        /* Check that we are within range of the array */
+        silk_assert( target_ptr >= frame_8kHz );
+        silk_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
+
+        energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ), 1 );
+        for( j = 0; j < length_d_comp; j++ ) {
+            d = d_comp[ j ];
+            basis_ptr = target_ptr - d;
+
+            /* Check that we are within range of the array */
+            silk_assert( basis_ptr >= frame_8kHz );
+            silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
+
+            cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ, arch );
+            if( cross_corr > 0 ) {
+                energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch );
+                matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) =
+                    (opus_int16)silk_DIV32_varQ( cross_corr,
+                                                 silk_ADD32( energy_target,
+                                                             energy_basis ),
+                                                 13 + 1 );                                      /* Q13 */
+            } else {
+                matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0;
+            }
+        }
+        target_ptr += SF_LENGTH_8KHZ;
+    }
+
+    /* search over lag range and lags codebook */
+    /* scale factor for lag codebook, as a function of center lag */
+
+    CCmax   = silk_int32_MIN;
+    CCmax_b = silk_int32_MIN;
+
+    CBimax = 0; /* To avoid returning undefined lag values */
+    lag = -1;   /* To check if lag with strong enough correlation has been found */
+
+    if( prevLag > 0 ) {
+        if( Fs_kHz == 12 ) {
+            prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 );
+        } else if( Fs_kHz == 16 ) {
+            prevLag = silk_RSHIFT( prevLag, 1 );
+        }
+        prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag );
+    } else {
+        prevLag_log2_Q7 = 0;
+    }
+    silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) );
+    /* Set up stage 2 codebook based on number of subframes */
+    if( nb_subfr == PE_MAX_NB_SUBFR ) {
+        cbk_size   = PE_NB_CBKS_STAGE2_EXT;
+        Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+        if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
+            /* If input is 8 khz use a larger codebook here because it is last stage */
+            nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
+        } else {
+            nb_cbk_search = PE_NB_CBKS_STAGE2;
+        }
+    } else {
+        cbk_size       = PE_NB_CBKS_STAGE2_10MS;
+        Lag_CB_ptr     = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+        nb_cbk_search  = PE_NB_CBKS_STAGE2_10MS;
+    }
+
+    for( k = 0; k < length_d_srch; k++ ) {
+        d = d_srch[ k ];
+        for( j = 0; j < nb_cbk_search; j++ ) {
+            CC[ j ] = 0;
+            for( i = 0; i < nb_subfr; i++ ) {
+                opus_int d_subfr;
+                /* Try all codebooks */
+                d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size );
+                CC[ j ] = CC[ j ]
+                    + (opus_int32)matrix_ptr( C, i,
+                                              d_subfr - ( MIN_LAG_8KHZ - 2 ),
+                                              CSTRIDE_8KHZ );
+            }
+        }
+        /* Find best codebook */
+        CCmax_new = silk_int32_MIN;
+        CBimax_new = 0;
+        for( i = 0; i < nb_cbk_search; i++ ) {
+            if( CC[ i ] > CCmax_new ) {
+                CCmax_new = CC[ i ];
+                CBimax_new = i;
+            }
+        }
+
+        /* Bias towards shorter lags */
+        lag_log2_Q7 = silk_lin2log( d ); /* Q7 */
+        silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) );
+        silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) );
+        CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */
+
+        /* Bias towards previous lag */
+        silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) );
+        if( prevLag > 0 ) {
+            delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7;
+            silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) );
+            delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 );
+            prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */
+            prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) );
+            CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */
+        }
+
+        if( CCmax_new_b > CCmax_b                                   &&  /* Find maximum biased correlation                  */
+            CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 )  &&  /* Correlation needs to be high enough to be voiced */
+            silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ      /* Lag must be in range                             */
+         ) {
+            CCmax_b = CCmax_new_b;
+            CCmax   = CCmax_new;
+            lag     = d;
+            CBimax  = CBimax_new;
+        }
+    }
+
+    if( lag == -1 ) {
+        /* No suitable candidate found */
+        silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+        *LTPCorr_Q15  = 0;
+        *lagIndex     = 0;
+        *contourIndex = 0;
+        RESTORE_STACK;
+        return 1;
+    }
+
+    /* Output normalized correlation */
+    *LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 );
+    silk_assert( *LTPCorr_Q15 >= 0 );
+
+    if( Fs_kHz > 8 ) {
+        VARDECL( opus_int16, scratch_mem );
+        /***************************************************************************/
+        /* Scale input signal down to avoid correlations measures from overflowing */
+        /***************************************************************************/
+        /* find scaling as max scaling for each subframe */
+        silk_sum_sqr_shift( &energy, &shift, frame, frame_length );
+        ALLOC( scratch_mem, shift > 0 ? frame_length : ALLOC_NONE, opus_int16 );
+        if( shift > 0 ) {
+            /* Move signal to scratch mem because the input signal should be unchanged */
+            shift = silk_RSHIFT( shift, 1 );
+            for( i = 0; i < frame_length; i++ ) {
+                scratch_mem[ i ] = silk_RSHIFT( frame[ i ], shift );
+            }
+            input_frame_ptr = scratch_mem;
+        } else {
+            input_frame_ptr = frame;
+        }
+
+        /* Search in original signal */
+
+        CBimax_old = CBimax;
+        /* Compensate for decimation */
+        silk_assert( lag == silk_SAT16( lag ) );
+        if( Fs_kHz == 12 ) {
+            lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 );
+        } else if( Fs_kHz == 16 ) {
+            lag = silk_LSHIFT( lag, 1 );
+        } else {
+            lag = silk_SMULBB( lag, 3 );
+        }
+
+        lag = silk_LIMIT_int( lag, min_lag, max_lag );
+        start_lag = silk_max_int( lag - 2, min_lag );
+        end_lag   = silk_min_int( lag + 2, max_lag );
+        lag_new   = lag;                                    /* to avoid undefined lag */
+        CBimax    = 0;                                      /* to avoid undefined lag */
+
+        CCmax = silk_int32_MIN;
+        /* pitch lags according to second stage */
+        for( k = 0; k < nb_subfr; k++ ) {
+            pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ];
+        }
+
+        /* Set up codebook parameters according to complexity setting and frame length */
+        if( nb_subfr == PE_MAX_NB_SUBFR ) {
+            nb_cbk_search   = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
+            cbk_size        = PE_NB_CBKS_STAGE3_MAX;
+            Lag_CB_ptr      = &silk_CB_lags_stage3[ 0 ][ 0 ];
+        } else {
+            nb_cbk_search   = PE_NB_CBKS_STAGE3_10MS;
+            cbk_size        = PE_NB_CBKS_STAGE3_10MS;
+            Lag_CB_ptr      = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+        }
+
+        /* Calculate the correlations and energies needed in stage 3 */
+        ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
+        ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
+        silk_P_Ana_calc_corr_st3(  cross_corr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity, arch );
+        silk_P_Ana_calc_energy_st3( energies_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity, arch );
+
+        lag_counter = 0;
+        silk_assert( lag == silk_SAT16( lag ) );
+        contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag );
+
+        target_ptr = &input_frame_ptr[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
+        energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length, arch ), 1 );
+        for( d = start_lag; d <= end_lag; d++ ) {
+            for( j = 0; j < nb_cbk_search; j++ ) {
+                cross_corr = 0;
+                energy     = energy_target;
+                for( k = 0; k < nb_subfr; k++ ) {
+                    cross_corr = silk_ADD32( cross_corr,
+                        matrix_ptr( cross_corr_st3, k, j,
+                                    nb_cbk_search )[ lag_counter ] );
+                    energy     = silk_ADD32( energy,
+                        matrix_ptr( energies_st3, k, j,
+                                    nb_cbk_search )[ lag_counter ] );
+                    silk_assert( energy >= 0 );
+                }
+                if( cross_corr > 0 ) {
+                    CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 );          /* Q13 */
+                    /* Reduce depending on flatness of contour */
+                    diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j );            /* Q15 */
+                    silk_assert( diff == silk_SAT16( diff ) );
+                    CCmax_new = silk_SMULWB( CCmax_new, diff );                         /* Q14 */
+                } else {
+                    CCmax_new = 0;
+                }
+
+                if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
+                    CCmax   = CCmax_new;
+                    lag_new = d;
+                    CBimax  = j;
+                }
+            }
+            lag_counter++;
+        }
+
+        for( k = 0; k < nb_subfr; k++ ) {
+            pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+            pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
+        }
+        *lagIndex = (opus_int16)( lag_new - min_lag);
+        *contourIndex = (opus_int8)CBimax;
+    } else {        /* Fs_kHz == 8 */
+        /* Save Lags */
+        for( k = 0; k < nb_subfr; k++ ) {
+            pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+            pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 );
+        }
+        *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ );
+        *contourIndex = (opus_int8)CBimax;
+    }
+    silk_assert( *lagIndex >= 0 );
+    /* return as voiced */
+    RESTORE_STACK;
+    return 0;
+}
+
+/***********************************************************************
+ * Calculates the correlations used in stage 3 search. In order to cover
+ * the whole lag codebook for all the searched offset lags (lag +- 2),
+ * the following correlations are needed in each sub frame:
+ *
+ * sf1: lag range [-8,...,7] total 16 correlations
+ * sf2: lag range [-4,...,4] total 9 correlations
+ * sf3: lag range [-3,....4] total 8 correltions
+ * sf4: lag range [-6,....8] total 15 correlations
+ *
+ * In total 48 correlations. The direct implementation computed in worst
+ * case 4*12*5 = 240 correlations, but more likely around 120.
+ ***********************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+    silk_pe_stage3_vals cross_corr_st3[],              /* O 3 DIM correlation array */
+    const opus_int16  frame[],                         /* I vector to correlate         */
+    opus_int          start_lag,                       /* I lag offset to search around */
+    opus_int          sf_length,                       /* I length of a 5 ms subframe   */
+    opus_int          nb_subfr,                        /* I number of subframes         */
+    opus_int          complexity,                      /* I Complexity setting          */
+    int               arch                             /* I Run-time architecture       */
+)
+{
+    const opus_int16 *target_ptr;
+    opus_int   i, j, k, lag_counter, lag_low, lag_high;
+    opus_int   nb_cbk_search, delta, idx, cbk_size;
+    VARDECL( opus_int32, scratch_mem );
+    VARDECL( opus_int32, xcorr32 );
+    const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+    SAVE_STACK;
+
+    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+    if( nb_subfr == PE_MAX_NB_SUBFR ) {
+        Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+        Lag_CB_ptr    = &silk_CB_lags_stage3[ 0 ][ 0 ];
+        nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+        cbk_size      = PE_NB_CBKS_STAGE3_MAX;
+    } else {
+        silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+        Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+        Lag_CB_ptr    = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+        nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+        cbk_size      = PE_NB_CBKS_STAGE3_10MS;
+    }
+    ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
+    ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 );
+
+    target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
+    for( k = 0; k < nb_subfr; k++ ) {
+        lag_counter = 0;
+
+        /* Calculate the correlations for each subframe */
+        lag_low  = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+        lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
+        silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
+        celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch );
+        for( j = lag_low; j <= lag_high; j++ ) {
+            silk_assert( lag_counter < SCRATCH_SIZE );
+            scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ];
+            lag_counter++;
+        }
+
+        delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+        for( i = 0; i < nb_cbk_search; i++ ) {
+            /* Fill out the 3 dim array that stores the correlations for */
+            /* each code_book vector for each start lag */
+            idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+            for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+                silk_assert( idx + j < SCRATCH_SIZE );
+                silk_assert( idx + j < lag_counter );
+                matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] =
+                    scratch_mem[ idx + j ];
+            }
+        }
+        target_ptr += sf_length;
+    }
+    RESTORE_STACK;
+}
+
+/********************************************************************/
+/* Calculate the energies for first two subframes. The energies are */
+/* calculated recursively.                                          */
+/********************************************************************/
+static void silk_P_Ana_calc_energy_st3(
+    silk_pe_stage3_vals energies_st3[],                 /* O 3 DIM energy array */
+    const opus_int16  frame[],                          /* I vector to calc energy in    */
+    opus_int          start_lag,                        /* I lag offset to search around */
+    opus_int          sf_length,                        /* I length of one 5 ms subframe */
+    opus_int          nb_subfr,                         /* I number of subframes         */
+    opus_int          complexity,                       /* I Complexity setting          */
+    int               arch                              /* I Run-time architecture       */
+)
+{
+    const opus_int16 *target_ptr, *basis_ptr;
+    opus_int32 energy;
+    opus_int   k, i, j, lag_counter;
+    opus_int   nb_cbk_search, delta, idx, cbk_size, lag_diff;
+    VARDECL( opus_int32, scratch_mem );
+    const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+    SAVE_STACK;
+
+    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+    if( nb_subfr == PE_MAX_NB_SUBFR ) {
+        Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+        Lag_CB_ptr    = &silk_CB_lags_stage3[ 0 ][ 0 ];
+        nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+        cbk_size      = PE_NB_CBKS_STAGE3_MAX;
+    } else {
+        silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+        Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+        Lag_CB_ptr    = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+        nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+        cbk_size      = PE_NB_CBKS_STAGE3_10MS;
+    }
+    ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
+
+    target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
+    for( k = 0; k < nb_subfr; k++ ) {
+        lag_counter = 0;
+
+        /* Calculate the energy for first lag */
+        basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
+        energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length, arch );
+        silk_assert( energy >= 0 );
+        scratch_mem[ lag_counter ] = energy;
+        lag_counter++;
+
+        lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) -  matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
+        for( i = 1; i < lag_diff; i++ ) {
+            /* remove part outside new window */
+            energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] );
+            silk_assert( energy >= 0 );
+
+            /* add part that comes into window */
+            energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) );
+            silk_assert( energy >= 0 );
+            silk_assert( lag_counter < SCRATCH_SIZE );
+            scratch_mem[ lag_counter ] = energy;
+            lag_counter++;
+        }
+
+        delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+        for( i = 0; i < nb_cbk_search; i++ ) {
+            /* Fill out the 3 dim array that stores the correlations for    */
+            /* each code_book vector for each start lag                     */
+            idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+            for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+                silk_assert( idx + j < SCRATCH_SIZE );
+                silk_assert( idx + j < lag_counter );
+                matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] =
+                    scratch_mem[ idx + j ];
+                silk_assert(
+                    matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 );
+            }
+        }
+        target_ptr += sf_length;
+    }
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/fixed/prefilter_FIX.c b/third_party/opus/src/silk/fixed/prefilter_FIX.c
new file mode 100644
index 0000000..6a8e3515
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/prefilter_FIX.c
@@ -0,0 +1,221 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+#if defined(MIPSr1_ASM)
+#include "mips/prefilter_FIX_mipsr1.h"
+#endif
+
+
+#if !defined(OVERRIDE_silk_warped_LPC_analysis_filter_FIX)
+#define silk_warped_LPC_analysis_filter_FIX(state, res_Q2, coef_Q13, input, lambda_Q16, length, order, arch) \
+    ((void)(arch),silk_warped_LPC_analysis_filter_FIX_c(state, res_Q2, coef_Q13, input, lambda_Q16, length, order))
+#endif
+
+/* Prefilter for finding Quantizer input signal */
+static OPUS_INLINE void silk_prefilt_FIX(
+    silk_prefilter_state_FIX    *P,                         /* I/O  state                               */
+    opus_int32                  st_res_Q12[],               /* I    short term residual signal          */
+    opus_int32                  xw_Q3[],                    /* O    prefiltered signal                  */
+    opus_int32                  HarmShapeFIRPacked_Q12,     /* I    Harmonic shaping coeficients        */
+    opus_int                    Tilt_Q14,                   /* I    Tilt shaping coeficient             */
+    opus_int32                  LF_shp_Q14,                 /* I    Low-frequancy shaping coeficients   */
+    opus_int                    lag,                        /* I    Lag for harmonic shaping            */
+    opus_int                    length                      /* I    Length of signals                   */
+);
+
+void silk_warped_LPC_analysis_filter_FIX_c(
+          opus_int32            state[],                    /* I/O  State [order + 1]                   */
+          opus_int32            res_Q2[],                   /* O    Residual signal [length]            */
+    const opus_int16            coef_Q13[],                 /* I    Coefficients [order]                */
+    const opus_int16            input[],                    /* I    Input signal [length]               */
+    const opus_int16            lambda_Q16,                 /* I    Warping factor                      */
+    const opus_int              length,                     /* I    Length of input signal              */
+    const opus_int              order                       /* I    Filter order (even)                 */
+)
+{
+    opus_int     n, i;
+    opus_int32   acc_Q11, tmp1, tmp2;
+
+    /* Order must be even */
+    silk_assert( ( order & 1 ) == 0 );
+
+    for( n = 0; n < length; n++ ) {
+        /* Output of lowpass section */
+        tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 );
+        state[ 0 ] = silk_LSHIFT( input[ n ], 14 );
+        /* Output of allpass section */
+        tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 );
+        state[ 1 ] = tmp2;
+        acc_Q11 = silk_RSHIFT( order, 1 );
+        acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] );
+        /* Loop over allpass sections */
+        for( i = 2; i < order; i += 2 ) {
+            /* Output of allpass section */
+            tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 );
+            state[ i ] = tmp1;
+            acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] );
+            /* Output of allpass section */
+            tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 );
+            state[ i + 1 ] = tmp2;
+            acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] );
+        }
+        state[ order ] = tmp1;
+        acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] );
+        res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 );
+    }
+}
+
+void silk_prefilter_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Encoder state                                                               */
+    const silk_encoder_control_FIX  *psEncCtrl,                             /* I    Encoder control                                                             */
+    opus_int32                      xw_Q3[],                                /* O    Weighted signal                                                             */
+    const opus_int16                x[]                                     /* I    Speech signal                                                               */
+)
+{
+    silk_prefilter_state_FIX *P = &psEnc->sPrefilt;
+    opus_int   j, k, lag;
+    opus_int32 tmp_32;
+    const opus_int16 *AR1_shp_Q13;
+    const opus_int16 *px;
+    opus_int32 *pxw_Q3;
+    opus_int   HarmShapeGain_Q12, Tilt_Q14;
+    opus_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14;
+    VARDECL( opus_int32, x_filt_Q12 );
+    VARDECL( opus_int32, st_res_Q2 );
+    opus_int16 B_Q10[ 2 ];
+    SAVE_STACK;
+
+    /* Set up pointers */
+    px  = x;
+    pxw_Q3 = xw_Q3;
+    lag = P->lagPrev;
+    ALLOC( x_filt_Q12, psEnc->sCmn.subfr_length, opus_int32 );
+    ALLOC( st_res_Q2, psEnc->sCmn.subfr_length, opus_int32 );
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        /* Update Variables that change per sub frame */
+        if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+            lag = psEncCtrl->pitchL[ k ];
+        }
+
+        /* Noise shape parameters */
+        HarmShapeGain_Q12 = silk_SMULWB( (opus_int32)psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] );
+        silk_assert( HarmShapeGain_Q12 >= 0 );
+        HarmShapeFIRPacked_Q12  =                          silk_RSHIFT( HarmShapeGain_Q12, 2 );
+        HarmShapeFIRPacked_Q12 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q12, 1 ), 16 );
+        Tilt_Q14    = psEncCtrl->Tilt_Q14[   k ];
+        LF_shp_Q14  = psEncCtrl->LF_shp_Q14[ k ];
+        AR1_shp_Q13 = &psEncCtrl->AR1_Q13[   k * MAX_SHAPE_LPC_ORDER ];
+
+        /* Short term FIR filtering*/
+        silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res_Q2, AR1_shp_Q13, px,
+            psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder, psEnc->sCmn.arch );
+
+        /* Reduce (mainly) low frequencies during harmonic emphasis */
+        B_Q10[ 0 ] = silk_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 4 );
+        tmp_32 = silk_SMLABB( SILK_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 );   /* Q26 */
+        tmp_32 = silk_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) );    /* Q26 */
+        tmp_32 = silk_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] );                                                /* Q24 */
+        tmp_32 = silk_RSHIFT_ROUND( tmp_32, 14 );                                                                     /* Q10 */
+        B_Q10[ 1 ]= silk_SAT16( tmp_32 );
+        x_filt_Q12[ 0 ] = silk_MLA( silk_MUL( st_res_Q2[ 0 ], B_Q10[ 0 ] ), P->sHarmHP_Q2, B_Q10[ 1 ] );
+        for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) {
+            x_filt_Q12[ j ] = silk_MLA( silk_MUL( st_res_Q2[ j ], B_Q10[ 0 ] ), st_res_Q2[ j - 1 ], B_Q10[ 1 ] );
+        }
+        P->sHarmHP_Q2 = st_res_Q2[ psEnc->sCmn.subfr_length - 1 ];
+
+        silk_prefilt_FIX( P, x_filt_Q12, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc->sCmn.subfr_length );
+
+        px  += psEnc->sCmn.subfr_length;
+        pxw_Q3 += psEnc->sCmn.subfr_length;
+    }
+
+    P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+    RESTORE_STACK;
+}
+
+#ifndef OVERRIDE_silk_prefilt_FIX
+/* Prefilter for finding Quantizer input signal */
+static OPUS_INLINE void silk_prefilt_FIX(
+    silk_prefilter_state_FIX    *P,                         /* I/O  state                               */
+    opus_int32                  st_res_Q12[],               /* I    short term residual signal          */
+    opus_int32                  xw_Q3[],                    /* O    prefiltered signal                  */
+    opus_int32                  HarmShapeFIRPacked_Q12,     /* I    Harmonic shaping coeficients        */
+    opus_int                    Tilt_Q14,                   /* I    Tilt shaping coeficient             */
+    opus_int32                  LF_shp_Q14,                 /* I    Low-frequancy shaping coeficients   */
+    opus_int                    lag,                        /* I    Lag for harmonic shaping            */
+    opus_int                    length                      /* I    Length of signals                   */
+)
+{
+    opus_int   i, idx, LTP_shp_buf_idx;
+    opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10;
+    opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12;
+    opus_int16 *LTP_shp_buf;
+
+    /* To speed up use temp variables instead of using the struct */
+    LTP_shp_buf     = P->sLTP_shp;
+    LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
+    sLF_AR_shp_Q12  = P->sLF_AR_shp_Q12;
+    sLF_MA_shp_Q12  = P->sLF_MA_shp_Q12;
+
+    for( i = 0; i < length; i++ ) {
+        if( lag > 0 ) {
+            /* unrolled loop */
+            silk_assert( HARM_SHAPE_FIR_TAPS == 3 );
+            idx = lag + LTP_shp_buf_idx;
+            n_LTP_Q12 = silk_SMULBB(            LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+            n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2    ) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+            n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+        } else {
+            n_LTP_Q12 = 0;
+        }
+
+        n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 );
+        n_LF_Q10   = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 );
+
+        sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) );
+        sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12,  silk_LSHIFT( n_LF_Q10,   2 ) );
+
+        LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
+        LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) );
+
+        xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 );
+    }
+
+    /* Copy temp variable back to state */
+    P->sLF_AR_shp_Q12   = sLF_AR_shp_Q12;
+    P->sLF_MA_shp_Q12   = sLF_MA_shp_Q12;
+    P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
+}
+#endif /* OVERRIDE_silk_prefilt_FIX */
diff --git a/third_party/opus/src/silk/fixed/process_gains_FIX.c b/third_party/opus/src/silk/fixed/process_gains_FIX.c
new file mode 100644
index 0000000..05aba317
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/process_gains_FIX.c
@@ -0,0 +1,117 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "tuning_parameters.h"
+
+/* Processing of gains */
+void silk_process_gains_FIX(
+    silk_encoder_state_FIX          *psEnc,                                 /* I/O  Encoder state                                                               */
+    silk_encoder_control_FIX        *psEncCtrl,                             /* I/O  Encoder control                                                             */
+    opus_int                        condCoding                              /* I    The type of conditional coding to use                                       */
+)
+{
+    silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+    opus_int     k;
+    opus_int32   s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10;
+
+    /* Gain reduction when LTP coding gain is high */
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */
+        s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) );
+        for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+            psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 );
+        }
+    }
+
+    /* Limit the quantized signal */
+    /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */
+    InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin(
+        silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length );
+
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        /* Soft limit on ratio residual energy and squared gains */
+        ResNrg     = psEncCtrl->ResNrg[ k ];
+        ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 );
+        if( psEncCtrl->ResNrgQ[ k ] > 0 ) {
+            ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] );
+        } else {
+            if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) {
+                ResNrgPart = silk_int32_MAX;
+            } else {
+                ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] );
+            }
+        }
+        gain = psEncCtrl->Gains_Q16[ k ];
+        gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) );
+        if( gain_squared < silk_int16_MAX ) {
+            /* recalculate with higher precision */
+            gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain );
+            silk_assert( gain_squared > 0 );
+            gain = silk_SQRT_APPROX( gain_squared );                    /* Q8   */
+            gain = silk_min( gain, silk_int32_MAX >> 8 );
+            psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 );   /* Q16  */
+        } else {
+            gain = silk_SQRT_APPROX( gain_squared );                    /* Q0   */
+            gain = silk_min( gain, silk_int32_MAX >> 16 );
+            psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 );  /* Q16  */
+        }
+    }
+
+    /* Save unquantized gains and gain Index */
+    silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+    psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
+    /* Quantize gains */
+    silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16,
+        &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+    /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) {
+            psEnc->sCmn.indices.quantOffsetType = 0;
+        } else {
+            psEnc->sCmn.indices.quantOffsetType = 1;
+        }
+    }
+
+    /* Quantizer boundary adjustment */
+    quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ];
+    psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 )
+                          + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision )
+                          + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT,        18 ), psEnc->sCmn.speech_activity_Q8     )
+                          + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY,     12 ), psEncCtrl->input_quality_Q14       )
+                          + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY,    12 ), psEncCtrl->coding_quality_Q14      )
+                          + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET,      16 ), quant_offset_Q10                   );
+
+    silk_assert( psEncCtrl->Lambda_Q10 > 0 );
+    silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) );
+}
diff --git a/third_party/opus/src/silk/fixed/regularize_correlations_FIX.c b/third_party/opus/src/silk/fixed/regularize_correlations_FIX.c
new file mode 100644
index 0000000..a2836b0
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/regularize_correlations_FIX.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FIX(
+    opus_int32                      *XX,                                    /* I/O  Correlation matrices                                                        */
+    opus_int32                      *xx,                                    /* I/O  Correlation values                                                          */
+    opus_int32                      noise,                                  /* I    Noise to add                                                                */
+    opus_int                        D                                       /* I    Dimension of XX                                                             */
+)
+{
+    opus_int i;
+    for( i = 0; i < D; i++ ) {
+        matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise );
+    }
+    xx[ 0 ] += noise;
+}
diff --git a/third_party/opus/src/silk/fixed/residual_energy16_FIX.c b/third_party/opus/src/silk/fixed/residual_energy16_FIX.c
new file mode 100644
index 0000000..ebffb2a
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/residual_energy16_FIX.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+opus_int32 silk_residual_energy16_covar_FIX(
+    const opus_int16                *c,                                     /* I    Prediction vector                                                           */
+    const opus_int32                *wXX,                                   /* I    Correlation matrix                                                          */
+    const opus_int32                *wXx,                                   /* I    Correlation vector                                                          */
+    opus_int32                      wxx,                                    /* I    Signal energy                                                               */
+    opus_int                        D,                                      /* I    Dimension                                                                   */
+    opus_int                        cQ                                      /* I    Q value for c vector 0 - 15                                                 */
+)
+{
+    opus_int   i, j, lshifts, Qxtra;
+    opus_int32 c_max, w_max, tmp, tmp2, nrg;
+    opus_int   cn[ MAX_MATRIX_SIZE ];
+    const opus_int32 *pRow;
+
+    /* Safety checks */
+    silk_assert( D >=  0 );
+    silk_assert( D <= 16 );
+    silk_assert( cQ >  0 );
+    silk_assert( cQ < 16 );
+
+    lshifts = 16 - cQ;
+    Qxtra = lshifts;
+
+    c_max = 0;
+    for( i = 0; i < D; i++ ) {
+        c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) );
+    }
+    Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 );
+
+    w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] );
+    Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 );
+    Qxtra = silk_max_int( Qxtra, 0 );
+    for( i = 0; i < D; i++ ) {
+        cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra );
+        silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */
+    }
+    lshifts -= Qxtra;
+
+    /* Compute wxx - 2 * wXx * c */
+    tmp = 0;
+    for( i = 0; i < D; i++ ) {
+        tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] );
+    }
+    nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp;                         /* Q: -lshifts - 1 */
+
+    /* Add c' * wXX * c, assuming wXX is symmetric */
+    tmp2 = 0;
+    for( i = 0; i < D; i++ ) {
+        tmp = 0;
+        pRow = &wXX[ i * D ];
+        for( j = i + 1; j < D; j++ ) {
+            tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] );
+        }
+        tmp  = silk_SMLAWB( tmp,  silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] );
+        tmp2 = silk_SMLAWB( tmp2, tmp,                        cn[ i ] );
+    }
+    nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts );                       /* Q: -lshifts - 1 */
+
+    /* Keep one bit free always, because we add them for LSF interpolation */
+    if( nrg < 1 ) {
+        nrg = 1;
+    } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) {
+        nrg = silk_int32_MAX >> 1;
+    } else {
+        nrg = silk_LSHIFT( nrg, lshifts + 1 );                           /* Q0 */
+    }
+    return nrg;
+
+}
diff --git a/third_party/opus/src/silk/fixed/residual_energy_FIX.c b/third_party/opus/src/silk/fixed/residual_energy_FIX.c
new file mode 100644
index 0000000..41f74778
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/residual_energy_FIX.c
@@ -0,0 +1,98 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order   */
+/* of preceding samples                                                                 */
+void silk_residual_energy_FIX(
+          opus_int32                nrgs[ MAX_NB_SUBFR ],                   /* O    Residual energy per subframe                                                */
+          opus_int                  nrgsQ[ MAX_NB_SUBFR ],                  /* O    Q value per subframe                                                        */
+    const opus_int16                x[],                                    /* I    Input signal                                                                */
+          opus_int16                a_Q12[ 2 ][ MAX_LPC_ORDER ],            /* I    AR coefs for each frame half                                                */
+    const opus_int32                gains[ MAX_NB_SUBFR ],                  /* I    Quantization gains                                                          */
+    const opus_int                  subfr_length,                           /* I    Subframe length                                                             */
+    const opus_int                  nb_subfr,                               /* I    Number of subframes                                                         */
+    const opus_int                  LPC_order,                              /* I    LPC order                                                                   */
+          int                       arch                                    /* I    Run-time architecture                                                       */
+)
+{
+    opus_int         offset, i, j, rshift, lz1, lz2;
+    opus_int16       *LPC_res_ptr;
+    VARDECL( opus_int16, LPC_res );
+    const opus_int16 *x_ptr;
+    opus_int32       tmp32;
+    SAVE_STACK;
+
+    x_ptr  = x;
+    offset = LPC_order + subfr_length;
+
+    /* Filter input to create the LPC residual for each frame half, and measure subframe energies */
+    ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 );
+    silk_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr );
+    for( i = 0; i < nb_subfr >> 1; i++ ) {
+        /* Calculate half frame LPC residual signal including preceding samples */
+        silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order, arch );
+
+        /* Point to first subframe of the just calculated LPC residual signal */
+        LPC_res_ptr = LPC_res + LPC_order;
+        for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) {
+            /* Measure subframe energy */
+            silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length );
+
+            /* Set Q values for the measured energy */
+            nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift;
+
+            /* Move to next subframe */
+            LPC_res_ptr += offset;
+        }
+        /* Move to next frame half */
+        x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset;
+    }
+
+    /* Apply the squared subframe gains */
+    for( i = 0; i < nb_subfr; i++ ) {
+        /* Fully upscale gains and energies */
+        lz1 = silk_CLZ32( nrgs[  i ] ) - 1;
+        lz2 = silk_CLZ32( gains[ i ] ) - 1;
+
+        tmp32 = silk_LSHIFT32( gains[ i ], lz2 );
+
+        /* Find squared gains */
+        tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/
+
+        /* Scale energies */
+        nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/
+        nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32;
+    }
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/fixed/schur64_FIX.c b/third_party/opus/src/silk/fixed/schur64_FIX.c
new file mode 100644
index 0000000..764a10e
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/schur64_FIX.c
@@ -0,0 +1,92 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Slower than schur(), but more accurate.                              */
+/* Uses SMULL(), available on armv4                                     */
+opus_int32 silk_schur64(                            /* O    returns residual energy                                     */
+    opus_int32                  rc_Q16[],           /* O    Reflection coefficients [order] Q16                         */
+    const opus_int32            c[],                /* I    Correlations [order+1]                                      */
+    opus_int32                  order               /* I    Prediction order                                            */
+)
+{
+    opus_int   k, n;
+    opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+    opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31;
+
+    silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+    /* Check for invalid input */
+    if( c[ 0 ] <= 0 ) {
+        silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) );
+        return 0;
+    }
+
+    for( k = 0; k < order + 1; k++ ) {
+        C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
+    }
+
+    for( k = 0; k < order; k++ ) {
+        /* Check that we won't be getting an unstable rc, otherwise stop here. */
+        if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
+           if ( C[ k + 1 ][ 0 ] > 0 ) {
+              rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 );
+           } else {
+              rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 );
+           }
+           k++;
+           break;
+        }
+
+        /* Get reflection coefficient: divide two Q30 values and get result in Q31 */
+        rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 );
+
+        /* Save the output */
+        rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 );
+
+        /* Update correlations */
+        for( n = 0; n < order - k; n++ ) {
+            Ctmp1_Q30 = C[ n + k + 1 ][ 0 ];
+            Ctmp2_Q30 = C[ n ][ 1 ];
+
+            /* Multiply and add the highest int32 */
+            C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 );
+            C[ n ][ 1 ]         = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 );
+        }
+    }
+
+    for(; k < order; k++ ) {
+       rc_Q16[ k ] = 0;
+    }
+
+    return silk_max_32( 1, C[ 0 ][ 1 ] );
+}
diff --git a/third_party/opus/src/silk/fixed/schur_FIX.c b/third_party/opus/src/silk/fixed/schur_FIX.c
new file mode 100644
index 0000000..c4c0ef2
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/schur_FIX.c
@@ -0,0 +1,106 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Faster than schur64(), but much less accurate.                       */
+/* uses SMLAWB(), requiring armv5E and higher.                          */
+opus_int32 silk_schur(                              /* O    Returns residual energy                                     */
+    opus_int16                  *rc_Q15,            /* O    reflection coefficients [order] Q15                         */
+    const opus_int32            *c,                 /* I    correlations [order+1]                                      */
+    const opus_int32            order               /* I    prediction order                                            */
+)
+{
+    opus_int        k, n, lz;
+    opus_int32    C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+    opus_int32    Ctmp1, Ctmp2, rc_tmp_Q15;
+
+    silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+    /* Get number of leading zeros */
+    lz = silk_CLZ32( c[ 0 ] );
+
+    /* Copy correlations and adjust level to Q30 */
+    if( lz < 2 ) {
+        /* lz must be 1, so shift one to the right */
+        for( k = 0; k < order + 1; k++ ) {
+            C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 );
+        }
+    } else if( lz > 2 ) {
+        /* Shift to the left */
+        lz -= 2;
+        for( k = 0; k < order + 1; k++ ) {
+            C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz );
+        }
+    } else {
+        /* No need to shift */
+        for( k = 0; k < order + 1; k++ ) {
+            C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
+        }
+    }
+
+    for( k = 0; k < order; k++ ) {
+        /* Check that we won't be getting an unstable rc, otherwise stop here. */
+        if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
+           if ( C[ k + 1 ][ 0 ] > 0 ) {
+              rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 );
+           } else {
+              rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 );
+           }
+           k++;
+           break;
+        }
+
+        /* Get reflection coefficient */
+        rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) );
+
+        /* Clip (shouldn't happen for properly conditioned inputs) */
+        rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 );
+
+        /* Store */
+        rc_Q15[ k ] = (opus_int16)rc_tmp_Q15;
+
+        /* Update correlations */
+        for( n = 0; n < order - k; n++ ) {
+            Ctmp1 = C[ n + k + 1 ][ 0 ];
+            Ctmp2 = C[ n ][ 1 ];
+            C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 );
+            C[ n ][ 1 ]         = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 );
+        }
+    }
+
+    for(; k < order; k++ ) {
+       rc_Q15[ k ] = 0;
+    }
+
+    /* return residual energy */
+    return silk_max_32( 1, C[ 0 ][ 1 ] );
+}
diff --git a/third_party/opus/src/silk/fixed/solve_LS_FIX.c b/third_party/opus/src/silk/fixed/solve_LS_FIX.c
new file mode 100644
index 0000000..51d7d49d
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/solve_LS_FIX.c
@@ -0,0 +1,249 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/*****************************/
+/* Internal function headers */
+/*****************************/
+
+typedef struct {
+    opus_int32 Q36_part;
+    opus_int32 Q48_part;
+} inv_D_t;
+
+/* Factorize square matrix A into LDL form */
+static OPUS_INLINE void silk_LDL_factorize_FIX(
+    opus_int32          *A,         /* I/O Pointer to Symetric Square Matrix                            */
+    opus_int            M,          /* I   Size of Matrix                                               */
+    opus_int32          *L_Q16,     /* I/O Pointer to Square Upper triangular Matrix                    */
+    inv_D_t             *inv_D      /* I/O Pointer to vector holding inverted diagonal elements of D    */
+);
+
+/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveFirst_FIX(
+    const opus_int32    *L_Q16,     /* I    Pointer to Lower Triangular Matrix                          */
+    opus_int            M,          /* I    Dim of Matrix equation                                      */
+    const opus_int32    *b,         /* I    b Vector                                                    */
+    opus_int32          *x_Q16      /* O    x Vector                                                    */
+);
+
+/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveLast_FIX(
+    const opus_int32    *L_Q16,     /* I    Pointer to Lower Triangular Matrix                          */
+    const opus_int      M,          /* I    Dim of Matrix equation                                      */
+    const opus_int32    *b,         /* I    b Vector                                                    */
+    opus_int32          *x_Q16      /* O    x Vector                                                    */
+);
+
+static OPUS_INLINE void silk_LS_divide_Q16_FIX(
+    opus_int32          T[],        /* I/O  Numenator vector                                            */
+    inv_D_t             *inv_D,     /* I    1 / D vector                                                */
+    opus_int            M           /* I    dimension                                                   */
+);
+
+/* Solves Ax = b, assuming A is symmetric */
+void silk_solve_LDL_FIX(
+    opus_int32                      *A,                                     /* I    Pointer to symetric square matrix A                                         */
+    opus_int                        M,                                      /* I    Size of matrix                                                              */
+    const opus_int32                *b,                                     /* I    Pointer to b vector                                                         */
+    opus_int32                      *x_Q16                                  /* O    Pointer to x solution vector                                                */
+)
+{
+    VARDECL( opus_int32, L_Q16 );
+    opus_int32 Y[      MAX_MATRIX_SIZE ];
+    inv_D_t   inv_D[  MAX_MATRIX_SIZE ];
+    SAVE_STACK;
+
+    silk_assert( M <= MAX_MATRIX_SIZE );
+    ALLOC( L_Q16, M * M, opus_int32 );
+
+    /***************************************************
+    Factorize A by LDL such that A = L*D*L',
+    where L is lower triangular with ones on diagonal
+    ****************************************************/
+    silk_LDL_factorize_FIX( A, M, L_Q16, inv_D );
+
+    /****************************************************
+    * substitute D*L'*x = Y. ie:
+    L*D*L'*x = b => L*Y = b <=> Y = inv(L)*b
+    ******************************************************/
+    silk_LS_SolveFirst_FIX( L_Q16, M, b, Y );
+
+    /****************************************************
+    D*L'*x = Y <=> L'*x = inv(D)*Y, because D is
+    diagonal just multiply with 1/d_i
+    ****************************************************/
+    silk_LS_divide_Q16_FIX( Y, inv_D, M );
+
+    /****************************************************
+    x = inv(L') * inv(D) * Y
+    *****************************************************/
+    silk_LS_SolveLast_FIX( L_Q16, M, Y, x_Q16 );
+    RESTORE_STACK;
+}
+
+static OPUS_INLINE void silk_LDL_factorize_FIX(
+    opus_int32          *A,         /* I/O Pointer to Symetric Square Matrix                            */
+    opus_int            M,          /* I   Size of Matrix                                               */
+    opus_int32          *L_Q16,     /* I/O Pointer to Square Upper triangular Matrix                    */
+    inv_D_t             *inv_D      /* I/O Pointer to vector holding inverted diagonal elements of D    */
+)
+{
+    opus_int   i, j, k, status, loop_count;
+    const opus_int32 *ptr1, *ptr2;
+    opus_int32 diag_min_value, tmp_32, err;
+    opus_int32 v_Q0[ MAX_MATRIX_SIZE ], D_Q0[ MAX_MATRIX_SIZE ];
+    opus_int32 one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48;
+
+    silk_assert( M <= MAX_MATRIX_SIZE );
+
+    status = 1;
+    diag_min_value = silk_max_32( silk_SMMUL( silk_ADD_SAT32( A[ 0 ], A[ silk_SMULBB( M, M ) - 1 ] ), SILK_FIX_CONST( FIND_LTP_COND_FAC, 31 ) ), 1 << 9 );
+    for( loop_count = 0; loop_count < M && status == 1; loop_count++ ) {
+        status = 0;
+        for( j = 0; j < M; j++ ) {
+            ptr1 = matrix_adr( L_Q16, j, 0, M );
+            tmp_32 = 0;
+            for( i = 0; i < j; i++ ) {
+                v_Q0[ i ] = silk_SMULWW(         D_Q0[ i ], ptr1[ i ] ); /* Q0 */
+                tmp_32    = silk_SMLAWW( tmp_32, v_Q0[ i ], ptr1[ i ] ); /* Q0 */
+            }
+            tmp_32 = silk_SUB32( matrix_ptr( A, j, j, M ), tmp_32 );
+
+            if( tmp_32 < diag_min_value ) {
+                tmp_32 = silk_SUB32( silk_SMULBB( loop_count + 1, diag_min_value ), tmp_32 );
+                /* Matrix not positive semi-definite, or ill conditioned */
+                for( i = 0; i < M; i++ ) {
+                    matrix_ptr( A, i, i, M ) = silk_ADD32( matrix_ptr( A, i, i, M ), tmp_32 );
+                }
+                status = 1;
+                break;
+            }
+            D_Q0[ j ] = tmp_32;                         /* always < max(Correlation) */
+
+            /* two-step division */
+            one_div_diag_Q36 = silk_INVERSE32_varQ( tmp_32, 36 );                    /* Q36 */
+            one_div_diag_Q40 = silk_LSHIFT( one_div_diag_Q36, 4 );                   /* Q40 */
+            err = silk_SUB32( (opus_int32)1 << 24, silk_SMULWW( tmp_32, one_div_diag_Q40 ) );     /* Q24 */
+            one_div_diag_Q48 = silk_SMULWW( err, one_div_diag_Q40 );                 /* Q48 */
+
+            /* Save 1/Ds */
+            inv_D[ j ].Q36_part = one_div_diag_Q36;
+            inv_D[ j ].Q48_part = one_div_diag_Q48;
+
+            matrix_ptr( L_Q16, j, j, M ) = 65536; /* 1.0 in Q16 */
+            ptr1 = matrix_adr( A, j, 0, M );
+            ptr2 = matrix_adr( L_Q16, j + 1, 0, M );
+            for( i = j + 1; i < M; i++ ) {
+                tmp_32 = 0;
+                for( k = 0; k < j; k++ ) {
+                    tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ k ], ptr2[ k ] ); /* Q0 */
+                }
+                tmp_32 = silk_SUB32( ptr1[ i ], tmp_32 ); /* always < max(Correlation) */
+
+                /* tmp_32 / D_Q0[j] : Divide to Q16 */
+                matrix_ptr( L_Q16, i, j, M ) = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ),
+                    silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) );
+
+                /* go to next column */
+                ptr2 += M;
+            }
+        }
+    }
+
+    silk_assert( status == 0 );
+}
+
+static OPUS_INLINE void silk_LS_divide_Q16_FIX(
+    opus_int32          T[],        /* I/O  Numenator vector                                            */
+    inv_D_t             *inv_D,     /* I    1 / D vector                                                */
+    opus_int            M           /* I    dimension                                                   */
+)
+{
+    opus_int   i;
+    opus_int32 tmp_32;
+    opus_int32 one_div_diag_Q36, one_div_diag_Q48;
+
+    for( i = 0; i < M; i++ ) {
+        one_div_diag_Q36 = inv_D[ i ].Q36_part;
+        one_div_diag_Q48 = inv_D[ i ].Q48_part;
+
+        tmp_32 = T[ i ];
+        T[ i ] = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) );
+    }
+}
+
+/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveFirst_FIX(
+    const opus_int32    *L_Q16,     /* I    Pointer to Lower Triangular Matrix                          */
+    opus_int            M,          /* I    Dim of Matrix equation                                      */
+    const opus_int32    *b,         /* I    b Vector                                                    */
+    opus_int32          *x_Q16      /* O    x Vector                                                    */
+)
+{
+    opus_int i, j;
+    const opus_int32 *ptr32;
+    opus_int32 tmp_32;
+
+    for( i = 0; i < M; i++ ) {
+        ptr32 = matrix_adr( L_Q16, i, 0, M );
+        tmp_32 = 0;
+        for( j = 0; j < i; j++ ) {
+            tmp_32 = silk_SMLAWW( tmp_32, ptr32[ j ], x_Q16[ j ] );
+        }
+        x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 );
+    }
+}
+
+/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveLast_FIX(
+    const opus_int32    *L_Q16,     /* I    Pointer to Lower Triangular Matrix                          */
+    const opus_int      M,          /* I    Dim of Matrix equation                                      */
+    const opus_int32    *b,         /* I    b Vector                                                    */
+    opus_int32          *x_Q16      /* O    x Vector                                                    */
+)
+{
+    opus_int i, j;
+    const opus_int32 *ptr32;
+    opus_int32 tmp_32;
+
+    for( i = M - 1; i >= 0; i-- ) {
+        ptr32 = matrix_adr( L_Q16, 0, i, M );
+        tmp_32 = 0;
+        for( j = M - 1; j > i; j-- ) {
+            tmp_32 = silk_SMLAWW( tmp_32, ptr32[ silk_SMULBB( j, M ) ], x_Q16[ j ] );
+        }
+        x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 );
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/structs_FIX.h b/third_party/opus/src/silk/fixed/structs_FIX.h
new file mode 100644
index 0000000..3294b25
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/structs_FIX.h
@@ -0,0 +1,134 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_FIX_H
+#define SILK_STRUCTS_FIX_H
+
+#include "typedef.h"
+#include "main.h"
+#include "structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/********************************/
+/* Noise shaping analysis state */
+/********************************/
+typedef struct {
+    opus_int8                   LastGainIndex;
+    opus_int32                  HarmBoost_smth_Q16;
+    opus_int32                  HarmShapeGain_smth_Q16;
+    opus_int32                  Tilt_smth_Q16;
+} silk_shape_state_FIX;
+
+/********************************/
+/* Prefilter state              */
+/********************************/
+typedef struct {
+    opus_int16                  sLTP_shp[ LTP_BUF_LENGTH ];
+    opus_int32                  sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ];
+    opus_int                    sLTP_shp_buf_idx;
+    opus_int32                  sLF_AR_shp_Q12;
+    opus_int32                  sLF_MA_shp_Q12;
+    opus_int32                  sHarmHP_Q2;
+    opus_int32                  rand_seed;
+    opus_int                    lagPrev;
+} silk_prefilter_state_FIX;
+
+/********************************/
+/* Encoder state FIX            */
+/********************************/
+typedef struct {
+    silk_encoder_state          sCmn;                                   /* Common struct, shared with floating-point code       */
+    silk_shape_state_FIX        sShape;                                 /* Shape state                                          */
+    silk_prefilter_state_FIX    sPrefilt;                               /* Prefilter State                                      */
+
+    /* Buffer for find pitch and noise shape analysis */
+    silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis  */
+    opus_int                    LTPCorr_Q15;                            /* Normalized correlation from pitch lag estimator      */
+} silk_encoder_state_FIX;
+
+/************************/
+/* Encoder control FIX  */
+/************************/
+typedef struct {
+    /* Prediction and coding parameters */
+    opus_int32                  Gains_Q16[ MAX_NB_SUBFR ];
+    silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+    opus_int16                  LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+    opus_int                    LTP_scale_Q14;
+    opus_int                    pitchL[ MAX_NB_SUBFR ];
+
+    /* Noise shaping parameters */
+    /* Testing */
+    silk_DWORD_ALIGN opus_int16 AR1_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+    silk_DWORD_ALIGN opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+    opus_int32                  LF_shp_Q14[        MAX_NB_SUBFR ];      /* Packs two int16 coefficients per int32 value         */
+    opus_int                    GainsPre_Q14[      MAX_NB_SUBFR ];
+    opus_int                    HarmBoost_Q14[     MAX_NB_SUBFR ];
+    opus_int                    Tilt_Q14[          MAX_NB_SUBFR ];
+    opus_int                    HarmShapeGain_Q14[ MAX_NB_SUBFR ];
+    opus_int                    Lambda_Q10;
+    opus_int                    input_quality_Q14;
+    opus_int                    coding_quality_Q14;
+
+    /* measures */
+    opus_int                    sparseness_Q8;
+    opus_int32                  predGain_Q16;
+    opus_int                    LTPredCodGain_Q7;
+    opus_int32                  ResNrg[ MAX_NB_SUBFR ];                 /* Residual energy per subframe                         */
+    opus_int                    ResNrgQ[ MAX_NB_SUBFR ];                /* Q domain for the residual energy > 0                 */
+
+    /* Parameters for CBR mode */
+    opus_int32                  GainsUnq_Q16[ MAX_NB_SUBFR ];
+    opus_int8                   lastGainIndexPrev;
+} silk_encoder_control_FIX;
+
+/************************/
+/* Encoder Super Struct */
+/************************/
+typedef struct {
+    silk_encoder_state_FIX      state_Fxx[ ENCODER_NUM_CHANNELS ];
+    stereo_enc_state            sStereo;
+    opus_int32                  nBitsUsedLBRR;
+    opus_int32                  nBitsExceeded;
+    opus_int                    nChannelsAPI;
+    opus_int                    nChannelsInternal;
+    opus_int                    nPrevChannelsInternal;
+    opus_int                    timeSinceSwitchAllowed_ms;
+    opus_int                    allowBandwidthSwitch;
+    opus_int                    prev_decode_only_middle;
+} silk_encoder;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/fixed/vector_ops_FIX.c b/third_party/opus/src/silk/fixed/vector_ops_FIX.c
new file mode 100644
index 0000000..d9498001
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/vector_ops_FIX.c
@@ -0,0 +1,102 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "pitch.h"
+
+/* Copy and multiply a vector by a constant */
+void silk_scale_copy_vector16(
+    opus_int16                  *data_out,
+    const opus_int16            *data_in,
+    opus_int32                  gain_Q16,           /* I    Gain in Q16                                                 */
+    const opus_int              dataSize            /* I    Length                                                      */
+)
+{
+    opus_int  i;
+    opus_int32 tmp32;
+
+    for( i = 0; i < dataSize; i++ ) {
+        tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] );
+        data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 );
+    }
+}
+
+/* Multiply a vector by a constant */
+void silk_scale_vector32_Q26_lshift_18(
+    opus_int32                  *data1,             /* I/O  Q0/Q18                                                      */
+    opus_int32                  gain_Q26,           /* I    Q26                                                         */
+    opus_int                    dataSize            /* I    length                                                      */
+)
+{
+    opus_int  i;
+
+    for( i = 0; i < dataSize; i++ ) {
+        data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) );    /* OUTPUT: Q18 */
+    }
+}
+
+/* sum = for(i=0;i<len;i++)inVec1[i]*inVec2[i];      ---        inner product   */
+/* Note for ARM asm:                                                            */
+/*        * inVec1 and inVec2 should be at least 2 byte aligned.                */
+/*        * len should be positive 16bit integer.                               */
+/*        * only when len>6, memory access can be reduced by half.              */
+opus_int32 silk_inner_prod_aligned(
+    const opus_int16 *const     inVec1,             /*    I input vector 1                                              */
+    const opus_int16 *const     inVec2,             /*    I input vector 2                                              */
+    const opus_int              len,                /*    I vector lengths                                              */
+    int                         arch                /*    I Run-time architecture                                       */
+)
+{
+#ifdef FIXED_POINT
+   return celt_inner_prod(inVec1, inVec2, len, arch);
+#else
+    opus_int   i;
+    opus_int32 sum = 0;
+    for( i = 0; i < len; i++ ) {
+        sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] );
+    }
+    return sum;
+#endif
+}
+
+opus_int64 silk_inner_prod16_aligned_64_c(
+    const opus_int16            *inVec1,            /*    I input vector 1                                              */
+    const opus_int16            *inVec2,            /*    I input vector 2                                              */
+    const opus_int              len                 /*    I vector lengths                                              */
+)
+{
+    opus_int   i;
+    opus_int64 sum = 0;
+    for( i = 0; i < len; i++ ) {
+        sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] );
+    }
+    return sum;
+}
diff --git a/third_party/opus/src/silk/fixed/warped_autocorrelation_FIX.c b/third_party/opus/src/silk/fixed/warped_autocorrelation_FIX.c
new file mode 100644
index 0000000..6ca6c118
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/warped_autocorrelation_FIX.c
@@ -0,0 +1,95 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+#define QC  10
+#define QS  14
+
+#if defined(MIPSr1_ASM)
+#include "mips/warped_autocorrelation_FIX_mipsr1.h"
+#endif
+
+
+#ifndef OVERRIDE_silk_warped_autocorrelation_FIX
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FIX(
+          opus_int32                *corr,                                  /* O    Result [order + 1]                                                          */
+          opus_int                  *scale,                                 /* O    Scaling of the correlation vector                                           */
+    const opus_int16                *input,                                 /* I    Input data to correlate                                                     */
+    const opus_int                  warping_Q16,                            /* I    Warping coefficient                                                         */
+    const opus_int                  length,                                 /* I    Length of input                                                             */
+    const opus_int                  order                                   /* I    Correlation order (even)                                                    */
+)
+{
+    opus_int   n, i, lsh;
+    opus_int32 tmp1_QS, tmp2_QS;
+    opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+    opus_int64 corr_QC[  MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+
+    /* Order must be even */
+    silk_assert( ( order & 1 ) == 0 );
+    silk_assert( 2 * QS - QC >= 0 );
+
+    /* Loop over samples */
+    for( n = 0; n < length; n++ ) {
+        tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
+        /* Loop over allpass sections */
+        for( i = 0; i < order; i += 2 ) {
+            /* Output of allpass section */
+            tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
+            state_QS[ i ]  = tmp1_QS;
+            corr_QC[  i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
+            /* Output of allpass section */
+            tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
+            state_QS[ i + 1 ]  = tmp2_QS;
+            corr_QC[  i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC );
+        }
+        state_QS[ order ] = tmp1_QS;
+        corr_QC[  order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
+    }
+
+    lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35;
+    lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
+    *scale = -( QC + lsh );
+    silk_assert( *scale >= -30 && *scale <= 12 );
+    if( lsh >= 0 ) {
+        for( i = 0; i < order + 1; i++ ) {
+            corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) );
+        }
+    } else {
+        for( i = 0; i < order + 1; i++ ) {
+            corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) );
+        }
+    }
+    silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
+}
+#endif /* OVERRIDE_silk_warped_autocorrelation_FIX */
diff --git a/third_party/opus/src/silk/fixed/x86/burg_modified_FIX_sse.c b/third_party/opus/src/silk/fixed/x86/burg_modified_FIX_sse.c
new file mode 100644
index 0000000..3c3583c
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/x86/burg_modified_FIX_sse.c
@@ -0,0 +1,377 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+
+#include "SigProc_FIX.h"
+#include "define.h"
+#include "tuning_parameters.h"
+#include "pitch.h"
+#include "celt/x86/x86cpu.h"
+
+#define MAX_FRAME_SIZE              384             /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
+
+#define QA                          25
+#define N_BITS_HEAD_ROOM            2
+#define MIN_RSHIFTS                 -16
+#define MAX_RSHIFTS                 (32 - QA)
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified_sse4_1(
+    opus_int32                  *res_nrg,           /* O    Residual energy                                             */
+    opus_int                    *res_nrg_Q,         /* O    Residual energy Q value                                     */
+    opus_int32                  A_Q16[],            /* O    Prediction coefficients (length order)                      */
+    const opus_int16            x[],                /* I    Input signal, length: nb_subfr * ( D + subfr_length )       */
+    const opus_int32            minInvGain_Q30,     /* I    Inverse of max prediction gain                              */
+    const opus_int              subfr_length,       /* I    Input signal subframe length (incl. D preceding samples)    */
+    const opus_int              nb_subfr,           /* I    Number of subframes stacked in x                            */
+    const opus_int              D,                  /* I    Order                                                       */
+    int                         arch                /* I    Run-time architecture                                       */
+)
+{
+    opus_int         k, n, s, lz, rshifts, rshifts_extra, reached_max_gain;
+    opus_int32       C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
+    const opus_int16 *x_ptr;
+    opus_int32       C_first_row[ SILK_MAX_ORDER_LPC ];
+    opus_int32       C_last_row[  SILK_MAX_ORDER_LPC ];
+    opus_int32       Af_QA[       SILK_MAX_ORDER_LPC ];
+    opus_int32       CAf[ SILK_MAX_ORDER_LPC + 1 ];
+    opus_int32       CAb[ SILK_MAX_ORDER_LPC + 1 ];
+    opus_int32       xcorr[ SILK_MAX_ORDER_LPC ];
+
+    __m128i FIRST_3210, LAST_3210, ATMP_3210, TMP1_3210, TMP2_3210, T1_3210, T2_3210, PTR_3210, SUBFR_3210, X1_3210, X2_3210;
+    __m128i CONST1 = _mm_set1_epi32(1);
+
+    silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+    /* Compute autocorrelations, added over subframes */
+    silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length );
+    if( rshifts > MAX_RSHIFTS ) {
+        C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS );
+        silk_assert( C0 > 0 );
+        rshifts = MAX_RSHIFTS;
+    } else {
+        lz = silk_CLZ32( C0 ) - 1;
+        rshifts_extra = N_BITS_HEAD_ROOM - lz;
+        if( rshifts_extra > 0 ) {
+            rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts );
+            C0 = silk_RSHIFT32( C0, rshifts_extra );
+        } else {
+            rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts );
+            C0 = silk_LSHIFT32( C0, -rshifts_extra );
+        }
+        rshifts += rshifts_extra;
+    }
+    CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1;                                /* Q(-rshifts) */
+    silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+    if( rshifts > 0 ) {
+        for( s = 0; s < nb_subfr; s++ ) {
+            x_ptr = x + s * subfr_length;
+            for( n = 1; n < D + 1; n++ ) {
+                C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64(
+                    silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts );
+            }
+        }
+    } else {
+        for( s = 0; s < nb_subfr; s++ ) {
+            int i;
+            opus_int32 d;
+            x_ptr = x + s * subfr_length;
+            celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch );
+            for( n = 1; n < D + 1; n++ ) {
+               for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ )
+                  d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] );
+               xcorr[ n - 1 ] += d;
+            }
+            for( n = 1; n < D + 1; n++ ) {
+                C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts );
+            }
+        }
+    }
+    silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+
+    /* Initialize */
+    CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1;                                /* Q(-rshifts) */
+
+    invGain_Q30 = (opus_int32)1 << 30;
+    reached_max_gain = 0;
+    for( n = 0; n < D; n++ ) {
+        /* Update first row of correlation matrix (without first element) */
+        /* Update last row of correlation matrix (without last element, stored in reversed order) */
+        /* Update C * Af */
+        /* Update C * flipud(Af) (stored in reversed order) */
+        if( rshifts > -2 ) {
+            for( s = 0; s < nb_subfr; s++ ) {
+                x_ptr = x + s * subfr_length;
+                x1  = -silk_LSHIFT32( (opus_int32)x_ptr[ n ],                    16 - rshifts );        /* Q(16-rshifts) */
+                x2  = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts );        /* Q(16-rshifts) */
+                tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ],                    QA - 16 );             /* Q(QA-16) */
+                tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 );             /* Q(QA-16) */
+                for( k = 0; k < n; k++ ) {
+                    C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ]            ); /* Q( -rshifts ) */
+                    C_last_row[ k ]  = silk_SMLAWB( C_last_row[ k ],  x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+                    Atmp_QA = Af_QA[ k ];
+                    tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ]            );                 /* Q(QA-16) */
+                    tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] );                 /* Q(QA-16) */
+                }
+                tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts );                                       /* Q(16-rshifts) */
+                tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts );                                       /* Q(16-rshifts) */
+                for( k = 0; k <= n; k++ ) {
+                    CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ]                    );        /* Q( -rshift ) */
+                    CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] );        /* Q( -rshift ) */
+                }
+            }
+        } else {
+            for( s = 0; s < nb_subfr; s++ ) {
+                x_ptr = x + s * subfr_length;
+                x1  = -silk_LSHIFT32( (opus_int32)x_ptr[ n ],                    -rshifts );            /* Q( -rshifts ) */
+                x2  = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts );            /* Q( -rshifts ) */
+                tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ],                    17 );                  /* Q17 */
+                tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 );                  /* Q17 */
+
+                X1_3210 = _mm_set1_epi32( x1 );
+                X2_3210 = _mm_set1_epi32( x2 );
+                TMP1_3210 = _mm_setzero_si128();
+                TMP2_3210 = _mm_setzero_si128();
+                for( k = 0; k < n - 3; k += 4 ) {
+                    PTR_3210   = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 1 - 3 ] );
+                    SUBFR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k ] );
+                    FIRST_3210 = _mm_loadu_si128( (__m128i *)&C_first_row[ k ] );
+                    PTR_3210   = _mm_shuffle_epi32( PTR_3210,  _MM_SHUFFLE( 0, 1, 2, 3 ) );
+                    LAST_3210  = _mm_loadu_si128( (__m128i *)&C_last_row[ k ] );
+                    ATMP_3210  = _mm_loadu_si128( (__m128i *)&Af_QA[ k ] );
+
+                    T1_3210 = _mm_mullo_epi32( PTR_3210, X1_3210 );
+                    T2_3210 = _mm_mullo_epi32( SUBFR_3210, X2_3210 );
+
+                    ATMP_3210 = _mm_srai_epi32( ATMP_3210, 7 );
+                    ATMP_3210 = _mm_add_epi32( ATMP_3210, CONST1 );
+                    ATMP_3210 = _mm_srai_epi32( ATMP_3210, 1 );
+
+                    FIRST_3210 = _mm_add_epi32( FIRST_3210, T1_3210 );
+                    LAST_3210 = _mm_add_epi32( LAST_3210, T2_3210 );
+
+                    PTR_3210   = _mm_mullo_epi32( ATMP_3210, PTR_3210 );
+                    SUBFR_3210   = _mm_mullo_epi32( ATMP_3210, SUBFR_3210 );
+
+                    _mm_storeu_si128( (__m128i *)&C_first_row[ k ], FIRST_3210 );
+                    _mm_storeu_si128( (__m128i *)&C_last_row[ k ], LAST_3210 );
+
+                    TMP1_3210 = _mm_add_epi32( TMP1_3210, PTR_3210 );
+                    TMP2_3210 = _mm_add_epi32( TMP2_3210, SUBFR_3210 );
+                }
+
+                TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_unpackhi_epi64(TMP1_3210, TMP1_3210 ) );
+                TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_unpackhi_epi64(TMP2_3210, TMP2_3210 ) );
+                TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_shufflelo_epi16(TMP1_3210, 0x0E ) );
+                TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_shufflelo_epi16(TMP2_3210, 0x0E ) );
+
+                tmp1 += _mm_cvtsi128_si32( TMP1_3210 );
+                tmp2 += _mm_cvtsi128_si32( TMP2_3210 );
+
+                for( ; k < n; k++ ) {
+                    C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ]            ); /* Q( -rshifts ) */
+                    C_last_row[ k ]  = silk_MLA( C_last_row[ k ],  x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+                    Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 );                                   /* Q17 */
+                    tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ],            Atmp1 );                      /* Q17 */
+                    tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 );                      /* Q17 */
+                }
+
+                tmp1 = -tmp1;                /* Q17 */
+                tmp2 = -tmp2;                /* Q17 */
+
+                {
+                    __m128i xmm_tmp1, xmm_tmp2;
+                    __m128i xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1;
+                    __m128i xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1;
+
+                    xmm_tmp1 = _mm_set1_epi32( tmp1 );
+                    xmm_tmp2 = _mm_set1_epi32( tmp2 );
+
+                    for( k = 0; k <= n - 3; k += 4 ) {
+                        xmm_x_ptr_n_k_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 3 ] );
+                        xmm_x_ptr_sub_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k - 1 ] );
+
+                        xmm_x_ptr_n_k_x2x0 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+
+                        xmm_x_ptr_n_k_x2x0 = _mm_slli_epi32( xmm_x_ptr_n_k_x2x0, -rshifts - 1 );
+                        xmm_x_ptr_sub_x2x0 = _mm_slli_epi32( xmm_x_ptr_sub_x2x0, -rshifts - 1 );
+
+                        /* equal shift right 4 bytes, xmm_x_ptr_n_k_x3x1 = _mm_srli_si128(xmm_x_ptr_n_k_x2x0, 4)*/
+                        xmm_x_ptr_n_k_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+                        xmm_x_ptr_sub_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_sub_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+                        xmm_x_ptr_n_k_x2x0 = _mm_mul_epi32( xmm_x_ptr_n_k_x2x0, xmm_tmp1 );
+                        xmm_x_ptr_n_k_x3x1 = _mm_mul_epi32( xmm_x_ptr_n_k_x3x1, xmm_tmp1 );
+                        xmm_x_ptr_sub_x2x0 = _mm_mul_epi32( xmm_x_ptr_sub_x2x0, xmm_tmp2 );
+                        xmm_x_ptr_sub_x3x1 = _mm_mul_epi32( xmm_x_ptr_sub_x3x1, xmm_tmp2 );
+
+                        xmm_x_ptr_n_k_x2x0 = _mm_srli_epi64( xmm_x_ptr_n_k_x2x0, 16 );
+                        xmm_x_ptr_n_k_x3x1 = _mm_slli_epi64( xmm_x_ptr_n_k_x3x1, 16 );
+                        xmm_x_ptr_sub_x2x0 = _mm_srli_epi64( xmm_x_ptr_sub_x2x0, 16 );
+                        xmm_x_ptr_sub_x3x1 = _mm_slli_epi64( xmm_x_ptr_sub_x3x1, 16 );
+
+                        xmm_x_ptr_n_k_x2x0 = _mm_blend_epi16( xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1, 0xCC );
+                        xmm_x_ptr_sub_x2x0 = _mm_blend_epi16( xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1, 0xCC );
+
+                        X1_3210  = _mm_loadu_si128( (__m128i *)&CAf[ k ] );
+                        PTR_3210 = _mm_loadu_si128( (__m128i *)&CAb[ k ] );
+
+                        X1_3210  = _mm_add_epi32( X1_3210, xmm_x_ptr_n_k_x2x0 );
+                        PTR_3210 = _mm_add_epi32( PTR_3210, xmm_x_ptr_sub_x2x0 );
+
+                        _mm_storeu_si128( (__m128i *)&CAf[ k ], X1_3210 );
+                        _mm_storeu_si128( (__m128i *)&CAb[ k ], PTR_3210 );
+                    }
+
+                    for( ; k <= n; k++ ) {
+                        CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1,
+                            silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) );                    /* Q( -rshift ) */
+                        CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2,
+                            silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */
+                    }
+                }
+            }
+        }
+
+        /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+        tmp1 = C_first_row[ n ];                                                                        /* Q( -rshifts ) */
+        tmp2 = C_last_row[ n ];                                                                         /* Q( -rshifts ) */
+        num  = 0;                                                                                       /* Q( -rshifts ) */
+        nrg  = silk_ADD32( CAb[ 0 ], CAf[ 0 ] );                                                        /* Q( 1-rshifts ) */
+        for( k = 0; k < n; k++ ) {
+            Atmp_QA = Af_QA[ k ];
+            lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1;
+            lz = silk_min( 32 - QA, lz );
+            Atmp1 = silk_LSHIFT32( Atmp_QA, lz );                                                       /* Q( QA + lz ) */
+
+            tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[  n - k - 1 ], Atmp1 ), 32 - QA - lz );  /* Q( -rshifts ) */
+            tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz );  /* Q( -rshifts ) */
+            num  = silk_ADD_LSHIFT32( num,  silk_SMMUL( CAb[ n - k ],             Atmp1 ), 32 - QA - lz );  /* Q( -rshifts ) */
+            nrg  = silk_ADD_LSHIFT32( nrg,  silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ),
+                                                                                Atmp1 ), 32 - QA - lz );    /* Q( 1-rshifts ) */
+        }
+        CAf[ n + 1 ] = tmp1;                                                                            /* Q( -rshifts ) */
+        CAb[ n + 1 ] = tmp2;                                                                            /* Q( -rshifts ) */
+        num = silk_ADD32( num, tmp2 );                                                                  /* Q( -rshifts ) */
+        num = silk_LSHIFT32( -num, 1 );                                                                 /* Q( 1-rshifts ) */
+
+        /* Calculate the next order reflection (parcor) coefficient */
+        if( silk_abs( num ) < nrg ) {
+            rc_Q31 = silk_DIV32_varQ( num, nrg, 31 );
+        } else {
+            rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN;
+        }
+
+        /* Update inverse prediction gain */
+        tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+        tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 );
+        if( tmp1 <= minInvGain_Q30 ) {
+            /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+            tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 );            /* Q30 */
+            rc_Q31 = silk_SQRT_APPROX( tmp2 );                                                  /* Q15 */
+            if( rc_Q31 > 0 ) {
+                 /* Newton-Raphson iteration */
+                rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 );                   /* Q15 */
+                rc_Q31 = silk_LSHIFT32( rc_Q31, 16 );                                               /* Q31 */
+                if( num < 0 ) {
+                    /* Ensure adjusted reflection coefficients has the original sign */
+                    rc_Q31 = -rc_Q31;
+                }
+            }
+            invGain_Q30 = minInvGain_Q30;
+            reached_max_gain = 1;
+        } else {
+            invGain_Q30 = tmp1;
+        }
+
+        /* Update the AR coefficients */
+        for( k = 0; k < (n + 1) >> 1; k++ ) {
+            tmp1 = Af_QA[ k ];                                                                  /* QA */
+            tmp2 = Af_QA[ n - k - 1 ];                                                          /* QA */
+            Af_QA[ k ]         = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 );      /* QA */
+            Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 );      /* QA */
+        }
+        Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA );                                          /* QA */
+
+        if( reached_max_gain ) {
+            /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+            for( k = n + 1; k < D; k++ ) {
+                Af_QA[ k ] = 0;
+            }
+            break;
+        }
+
+        /* Update C * Af and C * Ab */
+        for( k = 0; k <= n + 1; k++ ) {
+            tmp1 = CAf[ k ];                                                                    /* Q( -rshifts ) */
+            tmp2 = CAb[ n - k + 1 ];                                                            /* Q( -rshifts ) */
+            CAf[ k ]         = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 );        /* Q( -rshifts ) */
+            CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 );        /* Q( -rshifts ) */
+        }
+    }
+
+    if( reached_max_gain ) {
+        for( k = 0; k < D; k++ ) {
+            /* Scale coefficients */
+            A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );
+        }
+        /* Subtract energy of preceding samples from C0 */
+        if( rshifts > 0 ) {
+            for( s = 0; s < nb_subfr; s++ ) {
+                x_ptr = x + s * subfr_length;
+                C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts );
+            }
+        } else {
+            for( s = 0; s < nb_subfr; s++ ) {
+                x_ptr = x + s * subfr_length;
+                C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch ), -rshifts );
+            }
+        }
+        /* Approximate residual energy */
+        *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 );
+        *res_nrg_Q = -rshifts;
+    } else {
+        /* Return residual energy */
+        nrg  = CAf[ 0 ];                                                                            /* Q( -rshifts ) */
+        tmp1 = (opus_int32)1 << 16;                                                                             /* Q16 */
+        for( k = 0; k < D; k++ ) {
+            Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );                                       /* Q16 */
+            nrg  = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 );                                         /* Q( -rshifts ) */
+            tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 );                                               /* Q16 */
+            A_Q16[ k ] = -Atmp1;
+        }
+        *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
+        *res_nrg_Q = -rshifts;
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/x86/prefilter_FIX_sse.c b/third_party/opus/src/silk/fixed/x86/prefilter_FIX_sse.c
new file mode 100644
index 0000000..488a603
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/x86/prefilter_FIX_sse.c
@@ -0,0 +1,160 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "main.h"
+#include "celt/x86/x86cpu.h"
+
+void silk_warped_LPC_analysis_filter_FIX_sse4_1(
+    opus_int32                  state[],                    /* I/O  State [order + 1]                   */
+    opus_int32                  res_Q2[],                   /* O    Residual signal [length]            */
+    const opus_int16            coef_Q13[],                 /* I    Coefficients [order]                */
+    const opus_int16            input[],                    /* I    Input signal [length]               */
+    const opus_int16            lambda_Q16,                 /* I    Warping factor                      */
+    const opus_int              length,                     /* I    Length of input signal              */
+    const opus_int              order                       /* I    Filter order (even)                 */
+)
+{
+    opus_int     n, i;
+    opus_int32   acc_Q11, tmp1, tmp2;
+
+    /* Order must be even */
+    silk_assert( ( order & 1 ) == 0 );
+
+    if (order == 10)
+    {
+        if (0 == lambda_Q16)
+        {
+            __m128i coef_Q13_3210, coef_Q13_7654;
+            __m128i coef_Q13_0123, coef_Q13_4567;
+            __m128i state_0123, state_4567;
+            __m128i xmm_product1, xmm_product2;
+            __m128i xmm_tempa, xmm_tempb;
+
+            register opus_int32 sum;
+            register opus_int32 state_8, state_9, state_a;
+            register opus_int64 coef_Q13_8, coef_Q13_9;
+
+            silk_assert( length > 0 );
+
+            coef_Q13_3210 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 0 ] );
+            coef_Q13_7654 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 4 ] );
+
+            coef_Q13_0123 = _mm_shuffle_epi32( coef_Q13_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+            coef_Q13_4567 = _mm_shuffle_epi32( coef_Q13_7654, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+
+            coef_Q13_8 = (opus_int64) coef_Q13[ 8 ];
+            coef_Q13_9 = (opus_int64) coef_Q13[ 9 ];
+
+            state_0123 = _mm_loadu_si128( (__m128i *)(&state[ 0 ] ) );
+            state_4567 = _mm_loadu_si128( (__m128i *)(&state[ 4 ] ) );
+
+            state_0123 = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+            state_4567 = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+
+            state_8 = state[ 8 ];
+            state_9 = state[ 9 ];
+            state_a = 0;
+
+            for( n = 0; n < length; n++ )
+            {
+                xmm_product1 = _mm_mul_epi32( coef_Q13_0123, state_0123 ); /* 64-bit multiply, only 2 pairs */
+                xmm_product2 = _mm_mul_epi32( coef_Q13_4567, state_4567 );
+
+                xmm_tempa = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+                xmm_tempb = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+
+                xmm_product1 = _mm_srli_epi64( xmm_product1, 16 ); /* >> 16, zero extending works */
+                xmm_product2 = _mm_srli_epi64( xmm_product2, 16 );
+
+                xmm_tempa = _mm_mul_epi32( coef_Q13_3210, xmm_tempa );
+                xmm_tempb = _mm_mul_epi32( coef_Q13_7654, xmm_tempb );
+
+                xmm_tempa = _mm_srli_epi64( xmm_tempa, 16 );
+                xmm_tempb = _mm_srli_epi64( xmm_tempb, 16 );
+
+                xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_product1 );
+                xmm_tempb = _mm_add_epi32( xmm_tempb, xmm_product2 );
+                xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_tempb );
+
+                sum  = (coef_Q13_8 * state_8) >> 16;
+                sum += (coef_Q13_9 * state_9) >> 16;
+
+                xmm_tempa = _mm_add_epi32( xmm_tempa, _mm_shuffle_epi32( xmm_tempa, _MM_SHUFFLE( 0, 0, 0, 2 ) ) );
+                sum += _mm_cvtsi128_si32( xmm_tempa);
+                res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( ( 5 + sum ), 9);
+
+                /* move right */
+                state_a = state_9;
+                state_9 = state_8;
+                state_8 = _mm_cvtsi128_si32( state_4567 );
+                state_4567 = _mm_alignr_epi8( state_0123, state_4567, 4 );
+
+                state_0123 = _mm_alignr_epi8( _mm_cvtsi32_si128( silk_LSHIFT( input[ n ], 14 ) ), state_0123, 4 );
+            }
+
+            _mm_storeu_si128( (__m128i *)( &state[ 0 ] ), _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ) );
+            _mm_storeu_si128( (__m128i *)( &state[ 4 ] ), _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ) );
+            state[ 8 ] = state_8;
+            state[ 9 ] = state_9;
+            state[ 10 ] = state_a;
+
+            return;
+        }
+    }
+
+    for( n = 0; n < length; n++ ) {
+        /* Output of lowpass section */
+        tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 );
+        state[ 0 ] = silk_LSHIFT( input[ n ], 14 );
+        /* Output of allpass section */
+        tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 );
+        state[ 1 ] = tmp2;
+        acc_Q11 = silk_RSHIFT( order, 1 );
+        acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] );
+        /* Loop over allpass sections */
+        for( i = 2; i < order; i += 2 ) {
+            /* Output of allpass section */
+            tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 );
+            state[ i ] = tmp1;
+            acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] );
+            /* Output of allpass section */
+            tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 );
+            state[ i + 1 ] = tmp2;
+            acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] );
+        }
+        state[ order ] = tmp1;
+        acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] );
+        res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 );
+    }
+}
diff --git a/third_party/opus/src/silk/fixed/x86/vector_ops_FIX_sse.c b/third_party/opus/src/silk/fixed/x86/vector_ops_FIX_sse.c
new file mode 100644
index 0000000..c1e9056
--- /dev/null
+++ b/third_party/opus/src/silk/fixed/x86/vector_ops_FIX_sse.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "main.h"
+
+#include "SigProc_FIX.h"
+#include "pitch.h"
+
+opus_int64 silk_inner_prod16_aligned_64_sse4_1(
+    const opus_int16            *inVec1,            /*    I input vector 1                                              */
+    const opus_int16            *inVec2,            /*    I input vector 2                                              */
+    const opus_int              len                 /*    I vector lengths                                              */
+)
+{
+    opus_int  i, dataSize8;
+    opus_int64 sum;
+
+    __m128i xmm_tempa;
+    __m128i inVec1_76543210, acc1;
+    __m128i inVec2_76543210, acc2;
+
+    sum = 0;
+    dataSize8 = len & ~7;
+
+    acc1 = _mm_setzero_si128();
+    acc2 = _mm_setzero_si128();
+
+    for( i = 0; i < dataSize8; i += 8 ) {
+        inVec1_76543210 = _mm_loadu_si128( (__m128i *)(&inVec1[i + 0] ) );
+        inVec2_76543210 = _mm_loadu_si128( (__m128i *)(&inVec2[i + 0] ) );
+
+        /* only when all 4 operands are -32768 (0x8000), this results in wrap around */
+        inVec1_76543210 = _mm_madd_epi16( inVec1_76543210, inVec2_76543210 );
+
+        xmm_tempa       = _mm_cvtepi32_epi64( inVec1_76543210 );
+        /* equal shift right 8 bytes */
+        inVec1_76543210 = _mm_shuffle_epi32( inVec1_76543210, _MM_SHUFFLE( 0, 0, 3, 2 ) );
+        inVec1_76543210 = _mm_cvtepi32_epi64( inVec1_76543210 );
+
+        acc1 = _mm_add_epi64( acc1, xmm_tempa );
+        acc2 = _mm_add_epi64( acc2, inVec1_76543210 );
+    }
+
+    acc1 = _mm_add_epi64( acc1, acc2 );
+
+    /* equal shift right 8 bytes */
+    acc2 = _mm_shuffle_epi32( acc1, _MM_SHUFFLE( 0, 0, 3, 2 ) );
+    acc1 = _mm_add_epi64( acc1, acc2 );
+
+    _mm_storel_epi64( (__m128i *)&sum, acc1 );
+
+    for( ; i < len; i++ ) {
+        sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] );
+    }
+
+    return sum;
+}
diff --git a/third_party/opus/src/silk/float/LPC_analysis_filter_FLP.c b/third_party/opus/src/silk/float/LPC_analysis_filter_FLP.c
new file mode 100644
index 0000000..cae89a0a
--- /dev/null
+++ b/third_party/opus/src/silk/float/LPC_analysis_filter_FLP.c
@@ -0,0 +1,249 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include "main_FLP.h"
+
+/************************************************/
+/* LPC analysis filter                          */
+/* NB! State is kept internally and the         */
+/* filter always starts with zero state         */
+/* first Order output samples are set to zero   */
+/************************************************/
+
+/* 16th order LPC analysis filter, does not write first 16 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter16_FLP(
+          silk_float                 r_LPC[],            /* O    LPC residual signal                     */
+    const silk_float                 PredCoef[],         /* I    LPC coefficients                        */
+    const silk_float                 s[],                /* I    Input signal                            */
+    const opus_int                   length              /* I    Length of input signal                  */
+)
+{
+    opus_int   ix;
+    silk_float LPC_pred;
+    const silk_float *s_ptr;
+
+    for( ix = 16; ix < length; ix++ ) {
+        s_ptr = &s[ix - 1];
+
+        /* short-term prediction */
+        LPC_pred = s_ptr[  0 ]  * PredCoef[ 0 ]  +
+                   s_ptr[ -1 ]  * PredCoef[ 1 ]  +
+                   s_ptr[ -2 ]  * PredCoef[ 2 ]  +
+                   s_ptr[ -3 ]  * PredCoef[ 3 ]  +
+                   s_ptr[ -4 ]  * PredCoef[ 4 ]  +
+                   s_ptr[ -5 ]  * PredCoef[ 5 ]  +
+                   s_ptr[ -6 ]  * PredCoef[ 6 ]  +
+                   s_ptr[ -7 ]  * PredCoef[ 7 ]  +
+                   s_ptr[ -8 ]  * PredCoef[ 8 ]  +
+                   s_ptr[ -9 ]  * PredCoef[ 9 ]  +
+                   s_ptr[ -10 ] * PredCoef[ 10 ] +
+                   s_ptr[ -11 ] * PredCoef[ 11 ] +
+                   s_ptr[ -12 ] * PredCoef[ 12 ] +
+                   s_ptr[ -13 ] * PredCoef[ 13 ] +
+                   s_ptr[ -14 ] * PredCoef[ 14 ] +
+                   s_ptr[ -15 ] * PredCoef[ 15 ];
+
+        /* prediction error */
+        r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+    }
+}
+
+/* 12th order LPC analysis filter, does not write first 12 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter12_FLP(
+          silk_float                 r_LPC[],            /* O    LPC residual signal                     */
+    const silk_float                 PredCoef[],         /* I    LPC coefficients                        */
+    const silk_float                 s[],                /* I    Input signal                            */
+    const opus_int                   length              /* I    Length of input signal                  */
+)
+{
+    opus_int   ix;
+    silk_float LPC_pred;
+    const silk_float *s_ptr;
+
+    for( ix = 12; ix < length; ix++ ) {
+        s_ptr = &s[ix - 1];
+
+        /* short-term prediction */
+        LPC_pred = s_ptr[  0 ]  * PredCoef[ 0 ]  +
+                   s_ptr[ -1 ]  * PredCoef[ 1 ]  +
+                   s_ptr[ -2 ]  * PredCoef[ 2 ]  +
+                   s_ptr[ -3 ]  * PredCoef[ 3 ]  +
+                   s_ptr[ -4 ]  * PredCoef[ 4 ]  +
+                   s_ptr[ -5 ]  * PredCoef[ 5 ]  +
+                   s_ptr[ -6 ]  * PredCoef[ 6 ]  +
+                   s_ptr[ -7 ]  * PredCoef[ 7 ]  +
+                   s_ptr[ -8 ]  * PredCoef[ 8 ]  +
+                   s_ptr[ -9 ]  * PredCoef[ 9 ]  +
+                   s_ptr[ -10 ] * PredCoef[ 10 ] +
+                   s_ptr[ -11 ] * PredCoef[ 11 ];
+
+        /* prediction error */
+        r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+    }
+}
+
+/* 10th order LPC analysis filter, does not write first 10 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter10_FLP(
+          silk_float                 r_LPC[],            /* O    LPC residual signal                     */
+    const silk_float                 PredCoef[],         /* I    LPC coefficients                        */
+    const silk_float                 s[],                /* I    Input signal                            */
+    const opus_int                   length              /* I    Length of input signal                  */
+)
+{
+    opus_int   ix;
+    silk_float LPC_pred;
+    const silk_float *s_ptr;
+
+    for( ix = 10; ix < length; ix++ ) {
+        s_ptr = &s[ix - 1];
+
+        /* short-term prediction */
+        LPC_pred = s_ptr[  0 ] * PredCoef[ 0 ]  +
+                   s_ptr[ -1 ] * PredCoef[ 1 ]  +
+                   s_ptr[ -2 ] * PredCoef[ 2 ]  +
+                   s_ptr[ -3 ] * PredCoef[ 3 ]  +
+                   s_ptr[ -4 ] * PredCoef[ 4 ]  +
+                   s_ptr[ -5 ] * PredCoef[ 5 ]  +
+                   s_ptr[ -6 ] * PredCoef[ 6 ]  +
+                   s_ptr[ -7 ] * PredCoef[ 7 ]  +
+                   s_ptr[ -8 ] * PredCoef[ 8 ]  +
+                   s_ptr[ -9 ] * PredCoef[ 9 ];
+
+        /* prediction error */
+        r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+    }
+}
+
+/* 8th order LPC analysis filter, does not write first 8 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter8_FLP(
+          silk_float                 r_LPC[],            /* O    LPC residual signal                     */
+    const silk_float                 PredCoef[],         /* I    LPC coefficients                        */
+    const silk_float                 s[],                /* I    Input signal                            */
+    const opus_int                   length              /* I    Length of input signal                  */
+)
+{
+    opus_int   ix;
+    silk_float LPC_pred;
+    const silk_float *s_ptr;
+
+    for( ix = 8; ix < length; ix++ ) {
+        s_ptr = &s[ix - 1];
+
+        /* short-term prediction */
+        LPC_pred = s_ptr[  0 ] * PredCoef[ 0 ]  +
+                   s_ptr[ -1 ] * PredCoef[ 1 ]  +
+                   s_ptr[ -2 ] * PredCoef[ 2 ]  +
+                   s_ptr[ -3 ] * PredCoef[ 3 ]  +
+                   s_ptr[ -4 ] * PredCoef[ 4 ]  +
+                   s_ptr[ -5 ] * PredCoef[ 5 ]  +
+                   s_ptr[ -6 ] * PredCoef[ 6 ]  +
+                   s_ptr[ -7 ] * PredCoef[ 7 ];
+
+        /* prediction error */
+        r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+    }
+}
+
+/* 6th order LPC analysis filter, does not write first 6 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter6_FLP(
+          silk_float                 r_LPC[],            /* O    LPC residual signal                     */
+    const silk_float                 PredCoef[],         /* I    LPC coefficients                        */
+    const silk_float                 s[],                /* I    Input signal                            */
+    const opus_int                   length              /* I    Length of input signal                  */
+)
+{
+    opus_int   ix;
+    silk_float LPC_pred;
+    const silk_float *s_ptr;
+
+    for( ix = 6; ix < length; ix++ ) {
+        s_ptr = &s[ix - 1];
+
+        /* short-term prediction */
+        LPC_pred = s_ptr[  0 ] * PredCoef[ 0 ]  +
+                   s_ptr[ -1 ] * PredCoef[ 1 ]  +
+                   s_ptr[ -2 ] * PredCoef[ 2 ]  +
+                   s_ptr[ -3 ] * PredCoef[ 3 ]  +
+                   s_ptr[ -4 ] * PredCoef[ 4 ]  +
+                   s_ptr[ -5 ] * PredCoef[ 5 ];
+
+        /* prediction error */
+        r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+    }
+}
+
+/************************************************/
+/* LPC analysis filter                          */
+/* NB! State is kept internally and the         */
+/* filter always starts with zero state         */
+/* first Order output samples are set to zero   */
+/************************************************/
+void silk_LPC_analysis_filter_FLP(
+    silk_float                      r_LPC[],                            /* O    LPC residual signal                         */
+    const silk_float                PredCoef[],                         /* I    LPC coefficients                            */
+    const silk_float                s[],                                /* I    Input signal                                */
+    const opus_int                  length,                             /* I    Length of input signal                      */
+    const opus_int                  Order                               /* I    LPC order                                   */
+)
+{
+    silk_assert( Order <= length );
+
+    switch( Order ) {
+        case 6:
+            silk_LPC_analysis_filter6_FLP(  r_LPC, PredCoef, s, length );
+        break;
+
+        case 8:
+            silk_LPC_analysis_filter8_FLP(  r_LPC, PredCoef, s, length );
+        break;
+
+        case 10:
+            silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length );
+        break;
+
+        case 12:
+            silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length );
+        break;
+
+        case 16:
+            silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length );
+        break;
+
+        default:
+            silk_assert( 0 );
+        break;
+    }
+
+    /* Set first Order output samples to zero */
+    silk_memset( r_LPC, 0, Order * sizeof( silk_float ) );
+}
+
diff --git a/third_party/opus/src/silk/float/LPC_inv_pred_gain_FLP.c b/third_party/opus/src/silk/float/LPC_inv_pred_gain_FLP.c
new file mode 100644
index 0000000..25178ba
--- /dev/null
+++ b/third_party/opus/src/silk/float/LPC_inv_pred_gain_FLP.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "SigProc_FLP.h"
+
+#define RC_THRESHOLD        0.9999f
+
+/* compute inverse of LPC prediction gain, and                          */
+/* test if LPC coefficients are stable (all poles within unit circle)   */
+/* this code is based on silk_a2k_FLP()                                 */
+silk_float silk_LPC_inverse_pred_gain_FLP(  /* O    return inverse prediction gain, energy domain               */
+    const silk_float    *A,                 /* I    prediction coefficients [order]                             */
+    opus_int32          order               /* I    prediction order                                            */
+)
+{
+    opus_int   k, n;
+    double     invGain, rc, rc_mult1, rc_mult2;
+    silk_float Atmp[ 2 ][ SILK_MAX_ORDER_LPC ];
+    silk_float *Aold, *Anew;
+
+    Anew = Atmp[ order & 1 ];
+    silk_memcpy( Anew, A, order * sizeof(silk_float) );
+
+    invGain = 1.0;
+    for( k = order - 1; k > 0; k-- ) {
+        rc = -Anew[ k ];
+        if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) {
+            return 0.0f;
+        }
+        rc_mult1 = 1.0f - rc * rc;
+        rc_mult2 = 1.0f / rc_mult1;
+        invGain *= rc_mult1;
+        /* swap pointers */
+        Aold = Anew;
+        Anew = Atmp[ k & 1 ];
+        for( n = 0; n < k; n++ ) {
+            Anew[ n ] = (silk_float)( ( Aold[ n ] - Aold[ k - n - 1 ] * rc ) * rc_mult2 );
+        }
+    }
+    rc = -Anew[ 0 ];
+    if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) {
+        return 0.0f;
+    }
+    rc_mult1 = 1.0f - rc * rc;
+    invGain *= rc_mult1;
+    return (silk_float)invGain;
+}
diff --git a/third_party/opus/src/silk/float/LTP_analysis_filter_FLP.c b/third_party/opus/src/silk/float/LTP_analysis_filter_FLP.c
new file mode 100644
index 0000000..849b7c1
--- /dev/null
+++ b/third_party/opus/src/silk/float/LTP_analysis_filter_FLP.c
@@ -0,0 +1,75 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+void silk_LTP_analysis_filter_FLP(
+    silk_float                      *LTP_res,                           /* O    LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */
+    const silk_float                *x,                                 /* I    Input signal, with preceding samples        */
+    const silk_float                B[ LTP_ORDER * MAX_NB_SUBFR ],      /* I    LTP coefficients for each subframe          */
+    const opus_int                  pitchL[   MAX_NB_SUBFR ],           /* I    Pitch lags                                  */
+    const silk_float                invGains[ MAX_NB_SUBFR ],           /* I    Inverse quantization gains                  */
+    const opus_int                  subfr_length,                       /* I    Length of each subframe                     */
+    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
+    const opus_int                  pre_length                          /* I    Preceding samples for each subframe         */
+)
+{
+    const silk_float *x_ptr, *x_lag_ptr;
+    silk_float   Btmp[ LTP_ORDER ];
+    silk_float   *LTP_res_ptr;
+    silk_float   inv_gain;
+    opus_int     k, i, j;
+
+    x_ptr = x;
+    LTP_res_ptr = LTP_res;
+    for( k = 0; k < nb_subfr; k++ ) {
+        x_lag_ptr = x_ptr - pitchL[ k ];
+        inv_gain = invGains[ k ];
+        for( i = 0; i < LTP_ORDER; i++ ) {
+            Btmp[ i ] = B[ k * LTP_ORDER + i ];
+        }
+
+        /* LTP analysis FIR filter */
+        for( i = 0; i < subfr_length + pre_length; i++ ) {
+            LTP_res_ptr[ i ] = x_ptr[ i ];
+            /* Subtract long-term prediction */
+            for( j = 0; j < LTP_ORDER; j++ ) {
+                LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ];
+            }
+            LTP_res_ptr[ i ] *= inv_gain;
+            x_lag_ptr++;
+        }
+
+        /* Update pointers */
+        LTP_res_ptr += subfr_length + pre_length;
+        x_ptr       += subfr_length;
+    }
+}
diff --git a/third_party/opus/src/silk/float/LTP_scale_ctrl_FLP.c b/third_party/opus/src/silk/float/LTP_scale_ctrl_FLP.c
new file mode 100644
index 0000000..8dbe29d
--- /dev/null
+++ b/third_party/opus/src/silk/float/LTP_scale_ctrl_FLP.c
@@ -0,0 +1,52 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+void silk_LTP_scale_ctrl_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    opus_int                        condCoding                          /* I    The type of conditional coding to use       */
+)
+{
+    opus_int   round_loss;
+
+    if( condCoding == CODE_INDEPENDENTLY ) {
+        /* Only scale if first frame in packet */
+        round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket;
+        psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f );
+    } else {
+        /* Default is minimum scaling */
+        psEnc->sCmn.indices.LTP_scaleIndex = 0;
+    }
+
+    psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f;
+}
diff --git a/third_party/opus/src/silk/float/SigProc_FLP.h b/third_party/opus/src/silk/float/SigProc_FLP.h
new file mode 100644
index 0000000..f0cb373
--- /dev/null
+++ b/third_party/opus/src/silk/float/SigProc_FLP.h
@@ -0,0 +1,204 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FLP_H
+#define SILK_SIGPROC_FLP_H
+
+#include "SigProc_FIX.h"
+#include "float_cast.h"
+#include <math.h>
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+/********************************************************************/
+/*                    SIGNAL PROCESSING FUNCTIONS                   */
+/********************************************************************/
+
+/* Chirp (bw expand) LP AR filter */
+void silk_bwexpander_FLP(
+    silk_float          *ar,                /* I/O  AR filter to be expanded (without leading 1)                */
+    const opus_int      d,                  /* I    length of ar                                                */
+    const silk_float    chirp               /* I    chirp factor (typically in range (0..1) )                   */
+);
+
+/* compute inverse of LPC prediction gain, and                          */
+/* test if LPC coefficients are stable (all poles within unit circle)   */
+/* this code is based on silk_FLP_a2k()                                 */
+silk_float silk_LPC_inverse_pred_gain_FLP(  /* O    return inverse prediction gain, energy domain               */
+    const silk_float    *A,                 /* I    prediction coefficients [order]                             */
+    opus_int32          order               /* I    prediction order                                            */
+);
+
+silk_float silk_schur_FLP(                  /* O    returns residual energy                                     */
+    silk_float          refl_coef[],        /* O    reflection coefficients (length order)                      */
+    const silk_float    auto_corr[],        /* I    autocorrelation sequence (length order+1)                   */
+    opus_int            order               /* I    order                                                       */
+);
+
+void silk_k2a_FLP(
+    silk_float          *A,                 /* O     prediction coefficients [order]                            */
+    const silk_float    *rc,                /* I     reflection coefficients [order]                            */
+    opus_int32          order               /* I     prediction order                                           */
+);
+
+/* Solve the normal equations using the Levinson-Durbin recursion */
+silk_float silk_levinsondurbin_FLP(         /* O    prediction error energy                                     */
+    silk_float          A[],                /* O    prediction coefficients [order]                             */
+    const silk_float    corr[],             /* I    input auto-correlations [order + 1]                         */
+    const opus_int      order               /* I    prediction order                                            */
+);
+
+/* compute autocorrelation */
+void silk_autocorrelation_FLP(
+    silk_float          *results,           /* O    result (length correlationCount)                            */
+    const silk_float    *inputData,         /* I    input data to correlate                                     */
+    opus_int            inputDataSize,      /* I    length of input                                             */
+    opus_int            correlationCount    /* I    number of correlation taps to compute                       */
+);
+
+opus_int silk_pitch_analysis_core_FLP(      /* O    Voicing estimate: 0 voiced, 1 unvoiced                      */
+    const silk_float    *frame,             /* I    Signal of length PE_FRAME_LENGTH_MS*Fs_kHz                  */
+    opus_int            *pitch_out,         /* O    Pitch lag values [nb_subfr]                                 */
+    opus_int16          *lagIndex,          /* O    Lag Index                                                   */
+    opus_int8           *contourIndex,      /* O    Pitch contour Index                                         */
+    silk_float          *LTPCorr,           /* I/O  Normalized correlation; input: value from previous frame    */
+    opus_int            prevLag,            /* I    Last lag of previous frame; set to zero is unvoiced         */
+    const silk_float    search_thres1,      /* I    First stage threshold for lag candidates 0 - 1              */
+    const silk_float    search_thres2,      /* I    Final threshold for lag candidates 0 - 1                    */
+    const opus_int      Fs_kHz,             /* I    sample frequency (kHz)                                      */
+    const opus_int      complexity,         /* I    Complexity setting, 0-2, where 2 is highest                 */
+    const opus_int      nb_subfr,           /* I    Number of 5 ms subframes                                    */
+    int                 arch                /* I    Run-time architecture                                       */
+);
+
+void silk_insertion_sort_decreasing_FLP(
+    silk_float          *a,                 /* I/O  Unsorted / Sorted vector                                    */
+    opus_int            *idx,               /* O    Index vector for the sorted elements                        */
+    const opus_int      L,                  /* I    Vector length                                               */
+    const opus_int      K                   /* I    Number of correctly sorted positions                        */
+);
+
+/* Compute reflection coefficients from input signal */
+silk_float silk_burg_modified_FLP(          /* O    returns residual energy                                     */
+    silk_float          A[],                /* O    prediction coefficients (length order)                      */
+    const silk_float    x[],                /* I    input signal, length: nb_subfr*(D+L_sub)                    */
+    const silk_float    minInvGain,         /* I    minimum inverse prediction gain                             */
+    const opus_int      subfr_length,       /* I    input signal subframe length (incl. D preceding samples)    */
+    const opus_int      nb_subfr,           /* I    number of subframes stacked in x                            */
+    const opus_int      D                   /* I    order                                                       */
+);
+
+/* multiply a vector by a constant */
+void silk_scale_vector_FLP(
+    silk_float          *data1,
+    silk_float          gain,
+    opus_int            dataSize
+);
+
+/* copy and multiply a vector by a constant */
+void silk_scale_copy_vector_FLP(
+    silk_float          *data_out,
+    const silk_float    *data_in,
+    silk_float          gain,
+    opus_int            dataSize
+);
+
+/* inner product of two silk_float arrays, with result as double */
+double silk_inner_product_FLP(
+    const silk_float    *data1,
+    const silk_float    *data2,
+    opus_int            dataSize
+);
+
+/* sum of squares of a silk_float array, with result as double */
+double silk_energy_FLP(
+    const silk_float    *data,
+    opus_int            dataSize
+);
+
+/********************************************************************/
+/*                                MACROS                            */
+/********************************************************************/
+
+#define PI              (3.1415926536f)
+
+#define silk_min_float( a, b )                  (((a) < (b)) ? (a) :  (b))
+#define silk_max_float( a, b )                  (((a) > (b)) ? (a) :  (b))
+#define silk_abs_float( a )                     ((silk_float)fabs(a))
+
+/* sigmoid function */
+static OPUS_INLINE silk_float silk_sigmoid( silk_float x )
+{
+    return (silk_float)(1.0 / (1.0 + exp(-x)));
+}
+
+/* floating-point to integer conversion (rounding) */
+static OPUS_INLINE opus_int32 silk_float2int( silk_float x )
+{
+    return (opus_int32)float2int( x );
+}
+
+/* floating-point to integer conversion (rounding) */
+static OPUS_INLINE void silk_float2short_array(
+    opus_int16       *out,
+    const silk_float *in,
+    opus_int32       length
+)
+{
+    opus_int32 k;
+    for( k = length - 1; k >= 0; k-- ) {
+        out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) );
+    }
+}
+
+/* integer to floating-point conversion */
+static OPUS_INLINE void silk_short2float_array(
+    silk_float       *out,
+    const opus_int16 *in,
+    opus_int32       length
+)
+{
+    opus_int32 k;
+    for( k = length - 1; k >= 0; k-- ) {
+        out[k] = (silk_float)in[k];
+    }
+}
+
+/* using log2() helps the fixed-point conversion */
+static OPUS_INLINE silk_float silk_log2( double x )
+{
+    return ( silk_float )( 3.32192809488736 * log10( x ) );
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* SILK_SIGPROC_FLP_H */
diff --git a/third_party/opus/src/silk/float/apply_sine_window_FLP.c b/third_party/opus/src/silk/float/apply_sine_window_FLP.c
new file mode 100644
index 0000000..6aae57c
--- /dev/null
+++ b/third_party/opus/src/silk/float/apply_sine_window_FLP.c
@@ -0,0 +1,81 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Apply sine window to signal vector   */
+/* Window types:                        */
+/*  1 -> sine window from 0 to pi/2     */
+/*  2 -> sine window from pi/2 to pi    */
+void silk_apply_sine_window_FLP(
+    silk_float                      px_win[],                           /* O    Pointer to windowed signal                  */
+    const silk_float                px[],                               /* I    Pointer to input signal                     */
+    const opus_int                  win_type,                           /* I    Selects a window type                       */
+    const opus_int                  length                              /* I    Window length, multiple of 4                */
+)
+{
+    opus_int   k;
+    silk_float freq, c, S0, S1;
+
+    silk_assert( win_type == 1 || win_type == 2 );
+
+    /* Length must be multiple of 4 */
+    silk_assert( ( length & 3 ) == 0 );
+
+    freq = PI / ( length + 1 );
+
+    /* Approximation of 2 * cos(f) */
+    c = 2.0f - freq * freq;
+
+    /* Initialize state */
+    if( win_type < 2 ) {
+        /* Start from 0 */
+        S0 = 0.0f;
+        /* Approximation of sin(f) */
+        S1 = freq;
+    } else {
+        /* Start from 1 */
+        S0 = 1.0f;
+        /* Approximation of cos(f) */
+        S1 = 0.5f * c;
+    }
+
+    /* Uses the recursive equation:   sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f)   */
+    /* 4 samples at a time */
+    for( k = 0; k < length; k += 4 ) {
+        px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 );
+        px_win[ k + 1 ] = px[ k + 1 ] * S1;
+        S0 = c * S1 - S0;
+        px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 );
+        px_win[ k + 3 ] = px[ k + 3 ] * S0;
+        S1 = c * S0 - S1;
+    }
+}
diff --git a/third_party/opus/src/silk/float/autocorrelation_FLP.c b/third_party/opus/src/silk/float/autocorrelation_FLP.c
new file mode 100644
index 0000000..8b8a9e65
--- /dev/null
+++ b/third_party/opus/src/silk/float/autocorrelation_FLP.c
@@ -0,0 +1,52 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "typedef.h"
+#include "SigProc_FLP.h"
+
+/* compute autocorrelation */
+void silk_autocorrelation_FLP(
+    silk_float          *results,           /* O    result (length correlationCount)                            */
+    const silk_float    *inputData,         /* I    input data to correlate                                     */
+    opus_int            inputDataSize,      /* I    length of input                                             */
+    opus_int            correlationCount    /* I    number of correlation taps to compute                       */
+)
+{
+    opus_int i;
+
+    if( correlationCount > inputDataSize ) {
+        correlationCount = inputDataSize;
+    }
+
+    for( i = 0; i < correlationCount; i++ ) {
+        results[ i ] =  (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i );
+    }
+}
diff --git a/third_party/opus/src/silk/float/burg_modified_FLP.c b/third_party/opus/src/silk/float/burg_modified_FLP.c
new file mode 100644
index 0000000..ea5dc25
--- /dev/null
+++ b/third_party/opus/src/silk/float/burg_modified_FLP.c
@@ -0,0 +1,186 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+#include "tuning_parameters.h"
+#include "define.h"
+
+#define MAX_FRAME_SIZE              384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/
+
+/* Compute reflection coefficients from input signal */
+silk_float silk_burg_modified_FLP(          /* O    returns residual energy                                     */
+    silk_float          A[],                /* O    prediction coefficients (length order)                      */
+    const silk_float    x[],                /* I    input signal, length: nb_subfr*(D+L_sub)                    */
+    const silk_float    minInvGain,         /* I    minimum inverse prediction gain                             */
+    const opus_int      subfr_length,       /* I    input signal subframe length (incl. D preceding samples)    */
+    const opus_int      nb_subfr,           /* I    number of subframes stacked in x                            */
+    const opus_int      D                   /* I    order                                                       */
+)
+{
+    opus_int         k, n, s, reached_max_gain;
+    double           C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2;
+    const silk_float *x_ptr;
+    double           C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ];
+    double           CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ];
+    double           Af[ SILK_MAX_ORDER_LPC ];
+
+    silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+    /* Compute autocorrelations, added over subframes */
+    C0 = silk_energy_FLP( x, nb_subfr * subfr_length );
+    silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) );
+    for( s = 0; s < nb_subfr; s++ ) {
+        x_ptr = x + s * subfr_length;
+        for( n = 1; n < D + 1; n++ ) {
+            C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n );
+        }
+    }
+    silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) );
+
+    /* Initialize */
+    CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f;
+    invGain = 1.0f;
+    reached_max_gain = 0;
+    for( n = 0; n < D; n++ ) {
+        /* Update first row of correlation matrix (without first element) */
+        /* Update last row of correlation matrix (without last element, stored in reversed order) */
+        /* Update C * Af */
+        /* Update C * flipud(Af) (stored in reversed order) */
+        for( s = 0; s < nb_subfr; s++ ) {
+            x_ptr = x + s * subfr_length;
+            tmp1 = x_ptr[ n ];
+            tmp2 = x_ptr[ subfr_length - n - 1 ];
+            for( k = 0; k < n; k++ ) {
+                C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ];
+                C_last_row[ k ]  -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ];
+                Atmp = Af[ k ];
+                tmp1 += x_ptr[ n - k - 1 ] * Atmp;
+                tmp2 += x_ptr[ subfr_length - n + k ] * Atmp;
+            }
+            for( k = 0; k <= n; k++ ) {
+                CAf[ k ] -= tmp1 * x_ptr[ n - k ];
+                CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ];
+            }
+        }
+        tmp1 = C_first_row[ n ];
+        tmp2 = C_last_row[ n ];
+        for( k = 0; k < n; k++ ) {
+            Atmp = Af[ k ];
+            tmp1 += C_last_row[  n - k - 1 ] * Atmp;
+            tmp2 += C_first_row[ n - k - 1 ] * Atmp;
+        }
+        CAf[ n + 1 ] = tmp1;
+        CAb[ n + 1 ] = tmp2;
+
+        /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+        num = CAb[ n + 1 ];
+        nrg_b = CAb[ 0 ];
+        nrg_f = CAf[ 0 ];
+        for( k = 0; k < n; k++ ) {
+            Atmp = Af[ k ];
+            num   += CAb[ n - k ] * Atmp;
+            nrg_b += CAb[ k + 1 ] * Atmp;
+            nrg_f += CAf[ k + 1 ] * Atmp;
+        }
+        silk_assert( nrg_f > 0.0 );
+        silk_assert( nrg_b > 0.0 );
+
+        /* Calculate the next order reflection (parcor) coefficient */
+        rc = -2.0 * num / ( nrg_f + nrg_b );
+        silk_assert( rc > -1.0 && rc < 1.0 );
+
+        /* Update inverse prediction gain */
+        tmp1 = invGain * ( 1.0 - rc * rc );
+        if( tmp1 <= minInvGain ) {
+            /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+            rc = sqrt( 1.0 - minInvGain / invGain );
+            if( num > 0 ) {
+                /* Ensure adjusted reflection coefficients has the original sign */
+                rc = -rc;
+            }
+            invGain = minInvGain;
+            reached_max_gain = 1;
+        } else {
+            invGain = tmp1;
+        }
+
+        /* Update the AR coefficients */
+        for( k = 0; k < (n + 1) >> 1; k++ ) {
+            tmp1 = Af[ k ];
+            tmp2 = Af[ n - k - 1 ];
+            Af[ k ]         = tmp1 + rc * tmp2;
+            Af[ n - k - 1 ] = tmp2 + rc * tmp1;
+        }
+        Af[ n ] = rc;
+
+        if( reached_max_gain ) {
+            /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+            for( k = n + 1; k < D; k++ ) {
+                Af[ k ] = 0.0;
+            }
+            break;
+        }
+
+        /* Update C * Af and C * Ab */
+        for( k = 0; k <= n + 1; k++ ) {
+            tmp1 = CAf[ k ];
+            CAf[ k ]          += rc * CAb[ n - k + 1 ];
+            CAb[ n - k + 1  ] += rc * tmp1;
+        }
+    }
+
+    if( reached_max_gain ) {
+        /* Convert to silk_float */
+        for( k = 0; k < D; k++ ) {
+            A[ k ] = (silk_float)( -Af[ k ] );
+        }
+        /* Subtract energy of preceding samples from C0 */
+        for( s = 0; s < nb_subfr; s++ ) {
+            C0 -= silk_energy_FLP( x + s * subfr_length, D );
+        }
+        /* Approximate residual energy */
+        nrg_f = C0 * invGain;
+    } else {
+        /* Compute residual energy and store coefficients as silk_float */
+        nrg_f = CAf[ 0 ];
+        tmp1 = 1.0;
+        for( k = 0; k < D; k++ ) {
+            Atmp = Af[ k ];
+            nrg_f += CAf[ k + 1 ] * Atmp;
+            tmp1  += Atmp * Atmp;
+            A[ k ] = (silk_float)(-Atmp);
+        }
+        nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1;
+    }
+
+    /* Return residual energy */
+    return (silk_float)nrg_f;
+}
diff --git a/third_party/opus/src/silk/float/bwexpander_FLP.c b/third_party/opus/src/silk/float/bwexpander_FLP.c
new file mode 100644
index 0000000..d55a4d79
--- /dev/null
+++ b/third_party/opus/src/silk/float/bwexpander_FLP.c
@@ -0,0 +1,49 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* Chirp (bw expand) LP AR filter */
+void silk_bwexpander_FLP(
+    silk_float          *ar,                /* I/O  AR filter to be expanded (without leading 1)                */
+    const opus_int      d,                  /* I    length of ar                                                */
+    const silk_float    chirp               /* I    chirp factor (typically in range (0..1) )                   */
+)
+{
+    opus_int   i;
+    silk_float cfac = chirp;
+
+    for( i = 0; i < d - 1; i++ ) {
+        ar[ i ] *=  cfac;
+        cfac    *=  chirp;
+    }
+    ar[ d - 1 ] *=  cfac;
+}
diff --git a/third_party/opus/src/silk/float/corrMatrix_FLP.c b/third_party/opus/src/silk/float/corrMatrix_FLP.c
new file mode 100644
index 0000000..eae6a1cf
--- /dev/null
+++ b/third_party/opus/src/silk/float/corrMatrix_FLP.c
@@ -0,0 +1,93 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/**********************************************************************
+ * Correlation matrix computations for LS estimate.
+ **********************************************************************/
+
+#include "main_FLP.h"
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FLP(
+    const silk_float                *x,                                 /* I    x vector [L+order-1] used to create X       */
+    const silk_float                *t,                                 /* I    Target vector [L]                           */
+    const opus_int                  L,                                  /* I    Length of vecors                            */
+    const opus_int                  Order,                              /* I    Max lag for correlation                     */
+    silk_float                      *Xt                                 /* O    X'*t correlation vector [order]             */
+)
+{
+    opus_int lag;
+    const silk_float *ptr1;
+
+    ptr1 = &x[ Order - 1 ];                     /* Points to first sample of column 0 of X: X[:,0] */
+    for( lag = 0; lag < Order; lag++ ) {
+        /* Calculate X[:,lag]'*t */
+        Xt[ lag ] = (silk_float)silk_inner_product_FLP( ptr1, t, L );
+        ptr1--;                                 /* Next column of X */
+    }
+}
+
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FLP(
+    const silk_float                *x,                                 /* I    x vector [ L+order-1 ] used to create X     */
+    const opus_int                  L,                                  /* I    Length of vectors                           */
+    const opus_int                  Order,                              /* I    Max lag for correlation                     */
+    silk_float                      *XX                                 /* O    X'*X correlation matrix [order x order]     */
+)
+{
+    opus_int j, lag;
+    double  energy;
+    const silk_float *ptr1, *ptr2;
+
+    ptr1 = &x[ Order - 1 ];                     /* First sample of column 0 of X */
+    energy = silk_energy_FLP( ptr1, L );  /* X[:,0]'*X[:,0] */
+    matrix_ptr( XX, 0, 0, Order ) = ( silk_float )energy;
+    for( j = 1; j < Order; j++ ) {
+        /* Calculate X[:,j]'*X[:,j] */
+        energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ];
+        matrix_ptr( XX, j, j, Order ) = ( silk_float )energy;
+    }
+
+    ptr2 = &x[ Order - 2 ];                     /* First sample of column 1 of X */
+    for( lag = 1; lag < Order; lag++ ) {
+        /* Calculate X[:,0]'*X[:,lag] */
+        energy = silk_inner_product_FLP( ptr1, ptr2, L );
+        matrix_ptr( XX, lag, 0, Order ) = ( silk_float )energy;
+        matrix_ptr( XX, 0, lag, Order ) = ( silk_float )energy;
+        /* Calculate X[:,j]'*X[:,j + lag] */
+        for( j = 1; j < ( Order - lag ); j++ ) {
+            energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ];
+            matrix_ptr( XX, lag + j, j, Order ) = ( silk_float )energy;
+            matrix_ptr( XX, j, lag + j, Order ) = ( silk_float )energy;
+        }
+        ptr2--;                                 /* Next column of X */
+    }
+}
diff --git a/third_party/opus/src/silk/float/encode_frame_FLP.c b/third_party/opus/src/silk/float/encode_frame_FLP.c
new file mode 100644
index 0000000..2092a4d
--- /dev/null
+++ b/third_party/opus/src/silk/float/encode_frame_FLP.c
@@ -0,0 +1,372 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    const silk_float                xfw[],                              /* I    Input signal                                */
+    opus_int                        condCoding                          /* I    The type of conditional coding used so far for this frame */
+);
+
+void silk_encode_do_VAD_FLP(
+    silk_encoder_state_FLP          *psEnc                              /* I/O  Encoder state FLP                           */
+)
+{
+    /****************************/
+    /* Voice Activity Detection */
+    /****************************/
+    silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch );
+
+    /**************************************************/
+    /* Convert speech activity into VAD and DTX flags */
+    /**************************************************/
+    if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) {
+        psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
+        psEnc->sCmn.noSpeechCounter++;
+        if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) {
+            psEnc->sCmn.inDTX = 0;
+        } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
+            psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
+            psEnc->sCmn.inDTX           = 0;
+        }
+        psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
+    } else {
+        psEnc->sCmn.noSpeechCounter    = 0;
+        psEnc->sCmn.inDTX              = 0;
+        psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+        psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+    }
+}
+
+/****************/
+/* Encode frame */
+/****************/
+opus_int silk_encode_frame_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    opus_int32                      *pnBytesOut,                        /* O    Number of payload bytes;                    */
+    ec_enc                          *psRangeEnc,                        /* I/O  compressor data structure                   */
+    opus_int                        condCoding,                         /* I    The type of conditional coding to use       */
+    opus_int                        maxBits,                            /* I    If > 0: maximum number of output bits       */
+    opus_int                        useCBR                              /* I    Flag to force constant-bitrate operation    */
+)
+{
+    silk_encoder_control_FLP sEncCtrl;
+    opus_int     i, iter, maxIter, found_upper, found_lower, ret = 0;
+    silk_float   *x_frame, *res_pitch_frame;
+    silk_float   xfw[ MAX_FRAME_LENGTH ];
+    silk_float   res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ];
+    ec_enc       sRangeEnc_copy, sRangeEnc_copy2;
+    silk_nsq_state sNSQ_copy, sNSQ_copy2;
+    opus_int32   seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+    opus_int32   gainsID, gainsID_lower, gainsID_upper;
+    opus_int16   gainMult_Q8;
+    opus_int16   ec_prevLagIndex_copy;
+    opus_int     ec_prevSignalType_copy;
+    opus_int8    LastGainIndex_copy2;
+    opus_int32   pGains_Q16[ MAX_NB_SUBFR ];
+    opus_uint8   ec_buf_copy[ 1275 ];
+
+    /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
+    LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
+    psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
+
+    /**************************************************************/
+    /* Set up Input Pointers, and insert frame in input buffer    */
+    /**************************************************************/
+    /* pointers aligned with start of frame to encode */
+    x_frame         = psEnc->x_buf + psEnc->sCmn.ltp_mem_length;    /* start of frame to encode */
+    res_pitch_frame = res_pitch    + psEnc->sCmn.ltp_mem_length;    /* start of pitch LPC residual frame */
+
+    /***************************************/
+    /* Ensure smooth bandwidth transitions */
+    /***************************************/
+    silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+    /*******************************************/
+    /* Copy new frame to front of input buffer */
+    /*******************************************/
+    silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+    /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */
+    for( i = 0; i < 8; i++ ) {
+        x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f;
+    }
+
+    if( !psEnc->sCmn.prefillFlag ) {
+        /*****************************************/
+        /* Find pitch lags, initial LPC analysis */
+        /*****************************************/
+        silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch );
+
+        /************************/
+        /* Noise shape analysis */
+        /************************/
+        silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame );
+
+        /***************************************************/
+        /* Find linear prediction coefficients (LPC + LTP) */
+        /***************************************************/
+        silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding );
+
+        /****************************************/
+        /* Process gains                        */
+        /****************************************/
+        silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding );
+
+        /*****************************************/
+        /* Prefiltering for noise shaper         */
+        /*****************************************/
+        silk_prefilter_FLP( psEnc, &sEncCtrl, xfw, x_frame );
+
+        /****************************************/
+        /* Low Bitrate Redundant Encoding       */
+        /****************************************/
+        silk_LBRR_encode_FLP( psEnc, &sEncCtrl, xfw, condCoding );
+
+        /* Loop over quantizer and entroy coding to control bitrate */
+        maxIter = 6;
+        gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
+        found_lower = 0;
+        found_upper = 0;
+        gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+        gainsID_lower = -1;
+        gainsID_upper = -1;
+        /* Copy part of the input state */
+        silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+        silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+        seed_copy = psEnc->sCmn.indices.Seed;
+        ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+        ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
+        for( iter = 0; ; iter++ ) {
+            if( gainsID == gainsID_lower ) {
+                nBits = nBits_lower;
+            } else if( gainsID == gainsID_upper ) {
+                nBits = nBits_upper;
+            } else {
+                /* Restore part of the input state */
+                if( iter > 0 ) {
+                    silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+                    silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
+                    psEnc->sCmn.indices.Seed = seed_copy;
+                    psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+                    psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+                }
+
+                /*****************************************/
+                /* Noise shaping quantization            */
+                /*****************************************/
+                silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw );
+
+                /****************************************/
+                /* Encode Parameters                    */
+                /****************************************/
+                silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+
+                /****************************************/
+                /* Encode Excitation Signal             */
+                /****************************************/
+                silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+                      psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+
+                nBits = ec_tell( psRangeEnc );
+
+                if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+                    break;
+                }
+            }
+
+            if( iter == maxIter ) {
+                if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
+                    /* Restore output state from earlier iteration that did meet the bitrate budget */
+                    silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+                    silk_assert( sRangeEnc_copy2.offs <= 1275 );
+                    silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
+                    silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
+                    psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
+                }
+                break;
+            }
+
+            if( nBits > maxBits ) {
+                if( found_lower == 0 && iter >= 2 ) {
+                    /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
+                    sEncCtrl.Lambda *= 1.5f;
+                    found_upper = 0;
+                    gainsID_upper = -1;
+                } else {
+                    found_upper = 1;
+                    nBits_upper = nBits;
+                    gainMult_upper = gainMult_Q8;
+                    gainsID_upper = gainsID;
+                }
+            } else if( nBits < maxBits - 5 ) {
+                found_lower = 1;
+                nBits_lower = nBits;
+                gainMult_lower = gainMult_Q8;
+                if( gainsID != gainsID_lower ) {
+                    gainsID_lower = gainsID;
+                    /* Copy part of the output state */
+                    silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+                    silk_assert( psRangeEnc->offs <= 1275 );
+                    silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+                    silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+                    LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+                }
+            } else {
+                /* Within 5 bits of budget: close enough */
+                break;
+            }
+
+            if( ( found_lower & found_upper ) == 0 ) {
+                /* Adjust gain according to high-rate rate/distortion curve */
+                opus_int32 gain_factor_Q16;
+                gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+                gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) );
+                if( nBits > maxBits ) {
+                    gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
+                }
+                gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 );
+            } else {
+                /* Adjust gain by interpolating */
+                gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower );
+                /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
+                if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
+                } else
+                if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+                }
+            }
+
+            for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+                pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 );
+            }
+
+            /* Quantize gains */
+            psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+            silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
+                  &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+            /* Unique identifier of gains vector */
+            gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+
+            /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+            for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+                sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f;
+            }
+        }
+    }
+
+    /* Update input buffer */
+    silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
+        ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) );
+
+    /* Exit without entropy coding */
+    if( psEnc->sCmn.prefillFlag ) {
+        /* No payload */
+        *pnBytesOut = 0;
+        return ret;
+    }
+
+    /* Parameters needed for next frame */
+    psEnc->sCmn.prevLag        = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+    psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
+
+    /****************************************/
+    /* Finalize payload                     */
+    /****************************************/
+    psEnc->sCmn.first_frame_after_reset = 0;
+    /* Payload size */
+    *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
+
+    return ret;
+}
+
+/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate  */
+static OPUS_INLINE void silk_LBRR_encode_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    const silk_float                xfw[],                              /* I    Input signal                                */
+    opus_int                        condCoding                          /* I    The type of conditional coding used so far for this frame */
+)
+{
+    opus_int     k;
+    opus_int32   Gains_Q16[ MAX_NB_SUBFR ];
+    silk_float   TempGains[ MAX_NB_SUBFR ];
+    SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
+    silk_nsq_state sNSQ_LBRR;
+
+    /*******************************************/
+    /* Control use of inband LBRR              */
+    /*******************************************/
+    if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
+        psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+
+        /* Copy noise shaping quantizer state and quantization indices from regular encoding */
+        silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+        silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
+
+        /* Save original gains */
+        silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) );
+
+        if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
+            /* First frame in packet or previous frame not LBRR coded */
+            psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
+
+            /* Increase Gains to get target LBRR rate */
+            psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases;
+            psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
+        }
+
+        /* Decode to get gains in sync with decoder */
+        silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices,
+            &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+        /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+        for( k = 0; k <  psEnc->sCmn.nb_subfr; k++ ) {
+            psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f );
+        }
+
+        /*****************************************/
+        /* Noise shaping quantization            */
+        /*****************************************/
+        silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR,
+            psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw );
+
+        /* Restore original gains */
+        silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) );
+    }
+}
diff --git a/third_party/opus/src/silk/float/energy_FLP.c b/third_party/opus/src/silk/float/energy_FLP.c
new file mode 100644
index 0000000..24b8179
--- /dev/null
+++ b/third_party/opus/src/silk/float/energy_FLP.c
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* sum of squares of a silk_float array, with result as double */
+double silk_energy_FLP(
+    const silk_float    *data,
+    opus_int            dataSize
+)
+{
+    opus_int  i, dataSize4;
+    double   result;
+
+    /* 4x unrolled loop */
+    result = 0.0;
+    dataSize4 = dataSize & 0xFFFC;
+    for( i = 0; i < dataSize4; i += 4 ) {
+        result += data[ i + 0 ] * (double)data[ i + 0 ] +
+                  data[ i + 1 ] * (double)data[ i + 1 ] +
+                  data[ i + 2 ] * (double)data[ i + 2 ] +
+                  data[ i + 3 ] * (double)data[ i + 3 ];
+    }
+
+    /* add any remaining products */
+    for( ; i < dataSize; i++ ) {
+        result += data[ i ] * (double)data[ i ];
+    }
+
+    silk_assert( result >= 0.0 );
+    return result;
+}
diff --git a/third_party/opus/src/silk/float/find_LPC_FLP.c b/third_party/opus/src/silk/float/find_LPC_FLP.c
new file mode 100644
index 0000000..fcfe1c36
--- /dev/null
+++ b/third_party/opus/src/silk/float/find_LPC_FLP.c
@@ -0,0 +1,104 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "define.h"
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/* LPC analysis */
+void silk_find_LPC_FLP(
+    silk_encoder_state              *psEncC,                            /* I/O  Encoder state                               */
+    opus_int16                      NLSF_Q15[],                         /* O    NLSFs                                       */
+    const silk_float                x[],                                /* I    Input signal                                */
+    const silk_float                minInvGain                          /* I    Inverse of max prediction gain              */
+)
+{
+    opus_int    k, subfr_length;
+    silk_float  a[ MAX_LPC_ORDER ];
+
+    /* Used only for NLSF interpolation */
+    silk_float  res_nrg, res_nrg_2nd, res_nrg_interp;
+    opus_int16  NLSF0_Q15[ MAX_LPC_ORDER ];
+    silk_float  a_tmp[ MAX_LPC_ORDER ];
+    silk_float  LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ];
+
+    subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder;
+
+    /* Default: No interpolation */
+    psEncC->indices.NLSFInterpCoef_Q2 = 4;
+
+    /* Burg AR analysis for the full frame */
+    res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder );
+
+    if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) {
+        /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than        */
+        /* adding it to the residual energy of the first 10 ms in each iteration of the search below    */
+        res_nrg -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder );
+
+        /* Convert to NLSFs */
+        silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder );
+
+        /* Search over interpolation indices to find the one with lowest residual energy */
+        res_nrg_2nd = silk_float_MAX;
+        for( k = 3; k >= 0; k-- ) {
+            /* Interpolate NLSFs for first half */
+            silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder );
+
+            /* Convert to LPC for residual energy evaluation */
+            silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder );
+
+            /* Calculate residual energy with LSF interpolation */
+            silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder );
+            res_nrg_interp = (silk_float)(
+                silk_energy_FLP( LPC_res + psEncC->predictLPCOrder,                subfr_length - psEncC->predictLPCOrder ) +
+                silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) );
+
+            /* Determine whether current interpolated NLSFs are best so far */
+            if( res_nrg_interp < res_nrg ) {
+                /* Interpolation has lower residual energy */
+                res_nrg = res_nrg_interp;
+                psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k;
+            } else if( res_nrg_interp > res_nrg_2nd ) {
+                /* No reason to continue iterating - residual energies will continue to climb */
+                break;
+            }
+            res_nrg_2nd = res_nrg_interp;
+        }
+    }
+
+    if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) {
+        /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
+        silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder );
+    }
+
+    silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 ||
+        ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) );
+}
diff --git a/third_party/opus/src/silk/float/find_LTP_FLP.c b/third_party/opus/src/silk/float/find_LTP_FLP.c
new file mode 100644
index 0000000..72299960
--- /dev/null
+++ b/third_party/opus/src/silk/float/find_LTP_FLP.c
@@ -0,0 +1,132 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+void silk_find_LTP_FLP(
+    silk_float                      b[ MAX_NB_SUBFR * LTP_ORDER ],      /* O    LTP coefs                                   */
+    silk_float                      WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O    Weight for LTP quantization       */
+    silk_float                      *LTPredCodGain,                     /* O    LTP coding gain                             */
+    const silk_float                r_lpc[],                            /* I    LPC residual                                */
+    const opus_int                  lag[  MAX_NB_SUBFR ],               /* I    LTP lags                                    */
+    const silk_float                Wght[ MAX_NB_SUBFR ],               /* I    Weights                                     */
+    const opus_int                  subfr_length,                       /* I    Subframe length                             */
+    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
+    const opus_int                  mem_offset                          /* I    Number of samples in LTP memory             */
+)
+{
+    opus_int   i, k;
+    silk_float *b_ptr, temp, *WLTP_ptr;
+    silk_float LPC_res_nrg, LPC_LTP_res_nrg;
+    silk_float d[ MAX_NB_SUBFR ], m, g, delta_b[ LTP_ORDER ];
+    silk_float w[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], regu;
+    silk_float Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ];
+    const silk_float *r_ptr, *lag_ptr;
+
+    b_ptr    = b;
+    WLTP_ptr = WLTP;
+    r_ptr    = &r_lpc[ mem_offset ];
+    for( k = 0; k < nb_subfr; k++ ) {
+        lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
+
+        silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr );
+        silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr );
+
+        rr[ k ] = ( silk_float )silk_energy_FLP( r_ptr, subfr_length );
+        regu = 1.0f + rr[ k ] +
+            matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) +
+            matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER );
+        regu *= LTP_DAMPING / 3;
+        silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER );
+        silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr );
+
+        /* Calculate residual energy */
+        nrg[ k ] = silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER );
+
+        temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length );
+        silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER );
+        w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER );
+
+        r_ptr    += subfr_length;
+        b_ptr    += LTP_ORDER;
+        WLTP_ptr += LTP_ORDER * LTP_ORDER;
+    }
+
+    /* Compute LTP coding gain */
+    if( LTPredCodGain != NULL ) {
+        LPC_LTP_res_nrg = 1e-6f;
+        LPC_res_nrg     = 0.0f;
+        for( k = 0; k < nb_subfr; k++ ) {
+            LPC_res_nrg     += rr[  k ] * Wght[ k ];
+            LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ];
+        }
+
+        silk_assert( LPC_LTP_res_nrg > 0 );
+        *LTPredCodGain = 3.0f * silk_log2( LPC_res_nrg / LPC_LTP_res_nrg );
+    }
+
+    /* Smoothing */
+    /* d = sum( B, 1 ); */
+    b_ptr = b;
+    for( k = 0; k < nb_subfr; k++ ) {
+        d[ k ] = 0;
+        for( i = 0; i < LTP_ORDER; i++ ) {
+            d[ k ] += b_ptr[ i ];
+        }
+        b_ptr += LTP_ORDER;
+    }
+    /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
+    temp = 1e-3f;
+    for( k = 0; k < nb_subfr; k++ ) {
+        temp += w[ k ];
+    }
+    m = 0;
+    for( k = 0; k < nb_subfr; k++ ) {
+        m += d[ k ] * w[ k ];
+    }
+    m = m / temp;
+
+    b_ptr = b;
+    for( k = 0; k < nb_subfr; k++ ) {
+        g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] );
+        temp = 0;
+        for( i = 0; i < LTP_ORDER; i++ ) {
+            delta_b[ i ] = silk_max_float( b_ptr[ i ], 0.1f );
+            temp += delta_b[ i ];
+        }
+        temp = g / temp;
+        for( i = 0; i < LTP_ORDER; i++ ) {
+            b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp;
+        }
+        b_ptr += LTP_ORDER;
+    }
+}
diff --git a/third_party/opus/src/silk/float/find_pitch_lags_FLP.c b/third_party/opus/src/silk/float/find_pitch_lags_FLP.c
new file mode 100644
index 0000000..f3b22d25
--- /dev/null
+++ b/third_party/opus/src/silk/float/find_pitch_lags_FLP.c
@@ -0,0 +1,132 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+void silk_find_pitch_lags_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    silk_float                      res[],                              /* O    Residual                                    */
+    const silk_float                x[],                                /* I    Speech signal                               */
+    int                             arch                                /* I    Run-time architecture                       */
+)
+{
+    opus_int   buf_len;
+    silk_float thrhld, res_nrg;
+    const silk_float *x_buf_ptr, *x_buf;
+    silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ];
+    silk_float A[         MAX_FIND_PITCH_LPC_ORDER ];
+    silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ];
+    silk_float Wsig[      FIND_PITCH_LPC_WIN_MAX ];
+    silk_float *Wsig_ptr;
+
+    /******************************************/
+    /* Set up buffer lengths etc based on Fs  */
+    /******************************************/
+    buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length;
+
+    /* Safety check */
+    silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length );
+
+    x_buf = x - psEnc->sCmn.ltp_mem_length;
+
+    /******************************************/
+    /* Estimate LPC AR coeficients            */
+    /******************************************/
+
+    /* Calculate windowed signal */
+
+    /* First LA_LTP samples */
+    x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length;
+    Wsig_ptr  = Wsig;
+    silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch );
+
+    /* Middle non-windowed samples */
+    Wsig_ptr  += psEnc->sCmn.la_pitch;
+    x_buf_ptr += psEnc->sCmn.la_pitch;
+    silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) );
+
+    /* Last LA_LTP samples */
+    Wsig_ptr  += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 );
+    x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 );
+    silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch );
+
+    /* Calculate autocorrelation sequence */
+    silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 );
+
+    /* Add white noise, as a fraction of the energy */
+    auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1;
+
+    /* Calculate the reflection coefficients using Schur */
+    res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder );
+
+    /* Prediction gain */
+    psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f );
+
+    /* Convert reflection coefficients to prediction coefficients */
+    silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder );
+
+    /* Bandwidth expansion */
+    silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWIDTH_EXPANSION );
+
+    /*****************************************/
+    /* LPC analysis filtering                */
+    /*****************************************/
+    silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder );
+
+    if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) {
+        /* Threshold for pitch estimator */
+        thrhld  = 0.6f;
+        thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder;
+        thrhld -= 0.1f   * psEnc->sCmn.speech_activity_Q8 * ( 1.0f /  256.0f );
+        thrhld -= 0.15f  * (psEnc->sCmn.prevSignalType >> 1);
+        thrhld -= 0.1f   * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f );
+
+        /*****************************************/
+        /* Call Pitch estimator                  */
+        /*****************************************/
+        if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex,
+            &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f,
+            thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, arch ) == 0 )
+        {
+            psEnc->sCmn.indices.signalType = TYPE_VOICED;
+        } else {
+            psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+        }
+    } else {
+        silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) );
+        psEnc->sCmn.indices.lagIndex = 0;
+        psEnc->sCmn.indices.contourIndex = 0;
+        psEnc->LTPCorr = 0;
+    }
+}
diff --git a/third_party/opus/src/silk/float/find_pred_coefs_FLP.c b/third_party/opus/src/silk/float/find_pred_coefs_FLP.c
new file mode 100644
index 0000000..1af4fe5
--- /dev/null
+++ b/third_party/opus/src/silk/float/find_pred_coefs_FLP.c
@@ -0,0 +1,118 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    const silk_float                res_pitch[],                        /* I    Residual from pitch analysis                */
+    const silk_float                x[],                                /* I    Speech signal                               */
+    opus_int                        condCoding                          /* I    The type of conditional coding to use       */
+)
+{
+    opus_int         i;
+    silk_float       WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ];
+    silk_float       invGains[ MAX_NB_SUBFR ], Wght[ MAX_NB_SUBFR ];
+    opus_int16       NLSF_Q15[ MAX_LPC_ORDER ];
+    const silk_float *x_ptr;
+    silk_float       *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ];
+    silk_float       minInvGain;
+
+    /* Weighting for weighted least squares */
+    for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+        silk_assert( psEncCtrl->Gains[ i ] > 0.0f );
+        invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ];
+        Wght[ i ]     = invGains[ i ] * invGains[ i ];
+    }
+
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /**********/
+        /* VOICED */
+        /**********/
+        silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 );
+
+        /* LTP analysis */
+        silk_find_LTP_FLP( psEncCtrl->LTPCoef, WLTP, &psEncCtrl->LTPredCodGain, res_pitch,
+            psEncCtrl->pitchL, Wght, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length );
+
+        /* Quantize LTP gain parameters */
+        silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex,
+            &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr,
+            psEnc->sCmn.arch );
+
+        /* Control LTP scaling */
+        silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding );
+
+        /* Create LTP residual */
+        silk_LTP_analysis_filter_FLP( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef,
+            psEncCtrl->pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+    } else {
+        /************/
+        /* UNVOICED */
+        /************/
+        /* Create signal with prepended subframes, scaled by inverse gains */
+        x_ptr     = x - psEnc->sCmn.predictLPCOrder;
+        x_pre_ptr = LPC_in_pre;
+        for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+            silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ],
+                psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder );
+            x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder;
+            x_ptr     += psEnc->sCmn.subfr_length;
+        }
+        silk_memset( psEncCtrl->LTPCoef, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) );
+        psEncCtrl->LTPredCodGain = 0.0f;
+        psEnc->sCmn.sum_log_gain_Q7 = 0;
+    }
+
+    /* Limit on total predictive coding gain */
+    if( psEnc->sCmn.first_frame_after_reset ) {
+        minInvGain = 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET;
+    } else {
+        minInvGain = (silk_float)pow( 2, psEncCtrl->LTPredCodGain / 3 ) /  MAX_PREDICTION_POWER_GAIN;
+        minInvGain /= 0.25f + 0.75f * psEncCtrl->coding_quality;
+    }
+
+    /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
+    silk_find_LPC_FLP( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain );
+
+    /* Quantize LSFs */
+    silk_process_NLSFs_FLP( &psEnc->sCmn, psEncCtrl->PredCoef, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 );
+
+    /* Calculate residual energy using quantized LPC coefficients */
+    silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains,
+        psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+    /* Copy to prediction struct for use in next frame for interpolation */
+    silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+}
+
diff --git a/third_party/opus/src/silk/float/inner_product_FLP.c b/third_party/opus/src/silk/float/inner_product_FLP.c
new file mode 100644
index 0000000..029c012
--- /dev/null
+++ b/third_party/opus/src/silk/float/inner_product_FLP.c
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* inner product of two silk_float arrays, with result as double */
+double silk_inner_product_FLP(
+    const silk_float    *data1,
+    const silk_float    *data2,
+    opus_int            dataSize
+)
+{
+    opus_int  i, dataSize4;
+    double   result;
+
+    /* 4x unrolled loop */
+    result = 0.0;
+    dataSize4 = dataSize & 0xFFFC;
+    for( i = 0; i < dataSize4; i += 4 ) {
+        result += data1[ i + 0 ] * (double)data2[ i + 0 ] +
+                  data1[ i + 1 ] * (double)data2[ i + 1 ] +
+                  data1[ i + 2 ] * (double)data2[ i + 2 ] +
+                  data1[ i + 3 ] * (double)data2[ i + 3 ];
+    }
+
+    /* add any remaining products */
+    for( ; i < dataSize; i++ ) {
+        result += data1[ i ] * (double)data2[ i ];
+    }
+
+    return result;
+}
diff --git a/third_party/opus/src/silk/float/k2a_FLP.c b/third_party/opus/src/silk/float/k2a_FLP.c
new file mode 100644
index 0000000..12af4e7
--- /dev/null
+++ b/third_party/opus/src/silk/float/k2a_FLP.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_FLP(
+    silk_float          *A,                 /* O     prediction coefficients [order]                            */
+    const silk_float    *rc,                /* I     reflection coefficients [order]                            */
+    opus_int32          order               /* I     prediction order                                           */
+)
+{
+    opus_int   k, n;
+    silk_float Atmp[ SILK_MAX_ORDER_LPC ];
+
+    for( k = 0; k < order; k++ ) {
+        for( n = 0; n < k; n++ ) {
+            Atmp[ n ] = A[ n ];
+        }
+        for( n = 0; n < k; n++ ) {
+            A[ n ] += Atmp[ k - n - 1 ] * rc[ k ];
+        }
+        A[ k ] = -rc[ k ];
+    }
+}
diff --git a/third_party/opus/src/silk/float/levinsondurbin_FLP.c b/third_party/opus/src/silk/float/levinsondurbin_FLP.c
new file mode 100644
index 0000000..f0ba606
--- /dev/null
+++ b/third_party/opus/src/silk/float/levinsondurbin_FLP.c
@@ -0,0 +1,81 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* Solve the normal equations using the Levinson-Durbin recursion */
+silk_float silk_levinsondurbin_FLP(         /* O    prediction error energy                                     */
+    silk_float          A[],                /* O    prediction coefficients    [order]                          */
+    const silk_float    corr[],             /* I    input auto-correlations [order + 1]                         */
+    const opus_int      order               /* I    prediction order                                            */
+)
+{
+    opus_int   i, mHalf, m;
+    silk_float min_nrg, nrg, t, km, Atmp1, Atmp2;
+
+    min_nrg = 1e-12f * corr[ 0 ] + 1e-9f;
+    nrg = corr[ 0 ];
+    nrg = silk_max_float(min_nrg, nrg);
+    A[ 0 ] = corr[ 1 ] / nrg;
+    nrg -= A[ 0 ] * corr[ 1 ];
+    nrg = silk_max_float(min_nrg, nrg);
+
+    for( m = 1; m < order; m++ )
+    {
+        t = corr[ m + 1 ];
+        for( i = 0; i < m; i++ ) {
+            t -= A[ i ] * corr[ m - i ];
+        }
+
+        /* reflection coefficient */
+        km = t / nrg;
+
+        /* residual energy */
+        nrg -= km * t;
+        nrg = silk_max_float(min_nrg, nrg);
+
+        mHalf = m >> 1;
+        for( i = 0; i < mHalf; i++ ) {
+            Atmp1 = A[ i ];
+            Atmp2 = A[ m - i - 1 ];
+            A[ m - i - 1 ] -= km * Atmp1;
+            A[ i ]         -= km * Atmp2;
+        }
+        if( m & 1 ) {
+            A[ mHalf ]     -= km * A[ mHalf ];
+        }
+        A[ m ] = km;
+    }
+
+    /* return the residual energy */
+    return nrg;
+}
+
diff --git a/third_party/opus/src/silk/float/main_FLP.h b/third_party/opus/src/silk/float/main_FLP.h
new file mode 100644
index 0000000..e5a75972e
--- /dev/null
+++ b/third_party/opus/src/silk/float/main_FLP.h
@@ -0,0 +1,313 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MAIN_FLP_H
+#define SILK_MAIN_FLP_H
+
+#include "SigProc_FLP.h"
+#include "SigProc_FIX.h"
+#include "structs_FLP.h"
+#include "main.h"
+#include "define.h"
+#include "debug.h"
+#include "entenc.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define silk_encoder_state_Fxx      silk_encoder_state_FLP
+#define silk_encode_do_VAD_Fxx      silk_encode_do_VAD_FLP
+#define silk_encode_frame_Fxx       silk_encode_frame_FLP
+
+/*********************/
+/* Encoder Functions */
+/*********************/
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+    silk_encoder_state_Fxx          state_Fxx[]                         /* I/O  Encoder states                              */
+);
+
+/* Encoder main function */
+void silk_encode_do_VAD_FLP(
+    silk_encoder_state_FLP          *psEnc                              /* I/O  Encoder state FLP                           */
+);
+
+/* Encoder main function */
+opus_int silk_encode_frame_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    opus_int32                      *pnBytesOut,                        /* O    Number of payload bytes;                    */
+    ec_enc                          *psRangeEnc,                        /* I/O  compressor data structure                   */
+    opus_int                        condCoding,                         /* I    The type of conditional coding to use       */
+    opus_int                        maxBits,                            /* I    If > 0: maximum number of output bits       */
+    opus_int                        useCBR                              /* I    Flag to force constant-bitrate operation    */
+);
+
+/* Initializes the Silk encoder state */
+opus_int silk_init_encoder(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    int                              arch                               /* I    Run-tim architecture                        */
+);
+
+/* Control the Silk encoder */
+opus_int silk_control_encoder(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Pointer to Silk encoder state FLP           */
+    silk_EncControlStruct           *encControl,                        /* I    Control structure                           */
+    const opus_int32                TargetRate_bps,                     /* I    Target max bitrate (bps)                    */
+    const opus_int                  allow_bw_switch,                    /* I    Flag to allow switching audio bandwidth     */
+    const opus_int                  channelNb,                          /* I    Channel number                              */
+    const opus_int                  force_fs_kHz
+);
+
+/****************/
+/* Prefiltering */
+/****************/
+void silk_prefilter_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    const silk_encoder_control_FLP  *psEncCtrl,                         /* I    Encoder control FLP                         */
+    silk_float                      xw[],                               /* O    Weighted signal                             */
+    const silk_float                x[]                                 /* I    Speech signal                               */
+);
+
+/**************************/
+/* Noise shaping analysis */
+/**************************/
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    const silk_float                *pitch_res,                         /* I    LPC residual from pitch analysis            */
+    const silk_float                *x                                  /* I    Input signal [frame_length + la_shape]      */
+);
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FLP(
+    silk_float                      *corr,                              /* O    Result [order + 1]                          */
+    const silk_float                *input,                             /* I    Input data to correlate                     */
+    const silk_float                warping,                            /* I    Warping coefficient                         */
+    const opus_int                  length,                             /* I    Length of input                             */
+    const opus_int                  order                               /* I    Correlation order (even)                    */
+);
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    opus_int                        condCoding                          /* I    The type of conditional coding to use       */
+);
+
+/**********************************************/
+/* Prediction Analysis                        */
+/**********************************************/
+/* Find pitch lags */
+void silk_find_pitch_lags_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    silk_float                      res[],                              /* O    Residual                                    */
+    const silk_float                x[],                                /* I    Speech signal                               */
+    int                             arch                                /* I    Run-time architecture                       */
+);
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    const silk_float                res_pitch[],                        /* I    Residual from pitch analysis                */
+    const silk_float                x[],                                /* I    Speech signal                               */
+    opus_int                        condCoding                          /* I    The type of conditional coding to use       */
+);
+
+/* LPC analysis */
+void silk_find_LPC_FLP(
+    silk_encoder_state              *psEncC,                            /* I/O  Encoder state                               */
+    opus_int16                      NLSF_Q15[],                         /* O    NLSFs                                       */
+    const silk_float                x[],                                /* I    Input signal                                */
+    const silk_float                minInvGain                          /* I    Prediction gain from LTP (dB)               */
+);
+
+/* LTP analysis */
+void silk_find_LTP_FLP(
+    silk_float                      b[ MAX_NB_SUBFR * LTP_ORDER ],      /* O    LTP coefs                                   */
+    silk_float                      WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O    Weight for LTP quantization       */
+    silk_float                      *LTPredCodGain,                     /* O    LTP coding gain                             */
+    const silk_float                r_lpc[],                            /* I    LPC residual                                */
+    const opus_int                  lag[  MAX_NB_SUBFR ],               /* I    LTP lags                                    */
+    const silk_float                Wght[ MAX_NB_SUBFR ],               /* I    Weights                                     */
+    const opus_int                  subfr_length,                       /* I    Subframe length                             */
+    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
+    const opus_int                  mem_offset                          /* I    Number of samples in LTP memory             */
+);
+
+void silk_LTP_analysis_filter_FLP(
+    silk_float                      *LTP_res,                           /* O    LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */
+    const silk_float                *x,                                 /* I    Input signal, with preceding samples        */
+    const silk_float                B[ LTP_ORDER * MAX_NB_SUBFR ],      /* I    LTP coefficients for each subframe          */
+    const opus_int                  pitchL[   MAX_NB_SUBFR ],           /* I    Pitch lags                                  */
+    const silk_float                invGains[ MAX_NB_SUBFR ],           /* I    Inverse quantization gains                  */
+    const opus_int                  subfr_length,                       /* I    Length of each subframe                     */
+    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
+    const opus_int                  pre_length                          /* I    Preceding samples for each subframe         */
+);
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order   */
+/* of preceding samples                                                                 */
+void silk_residual_energy_FLP(
+    silk_float                      nrgs[ MAX_NB_SUBFR ],               /* O    Residual energy per subframe                */
+    const silk_float                x[],                                /* I    Input signal                                */
+    silk_float                      a[ 2 ][ MAX_LPC_ORDER ],            /* I    AR coefs for each frame half                */
+    const silk_float                gains[],                            /* I    Quantization gains                          */
+    const opus_int                  subfr_length,                       /* I    Subframe length                             */
+    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
+    const opus_int                  LPC_order                           /* I    LPC order                                   */
+);
+
+/* 16th order LPC analysis filter */
+void silk_LPC_analysis_filter_FLP(
+    silk_float                      r_LPC[],                            /* O    LPC residual signal                         */
+    const silk_float                PredCoef[],                         /* I    LPC coefficients                            */
+    const silk_float                s[],                                /* I    Input signal                                */
+    const opus_int                  length,                             /* I    Length of input signal                      */
+    const opus_int                  Order                               /* I    LPC order                                   */
+);
+
+/* LTP tap quantizer */
+void silk_quant_LTP_gains_FLP(
+    silk_float                      B[ MAX_NB_SUBFR * LTP_ORDER ],      /* I/O  (Un-)quantized LTP gains                    */
+    opus_int8                       cbk_index[ MAX_NB_SUBFR ],          /* O    Codebook index                              */
+    opus_int8                       *periodicity_index,                 /* O    Periodicity index                           */
+    opus_int32                      *sum_log_gain_Q7,                   /* I/O  Cumulative max prediction gain  */
+    const silk_float                W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I    Error weights                        */
+    const opus_int                  mu_Q10,                             /* I    Mu value (R/D tradeoff)                     */
+    const opus_int                  lowComplexity,                      /* I    Flag for low complexity                     */
+    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
+    int                             arch                                /* I    Run-time architecture                       */
+);
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+silk_float silk_residual_energy_covar_FLP(                              /* O    Weighted residual energy                    */
+    const silk_float                *c,                                 /* I    Filter coefficients                         */
+    silk_float                      *wXX,                               /* I/O  Weighted correlation matrix, reg. out       */
+    const silk_float                *wXx,                               /* I    Weighted correlation vector                 */
+    const silk_float                wxx,                                /* I    Weighted correlation value                  */
+    const opus_int                  D                                   /* I    Dimension                                   */
+);
+
+/* Processing of gains */
+void silk_process_gains_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    opus_int                        condCoding                          /* I    The type of conditional coding to use       */
+);
+
+/******************/
+/* Linear Algebra */
+/******************/
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FLP(
+    const silk_float                *x,                                 /* I    x vector [ L+order-1 ] used to create X     */
+    const opus_int                  L,                                  /* I    Length of vectors                           */
+    const opus_int                  Order,                              /* I    Max lag for correlation                     */
+    silk_float                      *XX                                 /* O    X'*X correlation matrix [order x order]     */
+);
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FLP(
+    const silk_float                *x,                                 /* I    x vector [L+order-1] used to create X       */
+    const silk_float                *t,                                 /* I    Target vector [L]                           */
+    const opus_int                  L,                                  /* I    Length of vecors                            */
+    const opus_int                  Order,                              /* I    Max lag for correlation                     */
+    silk_float                      *Xt                                 /* O    X'*t correlation vector [order]             */
+);
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FLP(
+    silk_float                      *XX,                                /* I/O  Correlation matrices                        */
+    silk_float                      *xx,                                /* I/O  Correlation values                          */
+    const silk_float                noise,                              /* I    Noise energy to add                         */
+    const opus_int                  D                                   /* I    Dimension of XX                             */
+);
+
+/* Function to solve linear equation Ax = b, where A is an MxM symmetric matrix */
+void silk_solve_LDL_FLP(
+    silk_float                      *A,                                 /* I/O  Symmetric square matrix, out: reg.          */
+    const opus_int                  M,                                  /* I    Size of matrix                              */
+    const silk_float                *b,                                 /* I    Pointer to b vector                         */
+    silk_float                      *x                                  /* O    Pointer to x solution vector                */
+);
+
+/* Apply sine window to signal vector.  */
+/* Window types:                        */
+/*  1 -> sine window from 0 to pi/2     */
+/*  2 -> sine window from pi/2 to pi    */
+void silk_apply_sine_window_FLP(
+    silk_float                      px_win[],                           /* O    Pointer to windowed signal                  */
+    const silk_float                px[],                               /* I    Pointer to input signal                     */
+    const opus_int                  win_type,                           /* I    Selects a window type                       */
+    const opus_int                  length                              /* I    Window length, multiple of 4                */
+);
+
+/* Wrapper functions. Call flp / fix code */
+
+/* Convert AR filter coefficients to NLSF parameters */
+void silk_A2NLSF_FLP(
+    opus_int16                      *NLSF_Q15,                          /* O    NLSF vector      [ LPC_order ]              */
+    const silk_float                *pAR,                               /* I    LPC coefficients [ LPC_order ]              */
+    const opus_int                  LPC_order                           /* I    LPC order                                   */
+);
+
+/* Convert NLSF parameters to AR prediction filter coefficients */
+void silk_NLSF2A_FLP(
+    silk_float                      *pAR,                               /* O    LPC coefficients [ LPC_order ]              */
+    const opus_int16                *NLSF_Q15,                          /* I    NLSF vector      [ LPC_order ]              */
+    const opus_int                  LPC_order                           /* I    LPC order                                   */
+);
+
+/* Limit, stabilize, and quantize NLSFs */
+void silk_process_NLSFs_FLP(
+    silk_encoder_state              *psEncC,                            /* I/O  Encoder state                               */
+    silk_float                      PredCoef[ 2 ][ MAX_LPC_ORDER ],     /* O    Prediction coefficients                     */
+    opus_int16                      NLSF_Q15[      MAX_LPC_ORDER ],     /* I/O  Normalized LSFs (quant out) (0 - (2^15-1))  */
+    const opus_int16                prev_NLSF_Q15[ MAX_LPC_ORDER ]      /* I    Previous Normalized LSFs (0 - (2^15-1))     */
+);
+
+/* Floating-point Silk NSQ wrapper      */
+void silk_NSQ_wrapper_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    SideInfoIndices                 *psIndices,                         /* I/O  Quantization indices                        */
+    silk_nsq_state                  *psNSQ,                             /* I/O  Noise Shaping Quantzation state             */
+    opus_int8                       pulses[],                           /* O    Quantized pulse signal                      */
+    const silk_float                x[]                                 /* I    Prefiltered input signal                    */
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/float/noise_shape_analysis_FLP.c b/third_party/opus/src/silk/float/noise_shape_analysis_FLP.c
new file mode 100644
index 0000000..65f6ea58
--- /dev/null
+++ b/third_party/opus/src/silk/float/noise_shape_analysis_FLP.c
@@ -0,0 +1,365 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a   */
+/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
+/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
+/* coefficient in an array of coefficients, for monic filters.                                    */
+static OPUS_INLINE silk_float warped_gain(
+    const silk_float     *coefs,
+    silk_float           lambda,
+    opus_int             order
+) {
+    opus_int   i;
+    silk_float gain;
+
+    lambda = -lambda;
+    gain = coefs[ order - 1 ];
+    for( i = order - 2; i >= 0; i-- ) {
+        gain = lambda * gain + coefs[ i ];
+    }
+    return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) );
+}
+
+/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum     */
+/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
+static OPUS_INLINE void warped_true2monic_coefs(
+    silk_float           *coefs_syn,
+    silk_float           *coefs_ana,
+    silk_float           lambda,
+    silk_float           limit,
+    opus_int             order
+) {
+    opus_int   i, iter, ind = 0;
+    silk_float tmp, maxabs, chirp, gain_syn, gain_ana;
+
+    /* Convert to monic coefficients */
+    for( i = order - 1; i > 0; i-- ) {
+        coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ];
+        coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ];
+    }
+    gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] );
+    gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] );
+    for( i = 0; i < order; i++ ) {
+        coefs_syn[ i ] *= gain_syn;
+        coefs_ana[ i ] *= gain_ana;
+    }
+
+    /* Limit */
+    for( iter = 0; iter < 10; iter++ ) {
+        /* Find maximum absolute value */
+        maxabs = -1.0f;
+        for( i = 0; i < order; i++ ) {
+            tmp = silk_max( silk_abs_float( coefs_syn[ i ] ), silk_abs_float( coefs_ana[ i ] ) );
+            if( tmp > maxabs ) {
+                maxabs = tmp;
+                ind = i;
+            }
+        }
+        if( maxabs <= limit ) {
+            /* Coefficients are within range - done */
+            return;
+        }
+
+        /* Convert back to true warped coefficients */
+        for( i = 1; i < order; i++ ) {
+            coefs_syn[ i - 1 ] += lambda * coefs_syn[ i ];
+            coefs_ana[ i - 1 ] += lambda * coefs_ana[ i ];
+        }
+        gain_syn = 1.0f / gain_syn;
+        gain_ana = 1.0f / gain_ana;
+        for( i = 0; i < order; i++ ) {
+            coefs_syn[ i ] *= gain_syn;
+            coefs_ana[ i ] *= gain_ana;
+        }
+
+        /* Apply bandwidth expansion */
+        chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) );
+        silk_bwexpander_FLP( coefs_syn, order, chirp );
+        silk_bwexpander_FLP( coefs_ana, order, chirp );
+
+        /* Convert to monic warped coefficients */
+        for( i = order - 1; i > 0; i-- ) {
+            coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ];
+            coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ];
+        }
+        gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] );
+        gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] );
+        for( i = 0; i < order; i++ ) {
+            coefs_syn[ i ] *= gain_syn;
+            coefs_ana[ i ] *= gain_ana;
+        }
+    }
+    silk_assert( 0 );
+}
+
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    const silk_float                *pitch_res,                         /* I    LPC residual from pitch analysis            */
+    const silk_float                *x                                  /* I    Input signal [frame_length + la_shape]      */
+)
+{
+    silk_shape_state_FLP *psShapeSt = &psEnc->sShape;
+    opus_int     k, nSamples;
+    silk_float   SNR_adj_dB, HarmBoost, HarmShapeGain, Tilt;
+    silk_float   nrg, pre_nrg, log_energy, log_energy_prev, energy_variation;
+    silk_float   delta, BWExp1, BWExp2, gain_mult, gain_add, strength, b, warping;
+    silk_float   x_windowed[ SHAPE_LPC_WIN_MAX ];
+    silk_float   auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
+    const silk_float *x_ptr, *pitch_res_ptr;
+
+    /* Point to start of first LPC analysis block */
+    x_ptr = x - psEnc->sCmn.la_shape;
+
+    /****************/
+    /* GAIN CONTROL */
+    /****************/
+    SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f );
+
+    /* Input quality is the average of the quality in the lowest two VAD bands */
+    psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f );
+
+    /* Coding quality level, between 0.0 and 1.0 */
+    psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) );
+
+    if( psEnc->sCmn.useCBR == 0 ) {
+        /* Reduce coding SNR during low speech activity */
+        b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f /  256.0f );
+        SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b;
+    }
+
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Reduce gains for periodic signals */
+        SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr;
+    } else {
+        /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
+        SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality );
+    }
+
+    /*************************/
+    /* SPARSENESS PROCESSING */
+    /*************************/
+    /* Set quantizer offset */
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Initially set to 0; may be overruled in process_gains(..) */
+        psEnc->sCmn.indices.quantOffsetType = 0;
+        psEncCtrl->sparseness = 0.0f;
+    } else {
+        /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
+        nSamples = 2 * psEnc->sCmn.fs_kHz;
+        energy_variation = 0.0f;
+        log_energy_prev  = 0.0f;
+        pitch_res_ptr = pitch_res;
+        for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) {
+            nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples );
+            log_energy = silk_log2( nrg );
+            if( k > 0 ) {
+                energy_variation += silk_abs_float( log_energy - log_energy_prev );
+            }
+            log_energy_prev = log_energy;
+            pitch_res_ptr += nSamples;
+        }
+        psEncCtrl->sparseness = silk_sigmoid( 0.4f * ( energy_variation - 5.0f ) );
+
+        /* Set quantization offset depending on sparseness measure */
+        if( psEncCtrl->sparseness > SPARSENESS_THRESHOLD_QNT_OFFSET ) {
+            psEnc->sCmn.indices.quantOffsetType = 0;
+        } else {
+            psEnc->sCmn.indices.quantOffsetType = 1;
+        }
+
+        /* Increase coding SNR for sparse signals */
+        SNR_adj_dB += SPARSE_SNR_INCR_dB * ( psEncCtrl->sparseness - 0.5f );
+    }
+
+    /*******************************/
+    /* Control bandwidth expansion */
+    /*******************************/
+    /* More BWE for signals with high prediction gain */
+    strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain;           /* between 0.0 and 1.0 */
+    BWExp1 = BWExp2 = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength );
+    delta  = LOW_RATE_BANDWIDTH_EXPANSION_DELTA * ( 1.0f - 0.75f * psEncCtrl->coding_quality );
+    BWExp1 -= delta;
+    BWExp2 += delta;
+    /* BWExp1 will be applied after BWExp2, so make it relative */
+    BWExp1 /= BWExp2;
+
+    if( psEnc->sCmn.warping_Q16 > 0 ) {
+        /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
+        warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality;
+    } else {
+        warping = 0.0f;
+    }
+
+    /********************************************/
+    /* Compute noise shaping AR coefs and gains */
+    /********************************************/
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        /* Apply window: sine slope followed by flat part followed by cosine slope */
+        opus_int shift, slope_part, flat_part;
+        flat_part = psEnc->sCmn.fs_kHz * 3;
+        slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2;
+
+        silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part );
+        shift = slope_part;
+        silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) );
+        shift += flat_part;
+        silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part );
+
+        /* Update pointer: next LPC analysis block */
+        x_ptr += psEnc->sCmn.subfr_length;
+
+        if( psEnc->sCmn.warping_Q16 > 0 ) {
+            /* Calculate warped auto correlation */
+            silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping,
+                psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder );
+        } else {
+            /* Calculate regular auto correlation */
+            silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 );
+        }
+
+        /* Add white noise, as a fraction of energy */
+        auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION;
+
+        /* Convert correlations to prediction coefficients, and compute residual energy */
+        nrg = silk_levinsondurbin_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], auto_corr, psEnc->sCmn.shapingLPCOrder );
+        psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg );
+
+        if( psEnc->sCmn.warping_Q16 > 0 ) {
+            /* Adjust gain for warping */
+            psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder );
+        }
+
+        /* Bandwidth expansion for synthesis filter shaping */
+        silk_bwexpander_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp2 );
+
+        /* Compute noise shaping filter coefficients */
+        silk_memcpy(
+            &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ],
+            &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ],
+            psEnc->sCmn.shapingLPCOrder * sizeof( silk_float ) );
+
+        /* Bandwidth expansion for analysis filter shaping */
+        silk_bwexpander_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp1 );
+
+        /* Ratio of prediction gains, in energy domain */
+        pre_nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder );
+        nrg     = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder );
+        psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg );
+
+        /* Convert to monic warped prediction coefficients and limit absolute values */
+        warped_true2monic_coefs( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ],
+            warping, 3.999f, psEnc->sCmn.shapingLPCOrder );
+    }
+
+    /*****************/
+    /* Gain tweaking */
+    /*****************/
+    /* Increase gains during low speech activity */
+    gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB );
+    gain_add  = (silk_float)pow( 2.0f,  0.16f * MIN_QGAIN_DB );
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        psEncCtrl->Gains[ k ] *= gain_mult;
+        psEncCtrl->Gains[ k ] += gain_add;
+    }
+
+    gain_mult = 1.0f + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT;
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        psEncCtrl->GainsPre[ k ] *= gain_mult;
+    }
+
+    /************************************************/
+    /* Control low-frequency shaping and noise tilt */
+    /************************************************/
+    /* Less low frequency shaping for noisy inputs */
+    strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) );
+    strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f /  256.0f );
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
+        /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
+        for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+            b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ];
+            psEncCtrl->LF_MA_shp[ k ] = -1.0f + b;
+            psEncCtrl->LF_AR_shp[ k ] =  1.0f - b - b * strength;
+        }
+        Tilt = - HP_NOISE_COEF -
+            (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f /  256.0f );
+    } else {
+        b = 1.3f / psEnc->sCmn.fs_kHz;
+        psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b;
+        psEncCtrl->LF_AR_shp[ 0 ] =  1.0f - b - b * strength * 0.6f;
+        for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
+            psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ];
+            psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ];
+        }
+        Tilt = -HP_NOISE_COEF;
+    }
+
+    /****************************/
+    /* HARMONIC SHAPING CONTROL */
+    /****************************/
+    /* Control boosting of harmonic frequencies */
+    HarmBoost = LOW_RATE_HARMONIC_BOOST * ( 1.0f - psEncCtrl->coding_quality ) * psEnc->LTPCorr;
+
+    /* More harmonic boost for noisy input signals */
+    HarmBoost += LOW_INPUT_QUALITY_HARMONIC_BOOST * ( 1.0f - psEncCtrl->input_quality );
+
+    if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        /* Harmonic noise shaping */
+        HarmShapeGain = HARMONIC_SHAPING;
+
+        /* More harmonic noise shaping for high bitrates or noisy input */
+        HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING *
+            ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality );
+
+        /* Less harmonic noise shaping for less periodic signals */
+        HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr );
+    } else {
+        HarmShapeGain = 0.0f;
+    }
+
+    /*************************/
+    /* Smooth over subframes */
+    /*************************/
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        psShapeSt->HarmBoost_smth     += SUBFR_SMTH_COEF * ( HarmBoost - psShapeSt->HarmBoost_smth );
+        psEncCtrl->HarmBoost[ k ]      = psShapeSt->HarmBoost_smth;
+        psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth );
+        psEncCtrl->HarmShapeGain[ k ]  = psShapeSt->HarmShapeGain_smth;
+        psShapeSt->Tilt_smth          += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth );
+        psEncCtrl->Tilt[ k ]           = psShapeSt->Tilt_smth;
+    }
+}
diff --git a/third_party/opus/src/silk/float/pitch_analysis_core_FLP.c b/third_party/opus/src/silk/float/pitch_analysis_core_FLP.c
new file mode 100644
index 0000000..d0e637a
--- /dev/null
+++ b/third_party/opus/src/silk/float/pitch_analysis_core_FLP.c
@@ -0,0 +1,630 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*****************************************************************************
+* Pitch analyser function
+******************************************************************************/
+#include "SigProc_FLP.h"
+#include "SigProc_FIX.h"
+#include "pitch_est_defines.h"
+#include "pitch.h"
+
+#define SCRATCH_SIZE        22
+
+/************************************************************/
+/* Internally used functions                                */
+/************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+    silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+    const silk_float    frame[],            /* I vector to correlate                                            */
+    opus_int            start_lag,          /* I start lag                                                      */
+    opus_int            sf_length,          /* I sub frame length                                               */
+    opus_int            nb_subfr,           /* I number of subframes                                            */
+    opus_int            complexity,         /* I Complexity setting                                             */
+    int                 arch                /* I Run-time architecture                                          */
+);
+
+static void silk_P_Ana_calc_energy_st3(
+    silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+    const silk_float    frame[],            /* I vector to correlate                                            */
+    opus_int            start_lag,          /* I start lag                                                      */
+    opus_int            sf_length,          /* I sub frame length                                               */
+    opus_int            nb_subfr,           /* I number of subframes                                            */
+    opus_int            complexity          /* I Complexity setting                                             */
+);
+
+/************************************************************/
+/* CORE PITCH ANALYSIS FUNCTION                             */
+/************************************************************/
+opus_int silk_pitch_analysis_core_FLP(      /* O    Voicing estimate: 0 voiced, 1 unvoiced                      */
+    const silk_float    *frame,             /* I    Signal of length PE_FRAME_LENGTH_MS*Fs_kHz                  */
+    opus_int            *pitch_out,         /* O    Pitch lag values [nb_subfr]                                 */
+    opus_int16          *lagIndex,          /* O    Lag Index                                                   */
+    opus_int8           *contourIndex,      /* O    Pitch contour Index                                         */
+    silk_float          *LTPCorr,           /* I/O  Normalized correlation; input: value from previous frame    */
+    opus_int            prevLag,            /* I    Last lag of previous frame; set to zero is unvoiced         */
+    const silk_float    search_thres1,      /* I    First stage threshold for lag candidates 0 - 1              */
+    const silk_float    search_thres2,      /* I    Final threshold for lag candidates 0 - 1                    */
+    const opus_int      Fs_kHz,             /* I    sample frequency (kHz)                                      */
+    const opus_int      complexity,         /* I    Complexity setting, 0-2, where 2 is highest                 */
+    const opus_int      nb_subfr,           /* I    Number of 5 ms subframes                                    */
+    int                 arch                /* I    Run-time architecture                                       */
+)
+{
+    opus_int   i, k, d, j;
+    silk_float frame_8kHz[  PE_MAX_FRAME_LENGTH_MS * 8 ];
+    silk_float frame_4kHz[  PE_MAX_FRAME_LENGTH_MS * 4 ];
+    opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ];
+    opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ];
+    opus_int32 filt_state[ 6 ];
+    silk_float threshold, contour_bias;
+    silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ];
+    opus_val32 xcorr[ PE_MAX_LAG_MS * 4 - PE_MIN_LAG_MS * 4 + 1 ];
+    silk_float CC[ PE_NB_CBKS_STAGE2_EXT ];
+    const silk_float *target_ptr, *basis_ptr;
+    double    cross_corr, normalizer, energy, energy_tmp;
+    opus_int   d_srch[ PE_D_SRCH_LENGTH ];
+    opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ];
+    opus_int   length_d_srch, length_d_comp;
+    silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new;
+    opus_int   CBimax, CBimax_new, lag, start_lag, end_lag, lag_new;
+    opus_int   cbk_size;
+    silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr;
+    silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ];
+    silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ];
+    opus_int   lag_counter;
+    opus_int   frame_length, frame_length_8kHz, frame_length_4kHz;
+    opus_int   sf_length, sf_length_8kHz, sf_length_4kHz;
+    opus_int   min_lag, min_lag_8kHz, min_lag_4kHz;
+    opus_int   max_lag, max_lag_8kHz, max_lag_4kHz;
+    opus_int   nb_cbk_search;
+    const opus_int8 *Lag_CB_ptr;
+
+    /* Check for valid sampling frequency */
+    silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
+
+    /* Check for valid complexity setting */
+    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+    silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f );
+    silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f );
+
+    /* Set up frame lengths max / min lag for the sampling frequency */
+    frame_length      = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
+    frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
+    frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
+    sf_length         = PE_SUBFR_LENGTH_MS * Fs_kHz;
+    sf_length_4kHz    = PE_SUBFR_LENGTH_MS * 4;
+    sf_length_8kHz    = PE_SUBFR_LENGTH_MS * 8;
+    min_lag           = PE_MIN_LAG_MS * Fs_kHz;
+    min_lag_4kHz      = PE_MIN_LAG_MS * 4;
+    min_lag_8kHz      = PE_MIN_LAG_MS * 8;
+    max_lag           = PE_MAX_LAG_MS * Fs_kHz - 1;
+    max_lag_4kHz      = PE_MAX_LAG_MS * 4;
+    max_lag_8kHz      = PE_MAX_LAG_MS * 8 - 1;
+
+    /* Resample from input sampled at Fs_kHz to 8 kHz */
+    if( Fs_kHz == 16 ) {
+        /* Resample to 16 -> 8 khz */
+        opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ];
+        silk_float2short_array( frame_16_FIX, frame, frame_length );
+        silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+        silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length );
+        silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz );
+    } else if( Fs_kHz == 12 ) {
+        /* Resample to 12 -> 8 khz */
+        opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ];
+        silk_float2short_array( frame_12_FIX, frame, frame_length );
+        silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
+        silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length );
+        silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz );
+    } else {
+        silk_assert( Fs_kHz == 8 );
+        silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz );
+    }
+
+    /* Decimate again to 4 kHz */
+    silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+    silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz );
+    silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz );
+
+    /* Low-pass filter */
+    for( i = frame_length_4kHz - 1; i > 0; i-- ) {
+        frame_4kHz[ i ] += frame_4kHz[ i - 1 ];
+    }
+
+    /******************************************************************************
+    * FIRST STAGE, operating in 4 khz
+    ******************************************************************************/
+    silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5));
+    target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ];
+    for( k = 0; k < nb_subfr >> 1; k++ ) {
+        /* Check that we are within range of the array */
+        silk_assert( target_ptr >= frame_4kHz );
+        silk_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+        basis_ptr = target_ptr - min_lag_4kHz;
+
+        /* Check that we are within range of the array */
+        silk_assert( basis_ptr >= frame_4kHz );
+        silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+        celt_pitch_xcorr( target_ptr, target_ptr-max_lag_4kHz, xcorr, sf_length_8kHz, max_lag_4kHz - min_lag_4kHz + 1, arch );
+
+        /* Calculate first vector products before loop */
+        cross_corr = xcorr[ max_lag_4kHz - min_lag_4kHz ];
+        normalizer = silk_energy_FLP( target_ptr, sf_length_8kHz ) +
+                     silk_energy_FLP( basis_ptr,  sf_length_8kHz ) +
+                     sf_length_8kHz * 4000.0f;
+
+        C[ 0 ][ min_lag_4kHz ] += (silk_float)( 2 * cross_corr / normalizer );
+
+        /* From now on normalizer is computed recursively */
+        for( d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++ ) {
+            basis_ptr--;
+
+            /* Check that we are within range of the array */
+            silk_assert( basis_ptr >= frame_4kHz );
+            silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+            cross_corr = xcorr[ max_lag_4kHz - d ];
+
+            /* Add contribution of new sample and remove contribution from oldest sample */
+            normalizer +=
+                basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] -
+                basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ];
+            C[ 0 ][ d ] += (silk_float)( 2 * cross_corr / normalizer );
+        }
+        /* Update target pointer */
+        target_ptr += sf_length_8kHz;
+    }
+
+    /* Apply short-lag bias */
+    for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) {
+        C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f;
+    }
+
+    /* Sort */
+    length_d_srch = 4 + 2 * complexity;
+    silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
+    silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch );
+
+    /* Escape if correlation is very low already here */
+    Cmax = C[ 0 ][ min_lag_4kHz ];
+    if( Cmax < 0.2f ) {
+        silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+        *LTPCorr      = 0.0f;
+        *lagIndex     = 0;
+        *contourIndex = 0;
+        return 1;
+    }
+
+    threshold = search_thres1 * Cmax;
+    for( i = 0; i < length_d_srch; i++ ) {
+        /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
+        if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) {
+            d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 );
+        } else {
+            length_d_srch = i;
+            break;
+        }
+    }
+    silk_assert( length_d_srch > 0 );
+
+    for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) {
+        d_comp[ i ] = 0;
+    }
+    for( i = 0; i < length_d_srch; i++ ) {
+        d_comp[ d_srch[ i ] ] = 1;
+    }
+
+    /* Convolution */
+    for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) {
+        d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ];
+    }
+
+    length_d_srch = 0;
+    for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) {
+        if( d_comp[ i + 1 ] > 0 ) {
+            d_srch[ length_d_srch ] = i;
+            length_d_srch++;
+        }
+    }
+
+    /* Convolution */
+    for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) {
+        d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ];
+    }
+
+    length_d_comp = 0;
+    for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) {
+        if( d_comp[ i ] > 0 ) {
+            d_comp[ length_d_comp ] = (opus_int16)( i - 2 );
+            length_d_comp++;
+        }
+    }
+
+    /**********************************************************************************
+    ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
+    *************************************************************************************/
+    /*********************************************************************************
+    * Find energy of each subframe projected onto its history, for a range of delays
+    *********************************************************************************/
+    silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float));
+
+    if( Fs_kHz == 8 ) {
+        target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ];
+    } else {
+        target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
+    }
+    for( k = 0; k < nb_subfr; k++ ) {
+        energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ) + 1.0;
+        for( j = 0; j < length_d_comp; j++ ) {
+            d = d_comp[ j ];
+            basis_ptr = target_ptr - d;
+            cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz );
+            if( cross_corr > 0.0f ) {
+                energy = silk_energy_FLP( basis_ptr, sf_length_8kHz );
+                C[ k ][ d ] = (silk_float)( 2 * cross_corr / ( energy + energy_tmp ) );
+            } else {
+                C[ k ][ d ] = 0.0f;
+            }
+        }
+        target_ptr += sf_length_8kHz;
+    }
+
+    /* search over lag range and lags codebook */
+    /* scale factor for lag codebook, as a function of center lag */
+
+    CCmax   = 0.0f; /* This value doesn't matter */
+    CCmax_b = -1000.0f;
+
+    CBimax = 0; /* To avoid returning undefined lag values */
+    lag = -1;   /* To check if lag with strong enough correlation has been found */
+
+    if( prevLag > 0 ) {
+        if( Fs_kHz == 12 ) {
+            prevLag = silk_LSHIFT( prevLag, 1 ) / 3;
+        } else if( Fs_kHz == 16 ) {
+            prevLag = silk_RSHIFT( prevLag, 1 );
+        }
+        prevLag_log2 = silk_log2( (silk_float)prevLag );
+    } else {
+        prevLag_log2 = 0;
+    }
+
+    /* Set up stage 2 codebook based on number of subframes */
+    if( nb_subfr == PE_MAX_NB_SUBFR ) {
+        cbk_size   = PE_NB_CBKS_STAGE2_EXT;
+        Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+        if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
+            /* If input is 8 khz use a larger codebook here because it is last stage */
+            nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
+        } else {
+            nb_cbk_search = PE_NB_CBKS_STAGE2;
+        }
+    } else {
+        cbk_size       = PE_NB_CBKS_STAGE2_10MS;
+        Lag_CB_ptr     = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+        nb_cbk_search  = PE_NB_CBKS_STAGE2_10MS;
+    }
+
+    for( k = 0; k < length_d_srch; k++ ) {
+        d = d_srch[ k ];
+        for( j = 0; j < nb_cbk_search; j++ ) {
+            CC[j] = 0.0f;
+            for( i = 0; i < nb_subfr; i++ ) {
+                /* Try all codebooks */
+                CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )];
+            }
+        }
+        /* Find best codebook */
+        CCmax_new  = -1000.0f;
+        CBimax_new = 0;
+        for( i = 0; i < nb_cbk_search; i++ ) {
+            if( CC[ i ] > CCmax_new ) {
+                CCmax_new = CC[ i ];
+                CBimax_new = i;
+            }
+        }
+
+        /* Bias towards shorter lags */
+        lag_log2 = silk_log2( (silk_float)d );
+        CCmax_new_b = CCmax_new - PE_SHORTLAG_BIAS * nb_subfr * lag_log2;
+
+        /* Bias towards previous lag */
+        if( prevLag > 0 ) {
+            delta_lag_log2_sqr = lag_log2 - prevLag_log2;
+            delta_lag_log2_sqr *= delta_lag_log2_sqr;
+            CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / ( delta_lag_log2_sqr + 0.5f );
+        }
+
+        if( CCmax_new_b > CCmax_b &&                /* Find maximum biased correlation                  */
+            CCmax_new > nb_subfr * search_thres2    /* Correlation needs to be high enough to be voiced */
+        ) {
+            CCmax_b = CCmax_new_b;
+            CCmax   = CCmax_new;
+            lag     = d;
+            CBimax  = CBimax_new;
+        }
+    }
+
+    if( lag == -1 ) {
+        /* No suitable candidate found */
+        silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) );
+        *LTPCorr      = 0.0f;
+        *lagIndex     = 0;
+        *contourIndex = 0;
+        return 1;
+    }
+
+    /* Output normalized correlation */
+    *LTPCorr = (silk_float)( CCmax / nb_subfr );
+    silk_assert( *LTPCorr >= 0.0f );
+
+    if( Fs_kHz > 8 ) {
+        /* Search in original signal */
+
+        /* Compensate for decimation */
+        silk_assert( lag == silk_SAT16( lag ) );
+        if( Fs_kHz == 12 ) {
+            lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 );
+        } else { /* Fs_kHz == 16 */
+            lag = silk_LSHIFT( lag, 1 );
+        }
+
+        lag = silk_LIMIT_int( lag, min_lag, max_lag );
+        start_lag = silk_max_int( lag - 2, min_lag );
+        end_lag   = silk_min_int( lag + 2, max_lag );
+        lag_new   = lag;                                    /* to avoid undefined lag */
+        CBimax    = 0;                                      /* to avoid undefined lag */
+
+        CCmax = -1000.0f;
+
+        /* Calculate the correlations and energies needed in stage 3 */
+        silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch );
+        silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity );
+
+        lag_counter = 0;
+        silk_assert( lag == silk_SAT16( lag ) );
+        contour_bias = PE_FLATCONTOUR_BIAS / lag;
+
+        /* Set up cbk parameters according to complexity setting and frame length */
+        if( nb_subfr == PE_MAX_NB_SUBFR ) {
+            nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
+            cbk_size      = PE_NB_CBKS_STAGE3_MAX;
+            Lag_CB_ptr    = &silk_CB_lags_stage3[ 0 ][ 0 ];
+        } else {
+            nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+            cbk_size      = PE_NB_CBKS_STAGE3_10MS;
+            Lag_CB_ptr    = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+        }
+
+        target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
+        energy_tmp = silk_energy_FLP( target_ptr, nb_subfr * sf_length ) + 1.0;
+        for( d = start_lag; d <= end_lag; d++ ) {
+            for( j = 0; j < nb_cbk_search; j++ ) {
+                cross_corr = 0.0;
+                energy = energy_tmp;
+                for( k = 0; k < nb_subfr; k++ ) {
+                    cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ];
+                    energy     +=   energies_st3[ k ][ j ][ lag_counter ];
+                }
+                if( cross_corr > 0.0 ) {
+                    CCmax_new = (silk_float)( 2 * cross_corr / energy );
+                    /* Reduce depending on flatness of contour */
+                    CCmax_new *= 1.0f - contour_bias * j;
+                } else {
+                    CCmax_new = 0.0f;
+                }
+
+                if( CCmax_new > CCmax && ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
+                    CCmax   = CCmax_new;
+                    lag_new = d;
+                    CBimax  = j;
+                }
+            }
+            lag_counter++;
+        }
+
+        for( k = 0; k < nb_subfr; k++ ) {
+            pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+            pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
+        }
+        *lagIndex = (opus_int16)( lag_new - min_lag );
+        *contourIndex = (opus_int8)CBimax;
+    } else {        /* Fs_kHz == 8 */
+        /* Save Lags */
+        for( k = 0; k < nb_subfr; k++ ) {
+            pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+            pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * 8 );
+        }
+        *lagIndex = (opus_int16)( lag - min_lag_8kHz );
+        *contourIndex = (opus_int8)CBimax;
+    }
+    silk_assert( *lagIndex >= 0 );
+    /* return as voiced */
+    return 0;
+}
+
+/***********************************************************************
+ * Calculates the correlations used in stage 3 search. In order to cover
+ * the whole lag codebook for all the searched offset lags (lag +- 2),
+ * the following correlations are needed in each sub frame:
+ *
+ * sf1: lag range [-8,...,7] total 16 correlations
+ * sf2: lag range [-4,...,4] total 9 correlations
+ * sf3: lag range [-3,....4] total 8 correltions
+ * sf4: lag range [-6,....8] total 15 correlations
+ *
+ * In total 48 correlations. The direct implementation computed in worst
+ * case 4*12*5 = 240 correlations, but more likely around 120.
+ ***********************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+    silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+    const silk_float    frame[],            /* I vector to correlate                                            */
+    opus_int            start_lag,          /* I start lag                                                      */
+    opus_int            sf_length,          /* I sub frame length                                               */
+    opus_int            nb_subfr,           /* I number of subframes                                            */
+    opus_int            complexity,         /* I Complexity setting                                             */
+    int                 arch                /* I Run-time architecture                                          */
+)
+{
+    const silk_float *target_ptr;
+    opus_int   i, j, k, lag_counter, lag_low, lag_high;
+    opus_int   nb_cbk_search, delta, idx, cbk_size;
+    silk_float scratch_mem[ SCRATCH_SIZE ];
+    opus_val32 xcorr[ SCRATCH_SIZE ];
+    const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+
+    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+    if( nb_subfr == PE_MAX_NB_SUBFR ) {
+        Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+        Lag_CB_ptr    = &silk_CB_lags_stage3[ 0 ][ 0 ];
+        nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+        cbk_size      = PE_NB_CBKS_STAGE3_MAX;
+    } else {
+        silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+        Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+        Lag_CB_ptr    = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+        nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+        cbk_size      = PE_NB_CBKS_STAGE3_10MS;
+    }
+
+    target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
+    for( k = 0; k < nb_subfr; k++ ) {
+        lag_counter = 0;
+
+        /* Calculate the correlations for each subframe */
+        lag_low  = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+        lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
+        silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
+        celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr, sf_length, lag_high - lag_low + 1, arch );
+        for( j = lag_low; j <= lag_high; j++ ) {
+            silk_assert( lag_counter < SCRATCH_SIZE );
+            scratch_mem[ lag_counter ] = xcorr[ lag_high - j ];
+            lag_counter++;
+        }
+
+        delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+        for( i = 0; i < nb_cbk_search; i++ ) {
+            /* Fill out the 3 dim array that stores the correlations for */
+            /* each code_book vector for each start lag */
+            idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+            for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+                silk_assert( idx + j < SCRATCH_SIZE );
+                silk_assert( idx + j < lag_counter );
+                cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ];
+            }
+        }
+        target_ptr += sf_length;
+    }
+}
+
+/********************************************************************/
+/* Calculate the energies for first two subframes. The energies are */
+/* calculated recursively.                                          */
+/********************************************************************/
+static void silk_P_Ana_calc_energy_st3(
+    silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+    const silk_float    frame[],            /* I vector to correlate                                            */
+    opus_int            start_lag,          /* I start lag                                                      */
+    opus_int            sf_length,          /* I sub frame length                                               */
+    opus_int            nb_subfr,           /* I number of subframes                                            */
+    opus_int            complexity          /* I Complexity setting                                             */
+)
+{
+    const silk_float *target_ptr, *basis_ptr;
+    double    energy;
+    opus_int   k, i, j, lag_counter;
+    opus_int   nb_cbk_search, delta, idx, cbk_size, lag_diff;
+    silk_float scratch_mem[ SCRATCH_SIZE ];
+    const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+
+    silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+    silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+    if( nb_subfr == PE_MAX_NB_SUBFR ) {
+        Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+        Lag_CB_ptr    = &silk_CB_lags_stage3[ 0 ][ 0 ];
+        nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+        cbk_size      = PE_NB_CBKS_STAGE3_MAX;
+    } else {
+        silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+        Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+        Lag_CB_ptr    = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+        nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+        cbk_size      = PE_NB_CBKS_STAGE3_10MS;
+    }
+
+    target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
+    for( k = 0; k < nb_subfr; k++ ) {
+        lag_counter = 0;
+
+        /* Calculate the energy for first lag */
+        basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
+        energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3;
+        silk_assert( energy >= 0.0 );
+        scratch_mem[lag_counter] = (silk_float)energy;
+        lag_counter++;
+
+        lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) -  matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
+        for( i = 1; i < lag_diff; i++ ) {
+            /* remove part outside new window */
+            energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i];
+            silk_assert( energy >= 0.0 );
+
+            /* add part that comes into window */
+            energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ];
+            silk_assert( energy >= 0.0 );
+            silk_assert( lag_counter < SCRATCH_SIZE );
+            scratch_mem[lag_counter] = (silk_float)energy;
+            lag_counter++;
+        }
+
+        delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+        for( i = 0; i < nb_cbk_search; i++ ) {
+            /* Fill out the 3 dim array that stores the correlations for    */
+            /* each code_book vector for each start lag                     */
+            idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+            for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+                silk_assert( idx + j < SCRATCH_SIZE );
+                silk_assert( idx + j < lag_counter );
+                energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ];
+                silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f );
+            }
+        }
+        target_ptr += sf_length;
+    }
+}
diff --git a/third_party/opus/src/silk/float/prefilter_FLP.c b/third_party/opus/src/silk/float/prefilter_FLP.c
new file mode 100644
index 0000000..8bc32fb
--- /dev/null
+++ b/third_party/opus/src/silk/float/prefilter_FLP.c
@@ -0,0 +1,206 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/*
+* Prefilter for finding Quantizer input signal
+*/
+static OPUS_INLINE void silk_prefilt_FLP(
+    silk_prefilter_state_FLP    *P,                 /* I/O state */
+    silk_float                  st_res[],           /* I */
+    silk_float                  xw[],               /* O */
+    silk_float                  *HarmShapeFIR,      /* I */
+    silk_float                  Tilt,               /* I */
+    silk_float                  LF_MA_shp,          /* I */
+    silk_float                  LF_AR_shp,          /* I */
+    opus_int                    lag,                /* I */
+    opus_int                    length              /* I */
+);
+
+static void silk_warped_LPC_analysis_filter_FLP(
+          silk_float                 state[],            /* I/O  State [order + 1]                       */
+          silk_float                 res[],              /* O    Residual signal [length]                */
+    const silk_float                 coef[],             /* I    Coefficients [order]                    */
+    const silk_float                 input[],            /* I    Input signal [length]                   */
+    const silk_float                 lambda,             /* I    Warping factor                          */
+    const opus_int                   length,             /* I    Length of input signal                  */
+    const opus_int                   order               /* I    Filter order (even)                     */
+)
+{
+    opus_int     n, i;
+    silk_float   acc, tmp1, tmp2;
+
+    /* Order must be even */
+    silk_assert( ( order & 1 ) == 0 );
+
+    for( n = 0; n < length; n++ ) {
+        /* Output of lowpass section */
+        tmp2 = state[ 0 ] + lambda * state[ 1 ];
+        state[ 0 ] = input[ n ];
+        /* Output of allpass section */
+        tmp1 = state[ 1 ] + lambda * ( state[ 2 ] - tmp2 );
+        state[ 1 ] = tmp2;
+        acc = coef[ 0 ] * tmp2;
+        /* Loop over allpass sections */
+        for( i = 2; i < order; i += 2 ) {
+            /* Output of allpass section */
+            tmp2 = state[ i ] + lambda * ( state[ i + 1 ] - tmp1 );
+            state[ i ] = tmp1;
+            acc += coef[ i - 1 ] * tmp1;
+            /* Output of allpass section */
+            tmp1 = state[ i + 1 ] + lambda * ( state[ i + 2 ] - tmp2 );
+            state[ i + 1 ] = tmp2;
+            acc += coef[ i ] * tmp2;
+        }
+        state[ order ] = tmp1;
+        acc += coef[ order - 1 ] * tmp1;
+        res[ n ] = input[ n ] - acc;
+    }
+}
+
+/*
+* silk_prefilter. Main prefilter function
+*/
+void silk_prefilter_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    const silk_encoder_control_FLP  *psEncCtrl,                         /* I    Encoder control FLP                         */
+    silk_float                      xw[],                               /* O    Weighted signal                             */
+    const silk_float                x[]                                 /* I    Speech signal                               */
+)
+{
+    silk_prefilter_state_FLP *P = &psEnc->sPrefilt;
+    opus_int   j, k, lag;
+    silk_float HarmShapeGain, Tilt, LF_MA_shp, LF_AR_shp;
+    silk_float B[ 2 ];
+    const silk_float *AR1_shp;
+    const silk_float *px;
+    silk_float *pxw;
+    silk_float HarmShapeFIR[ 3 ];
+    silk_float st_res[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ];
+
+    /* Set up pointers */
+    px  = x;
+    pxw = xw;
+    lag = P->lagPrev;
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        /* Update Variables that change per sub frame */
+        if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+            lag = psEncCtrl->pitchL[ k ];
+        }
+
+        /* Noise shape parameters */
+        HarmShapeGain = psEncCtrl->HarmShapeGain[ k ] * ( 1.0f - psEncCtrl->HarmBoost[ k ] );
+        HarmShapeFIR[ 0 ] = 0.25f               * HarmShapeGain;
+        HarmShapeFIR[ 1 ] = 32767.0f / 65536.0f * HarmShapeGain;
+        HarmShapeFIR[ 2 ] = 0.25f               * HarmShapeGain;
+        Tilt      =  psEncCtrl->Tilt[ k ];
+        LF_MA_shp =  psEncCtrl->LF_MA_shp[ k ];
+        LF_AR_shp =  psEncCtrl->LF_AR_shp[ k ];
+        AR1_shp   = &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ];
+
+        /* Short term FIR filtering */
+        silk_warped_LPC_analysis_filter_FLP( P->sAR_shp, st_res, AR1_shp, px,
+            (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder );
+
+        /* Reduce (mainly) low frequencies during harmonic emphasis */
+        B[ 0 ] =  psEncCtrl->GainsPre[ k ];
+        B[ 1 ] = -psEncCtrl->GainsPre[ k ] *
+            ( psEncCtrl->HarmBoost[ k ] * HarmShapeGain + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT );
+        pxw[ 0 ] = B[ 0 ] * st_res[ 0 ] + B[ 1 ] * P->sHarmHP;
+        for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) {
+            pxw[ j ] = B[ 0 ] * st_res[ j ] + B[ 1 ] * st_res[ j - 1 ];
+        }
+        P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ];
+
+        silk_prefilt_FLP( P, pxw, pxw, HarmShapeFIR, Tilt, LF_MA_shp, LF_AR_shp, lag, psEnc->sCmn.subfr_length );
+
+        px  += psEnc->sCmn.subfr_length;
+        pxw += psEnc->sCmn.subfr_length;
+    }
+    P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+}
+
+/*
+* Prefilter for finding Quantizer input signal
+*/
+static OPUS_INLINE void silk_prefilt_FLP(
+    silk_prefilter_state_FLP    *P,                 /* I/O state */
+    silk_float                  st_res[],           /* I */
+    silk_float                  xw[],               /* O */
+    silk_float                  *HarmShapeFIR,      /* I */
+    silk_float                  Tilt,               /* I */
+    silk_float                  LF_MA_shp,          /* I */
+    silk_float                  LF_AR_shp,          /* I */
+    opus_int                    lag,                /* I */
+    opus_int                    length              /* I */
+)
+{
+    opus_int   i;
+    opus_int   idx, LTP_shp_buf_idx;
+    silk_float n_Tilt, n_LF, n_LTP;
+    silk_float sLF_AR_shp, sLF_MA_shp;
+    silk_float *LTP_shp_buf;
+
+    /* To speed up use temp variables instead of using the struct */
+    LTP_shp_buf     = P->sLTP_shp;
+    LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
+    sLF_AR_shp      = P->sLF_AR_shp;
+    sLF_MA_shp      = P->sLF_MA_shp;
+
+    for( i = 0; i < length; i++ ) {
+        if( lag > 0 ) {
+            silk_assert( HARM_SHAPE_FIR_TAPS == 3 );
+            idx = lag + LTP_shp_buf_idx;
+            n_LTP  = LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ] * HarmShapeFIR[ 0 ];
+            n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2    ) & LTP_MASK ] * HarmShapeFIR[ 1 ];
+            n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ] * HarmShapeFIR[ 2 ];
+        } else {
+            n_LTP = 0;
+        }
+
+        n_Tilt = sLF_AR_shp * Tilt;
+        n_LF   = sLF_AR_shp * LF_AR_shp + sLF_MA_shp * LF_MA_shp;
+
+        sLF_AR_shp = st_res[ i ] - n_Tilt;
+        sLF_MA_shp = sLF_AR_shp - n_LF;
+
+        LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
+        LTP_shp_buf[ LTP_shp_buf_idx ] = sLF_MA_shp;
+
+        xw[ i ] = sLF_MA_shp - n_LTP;
+    }
+    /* Copy temp variable back to state */
+    P->sLF_AR_shp       = sLF_AR_shp;
+    P->sLF_MA_shp       = sLF_MA_shp;
+    P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
+}
diff --git a/third_party/opus/src/silk/float/process_gains_FLP.c b/third_party/opus/src/silk/float/process_gains_FLP.c
new file mode 100644
index 0000000..c0da0dae44
--- /dev/null
+++ b/third_party/opus/src/silk/float/process_gains_FLP.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/* Processing of gains */
+void silk_process_gains_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    opus_int                        condCoding                          /* I    The type of conditional coding to use       */
+)
+{
+    silk_shape_state_FLP *psShapeSt = &psEnc->sShape;
+    opus_int     k;
+    opus_int32   pGains_Q16[ MAX_NB_SUBFR ];
+    silk_float   s, InvMaxSqrVal, gain, quant_offset;
+
+    /* Gain reduction when LTP coding gain is high */
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        s = 1.0f - 0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) );
+        for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+            psEncCtrl->Gains[ k ] *= s;
+        }
+    }
+
+    /* Limit the quantized signal */
+    InvMaxSqrVal = ( silk_float )( pow( 2.0f, 0.33f * ( 21.0f - psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) ) ) / psEnc->sCmn.subfr_length );
+
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        /* Soft limit on ratio residual energy and squared gains */
+        gain = psEncCtrl->Gains[ k ];
+        gain = ( silk_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal );
+        psEncCtrl->Gains[ k ] = silk_min_float( gain, 32767.0f );
+    }
+
+    /* Prepare gains for noise shaping quantization */
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        pGains_Q16[ k ] = (opus_int32)( psEncCtrl->Gains[ k ] * 65536.0f );
+    }
+
+    /* Save unquantized gains and gain Index */
+    silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+    psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
+    /* Quantize gains */
+    silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
+            &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+    /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+    for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+        psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f;
+    }
+
+    /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
+    if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+        if( psEncCtrl->LTPredCodGain + psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ) > 1.0f ) {
+            psEnc->sCmn.indices.quantOffsetType = 0;
+        } else {
+            psEnc->sCmn.indices.quantOffsetType = 1;
+        }
+    }
+
+    /* Quantizer boundary adjustment */
+    quant_offset = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ] / 1024.0f;
+    psEncCtrl->Lambda = LAMBDA_OFFSET
+                      + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision
+                      + LAMBDA_SPEECH_ACT        * psEnc->sCmn.speech_activity_Q8 * ( 1.0f /  256.0f )
+                      + LAMBDA_INPUT_QUALITY     * psEncCtrl->input_quality
+                      + LAMBDA_CODING_QUALITY    * psEncCtrl->coding_quality
+                      + LAMBDA_QUANT_OFFSET      * quant_offset;
+
+    silk_assert( psEncCtrl->Lambda > 0.0f );
+    silk_assert( psEncCtrl->Lambda < 2.0f );
+}
diff --git a/third_party/opus/src/silk/float/regularize_correlations_FLP.c b/third_party/opus/src/silk/float/regularize_correlations_FLP.c
new file mode 100644
index 0000000..df461260
--- /dev/null
+++ b/third_party/opus/src/silk/float/regularize_correlations_FLP.c
@@ -0,0 +1,48 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FLP(
+    silk_float                      *XX,                                /* I/O  Correlation matrices                        */
+    silk_float                      *xx,                                /* I/O  Correlation values                          */
+    const silk_float                noise,                              /* I    Noise energy to add                         */
+    const opus_int                  D                                   /* I    Dimension of XX                             */
+)
+{
+    opus_int i;
+
+    for( i = 0; i < D; i++ ) {
+        matrix_ptr( &XX[ 0 ], i, i, D ) += noise;
+    }
+    xx[ 0 ] += noise;
+}
diff --git a/third_party/opus/src/silk/float/residual_energy_FLP.c b/third_party/opus/src/silk/float/residual_energy_FLP.c
new file mode 100644
index 0000000..b2e03a8
--- /dev/null
+++ b/third_party/opus/src/silk/float/residual_energy_FLP.c
@@ -0,0 +1,117 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+#define MAX_ITERATIONS_RESIDUAL_NRG         10
+#define REGULARIZATION_FACTOR               1e-8f
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+silk_float silk_residual_energy_covar_FLP(                              /* O    Weighted residual energy                    */
+    const silk_float                *c,                                 /* I    Filter coefficients                         */
+    silk_float                      *wXX,                               /* I/O  Weighted correlation matrix, reg. out       */
+    const silk_float                *wXx,                               /* I    Weighted correlation vector                 */
+    const silk_float                wxx,                                /* I    Weighted correlation value                  */
+    const opus_int                  D                                   /* I    Dimension                                   */
+)
+{
+    opus_int   i, j, k;
+    silk_float tmp, nrg = 0.0f, regularization;
+
+    /* Safety checks */
+    silk_assert( D >= 0 );
+
+    regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] );
+    for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) {
+        nrg = wxx;
+
+        tmp = 0.0f;
+        for( i = 0; i < D; i++ ) {
+            tmp += wXx[ i ] * c[ i ];
+        }
+        nrg -= 2.0f * tmp;
+
+        /* compute c' * wXX * c, assuming wXX is symmetric */
+        for( i = 0; i < D; i++ ) {
+            tmp = 0.0f;
+            for( j = i + 1; j < D; j++ ) {
+                tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ];
+            }
+            nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] );
+        }
+        if( nrg > 0 ) {
+            break;
+        } else {
+            /* Add white noise */
+            for( i = 0; i < D; i++ ) {
+                matrix_c_ptr( wXX, i, i, D ) +=  regularization;
+            }
+            /* Increase noise for next run */
+            regularization *= 2.0f;
+        }
+    }
+    if( k == MAX_ITERATIONS_RESIDUAL_NRG ) {
+        silk_assert( nrg == 0 );
+        nrg = 1.0f;
+    }
+
+    return nrg;
+}
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order   */
+/* of preceding samples                                                                 */
+void silk_residual_energy_FLP(
+    silk_float                      nrgs[ MAX_NB_SUBFR ],               /* O    Residual energy per subframe                */
+    const silk_float                x[],                                /* I    Input signal                                */
+    silk_float                      a[ 2 ][ MAX_LPC_ORDER ],            /* I    AR coefs for each frame half                */
+    const silk_float                gains[],                            /* I    Quantization gains                          */
+    const opus_int                  subfr_length,                       /* I    Subframe length                             */
+    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
+    const opus_int                  LPC_order                           /* I    LPC order                                   */
+)
+{
+    opus_int     shift;
+    silk_float   *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ];
+
+    LPC_res_ptr = LPC_res + LPC_order;
+    shift = LPC_order + subfr_length;
+
+    /* Filter input to create the LPC residual for each frame half, and measure subframe energies */
+    silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order );
+    nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) );
+    nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) );
+
+    if( nb_subfr == MAX_NB_SUBFR ) {
+        silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order );
+        nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) );
+        nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) );
+    }
+}
diff --git a/third_party/opus/src/silk/float/scale_copy_vector_FLP.c b/third_party/opus/src/silk/float/scale_copy_vector_FLP.c
new file mode 100644
index 0000000..20db32b
--- /dev/null
+++ b/third_party/opus/src/silk/float/scale_copy_vector_FLP.c
@@ -0,0 +1,57 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* copy and multiply a vector by a constant */
+void silk_scale_copy_vector_FLP(
+    silk_float          *data_out,
+    const silk_float    *data_in,
+    silk_float          gain,
+    opus_int            dataSize
+)
+{
+    opus_int  i, dataSize4;
+
+    /* 4x unrolled loop */
+    dataSize4 = dataSize & 0xFFFC;
+    for( i = 0; i < dataSize4; i += 4 ) {
+        data_out[ i + 0 ] = gain * data_in[ i + 0 ];
+        data_out[ i + 1 ] = gain * data_in[ i + 1 ];
+        data_out[ i + 2 ] = gain * data_in[ i + 2 ];
+        data_out[ i + 3 ] = gain * data_in[ i + 3 ];
+    }
+
+    /* any remaining elements */
+    for( ; i < dataSize; i++ ) {
+        data_out[ i ] = gain * data_in[ i ];
+    }
+}
diff --git a/third_party/opus/src/silk/float/scale_vector_FLP.c b/third_party/opus/src/silk/float/scale_vector_FLP.c
new file mode 100644
index 0000000..108fdcbe
--- /dev/null
+++ b/third_party/opus/src/silk/float/scale_vector_FLP.c
@@ -0,0 +1,56 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+/* multiply a vector by a constant */
+void silk_scale_vector_FLP(
+    silk_float          *data1,
+    silk_float          gain,
+    opus_int            dataSize
+)
+{
+    opus_int  i, dataSize4;
+
+    /* 4x unrolled loop */
+    dataSize4 = dataSize & 0xFFFC;
+    for( i = 0; i < dataSize4; i += 4 ) {
+        data1[ i + 0 ] *= gain;
+        data1[ i + 1 ] *= gain;
+        data1[ i + 2 ] *= gain;
+        data1[ i + 3 ] *= gain;
+    }
+
+    /* any remaining elements */
+    for( ; i < dataSize; i++ ) {
+        data1[ i ] *= gain;
+    }
+}
diff --git a/third_party/opus/src/silk/float/schur_FLP.c b/third_party/opus/src/silk/float/schur_FLP.c
new file mode 100644
index 0000000..ee436f8
--- /dev/null
+++ b/third_party/opus/src/silk/float/schur_FLP.c
@@ -0,0 +1,70 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FLP.h"
+
+silk_float silk_schur_FLP(                  /* O    returns residual energy                                     */
+    silk_float          refl_coef[],        /* O    reflection coefficients (length order)                      */
+    const silk_float    auto_corr[],        /* I    autocorrelation sequence (length order+1)                   */
+    opus_int            order               /* I    order                                                       */
+)
+{
+    opus_int   k, n;
+    silk_float C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+    silk_float Ctmp1, Ctmp2, rc_tmp;
+
+    silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+    /* Copy correlations */
+    for( k = 0; k < order+1; k++ ) {
+        C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ];
+    }
+
+    for( k = 0; k < order; k++ ) {
+        /* Get reflection coefficient */
+        rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f );
+
+        /* Save the output */
+        refl_coef[ k ] = rc_tmp;
+
+        /* Update correlations */
+        for( n = 0; n < order - k; n++ ) {
+            Ctmp1 = C[ n + k + 1 ][ 0 ];
+            Ctmp2 = C[ n ][ 1 ];
+            C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp;
+            C[ n ][ 1 ]         = Ctmp2 + Ctmp1 * rc_tmp;
+        }
+    }
+
+    /* Return residual energy */
+    return C[ 0 ][ 1 ];
+}
+
diff --git a/third_party/opus/src/silk/float/solve_LS_FLP.c b/third_party/opus/src/silk/float/solve_LS_FLP.c
new file mode 100644
index 0000000..7c90d665
--- /dev/null
+++ b/third_party/opus/src/silk/float/solve_LS_FLP.c
@@ -0,0 +1,207 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+#include "tuning_parameters.h"
+
+/**********************************************************************
+ * LDL Factorisation. Finds the upper triangular matrix L and the diagonal
+ * Matrix D (only the diagonal elements returned in a vector)such that
+ * the symmetric matric A is given by A = L*D*L'.
+ **********************************************************************/
+static OPUS_INLINE void silk_LDL_FLP(
+    silk_float          *A,         /* I/O  Pointer to Symetric Square Matrix                               */
+    opus_int            M,          /* I    Size of Matrix                                                  */
+    silk_float          *L,         /* I/O  Pointer to Square Upper triangular Matrix                       */
+    silk_float          *Dinv       /* I/O  Pointer to vector holding the inverse diagonal elements of D    */
+);
+
+/**********************************************************************
+ * Function to solve linear equation Ax = b, when A is a MxM lower
+ * triangular matrix, with ones on the diagonal.
+ **********************************************************************/
+static OPUS_INLINE void silk_SolveWithLowerTriangularWdiagOnes_FLP(
+    const silk_float    *L,         /* I    Pointer to Lower Triangular Matrix                              */
+    opus_int            M,          /* I    Dim of Matrix equation                                          */
+    const silk_float    *b,         /* I    b Vector                                                        */
+    silk_float          *x          /* O    x Vector                                                        */
+);
+
+/**********************************************************************
+ * Function to solve linear equation (A^T)x = b, when A is a MxM lower
+ * triangular, with ones on the diagonal. (ie then A^T is upper triangular)
+ **********************************************************************/
+static OPUS_INLINE void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP(
+    const silk_float    *L,         /* I    Pointer to Lower Triangular Matrix                              */
+    opus_int            M,          /* I    Dim of Matrix equation                                          */
+    const silk_float    *b,         /* I    b Vector                                                        */
+    silk_float          *x          /* O    x Vector                                                        */
+);
+
+/**********************************************************************
+ * Function to solve linear equation Ax = b, when A is a MxM
+ * symmetric square matrix - using LDL factorisation
+ **********************************************************************/
+void silk_solve_LDL_FLP(
+    silk_float                      *A,                                 /* I/O  Symmetric square matrix, out: reg.          */
+    const opus_int                  M,                                  /* I    Size of matrix                              */
+    const silk_float                *b,                                 /* I    Pointer to b vector                         */
+    silk_float                      *x                                  /* O    Pointer to x solution vector                */
+)
+{
+    opus_int   i;
+    silk_float L[    MAX_MATRIX_SIZE ][ MAX_MATRIX_SIZE ];
+    silk_float T[    MAX_MATRIX_SIZE ];
+    silk_float Dinv[ MAX_MATRIX_SIZE ]; /* inverse diagonal elements of D*/
+
+    silk_assert( M <= MAX_MATRIX_SIZE );
+
+    /***************************************************
+    Factorize A by LDL such that A = L*D*(L^T),
+    where L is lower triangular with ones on diagonal
+    ****************************************************/
+    silk_LDL_FLP( A, M, &L[ 0 ][ 0 ], Dinv );
+
+    /****************************************************
+    * substitute D*(L^T) = T. ie:
+    L*D*(L^T)*x = b => L*T = b <=> T = inv(L)*b
+    ******************************************************/
+    silk_SolveWithLowerTriangularWdiagOnes_FLP( &L[ 0 ][ 0 ], M, b, T );
+
+    /****************************************************
+    D*(L^T)*x = T <=> (L^T)*x = inv(D)*T, because D is
+    diagonal just multiply with 1/d_i
+    ****************************************************/
+    for( i = 0; i < M; i++ ) {
+        T[ i ] = T[ i ] * Dinv[ i ];
+    }
+    /****************************************************
+    x = inv(L') * inv(D) * T
+    *****************************************************/
+    silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( &L[ 0 ][ 0 ], M, T, x );
+}
+
+static OPUS_INLINE void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP(
+    const silk_float    *L,         /* I    Pointer to Lower Triangular Matrix                              */
+    opus_int            M,          /* I    Dim of Matrix equation                                          */
+    const silk_float    *b,         /* I    b Vector                                                        */
+    silk_float          *x          /* O    x Vector                                                        */
+)
+{
+    opus_int   i, j;
+    silk_float temp;
+    const silk_float *ptr1;
+
+    for( i = M - 1; i >= 0; i-- ) {
+        ptr1 =  matrix_adr( L, 0, i, M );
+        temp = 0;
+        for( j = M - 1; j > i ; j-- ) {
+            temp += ptr1[ j * M ] * x[ j ];
+        }
+        temp = b[ i ] - temp;
+        x[ i ] = temp;
+    }
+}
+
+static OPUS_INLINE void silk_SolveWithLowerTriangularWdiagOnes_FLP(
+    const silk_float    *L,         /* I    Pointer to Lower Triangular Matrix                              */
+    opus_int            M,          /* I    Dim of Matrix equation                                          */
+    const silk_float    *b,         /* I    b Vector                                                        */
+    silk_float          *x          /* O    x Vector                                                        */
+)
+{
+    opus_int   i, j;
+    silk_float temp;
+    const silk_float *ptr1;
+
+    for( i = 0; i < M; i++ ) {
+        ptr1 =  matrix_adr( L, i, 0, M );
+        temp = 0;
+        for( j = 0; j < i; j++ ) {
+            temp += ptr1[ j ] * x[ j ];
+        }
+        temp = b[ i ] - temp;
+        x[ i ] = temp;
+    }
+}
+
+static OPUS_INLINE void silk_LDL_FLP(
+    silk_float          *A,         /* I/O  Pointer to Symetric Square Matrix                               */
+    opus_int            M,          /* I    Size of Matrix                                                  */
+    silk_float          *L,         /* I/O  Pointer to Square Upper triangular Matrix                       */
+    silk_float          *Dinv       /* I/O  Pointer to vector holding the inverse diagonal elements of D    */
+)
+{
+    opus_int i, j, k, loop_count, err = 1;
+    silk_float *ptr1, *ptr2;
+    double temp, diag_min_value;
+    silk_float v[ MAX_MATRIX_SIZE ], D[ MAX_MATRIX_SIZE ]; /* temp arrays*/
+
+    silk_assert( M <= MAX_MATRIX_SIZE );
+
+    diag_min_value = FIND_LTP_COND_FAC * 0.5f * ( A[ 0 ] + A[ M * M - 1 ] );
+    for( loop_count = 0; loop_count < M && err == 1; loop_count++ ) {
+        err = 0;
+        for( j = 0; j < M; j++ ) {
+            ptr1 = matrix_adr( L, j, 0, M );
+            temp = matrix_ptr( A, j, j, M ); /* element in row j column j*/
+            for( i = 0; i < j; i++ ) {
+                v[ i ] = ptr1[ i ] * D[ i ];
+                temp  -= ptr1[ i ] * v[ i ];
+            }
+            if( temp < diag_min_value ) {
+                /* Badly conditioned matrix: add white noise and run again */
+                temp = ( loop_count + 1 ) * diag_min_value - temp;
+                for( i = 0; i < M; i++ ) {
+                    matrix_ptr( A, i, i, M ) += ( silk_float )temp;
+                }
+                err = 1;
+                break;
+            }
+            D[ j ]    = ( silk_float )temp;
+            Dinv[ j ] = ( silk_float )( 1.0f / temp );
+            matrix_ptr( L, j, j, M ) = 1.0f;
+
+            ptr1 = matrix_adr( A, j, 0, M );
+            ptr2 = matrix_adr( L, j + 1, 0, M);
+            for( i = j + 1; i < M; i++ ) {
+                temp = 0.0;
+                for( k = 0; k < j; k++ ) {
+                    temp += ptr2[ k ] * v[ k ];
+                }
+                matrix_ptr( L, i, j, M ) = ( silk_float )( ( ptr1[ i ] - temp ) * Dinv[ j ] );
+                ptr2 += M; /* go to next column*/
+            }
+        }
+    }
+    silk_assert( err == 0 );
+}
+
diff --git a/third_party/opus/src/silk/float/sort_FLP.c b/third_party/opus/src/silk/float/sort_FLP.c
new file mode 100644
index 0000000..f08d7592c
--- /dev/null
+++ b/third_party/opus/src/silk/float/sort_FLP.c
@@ -0,0 +1,83 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Insertion sort (fast for already almost sorted arrays):  */
+/* Best case:  O(n)   for an already sorted array           */
+/* Worst case: O(n^2) for an inversely sorted array         */
+
+#include "typedef.h"
+#include "SigProc_FLP.h"
+
+void silk_insertion_sort_decreasing_FLP(
+    silk_float          *a,                 /* I/O  Unsorted / Sorted vector                                    */
+    opus_int            *idx,               /* O    Index vector for the sorted elements                        */
+    const opus_int      L,                  /* I    Vector length                                               */
+    const opus_int      K                   /* I    Number of correctly sorted positions                        */
+)
+{
+    silk_float value;
+    opus_int   i, j;
+
+    /* Safety checks */
+    silk_assert( K >  0 );
+    silk_assert( L >  0 );
+    silk_assert( L >= K );
+
+    /* Write start indices in index vector */
+    for( i = 0; i < K; i++ ) {
+        idx[ i ] = i;
+    }
+
+    /* Sort vector elements by value, decreasing order */
+    for( i = 1; i < K; i++ ) {
+        value = a[ i ];
+        for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+            a[ j + 1 ]   = a[ j ];      /* Shift value */
+            idx[ j + 1 ] = idx[ j ];    /* Shift index */
+        }
+        a[ j + 1 ]   = value;   /* Write value */
+        idx[ j + 1 ] = i;       /* Write index */
+    }
+
+    /* If less than L values are asked check the remaining values,      */
+    /* but only spend CPU to ensure that the K first values are correct */
+    for( i = K; i < L; i++ ) {
+        value = a[ i ];
+        if( value > a[ K - 1 ] ) {
+            for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+                a[ j + 1 ]   = a[ j ];      /* Shift value */
+                idx[ j + 1 ] = idx[ j ];    /* Shift index */
+            }
+            a[ j + 1 ]   = value;   /* Write value */
+            idx[ j + 1 ] = i;       /* Write index */
+        }
+    }
+}
diff --git a/third_party/opus/src/silk/float/structs_FLP.h b/third_party/opus/src/silk/float/structs_FLP.h
new file mode 100644
index 0000000..14d647c
--- /dev/null
+++ b/third_party/opus/src/silk/float/structs_FLP.h
@@ -0,0 +1,132 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_FLP_H
+#define SILK_STRUCTS_FLP_H
+
+#include "typedef.h"
+#include "main.h"
+#include "structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/********************************/
+/* Noise shaping analysis state */
+/********************************/
+typedef struct {
+    opus_int8                   LastGainIndex;
+    silk_float                  HarmBoost_smth;
+    silk_float                  HarmShapeGain_smth;
+    silk_float                  Tilt_smth;
+} silk_shape_state_FLP;
+
+/********************************/
+/* Prefilter state              */
+/********************************/
+typedef struct {
+    silk_float                  sLTP_shp[ LTP_BUF_LENGTH ];
+    silk_float                  sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ];
+    opus_int                    sLTP_shp_buf_idx;
+    silk_float                  sLF_AR_shp;
+    silk_float                  sLF_MA_shp;
+    silk_float                  sHarmHP;
+    opus_int32                  rand_seed;
+    opus_int                    lagPrev;
+} silk_prefilter_state_FLP;
+
+/********************************/
+/* Encoder state FLP            */
+/********************************/
+typedef struct {
+    silk_encoder_state          sCmn;                               /* Common struct, shared with fixed-point code */
+    silk_shape_state_FLP        sShape;                             /* Noise shaping state */
+    silk_prefilter_state_FLP    sPrefilt;                           /* Prefilter State */
+
+    /* Buffer for find pitch and noise shape analysis */
+    silk_float                  x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */
+    silk_float                  LTPCorr;                            /* Normalized correlation from pitch lag estimator */
+} silk_encoder_state_FLP;
+
+/************************/
+/* Encoder control FLP  */
+/************************/
+typedef struct {
+    /* Prediction and coding parameters */
+    silk_float                  Gains[ MAX_NB_SUBFR ];
+    silk_float                  PredCoef[ 2 ][ MAX_LPC_ORDER ];     /* holds interpolated and final coefficients */
+    silk_float                  LTPCoef[LTP_ORDER * MAX_NB_SUBFR];
+    silk_float                  LTP_scale;
+    opus_int                    pitchL[ MAX_NB_SUBFR ];
+
+    /* Noise shaping parameters */
+    silk_float                  AR1[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+    silk_float                  AR2[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+    silk_float                  LF_MA_shp[     MAX_NB_SUBFR ];
+    silk_float                  LF_AR_shp[     MAX_NB_SUBFR ];
+    silk_float                  GainsPre[      MAX_NB_SUBFR ];
+    silk_float                  HarmBoost[     MAX_NB_SUBFR ];
+    silk_float                  Tilt[          MAX_NB_SUBFR ];
+    silk_float                  HarmShapeGain[ MAX_NB_SUBFR ];
+    silk_float                  Lambda;
+    silk_float                  input_quality;
+    silk_float                  coding_quality;
+
+    /* Measures */
+    silk_float                  sparseness;
+    silk_float                  predGain;
+    silk_float                  LTPredCodGain;
+    silk_float                  ResNrg[ MAX_NB_SUBFR ];             /* Residual energy per subframe */
+
+    /* Parameters for CBR mode */
+    opus_int32                  GainsUnq_Q16[ MAX_NB_SUBFR ];
+    opus_int8                   lastGainIndexPrev;
+} silk_encoder_control_FLP;
+
+/************************/
+/* Encoder Super Struct */
+/************************/
+typedef struct {
+    silk_encoder_state_FLP      state_Fxx[ ENCODER_NUM_CHANNELS ];
+    stereo_enc_state            sStereo;
+    opus_int32                  nBitsUsedLBRR;
+    opus_int32                  nBitsExceeded;
+    opus_int                    nChannelsAPI;
+    opus_int                    nChannelsInternal;
+    opus_int                    nPrevChannelsInternal;
+    opus_int                    timeSinceSwitchAllowed_ms;
+    opus_int                    allowBandwidthSwitch;
+    opus_int                    prev_decode_only_middle;
+} silk_encoder;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/float/warped_autocorrelation_FLP.c b/third_party/opus/src/silk/float/warped_autocorrelation_FLP.c
new file mode 100644
index 0000000..542414f
--- /dev/null
+++ b/third_party/opus/src/silk/float/warped_autocorrelation_FLP.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FLP(
+    silk_float                      *corr,                              /* O    Result [order + 1]                          */
+    const silk_float                *input,                             /* I    Input data to correlate                     */
+    const silk_float                warping,                            /* I    Warping coefficient                         */
+    const opus_int                  length,                             /* I    Length of input                             */
+    const opus_int                  order                               /* I    Correlation order (even)                    */
+)
+{
+    opus_int    n, i;
+    double      tmp1, tmp2;
+    double      state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+    double      C[     MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+    /* Order must be even */
+    silk_assert( ( order & 1 ) == 0 );
+
+    /* Loop over samples */
+    for( n = 0; n < length; n++ ) {
+        tmp1 = input[ n ];
+        /* Loop over allpass sections */
+        for( i = 0; i < order; i += 2 ) {
+            /* Output of allpass section */
+            tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 );
+            state[ i ] = tmp1;
+            C[ i ] += state[ 0 ] * tmp1;
+            /* Output of allpass section */
+            tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 );
+            state[ i + 1 ] = tmp2;
+            C[ i + 1 ] += state[ 0 ] * tmp2;
+        }
+        state[ order ] = tmp1;
+        C[ order ] += state[ 0 ] * tmp1;
+    }
+
+    /* Copy correlations in silk_float output format */
+    for( i = 0; i < order + 1; i++ ) {
+        corr[ i ] = ( silk_float )C[ i ];
+    }
+}
diff --git a/third_party/opus/src/silk/float/wrappers_FLP.c b/third_party/opus/src/silk/float/wrappers_FLP.c
new file mode 100644
index 0000000..6666b8e
--- /dev/null
+++ b/third_party/opus/src/silk/float/wrappers_FLP.c
@@ -0,0 +1,202 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FLP.h"
+
+/* Wrappers. Calls flp / fix code */
+
+/* Convert AR filter coefficients to NLSF parameters */
+void silk_A2NLSF_FLP(
+    opus_int16                      *NLSF_Q15,                          /* O    NLSF vector      [ LPC_order ]              */
+    const silk_float                *pAR,                               /* I    LPC coefficients [ LPC_order ]              */
+    const opus_int                  LPC_order                           /* I    LPC order                                   */
+)
+{
+    opus_int   i;
+    opus_int32 a_fix_Q16[ MAX_LPC_ORDER ];
+
+    for( i = 0; i < LPC_order; i++ ) {
+        a_fix_Q16[ i ] = silk_float2int( pAR[ i ] * 65536.0f );
+    }
+
+    silk_A2NLSF( NLSF_Q15, a_fix_Q16, LPC_order );
+}
+
+/* Convert LSF parameters to AR prediction filter coefficients */
+void silk_NLSF2A_FLP(
+    silk_float                      *pAR,                               /* O    LPC coefficients [ LPC_order ]              */
+    const opus_int16                *NLSF_Q15,                          /* I    NLSF vector      [ LPC_order ]              */
+    const opus_int                  LPC_order                           /* I    LPC order                                   */
+)
+{
+    opus_int   i;
+    opus_int16 a_fix_Q12[ MAX_LPC_ORDER ];
+
+    silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order );
+
+    for( i = 0; i < LPC_order; i++ ) {
+        pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f );
+    }
+}
+
+/******************************************/
+/* Floating-point NLSF processing wrapper */
+/******************************************/
+void silk_process_NLSFs_FLP(
+    silk_encoder_state              *psEncC,                            /* I/O  Encoder state                               */
+    silk_float                      PredCoef[ 2 ][ MAX_LPC_ORDER ],     /* O    Prediction coefficients                     */
+    opus_int16                      NLSF_Q15[      MAX_LPC_ORDER ],     /* I/O  Normalized LSFs (quant out) (0 - (2^15-1))  */
+    const opus_int16                prev_NLSF_Q15[ MAX_LPC_ORDER ]      /* I    Previous Normalized LSFs (0 - (2^15-1))     */
+)
+{
+    opus_int     i, j;
+    opus_int16   PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+
+    silk_process_NLSFs( psEncC, PredCoef_Q12, NLSF_Q15, prev_NLSF_Q15);
+
+    for( j = 0; j < 2; j++ ) {
+        for( i = 0; i < psEncC->predictLPCOrder; i++ ) {
+            PredCoef[ j ][ i ] = ( silk_float )PredCoef_Q12[ j ][ i ] * ( 1.0f / 4096.0f );
+        }
+    }
+}
+
+/****************************************/
+/* Floating-point Silk NSQ wrapper      */
+/****************************************/
+void silk_NSQ_wrapper_FLP(
+    silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
+    silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
+    SideInfoIndices                 *psIndices,                         /* I/O  Quantization indices                        */
+    silk_nsq_state                  *psNSQ,                             /* I/O  Noise Shaping Quantzation state             */
+    opus_int8                       pulses[],                           /* O    Quantized pulse signal                      */
+    const silk_float                x[]                                 /* I    Prefiltered input signal                    */
+)
+{
+    opus_int     i, j;
+    opus_int32   x_Q3[ MAX_FRAME_LENGTH ];
+    opus_int32   Gains_Q16[ MAX_NB_SUBFR ];
+    silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+    opus_int16   LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+    opus_int     LTP_scale_Q14;
+
+    /* Noise shaping parameters */
+    opus_int16   AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+    opus_int32   LF_shp_Q14[ MAX_NB_SUBFR ];         /* Packs two int16 coefficients per int32 value             */
+    opus_int     Lambda_Q10;
+    opus_int     Tilt_Q14[ MAX_NB_SUBFR ];
+    opus_int     HarmShapeGain_Q14[ MAX_NB_SUBFR ];
+
+    /* Convert control struct to fix control struct */
+    /* Noise shape parameters */
+    for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+        for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) {
+            AR2_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR2[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f );
+        }
+    }
+
+    for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+        LF_shp_Q14[ i ] =   silk_LSHIFT32( silk_float2int( psEncCtrl->LF_AR_shp[ i ]     * 16384.0f ), 16 ) |
+                              (opus_uint16)silk_float2int( psEncCtrl->LF_MA_shp[ i ]     * 16384.0f );
+        Tilt_Q14[ i ]   =        (opus_int)silk_float2int( psEncCtrl->Tilt[ i ]          * 16384.0f );
+        HarmShapeGain_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f );
+    }
+    Lambda_Q10 = ( opus_int )silk_float2int( psEncCtrl->Lambda * 1024.0f );
+
+    /* prediction and coding parameters */
+    for( i = 0; i < psEnc->sCmn.nb_subfr * LTP_ORDER; i++ ) {
+        LTPCoef_Q14[ i ] = (opus_int16)silk_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f );
+    }
+
+    for( j = 0; j < 2; j++ ) {
+        for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) {
+            PredCoef_Q12[ j ][ i ] = (opus_int16)silk_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f );
+        }
+    }
+
+    for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+        Gains_Q16[ i ] = silk_float2int( psEncCtrl->Gains[ i ] * 65536.0f );
+        silk_assert( Gains_Q16[ i ] > 0 );
+    }
+
+    if( psIndices->signalType == TYPE_VOICED ) {
+        LTP_scale_Q14 = silk_LTPScales_table_Q14[ psIndices->LTP_scaleIndex ];
+    } else {
+        LTP_scale_Q14 = 0;
+    }
+
+    /* Convert input to fix */
+    for( i = 0; i < psEnc->sCmn.frame_length; i++ ) {
+        x_Q3[ i ] = silk_float2int( 8.0f * x[ i ] );
+    }
+
+    /* Call NSQ */
+    if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+        silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14,
+            AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch );
+    } else {
+        silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14,
+            AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch );
+    }
+}
+
+/***********************************************/
+/* Floating-point Silk LTP quantiation wrapper */
+/***********************************************/
+void silk_quant_LTP_gains_FLP(
+    silk_float                      B[ MAX_NB_SUBFR * LTP_ORDER ],      /* I/O  (Un-)quantized LTP gains                    */
+    opus_int8                       cbk_index[ MAX_NB_SUBFR ],          /* O    Codebook index                              */
+    opus_int8                       *periodicity_index,                 /* O    Periodicity index                           */
+    opus_int32                      *sum_log_gain_Q7,                   /* I/O  Cumulative max prediction gain  */
+    const silk_float                W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I    Error weights                        */
+    const opus_int                  mu_Q10,                             /* I    Mu value (R/D tradeoff)                     */
+    const opus_int                  lowComplexity,                      /* I    Flag for low complexity                     */
+    const opus_int                  nb_subfr,                           /* I    number of subframes                         */
+    int                             arch                                /* I    Run-time architecture                       */
+)
+{
+    opus_int   i;
+    opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ];
+    opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ];
+
+    for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) {
+        B_Q14[ i ] = (opus_int16)silk_float2int( B[ i ] * 16384.0f );
+    }
+    for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) {
+        W_Q18[ i ] = (opus_int32)silk_float2int( W[ i ] * 262144.0f );
+    }
+
+    silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, sum_log_gain_Q7, W_Q18, mu_Q10, lowComplexity, nb_subfr, arch );
+
+    for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) {
+        B[ i ] = (silk_float)B_Q14[ i ] * ( 1.0f / 16384.0f );
+    }
+}
diff --git a/third_party/opus/src/silk/gain_quant.c b/third_party/opus/src/silk/gain_quant.c
new file mode 100644
index 0000000..64ccd06
--- /dev/null
+++ b/third_party/opus/src/silk/gain_quant.c
@@ -0,0 +1,141 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+#define OFFSET                  ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 )
+#define SCALE_Q16               ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) )
+#define INV_SCALE_Q16           ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) )
+
+/* Gain scalar quantization with hysteresis, uniform on log scale */
+void silk_gains_quant(
+    opus_int8                   ind[ MAX_NB_SUBFR ],            /* O    gain indices                                */
+    opus_int32                  gain_Q16[ MAX_NB_SUBFR ],       /* I/O  gains (quantized out)                       */
+    opus_int8                   *prev_ind,                      /* I/O  last index in previous frame                */
+    const opus_int              conditional,                    /* I    first gain is delta coded if 1              */
+    const opus_int              nb_subfr                        /* I    number of subframes                         */
+)
+{
+    opus_int k, double_step_size_threshold;
+
+    for( k = 0; k < nb_subfr; k++ ) {
+        /* Convert to log scale, scale, floor() */
+        ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET );
+
+        /* Round towards previous quantized gain (hysteresis) */
+        if( ind[ k ] < *prev_ind ) {
+            ind[ k ]++;
+        }
+        ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 );
+
+        /* Compute delta indices and limit */
+        if( k == 0 && conditional == 0 ) {
+            /* Full index */
+            ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 );
+            *prev_ind = ind[ k ];
+        } else {
+            /* Delta index */
+            ind[ k ] = ind[ k ] - *prev_ind;
+
+            /* Double the quantization step size for large gain increases, so that the max gain level can be reached */
+            double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
+            if( ind[ k ] > double_step_size_threshold ) {
+                ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 );
+            }
+
+            ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT );
+
+            /* Accumulate deltas */
+            if( ind[ k ] > double_step_size_threshold ) {
+                *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold;
+            } else {
+                *prev_ind += ind[ k ];
+            }
+
+            /* Shift to make non-negative */
+            ind[ k ] -= MIN_DELTA_GAIN_QUANT;
+        }
+
+        /* Scale and convert to linear scale */
+        gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
+    }
+}
+
+/* Gains scalar dequantization, uniform on log scale */
+void silk_gains_dequant(
+    opus_int32                  gain_Q16[ MAX_NB_SUBFR ],       /* O    quantized gains                             */
+    const opus_int8             ind[ MAX_NB_SUBFR ],            /* I    gain indices                                */
+    opus_int8                   *prev_ind,                      /* I/O  last index in previous frame                */
+    const opus_int              conditional,                    /* I    first gain is delta coded if 1              */
+    const opus_int              nb_subfr                        /* I    number of subframes                          */
+)
+{
+    opus_int   k, ind_tmp, double_step_size_threshold;
+
+    for( k = 0; k < nb_subfr; k++ ) {
+        if( k == 0 && conditional == 0 ) {
+            /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */
+            *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 );
+        } else {
+            /* Delta index */
+            ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT;
+
+            /* Accumulate deltas */
+            double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
+            if( ind_tmp > double_step_size_threshold ) {
+                *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold;
+            } else {
+                *prev_ind += ind_tmp;
+            }
+        }
+        *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 );
+
+        /* Scale and convert to linear scale */
+        gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
+    }
+}
+
+/* Compute unique identifier of gain indices vector */
+opus_int32 silk_gains_ID(                                       /* O    returns unique identifier of gains          */
+    const opus_int8             ind[ MAX_NB_SUBFR ],            /* I    gain indices                                */
+    const opus_int              nb_subfr                        /* I    number of subframes                         */
+)
+{
+    opus_int   k;
+    opus_int32 gainsID;
+
+    gainsID = 0;
+    for( k = 0; k < nb_subfr; k++ ) {
+        gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 );
+    }
+
+    return gainsID;
+}
diff --git a/third_party/opus/src/silk/init_decoder.c b/third_party/opus/src/silk/init_decoder.c
new file mode 100644
index 0000000..f887c678
--- /dev/null
+++ b/third_party/opus/src/silk/init_decoder.c
@@ -0,0 +1,56 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/************************/
+/* Init Decoder State   */
+/************************/
+opus_int silk_init_decoder(
+    silk_decoder_state          *psDec                          /* I/O  Decoder state pointer                       */
+)
+{
+    /* Clear the entire encoder state, except anything copied */
+    silk_memset( psDec, 0, sizeof( silk_decoder_state ) );
+
+    /* Used to deactivate LSF interpolation */
+    psDec->first_frame_after_reset = 1;
+    psDec->prev_gain_Q16 = 65536;
+
+    /* Reset CNG state */
+    silk_CNG_Reset( psDec );
+
+    /* Reset PLC state */
+    silk_PLC_Reset( psDec );
+
+    return(0);
+}
+
diff --git a/third_party/opus/src/silk/init_encoder.c b/third_party/opus/src/silk/init_encoder.c
new file mode 100644
index 0000000..65995c3
--- /dev/null
+++ b/third_party/opus/src/silk/init_encoder.c
@@ -0,0 +1,64 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#else
+#include "main_FLP.h"
+#endif
+#include "tuning_parameters.h"
+#include "cpu_support.h"
+
+/*********************************/
+/* Initialize Silk Encoder state */
+/*********************************/
+opus_int silk_init_encoder(
+    silk_encoder_state_Fxx          *psEnc,                                 /* I/O  Pointer to Silk FIX encoder state                                           */
+    int                              arch                                   /* I    Run-time architecture                                                       */
+)
+{
+    opus_int ret = 0;
+
+    /* Clear the entire encoder state */
+    silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) );
+
+    psEnc->sCmn.arch = arch;
+
+    psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 );
+    psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15;
+
+    /* Used to deactivate LSF interpolation, pitch prediction */
+    psEnc->sCmn.first_frame_after_reset = 1;
+
+    /* Initialize Silk VAD */
+    ret += silk_VAD_Init( &psEnc->sCmn.sVAD );
+
+    return  ret;
+}
diff --git a/third_party/opus/src/silk/inner_prod_aligned.c b/third_party/opus/src/silk/inner_prod_aligned.c
new file mode 100644
index 0000000..257ae9e
--- /dev/null
+++ b/third_party/opus/src/silk/inner_prod_aligned.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+opus_int32 silk_inner_prod_aligned_scale(
+    const opus_int16 *const     inVec1,             /*    I input vector 1                                              */
+    const opus_int16 *const     inVec2,             /*    I input vector 2                                              */
+    const opus_int              scale,              /*    I number of bits to shift                                     */
+    const opus_int              len                 /*    I vector lengths                                              */
+)
+{
+    opus_int   i;
+    opus_int32 sum = 0;
+    for( i = 0; i < len; i++ ) {
+        sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale );
+    }
+    return sum;
+}
diff --git a/third_party/opus/src/silk/interpolate.c b/third_party/opus/src/silk/interpolate.c
new file mode 100644
index 0000000..1bd8ca4d
--- /dev/null
+++ b/third_party/opus/src/silk/interpolate.c
@@ -0,0 +1,51 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Interpolate two vectors */
+void silk_interpolate(
+    opus_int16                  xi[ MAX_LPC_ORDER ],            /* O    interpolated vector                         */
+    const opus_int16            x0[ MAX_LPC_ORDER ],            /* I    first vector                                */
+    const opus_int16            x1[ MAX_LPC_ORDER ],            /* I    second vector                               */
+    const opus_int              ifact_Q2,                       /* I    interp. factor, weight on 2nd vector        */
+    const opus_int              d                               /* I    number of parameters                        */
+)
+{
+    opus_int i;
+
+    silk_assert( ifact_Q2 >= 0 );
+    silk_assert( ifact_Q2 <= 4 );
+
+    for( i = 0; i < d; i++ ) {
+        xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 );
+    }
+}
diff --git a/third_party/opus/src/silk/lin2log.c b/third_party/opus/src/silk/lin2log.c
new file mode 100644
index 0000000..d4fe515
--- /dev/null
+++ b/third_party/opus/src/silk/lin2log.c
@@ -0,0 +1,46 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */
+/* Convert input to a log scale    */
+opus_int32 silk_lin2log(
+    const opus_int32            inLin               /* I  input in linear scale                                         */
+)
+{
+    opus_int32 lz, frac_Q7;
+
+    silk_CLZ_FRAC( inLin, &lz, &frac_Q7 );
+
+    /* Piece-wise parabolic approximation */
+    return silk_LSHIFT( 31 - lz, 7 ) + silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 );
+}
+
diff --git a/third_party/opus/src/silk/log2lin.c b/third_party/opus/src/silk/log2lin.c
new file mode 100644
index 0000000..b7c48e47
--- /dev/null
+++ b/third_party/opus/src/silk/log2lin.c
@@ -0,0 +1,58 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Approximation of 2^() (very close inverse of silk_lin2log()) */
+/* Convert input to a linear scale    */
+opus_int32 silk_log2lin(
+    const opus_int32            inLog_Q7            /* I  input on log scale                                            */
+)
+{
+    opus_int32 out, frac_Q7;
+
+    if( inLog_Q7 < 0 ) {
+        return 0;
+    } else if ( inLog_Q7 >= 3967 ) {
+        return silk_int32_MAX;
+    }
+
+    out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) );
+    frac_Q7 = inLog_Q7 & 0x7F;
+    if( inLog_Q7 < 2048 ) {
+        /* Piece-wise parabolic approximation */
+        out = silk_ADD_RSHIFT32( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 );
+    } else {
+        /* Piece-wise parabolic approximation */
+        out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) );
+    }
+    return out;
+}
diff --git a/third_party/opus/src/silk/macros.h b/third_party/opus/src/silk/macros.h
new file mode 100644
index 0000000..d3ca347
--- /dev/null
+++ b/third_party/opus/src/silk/macros.h
@@ -0,0 +1,159 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MACROS_H
+#define SILK_MACROS_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_types.h"
+#include "opus_defines.h"
+#include "arch.h"
+
+#if OPUS_GNUC_PREREQ(3, 0)
+#define opus_likely(x)       (__builtin_expect(!!(x), 1))
+#define opus_unlikely(x)     (__builtin_expect(!!(x), 0))
+#else
+#define opus_likely(x)       (!!(x))
+#define opus_unlikely(x)     (!!(x))
+#endif
+
+/* This is an OPUS_INLINE header file for general platform. */
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#if OPUS_FAST_INT64
+#define silk_SMULWB(a32, b32)            ((opus_int32)(((a32) * (opus_int64)((opus_int16)(b32))) >> 16))
+#else
+#define silk_SMULWB(a32, b32)            ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16))
+#endif
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#if OPUS_FAST_INT64
+#define silk_SMLAWB(a32, b32, c32)       ((opus_int32)((a32) + (((b32) * (opus_int64)((opus_int16)(c32))) >> 16)))
+#else
+#define silk_SMLAWB(a32, b32, c32)       ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16)))
+#endif
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#if OPUS_FAST_INT64
+#define silk_SMULWT(a32, b32)            ((opus_int32)(((a32) * (opus_int64)((b32) >> 16)) >> 16))
+#else
+#define silk_SMULWT(a32, b32)            (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16))
+#endif
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#if OPUS_FAST_INT64
+#define silk_SMLAWT(a32, b32, c32)       ((opus_int32)((a32) + (((b32) * ((opus_int64)(c32) >> 16)) >> 16)))
+#else
+#define silk_SMLAWT(a32, b32, c32)       ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16))
+#endif
+
+/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */
+#define silk_SMULBB(a32, b32)            ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32)))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */
+#define silk_SMLABB(a32, b32, c32)       ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))
+
+/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */
+#define silk_SMULBT(a32, b32)            ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */
+#define silk_SMLABT(a32, b32, c32)       ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16))
+
+/* a64 + (b32 * c32) */
+#define silk_SMLAL(a64, b32, c32)        (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32))))
+
+/* (a32 * b32) >> 16 */
+#if OPUS_FAST_INT64
+#define silk_SMULWW(a32, b32)            ((opus_int32)(((opus_int64)(a32) * (b32)) >> 16))
+#else
+#define silk_SMULWW(a32, b32)            silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16))
+#endif
+
+/* a32 + ((b32 * c32) >> 16) */
+#if OPUS_FAST_INT64
+#define silk_SMLAWW(a32, b32, c32)       ((opus_int32)((a32) + (((opus_int64)(b32) * (c32)) >> 16)))
+#else
+#define silk_SMLAWW(a32, b32, c32)       silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16))
+#endif
+
+/* add/subtract with output saturated */
+#define silk_ADD_SAT32(a, b)             ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ?                              \
+                                        ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) :   \
+                                        ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) )
+
+#define silk_SUB_SAT32(a, b)             ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ?                                        \
+                                        (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) :    \
+                                        ((((a)^0x80000000) & (b)  & 0x80000000) ? silk_int32_MAX : (a)-(b)) )
+
+#if defined(MIPSr1_ASM)
+#include "mips/macros_mipsr1.h"
+#endif
+
+#include "ecintrin.h"
+#ifndef OVERRIDE_silk_CLZ16
+static OPUS_INLINE opus_int32 silk_CLZ16(opus_int16 in16)
+{
+    return 32 - EC_ILOG(in16<<16|0x8000);
+}
+#endif
+
+#ifndef OVERRIDE_silk_CLZ32
+static OPUS_INLINE opus_int32 silk_CLZ32(opus_int32 in32)
+{
+    return in32 ? 32 - EC_ILOG(in32) : 32;
+}
+#endif
+
+/* Row based */
+#define matrix_ptr(Matrix_base_adr, row, column, N) \
+    (*((Matrix_base_adr) + ((row)*(N)+(column))))
+#define matrix_adr(Matrix_base_adr, row, column, N) \
+      ((Matrix_base_adr) + ((row)*(N)+(column)))
+
+/* Column based */
+#ifndef matrix_c_ptr
+#   define matrix_c_ptr(Matrix_base_adr, row, column, M) \
+    (*((Matrix_base_adr) + ((row)+(M)*(column))))
+#endif
+
+#ifdef OPUS_ARM_INLINE_ASM
+#include "arm/macros_armv4.h"
+#endif
+
+#ifdef OPUS_ARM_INLINE_EDSP
+#include "arm/macros_armv5e.h"
+#endif
+
+#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR
+#include "arm/macros_arm64.h"
+#endif
+
+#endif /* SILK_MACROS_H */
+
diff --git a/third_party/opus/src/silk/main.h b/third_party/opus/src/silk/main.h
new file mode 100644
index 0000000..2f90d68
--- /dev/null
+++ b/third_party/opus/src/silk/main.h
@@ -0,0 +1,471 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MAIN_H
+#define SILK_MAIN_H
+
+#include "SigProc_FIX.h"
+#include "define.h"
+#include "structs.h"
+#include "tables.h"
+#include "PLC.h"
+#include "control.h"
+#include "debug.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+#include "x86/main_sse.h"
+#endif
+
+/* Convert Left/Right stereo signal to adaptive Mid/Side representation */
+void silk_stereo_LR_to_MS(
+    stereo_enc_state            *state,                         /* I/O  State                                       */
+    opus_int16                  x1[],                           /* I/O  Left input signal, becomes mid signal       */
+    opus_int16                  x2[],                           /* I/O  Right input signal, becomes side signal     */
+    opus_int8                   ix[ 2 ][ 3 ],                   /* O    Quantization indices                        */
+    opus_int8                   *mid_only_flag,                 /* O    Flag: only mid signal coded                 */
+    opus_int32                  mid_side_rates_bps[],           /* O    Bitrates for mid and side signals           */
+    opus_int32                  total_rate_bps,                 /* I    Total bitrate                               */
+    opus_int                    prev_speech_act_Q8,             /* I    Speech activity level in previous frame     */
+    opus_int                    toMono,                         /* I    Last frame before a stereo->mono transition */
+    opus_int                    fs_kHz,                         /* I    Sample rate (kHz)                           */
+    opus_int                    frame_length                    /* I    Number of samples                           */
+);
+
+/* Convert adaptive Mid/Side representation to Left/Right stereo signal */
+void silk_stereo_MS_to_LR(
+    stereo_dec_state            *state,                         /* I/O  State                                       */
+    opus_int16                  x1[],                           /* I/O  Left input signal, becomes mid signal       */
+    opus_int16                  x2[],                           /* I/O  Right input signal, becomes side signal     */
+    const opus_int32            pred_Q13[],                     /* I    Predictors                                  */
+    opus_int                    fs_kHz,                         /* I    Samples rate (kHz)                          */
+    opus_int                    frame_length                    /* I    Number of samples                           */
+);
+
+/* Find least-squares prediction gain for one signal based on another and quantize it */
+opus_int32 silk_stereo_find_predictor(                          /* O    Returns predictor in Q13                    */
+    opus_int32                  *ratio_Q14,                     /* O    Ratio of residual and mid energies          */
+    const opus_int16            x[],                            /* I    Basis signal                                */
+    const opus_int16            y[],                            /* I    Target signal                               */
+    opus_int32                  mid_res_amp_Q0[],               /* I/O  Smoothed mid, residual norms                */
+    opus_int                    length,                         /* I    Number of samples                           */
+    opus_int                    smooth_coef_Q16                 /* I    Smoothing coefficient                       */
+);
+
+/* Quantize mid/side predictors */
+void silk_stereo_quant_pred(
+    opus_int32                  pred_Q13[],                     /* I/O  Predictors (out: quantized)                 */
+    opus_int8                   ix[ 2 ][ 3 ]                    /* O    Quantization indices                        */
+);
+
+/* Entropy code the mid/side quantization indices */
+void silk_stereo_encode_pred(
+    ec_enc                      *psRangeEnc,                    /* I/O  Compressor data structure                   */
+    opus_int8                   ix[ 2 ][ 3 ]                    /* I    Quantization indices                        */
+);
+
+/* Entropy code the mid-only flag */
+void silk_stereo_encode_mid_only(
+    ec_enc                      *psRangeEnc,                    /* I/O  Compressor data structure                   */
+    opus_int8                   mid_only_flag
+);
+
+/* Decode mid/side predictors */
+void silk_stereo_decode_pred(
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int32                  pred_Q13[]                      /* O    Predictors                                  */
+);
+
+/* Decode mid-only flag */
+void silk_stereo_decode_mid_only(
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int                    *decode_only_mid                /* O    Flag that only mid channel has been coded   */
+);
+
+/* Encodes signs of excitation */
+void silk_encode_signs(
+    ec_enc                      *psRangeEnc,                        /* I/O  Compressor data structure                   */
+    const opus_int8             pulses[],                           /* I    pulse signal                                */
+    opus_int                    length,                             /* I    length of input                             */
+    const opus_int              signalType,                         /* I    Signal type                                 */
+    const opus_int              quantOffsetType,                    /* I    Quantization offset type                    */
+    const opus_int              sum_pulses[ MAX_NB_SHELL_BLOCKS ]   /* I    Sum of absolute pulses per block            */
+);
+
+/* Decodes signs of excitation */
+void silk_decode_signs(
+    ec_dec                      *psRangeDec,                        /* I/O  Compressor data structure                   */
+    opus_int16                  pulses[],                           /* I/O  pulse signal                                */
+    opus_int                    length,                             /* I    length of input                             */
+    const opus_int              signalType,                         /* I    Signal type                                 */
+    const opus_int              quantOffsetType,                    /* I    Quantization offset type                    */
+    const opus_int              sum_pulses[ MAX_NB_SHELL_BLOCKS ]   /* I    Sum of absolute pulses per block            */
+);
+
+/* Check encoder control struct */
+opus_int check_control_input(
+    silk_EncControlStruct        *encControl                    /* I    Control structure                           */
+);
+
+/* Control internal sampling rate */
+opus_int silk_control_audio_bandwidth(
+    silk_encoder_state          *psEncC,                        /* I/O  Pointer to Silk encoder state               */
+    silk_EncControlStruct       *encControl                     /* I    Control structure                           */
+);
+
+/* Control SNR of redidual quantizer */
+opus_int silk_control_SNR(
+    silk_encoder_state          *psEncC,                        /* I/O  Pointer to Silk encoder state               */
+    opus_int32                  TargetRate_bps                  /* I    Target max bitrate (bps)                    */
+);
+
+/***************/
+/* Shell coder */
+/***************/
+
+/* Encode quantization indices of excitation */
+void silk_encode_pulses(
+    ec_enc                      *psRangeEnc,                    /* I/O  compressor data structure                   */
+    const opus_int              signalType,                     /* I    Signal type                                 */
+    const opus_int              quantOffsetType,                /* I    quantOffsetType                             */
+    opus_int8                   pulses[],                       /* I    quantization indices                        */
+    const opus_int              frame_length                    /* I    Frame length                                */
+);
+
+/* Shell encoder, operates on one shell code frame of 16 pulses */
+void silk_shell_encoder(
+    ec_enc                      *psRangeEnc,                    /* I/O  compressor data structure                   */
+    const opus_int              *pulses0                        /* I    data: nonnegative pulse amplitudes          */
+);
+
+/* Shell decoder, operates on one shell code frame of 16 pulses */
+void silk_shell_decoder(
+    opus_int16                  *pulses0,                       /* O    data: nonnegative pulse amplitudes          */
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    const opus_int              pulses4                         /* I    number of pulses per pulse-subframe         */
+);
+
+/* Gain scalar quantization with hysteresis, uniform on log scale */
+void silk_gains_quant(
+    opus_int8                   ind[ MAX_NB_SUBFR ],            /* O    gain indices                                */
+    opus_int32                  gain_Q16[ MAX_NB_SUBFR ],       /* I/O  gains (quantized out)                       */
+    opus_int8                   *prev_ind,                      /* I/O  last index in previous frame                */
+    const opus_int              conditional,                    /* I    first gain is delta coded if 1              */
+    const opus_int              nb_subfr                        /* I    number of subframes                         */
+);
+
+/* Gains scalar dequantization, uniform on log scale */
+void silk_gains_dequant(
+    opus_int32                  gain_Q16[ MAX_NB_SUBFR ],       /* O    quantized gains                             */
+    const opus_int8             ind[ MAX_NB_SUBFR ],            /* I    gain indices                                */
+    opus_int8                   *prev_ind,                      /* I/O  last index in previous frame                */
+    const opus_int              conditional,                    /* I    first gain is delta coded if 1              */
+    const opus_int              nb_subfr                        /* I    number of subframes                          */
+);
+
+/* Compute unique identifier of gain indices vector */
+opus_int32 silk_gains_ID(                                       /* O    returns unique identifier of gains          */
+    const opus_int8             ind[ MAX_NB_SUBFR ],            /* I    gain indices                                */
+    const opus_int              nb_subfr                        /* I    number of subframes                         */
+);
+
+/* Interpolate two vectors */
+void silk_interpolate(
+    opus_int16                  xi[ MAX_LPC_ORDER ],            /* O    interpolated vector                         */
+    const opus_int16            x0[ MAX_LPC_ORDER ],            /* I    first vector                                */
+    const opus_int16            x1[ MAX_LPC_ORDER ],            /* I    second vector                               */
+    const opus_int              ifact_Q2,                       /* I    interp. factor, weight on 2nd vector        */
+    const opus_int              d                               /* I    number of parameters                        */
+);
+
+/* LTP tap quantizer */
+void silk_quant_LTP_gains(
+    opus_int16                  B_Q14[ MAX_NB_SUBFR * LTP_ORDER ],          /* I/O  (un)quantized LTP gains         */
+    opus_int8                   cbk_index[ MAX_NB_SUBFR ],                  /* O    Codebook Index                  */
+    opus_int8                   *periodicity_index,                         /* O    Periodicity Index               */
+    opus_int32                  *sum_gain_dB_Q7,                            /* I/O  Cumulative max prediction gain  */
+    const opus_int32            W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ],  /* I    Error Weights in Q18            */
+    opus_int                    mu_Q9,                                      /* I    Mu value (R/D tradeoff)         */
+    opus_int                    lowComplexity,                              /* I    Flag for low complexity         */
+    const opus_int              nb_subfr,                                   /* I    number of subframes             */
+    int                         arch                                        /* I    Run-time architecture           */
+);
+
+/* Entropy constrained matrix-weighted VQ, for a single input data vector */
+void silk_VQ_WMat_EC_c(
+    opus_int8                   *ind,                           /* O    index of best codebook vector               */
+    opus_int32                  *rate_dist_Q14,                 /* O    best weighted quant error + mu * rate       */
+    opus_int                    *gain_Q7,                       /* O    sum of absolute LTP coefficients            */
+    const opus_int16            *in_Q14,                        /* I    input vector to be quantized                */
+    const opus_int32            *W_Q18,                         /* I    weighting matrix                            */
+    const opus_int8             *cb_Q7,                         /* I    codebook                                    */
+    const opus_uint8            *cb_gain_Q7,                    /* I    codebook effective gain                     */
+    const opus_uint8            *cl_Q5,                         /* I    code length for each codebook vector        */
+    const opus_int              mu_Q9,                          /* I    tradeoff betw. weighted error and rate      */
+    const opus_int32            max_gain_Q7,                    /* I    maximum sum of absolute LTP coefficients    */
+    opus_int                    L                               /* I    number of vectors in codebook               */
+);
+
+#if !defined(OVERRIDE_silk_VQ_WMat_EC)
+#define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+                          mu_Q9, max_gain_Q7, L, arch) \
+    ((void)(arch),silk_VQ_WMat_EC_c(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+                          mu_Q9, max_gain_Q7, L))
+#endif
+
+/************************************/
+/* Noise shaping quantization (NSQ) */
+/************************************/
+
+void silk_NSQ_c(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+);
+
+#if !defined(OVERRIDE_silk_NSQ)
+#define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                   HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+    ((void)(arch),silk_NSQ_c(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                   HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+#endif
+
+/* Noise shaping using delayed decision */
+void silk_NSQ_del_dec_c(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+);
+
+#if !defined(OVERRIDE_silk_NSQ_del_dec)
+#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                           HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+    ((void)(arch),silk_NSQ_del_dec_c(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                           HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+#endif
+
+/************/
+/* Silk VAD */
+/************/
+/* Initialize the Silk VAD */
+opus_int silk_VAD_Init(                                         /* O    Return value, 0 if success                  */
+    silk_VAD_state              *psSilk_VAD                     /* I/O  Pointer to Silk VAD state                   */
+);
+
+/* Get speech activity level in Q8 */
+opus_int silk_VAD_GetSA_Q8_c(                                   /* O    Return value, 0 if success                  */
+    silk_encoder_state          *psEncC,                        /* I/O  Encoder state                               */
+    const opus_int16            pIn[]                           /* I    PCM input                                   */
+);
+
+#if !defined(OVERRIDE_silk_VAD_GetSA_Q8)
+#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_c(psEnC, pIn))
+#endif
+
+/* Low-pass filter with variable cutoff frequency based on  */
+/* piece-wise linear interpolation between elliptic filters */
+/* Start by setting transition_frame_no = 1;                */
+void silk_LP_variable_cutoff(
+    silk_LP_state               *psLP,                          /* I/O  LP filter state                             */
+    opus_int16                  *frame,                         /* I/O  Low-pass filtered output signal             */
+    const opus_int              frame_length                    /* I    Frame length                                */
+);
+
+/******************/
+/* NLSF Quantizer */
+/******************/
+/* Limit, stabilize, convert and quantize NLSFs */
+void silk_process_NLSFs(
+    silk_encoder_state          *psEncC,                            /* I/O  Encoder state                               */
+    opus_int16                  PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O    Prediction coefficients                     */
+    opus_int16                  pNLSF_Q15[         MAX_LPC_ORDER ], /* I/O  Normalized LSFs (quant out) (0 - (2^15-1))  */
+    const opus_int16            prev_NLSFq_Q15[    MAX_LPC_ORDER ]  /* I    Previous Normalized LSFs (0 - (2^15-1))     */
+);
+
+opus_int32 silk_NLSF_encode(                                    /* O    Returns RD value in Q25                     */
+          opus_int8             *NLSFIndices,                   /* I    Codebook path vector [ LPC_ORDER + 1 ]      */
+          opus_int16            *pNLSF_Q15,                     /* I/O  Quantized NLSF vector [ LPC_ORDER ]         */
+    const silk_NLSF_CB_struct   *psNLSF_CB,                     /* I    Codebook object                             */
+    const opus_int16            *pW_QW,                         /* I    NLSF weight vector [ LPC_ORDER ]            */
+    const opus_int              NLSF_mu_Q20,                    /* I    Rate weight for the RD optimization         */
+    const opus_int              nSurvivors,                     /* I    Max survivors after first stage             */
+    const opus_int              signalType                      /* I    Signal type: 0/1/2                          */
+);
+
+/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */
+void silk_NLSF_VQ(
+    opus_int32                  err_Q26[],                      /* O    Quantization errors [K]                     */
+    const opus_int16            in_Q15[],                       /* I    Input vectors to be quantized [LPC_order]   */
+    const opus_uint8            pCB_Q8[],                       /* I    Codebook vectors [K*LPC_order]              */
+    const opus_int              K,                              /* I    Number of codebook vectors                  */
+    const opus_int              LPC_order                       /* I    Number of LPCs                              */
+);
+
+/* Delayed-decision quantizer for NLSF residuals */
+opus_int32 silk_NLSF_del_dec_quant(                             /* O    Returns RD value in Q25                     */
+    opus_int8                   indices[],                      /* O    Quantization indices [ order ]              */
+    const opus_int16            x_Q10[],                        /* I    Input [ order ]                             */
+    const opus_int16            w_Q5[],                         /* I    Weights [ order ]                           */
+    const opus_uint8            pred_coef_Q8[],                 /* I    Backward predictor coefs [ order ]          */
+    const opus_int16            ec_ix[],                        /* I    Indices to entropy coding tables [ order ]  */
+    const opus_uint8            ec_rates_Q5[],                  /* I    Rates []                                    */
+    const opus_int              quant_step_size_Q16,            /* I    Quantization step size                      */
+    const opus_int16            inv_quant_step_size_Q6,         /* I    Inverse quantization step size              */
+    const opus_int32            mu_Q20,                         /* I    R/D tradeoff                                */
+    const opus_int16            order                           /* I    Number of input values                      */
+);
+
+/* Unpack predictor values and indices for entropy coding tables */
+void silk_NLSF_unpack(
+          opus_int16            ec_ix[],                        /* O    Indices to entropy tables [ LPC_ORDER ]     */
+          opus_uint8            pred_Q8[],                      /* O    LSF predictor [ LPC_ORDER ]                 */
+    const silk_NLSF_CB_struct   *psNLSF_CB,                     /* I    Codebook object                             */
+    const opus_int              CB1_index                       /* I    Index of vector in first LSF codebook       */
+);
+
+/***********************/
+/* NLSF vector decoder */
+/***********************/
+void silk_NLSF_decode(
+          opus_int16            *pNLSF_Q15,                     /* O    Quantized NLSF vector [ LPC_ORDER ]         */
+          opus_int8             *NLSFIndices,                   /* I    Codebook path vector [ LPC_ORDER + 1 ]      */
+    const silk_NLSF_CB_struct   *psNLSF_CB                      /* I    Codebook object                             */
+);
+
+/****************************************************/
+/* Decoder Functions                                */
+/****************************************************/
+opus_int silk_init_decoder(
+    silk_decoder_state          *psDec                          /* I/O  Decoder state pointer                       */
+);
+
+/* Set decoder sampling rate */
+opus_int silk_decoder_set_fs(
+    silk_decoder_state          *psDec,                         /* I/O  Decoder state pointer                       */
+    opus_int                    fs_kHz,                         /* I    Sampling frequency (kHz)                    */
+    opus_int32                  fs_API_Hz                       /* I    API Sampling frequency (Hz)                 */
+);
+
+/****************/
+/* Decode frame */
+/****************/
+opus_int silk_decode_frame(
+    silk_decoder_state          *psDec,                         /* I/O  Pointer to Silk decoder state               */
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int16                  pOut[],                         /* O    Pointer to output speech frame              */
+    opus_int32                  *pN,                            /* O    Pointer to size of output frame             */
+    opus_int                    lostFlag,                       /* I    0: no loss, 1 loss, 2 decode fec            */
+    opus_int                    condCoding,                     /* I    The type of conditional coding to use       */
+    int                         arch                            /* I    Run-time architecture                       */
+);
+
+/* Decode indices from bitstream */
+void silk_decode_indices(
+    silk_decoder_state          *psDec,                         /* I/O  State                                       */
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int                    FrameIndex,                     /* I    Frame number                                */
+    opus_int                    decode_LBRR,                    /* I    Flag indicating LBRR data is being decoded  */
+    opus_int                    condCoding                      /* I    The type of conditional coding to use       */
+);
+
+/* Decode parameters from payload */
+void silk_decode_parameters(
+    silk_decoder_state          *psDec,                         /* I/O  State                                       */
+    silk_decoder_control        *psDecCtrl,                     /* I/O  Decoder control                             */
+    opus_int                    condCoding                      /* I    The type of conditional coding to use       */
+);
+
+/* Core decoder. Performs inverse NSQ operation LTP + LPC */
+void silk_decode_core(
+    silk_decoder_state          *psDec,                         /* I/O  Decoder state                               */
+    silk_decoder_control        *psDecCtrl,                     /* I    Decoder control                             */
+    opus_int16                  xq[],                           /* O    Decoded speech                              */
+    const opus_int16            pulses[ MAX_FRAME_LENGTH ],     /* I    Pulse signal                                */
+    int                         arch                            /* I    Run-time architecture                       */
+);
+
+/* Decode quantization indices of excitation (Shell coding) */
+void silk_decode_pulses(
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int16                  pulses[],                       /* O    Excitation signal                           */
+    const opus_int              signalType,                     /* I    Sigtype                                     */
+    const opus_int              quantOffsetType,                /* I    quantOffsetType                             */
+    const opus_int              frame_length                    /* I    Frame length                                */
+);
+
+/******************/
+/* CNG */
+/******************/
+
+/* Reset CNG */
+void silk_CNG_Reset(
+    silk_decoder_state          *psDec                          /* I/O  Decoder state                               */
+);
+
+/* Updates CNG estimate, and applies the CNG when packet was lost */
+void silk_CNG(
+    silk_decoder_state          *psDec,                         /* I/O  Decoder state                               */
+    silk_decoder_control        *psDecCtrl,                     /* I/O  Decoder control                             */
+    opus_int16                  frame[],                        /* I/O  Signal                                      */
+    opus_int                    length                          /* I    Length of residual                          */
+);
+
+/* Encoding of various parameters */
+void silk_encode_indices(
+    silk_encoder_state          *psEncC,                        /* I/O  Encoder state                               */
+    ec_enc                      *psRangeEnc,                    /* I/O  Compressor data structure                   */
+    opus_int                    FrameIndex,                     /* I    Frame number                                */
+    opus_int                    encode_LBRR,                    /* I    Flag indicating LBRR data is being encoded  */
+    opus_int                    condCoding                      /* I    The type of conditional coding to use       */
+);
+
+#endif
diff --git a/third_party/opus/src/silk/mips/NSQ_del_dec_mipsr1.h b/third_party/opus/src/silk/mips/NSQ_del_dec_mipsr1.h
new file mode 100644
index 0000000..ad1cfe2
--- /dev/null
+++ b/third_party/opus/src/silk/mips/NSQ_del_dec_mipsr1.h
@@ -0,0 +1,409 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef __NSQ_DEL_DEC_MIPSR1_H__
+#define __NSQ_DEL_DEC_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+#define OVERRIDE_silk_noise_shape_quantizer_del_dec
+static inline void silk_noise_shape_quantizer_del_dec(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],             /* I/O  Delayed decision states             */
+    opus_int            signalType,             /* I    Signal type                         */
+    const opus_int32    x_Q10[],                /* I                                        */
+    opus_int8           pulses[],               /* O                                        */
+    opus_int16          xq[],                   /* O                                        */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP filter state                    */
+    opus_int32          delayedGain_Q10[],      /* I/O  Gain delay buffer                   */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs         */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs          */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping coefs                 */
+    opus_int            lag,                    /* I    Pitch lag                           */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                        */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                       */
+    opus_int32          LF_shp_Q14,             /* I                                        */
+    opus_int32          Gain_Q16,               /* I                                        */
+    opus_int            Lambda_Q10,             /* I                                        */
+    opus_int            offset_Q10,             /* I                                        */
+    opus_int            length,                 /* I    Input length                        */
+    opus_int            subfr,                  /* I    Subframe number                     */
+    opus_int            shapingLPCOrder,        /* I    Shaping LPC filter order            */
+    opus_int            predictLPCOrder,        /* I    Prediction filter order             */
+    opus_int            warping_Q16,            /* I                                        */
+    opus_int            nStatesDelayedDecision, /* I    Number of states in decision tree   */
+    opus_int            *smpl_buf_idx,          /* I    Index to newest samples in buffers  */
+    opus_int            decisionDelay,          /* I                                        */
+    int                 arch                    /* I                                        */
+)
+{
+    opus_int     i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+    opus_int32   Winner_rand_state;
+    opus_int32   LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+    opus_int32   n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+    opus_int32   q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+    opus_int32   tmp1, tmp2, sLF_AR_shp_Q14;
+    opus_int32   *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
+    NSQ_sample_struct  psSampleState[ MAX_DEL_DEC_STATES ][ 2 ];
+    NSQ_del_dec_struct *psDD;
+    NSQ_sample_struct  *psSS;
+    opus_int16 b_Q14_0, b_Q14_1, b_Q14_2, b_Q14_3, b_Q14_4;
+    opus_int16 a_Q12_0, a_Q12_1, a_Q12_2, a_Q12_3, a_Q12_4, a_Q12_5, a_Q12_6;
+    opus_int16 a_Q12_7, a_Q12_8, a_Q12_9, a_Q12_10, a_Q12_11, a_Q12_12, a_Q12_13;
+    opus_int16 a_Q12_14, a_Q12_15;
+
+    opus_int32 cur, prev, next;
+
+    /*Unused.*/
+    (void)arch;
+
+    //Intialize b_Q14 variables
+    b_Q14_0 = b_Q14[ 0 ];
+    b_Q14_1 = b_Q14[ 1 ];
+    b_Q14_2 = b_Q14[ 2 ];
+    b_Q14_3 = b_Q14[ 3 ];
+    b_Q14_4 = b_Q14[ 4 ];
+
+    //Intialize a_Q12 variables
+    a_Q12_0 = a_Q12[0];
+    a_Q12_1 = a_Q12[1];
+    a_Q12_2 = a_Q12[2];
+    a_Q12_3 = a_Q12[3];
+    a_Q12_4 = a_Q12[4];
+    a_Q12_5 = a_Q12[5];
+    a_Q12_6 = a_Q12[6];
+    a_Q12_7 = a_Q12[7];
+    a_Q12_8 = a_Q12[8];
+    a_Q12_9 = a_Q12[9];
+    a_Q12_10 = a_Q12[10];
+    a_Q12_11 = a_Q12[11];
+    a_Q12_12 = a_Q12[12];
+    a_Q12_13 = a_Q12[13];
+    a_Q12_14 = a_Q12[14];
+    a_Q12_15 = a_Q12[15];
+
+    long long temp64;
+
+    silk_assert( nStatesDelayedDecision > 0 );
+
+    shp_lag_ptr  = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+    pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+    Gain_Q10     = silk_RSHIFT( Gain_Q16, 6 );
+
+    for( i = 0; i < length; i++ ) {
+        /* Perform common calculations used in all states */
+
+        /* Long-term prediction */
+        if( signalType == TYPE_VOICED ) {
+            /* Unrolled loop */
+            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+            temp64 = __builtin_mips_mult(pred_lag_ptr[ 0 ], b_Q14_0 );
+            temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -1 ], b_Q14_1 );
+            temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -2 ], b_Q14_2 );
+            temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -3 ], b_Q14_3 );
+            temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -4 ], b_Q14_4 );
+            temp64 += 32768;
+            LTP_pred_Q14 = __builtin_mips_extr_w(temp64, 16);
+            LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 );                          /* Q13 -> Q14 */
+            pred_lag_ptr++;
+        } else {
+            LTP_pred_Q14 = 0;
+        }
+
+        /* Long-term shaping */
+        if( lag > 0 ) {
+            /* Symmetric, packed FIR coefficients */
+            n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+            n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ],                      HarmShapeFIRPacked_Q14 );
+            n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 );            /* Q12 -> Q14 */
+            shp_lag_ptr++;
+        } else {
+            n_LTP_Q14 = 0;
+        }
+
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            /* Delayed decision state */
+            psDD = &psDelDec[ k ];
+
+            /* Sample state */
+            psSS = psSampleState[ k ];
+
+            /* Generate dither */
+            psDD->Seed = silk_RAND( psDD->Seed );
+
+            /* Pointer used in short term prediction and shaping */
+            psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
+            /* Short-term prediction */
+            silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 );
+            temp64 = __builtin_mips_mult(psLPC_Q14[  0 ], a_Q12_0 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -1 ], a_Q12_1 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -2 ], a_Q12_2 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -3 ], a_Q12_3 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -4 ], a_Q12_4 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -5 ], a_Q12_5 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -6 ], a_Q12_6 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -7 ], a_Q12_7 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -8 ], a_Q12_8 );
+            temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -9 ], a_Q12_9 );
+            if( predictLPCOrder == 16 ) {
+                temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -10 ], a_Q12_10 );
+                temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -11 ], a_Q12_11 );
+                temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -12 ], a_Q12_12 );
+                temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -13 ], a_Q12_13 );
+                temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -14 ], a_Q12_14 );
+                temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -15 ], a_Q12_15 );
+            }
+            temp64 += 32768;
+            LPC_pred_Q14 = __builtin_mips_extr_w(temp64, 16);
+
+            LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 );                              /* Q10 -> Q14 */
+
+            /* Noise shape feedback */
+            silk_assert( ( shapingLPCOrder & 1 ) == 0 );   /* check that order is even */
+            /* Output of lowpass section */
+            tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 );
+            /* Output of allpass section */
+            tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 );
+            psDD->sAR2_Q14[ 0 ] = tmp2;
+
+            temp64 = __builtin_mips_mult(tmp2, AR_shp_Q13[ 0 ] );
+
+            prev = psDD->sAR2_Q14[ 1 ];
+
+            /* Loop over allpass sections */
+            for( j = 2; j < shapingLPCOrder; j += 2 ) {
+                cur = psDD->sAR2_Q14[ j ];
+                next = psDD->sAR2_Q14[ j+1 ];
+                /* Output of allpass section */
+                tmp2 = silk_SMLAWB( prev, cur - tmp1, warping_Q16 );
+                psDD->sAR2_Q14[ j - 1 ] = tmp1;
+                temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ j - 1 ] );
+                temp64 = __builtin_mips_madd( temp64, tmp2, AR_shp_Q13[ j ] );
+                /* Output of allpass section */
+                tmp1 = silk_SMLAWB( cur, next - tmp2, warping_Q16 );
+                psDD->sAR2_Q14[ j + 0 ] = tmp2;
+                prev = next;
+            }
+            psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+            temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+            temp64 += 32768;
+            n_AR_Q14 = __builtin_mips_extr_w(temp64, 16);
+            n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 );                                      /* Q11 -> Q12 */
+            n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 );              /* Q12 */
+            n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 );                                      /* Q12 -> Q14 */
+
+            n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 );     /* Q12 */
+            n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 );            /* Q12 */
+            n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 );                                      /* Q12 -> Q14 */
+
+            /* Input minus prediction plus noise feedback                       */
+            /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP  */
+            tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 );                                    /* Q14 */
+            tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 );                               /* Q13 */
+            tmp1 = silk_SUB32( tmp2, tmp1 );                                            /* Q13 */
+            tmp1 = silk_RSHIFT_ROUND( tmp1, 4 );                                        /* Q10 */
+
+            r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 );                                     /* residual error Q10 */
+
+            /* Flip sign depending on dither */
+            if ( psDD->Seed < 0 ) {
+                r_Q10 = -r_Q10;
+            }
+            r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+            /* Find two quantization level candidates and measure their rate-distortion */
+            q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+            q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+            if( q1_Q0 > 0 ) {
+                q1_Q10  = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+                q1_Q10  = silk_ADD32( q1_Q10, offset_Q10 );
+                q2_Q10  = silk_ADD32( q1_Q10, 1024 );
+                rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+                rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+            } else if( q1_Q0 == 0 ) {
+                q1_Q10  = offset_Q10;
+                q2_Q10  = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+                rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+                rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+            } else if( q1_Q0 == -1 ) {
+                q2_Q10  = offset_Q10;
+                q1_Q10  = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+                rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+                rd2_Q10 = silk_SMULBB(  q2_Q10, Lambda_Q10 );
+            } else {            /* q1_Q0 < -1 */
+                q1_Q10  = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+                q1_Q10  = silk_ADD32( q1_Q10, offset_Q10 );
+                q2_Q10  = silk_ADD32( q1_Q10, 1024 );
+                rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+                rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+            }
+            rr_Q10  = silk_SUB32( r_Q10, q1_Q10 );
+            rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
+            rr_Q10  = silk_SUB32( r_Q10, q2_Q10 );
+            rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
+
+            if( rd1_Q10 < rd2_Q10 ) {
+                psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+                psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+                psSS[ 0 ].Q_Q10  = q1_Q10;
+                psSS[ 1 ].Q_Q10  = q2_Q10;
+            } else {
+                psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+                psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+                psSS[ 0 ].Q_Q10  = q2_Q10;
+                psSS[ 1 ].Q_Q10  = q1_Q10;
+            }
+
+            /* Update states for best quantization */
+
+            /* Quantized excitation */
+            exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
+            if ( psDD->Seed < 0 ) {
+                exc_Q14 = -exc_Q14;
+            }
+
+            /* Add predictions */
+            LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+            xq_Q14      = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+            /* Update states */
+            sLF_AR_shp_Q14         = silk_SUB32( xq_Q14, n_AR_Q14 );
+            psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+            psSS[ 0 ].LF_AR_Q14    = sLF_AR_shp_Q14;
+            psSS[ 0 ].LPC_exc_Q14  = LPC_exc_Q14;
+            psSS[ 0 ].xq_Q14       = xq_Q14;
+
+            /* Update states for second best quantization */
+
+            /* Quantized excitation */
+            exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
+            if ( psDD->Seed < 0 ) {
+                exc_Q14 = -exc_Q14;
+            }
+
+
+            /* Add predictions */
+            LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+            xq_Q14      = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+            /* Update states */
+            sLF_AR_shp_Q14         = silk_SUB32( xq_Q14, n_AR_Q14 );
+            psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+            psSS[ 1 ].LF_AR_Q14    = sLF_AR_shp_Q14;
+            psSS[ 1 ].LPC_exc_Q14  = LPC_exc_Q14;
+            psSS[ 1 ].xq_Q14       = xq_Q14;
+        }
+
+        *smpl_buf_idx  = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK;                   /* Index to newest samples              */
+        last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK;       /* Index to decisionDelay old samples   */
+
+        /* Find winner */
+        RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+        Winner_ind = 0;
+        for( k = 1; k < nStatesDelayedDecision; k++ ) {
+            if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
+                RDmin_Q10  = psSampleState[ k ][ 0 ].RD_Q10;
+                Winner_ind = k;
+            }
+        }
+
+        /* Increase RD values of expired states */
+        Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
+                psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
+                psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
+                silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
+            }
+        }
+
+        /* Find worst in first set and best in second set */
+        RDmax_Q10  = psSampleState[ 0 ][ 0 ].RD_Q10;
+        RDmin_Q10  = psSampleState[ 0 ][ 1 ].RD_Q10;
+        RDmax_ind = 0;
+        RDmin_ind = 0;
+        for( k = 1; k < nStatesDelayedDecision; k++ ) {
+            /* find worst in first set */
+            if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
+                RDmax_Q10  = psSampleState[ k ][ 0 ].RD_Q10;
+                RDmax_ind = k;
+            }
+            /* find best in second set */
+            if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
+                RDmin_Q10  = psSampleState[ k ][ 1 ].RD_Q10;
+                RDmin_ind = k;
+            }
+        }
+
+        /* Replace a state if best from second set outperforms worst in first set */
+        if( RDmin_Q10 < RDmax_Q10 ) {
+            silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
+                         ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
+            silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
+        }
+
+        /* Write samples from winner to output and long-term filter states */
+        psDD = &psDelDec[ Winner_ind ];
+        if( subfr > 0 || i >= decisionDelay ) {
+            pulses[  i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+            xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+                silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
+            NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
+            sLTP_Q15[          NSQ->sLTP_buf_idx     - decisionDelay ] = psDD->Pred_Q15[  last_smple_idx ];
+        }
+        NSQ->sLTP_shp_buf_idx++;
+        NSQ->sLTP_buf_idx++;
+
+        /* Update states */
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            psDD                                     = &psDelDec[ k ];
+            psSS                                     = &psSampleState[ k ][ 0 ];
+            psDD->LF_AR_Q14                          = psSS->LF_AR_Q14;
+            psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
+            psDD->Xq_Q14[    *smpl_buf_idx ]         = psSS->xq_Q14;
+            psDD->Q_Q10[     *smpl_buf_idx ]         = psSS->Q_Q10;
+            psDD->Pred_Q15[  *smpl_buf_idx ]         = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
+            psDD->Shape_Q14[ *smpl_buf_idx ]         = psSS->sLTP_shp_Q14;
+            psDD->Seed                               = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
+            psDD->RandState[ *smpl_buf_idx ]         = psDD->Seed;
+            psDD->RD_Q10                             = psSS->RD_Q10;
+        }
+        delayedGain_Q10[     *smpl_buf_idx ]         = Gain_Q10;
+    }
+    /* Update LPC states */
+    for( k = 0; k < nStatesDelayedDecision; k++ ) {
+        psDD = &psDelDec[ k ];
+        silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+    }
+}
+
+#endif /* __NSQ_DEL_DEC_MIPSR1_H__ */
diff --git a/third_party/opus/src/silk/mips/macros_mipsr1.h b/third_party/opus/src/silk/mips/macros_mipsr1.h
new file mode 100644
index 0000000..12ed981
--- /dev/null
+++ b/third_party/opus/src/silk/mips/macros_mipsr1.h
@@ -0,0 +1,92 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+
+#ifndef __SILK_MACROS_MIPSR1_H__
+#define __SILK_MACROS_MIPSR1_H__
+
+#define mips_clz(x) __builtin_clz(x)
+
+#undef silk_SMULWB
+static inline int silk_SMULWB(int a, int b)
+{
+    long long ac;
+    int c;
+
+    ac = __builtin_mips_mult(a, (opus_int32)(opus_int16)b);
+    c = __builtin_mips_extr_w(ac, 16);
+
+    return c;
+}
+
+#undef silk_SMLAWB
+#define silk_SMLAWB(a32, b32, c32)       ((a32) + silk_SMULWB(b32, c32))
+
+#undef silk_SMULWW
+static inline int silk_SMULWW(int a, int b)
+{
+    long long ac;
+    int c;
+
+    ac = __builtin_mips_mult(a, b);
+    c = __builtin_mips_extr_w(ac, 16);
+
+    return c;
+}
+
+#undef silk_SMLAWW
+static inline int silk_SMLAWW(int a, int b, int c)
+{
+    long long ac;
+    int res;
+
+    ac = __builtin_mips_mult(b, c);
+    res = __builtin_mips_extr_w(ac, 16);
+    res += a;
+
+    return res;
+}
+
+#define OVERRIDE_silk_CLZ16
+static inline opus_int32 silk_CLZ16(opus_int16 in16)
+{
+    int re32;
+    opus_int32 in32 = (opus_int32 )in16;
+    re32 = mips_clz(in32);
+    re32-=16;
+    return re32;
+}
+
+#define OVERRIDE_silk_CLZ32
+static inline opus_int32 silk_CLZ32(opus_int32 in32)
+{
+    int re32;
+    re32 = mips_clz(in32);
+    return re32;
+}
+
+#endif /* __SILK_MACROS_MIPSR1_H__ */
diff --git a/third_party/opus/src/silk/mips/sigproc_fix_mipsr1.h b/third_party/opus/src/silk/mips/sigproc_fix_mipsr1.h
new file mode 100644
index 0000000..3b0a6953
--- /dev/null
+++ b/third_party/opus/src/silk/mips/sigproc_fix_mipsr1.h
@@ -0,0 +1,65 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_MIPSR1_H
+#define SILK_SIGPROC_FIX_MIPSR1_H
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+#undef silk_SAT16
+static inline short int silk_SAT16(int a)
+{
+    int c;
+    c = __builtin_mips_shll_s_w(a, 16);
+    c = c>>16;
+
+    return c;
+}
+
+#undef silk_LSHIFT_SAT32
+static inline int silk_LSHIFT_SAT32(int a, int shift)
+{
+    int r;
+
+    r = __builtin_mips_shll_s_w(a, shift);
+
+    return r;
+}
+
+#undef silk_RSHIFT_ROUND
+static inline int silk_RSHIFT_ROUND(int a, int shift)
+{
+    int r;
+
+    r = __builtin_mips_shra_r_w(a, shift);
+    return r;
+}
+
+#endif /* SILK_SIGPROC_FIX_MIPSR1_H */
diff --git a/third_party/opus/src/silk/pitch_est_defines.h b/third_party/opus/src/silk/pitch_est_defines.h
new file mode 100644
index 0000000..e1e4b5d
--- /dev/null
+++ b/third_party/opus/src/silk/pitch_est_defines.h
@@ -0,0 +1,88 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_PE_DEFINES_H
+#define SILK_PE_DEFINES_H
+
+#include "SigProc_FIX.h"
+
+/********************************************************/
+/* Definitions for pitch estimator                      */
+/********************************************************/
+
+#define PE_MAX_FS_KHZ               16 /* Maximum sampling frequency used */
+
+#define PE_MAX_NB_SUBFR             4
+#define PE_SUBFR_LENGTH_MS          5   /* 5 ms */
+
+#define PE_LTP_MEM_LENGTH_MS        ( 4 * PE_SUBFR_LENGTH_MS )
+
+#define PE_MAX_FRAME_LENGTH_MS      ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS )
+#define PE_MAX_FRAME_LENGTH         ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ )
+#define PE_MAX_FRAME_LENGTH_ST_1    ( PE_MAX_FRAME_LENGTH >> 2 )
+#define PE_MAX_FRAME_LENGTH_ST_2    ( PE_MAX_FRAME_LENGTH >> 1 )
+
+#define PE_MAX_LAG_MS               18           /* 18 ms -> 56 Hz */
+#define PE_MIN_LAG_MS               2            /* 2 ms -> 500 Hz */
+#define PE_MAX_LAG                  ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ )
+#define PE_MIN_LAG                  ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ )
+
+#define PE_D_SRCH_LENGTH            24
+
+#define PE_NB_STAGE3_LAGS           5
+
+#define PE_NB_CBKS_STAGE2           3
+#define PE_NB_CBKS_STAGE2_EXT       11
+
+#define PE_NB_CBKS_STAGE3_MAX       34
+#define PE_NB_CBKS_STAGE3_MID       24
+#define PE_NB_CBKS_STAGE3_MIN       16
+
+#define PE_NB_CBKS_STAGE3_10MS      12
+#define PE_NB_CBKS_STAGE2_10MS      3
+
+#define PE_SHORTLAG_BIAS            0.2f    /* for logarithmic weighting    */
+#define PE_PREVLAG_BIAS             0.2f    /* for logarithmic weighting    */
+#define PE_FLATCONTOUR_BIAS         0.05f
+
+#define SILK_PE_MIN_COMPLEX         0
+#define SILK_PE_MID_COMPLEX         1
+#define SILK_PE_MAX_COMPLEX         2
+
+/* Tables for 20 ms frames */
+extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ];
+extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ];
+extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ];
+extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ];
+
+/* Tables for 10 ms frames */
+extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ];
+extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ];
+extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ];
+
+#endif
+
diff --git a/third_party/opus/src/silk/pitch_est_tables.c b/third_party/opus/src/silk/pitch_est_tables.c
new file mode 100644
index 0000000..81a8baca
--- /dev/null
+++ b/third_party/opus/src/silk/pitch_est_tables.c
@@ -0,0 +1,99 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "typedef.h"
+#include "pitch_est_defines.h"
+
+const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] =
+{
+    {0, 1, 0},
+    {0, 0, 1}
+};
+
+const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] =
+{
+    { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3},
+    { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3}
+};
+
+const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] =
+{
+    {-3, 7},
+    {-2, 7}
+};
+
+const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ] =
+{
+    {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1},
+    {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
+    {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
+    {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1}
+};
+
+const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] =
+{
+    {0, 0, 1,-1, 0, 1,-1, 0,-1, 1,-2, 2,-2,-2, 2,-3, 2, 3,-3,-4, 3,-4, 4, 4,-5, 5,-6,-5, 6,-7, 6, 5, 8,-9},
+    {0, 0, 1, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 0, 1,-1,-1, 1,-1, 2, 1,-1, 2,-2,-2, 2,-2, 2, 2, 3,-3},
+    {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,-1, 1, 0, 0, 2, 1,-1, 2,-1,-1, 2,-1, 2, 2,-1, 3,-2,-2,-2, 3},
+    {0, 1, 0, 0, 1, 0, 1,-1, 2,-1, 2,-1, 2, 3,-2, 3,-2,-2, 4, 4,-3, 5,-3,-4, 6,-4, 6, 5,-5, 8,-6,-5,-7, 9}
+};
+
+const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] =
+{
+    /* Lags to search for low number of stage3 cbks */
+    {
+        {-5,8},
+        {-1,6},
+        {-1,6},
+        {-4,10}
+    },
+    /* Lags to search for middle number of stage3 cbks */
+    {
+        {-6,10},
+        {-2,6},
+        {-1,6},
+        {-5,10}
+    },
+    /* Lags to search for max number of stage3 cbks */
+    {
+        {-9,12},
+        {-3,7},
+        {-2,7},
+        {-7,13}
+    }
+};
+
+const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] =
+{
+    PE_NB_CBKS_STAGE3_MIN,
+    PE_NB_CBKS_STAGE3_MID,
+    PE_NB_CBKS_STAGE3_MAX
+};
diff --git a/third_party/opus/src/silk/process_NLSFs.c b/third_party/opus/src/silk/process_NLSFs.c
new file mode 100644
index 0000000..0ab71f0
--- /dev/null
+++ b/third_party/opus/src/silk/process_NLSFs.c
@@ -0,0 +1,107 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Limit, stabilize, convert and quantize NLSFs */
+void silk_process_NLSFs(
+    silk_encoder_state          *psEncC,                            /* I/O  Encoder state                               */
+    opus_int16                  PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O    Prediction coefficients                     */
+    opus_int16                  pNLSF_Q15[         MAX_LPC_ORDER ], /* I/O  Normalized LSFs (quant out) (0 - (2^15-1))  */
+    const opus_int16            prev_NLSFq_Q15[    MAX_LPC_ORDER ]  /* I    Previous Normalized LSFs (0 - (2^15-1))     */
+)
+{
+    opus_int     i, doInterpolate;
+    opus_int     NLSF_mu_Q20;
+    opus_int16   i_sqr_Q15;
+    opus_int16   pNLSF0_temp_Q15[ MAX_LPC_ORDER ];
+    opus_int16   pNLSFW_QW[ MAX_LPC_ORDER ];
+    opus_int16   pNLSFW0_temp_QW[ MAX_LPC_ORDER ];
+
+    silk_assert( psEncC->speech_activity_Q8 >=   0 );
+    silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) );
+    silk_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) );
+
+    /***********************/
+    /* Calculate mu values */
+    /***********************/
+    /* NLSF_mu  = 0.003 - 0.0015 * psEnc->speech_activity; */
+    NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 );
+    if( psEncC->nb_subfr == 2 ) {
+        /* Multiply by 1.5 for 10 ms packets */
+        NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 );
+    }
+
+    silk_assert( NLSF_mu_Q20 >  0 );
+    silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) );
+
+    /* Calculate NLSF weights */
+    silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder );
+
+    /* Update NLSF weights for interpolated NLSFs */
+    doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 );
+    if( doInterpolate ) {
+        /* Calculate the interpolated NLSF vector for the first half */
+        silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+            psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder );
+
+        /* Calculate first half NLSF weights for the interpolated NLSFs */
+        silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder );
+
+        /* Update NLSF weights with contribution from first half */
+        i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 );
+        for( i = 0; i < psEncC->predictLPCOrder; i++ ) {
+            pNLSFW_QW[ i ] = silk_ADD16( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), silk_RSHIFT(
+                  silk_SMULBB( pNLSFW0_temp_QW[ i ], i_sqr_Q15 ), 16) );
+            silk_assert( pNLSFW_QW[ i ] >= 1 );
+        }
+    }
+
+    silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW,
+        NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType );
+
+    /* Convert quantized NLSFs back to LPC coefficients */
+    silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder );
+
+    if( doInterpolate ) {
+        /* Calculate the interpolated, quantized LSF vector for the first half */
+        silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+            psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder );
+
+        /* Convert back to LPC coefficients */
+        silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder );
+
+    } else {
+        /* Copy LPC coefficients for first half from second half */
+        silk_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER );
+        silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) );
+    }
+}
diff --git a/third_party/opus/src/silk/quant_LTP_gains.c b/third_party/opus/src/silk/quant_LTP_gains.c
new file mode 100644
index 0000000..513a8c4
--- /dev/null
+++ b/third_party/opus/src/silk/quant_LTP_gains.c
@@ -0,0 +1,129 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+void silk_quant_LTP_gains(
+    opus_int16                  B_Q14[ MAX_NB_SUBFR * LTP_ORDER ],          /* I/O  (un)quantized LTP gains         */
+    opus_int8                   cbk_index[ MAX_NB_SUBFR ],                  /* O    Codebook Index                  */
+    opus_int8                   *periodicity_index,                         /* O    Periodicity Index               */
+    opus_int32                  *sum_log_gain_Q7,                           /* I/O  Cumulative max prediction gain  */
+    const opus_int32            W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ],  /* I    Error Weights in Q18            */
+    opus_int                    mu_Q9,                                      /* I    Mu value (R/D tradeoff)         */
+    opus_int                    lowComplexity,                              /* I    Flag for low complexity         */
+    const opus_int              nb_subfr,                                   /* I    number of subframes             */
+    int                         arch                                        /* I    Run-time architecture           */
+)
+{
+    opus_int             j, k, cbk_size;
+    opus_int8            temp_idx[ MAX_NB_SUBFR ];
+    const opus_uint8     *cl_ptr_Q5;
+    const opus_int8      *cbk_ptr_Q7;
+    const opus_uint8     *cbk_gain_ptr_Q7;
+    const opus_int16     *b_Q14_ptr;
+    const opus_int32     *W_Q18_ptr;
+    opus_int32           rate_dist_Q14_subfr, rate_dist_Q14, min_rate_dist_Q14;
+    opus_int32           sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7, gain_Q7;
+
+    /***************************************************/
+    /* iterate over different codebooks with different */
+    /* rates/distortions, and choose best */
+    /***************************************************/
+    min_rate_dist_Q14 = silk_int32_MAX;
+    best_sum_log_gain_Q7 = 0;
+    for( k = 0; k < 3; k++ ) {
+        /* Safety margin for pitch gain control, to take into account factors
+           such as state rescaling/rewhitening. */
+        opus_int32 gain_safety = SILK_FIX_CONST( 0.4, 7 );
+
+        cl_ptr_Q5  = silk_LTP_gain_BITS_Q5_ptrs[ k ];
+        cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[        k ];
+        cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ];
+        cbk_size   = silk_LTP_vq_sizes[          k ];
+
+        /* Set up pointer to first subframe */
+        W_Q18_ptr = W_Q18;
+        b_Q14_ptr = B_Q14;
+
+        rate_dist_Q14 = 0;
+        sum_log_gain_tmp_Q7 = *sum_log_gain_Q7;
+        for( j = 0; j < nb_subfr; j++ ) {
+            max_gain_Q7 = silk_log2lin( ( SILK_FIX_CONST( MAX_SUM_LOG_GAIN_DB / 6.0, 7 ) - sum_log_gain_tmp_Q7 )
+                                        + SILK_FIX_CONST( 7, 7 ) ) - gain_safety;
+
+            silk_VQ_WMat_EC(
+                &temp_idx[ j ],         /* O    index of best codebook vector                           */
+                &rate_dist_Q14_subfr,   /* O    best weighted quantization error + mu * rate            */
+                &gain_Q7,               /* O    sum of absolute LTP coefficients                        */
+                b_Q14_ptr,              /* I    input vector to be quantized                            */
+                W_Q18_ptr,              /* I    weighting matrix                                        */
+                cbk_ptr_Q7,             /* I    codebook                                                */
+                cbk_gain_ptr_Q7,        /* I    codebook effective gains                                */
+                cl_ptr_Q5,              /* I    code length for each codebook vector                    */
+                mu_Q9,                  /* I    tradeoff between weighted error and rate                */
+                max_gain_Q7,            /* I    maximum sum of absolute LTP coefficients                */
+                cbk_size,               /* I    number of vectors in codebook                           */
+                arch                    /* I    Run-time architecture                                   */
+            );
+
+            rate_dist_Q14 = silk_ADD_POS_SAT32( rate_dist_Q14, rate_dist_Q14_subfr );
+            sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7
+                                + silk_lin2log( gain_safety + gain_Q7 ) - SILK_FIX_CONST( 7, 7 ));
+
+            b_Q14_ptr += LTP_ORDER;
+            W_Q18_ptr += LTP_ORDER * LTP_ORDER;
+        }
+
+        /* Avoid never finding a codebook */
+        rate_dist_Q14 = silk_min( silk_int32_MAX - 1, rate_dist_Q14 );
+
+        if( rate_dist_Q14 < min_rate_dist_Q14 ) {
+            min_rate_dist_Q14 = rate_dist_Q14;
+            *periodicity_index = (opus_int8)k;
+            silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) );
+            best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7;
+        }
+
+        /* Break early in low-complexity mode if rate distortion is below threshold */
+        if( lowComplexity && ( rate_dist_Q14 < silk_LTP_gain_middle_avg_RD_Q14 ) ) {
+            break;
+        }
+    }
+
+    cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ];
+    for( j = 0; j < nb_subfr; j++ ) {
+        for( k = 0; k < LTP_ORDER; k++ ) {
+            B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 );
+        }
+    }
+    *sum_log_gain_Q7 = best_sum_log_gain_Q7;
+}
diff --git a/third_party/opus/src/silk/resampler.c b/third_party/opus/src/silk/resampler.c
new file mode 100644
index 0000000..374fbb37
--- /dev/null
+++ b/third_party/opus/src/silk/resampler.c
@@ -0,0 +1,215 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Matrix of resampling methods used:
+ *                                 Fs_out (kHz)
+ *                        8      12     16     24     48
+ *
+ *               8        C      UF     U      UF     UF
+ *              12        AF     C      UF     U      UF
+ * Fs_in (kHz)  16        D      AF     C      UF     UF
+ *              24        AF     D      AF     C      U
+ *              48        AF     AF     AF     D      C
+ *
+ * C   -> Copy (no resampling)
+ * D   -> Allpass-based 2x downsampling
+ * U   -> Allpass-based 2x upsampling
+ * UF  -> Allpass-based 2x upsampling followed by FIR interpolation
+ * AF  -> AR2 filter followed by FIR interpolation
+ */
+
+#include "resampler_private.h"
+
+/* Tables with delay compensation values to equalize total delay for different modes */
+static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = {
+/* in  \ out  8  12  16 */
+/*  8 */   {  6,  0,  3 },
+/* 12 */   {  0,  7,  3 },
+/* 16 */   {  0,  1, 10 },
+/* 24 */   {  0,  2,  6 },
+/* 48 */   { 18, 10, 12 }
+};
+
+static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = {
+/* in  \ out  8  12  16  24  48 */
+/*  8 */   {  4,  0,  2,  0,  0 },
+/* 12 */   {  0,  9,  4,  7,  4 },
+/* 16 */   {  0,  3, 12,  7,  7 }
+};
+
+/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */
+#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 )
+
+#define USE_silk_resampler_copy                     (0)
+#define USE_silk_resampler_private_up2_HQ_wrapper   (1)
+#define USE_silk_resampler_private_IIR_FIR          (2)
+#define USE_silk_resampler_private_down_FIR         (3)
+
+/* Initialize/reset the resampler state for a given pair of input/output sampling rates */
+opus_int silk_resampler_init(
+    silk_resampler_state_struct *S,                 /* I/O  Resampler state                                             */
+    opus_int32                  Fs_Hz_in,           /* I    Input sampling rate (Hz)                                    */
+    opus_int32                  Fs_Hz_out,          /* I    Output sampling rate (Hz)                                   */
+    opus_int                    forEnc              /* I    If 1: encoder; if 0: decoder                                */
+)
+{
+    opus_int up2x;
+
+    /* Clear state */
+    silk_memset( S, 0, sizeof( silk_resampler_state_struct ) );
+
+    /* Input checking */
+    if( forEnc ) {
+        if( ( Fs_Hz_in  != 8000 && Fs_Hz_in  != 12000 && Fs_Hz_in  != 16000 && Fs_Hz_in  != 24000 && Fs_Hz_in  != 48000 ) ||
+            ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 ) ) {
+            silk_assert( 0 );
+            return -1;
+        }
+        S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ];
+    } else {
+        if( ( Fs_Hz_in  != 8000 && Fs_Hz_in  != 12000 && Fs_Hz_in  != 16000 ) ||
+            ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000 ) ) {
+            silk_assert( 0 );
+            return -1;
+        }
+        S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ];
+    }
+
+    S->Fs_in_kHz  = silk_DIV32_16( Fs_Hz_in,  1000 );
+    S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 );
+
+    /* Number of samples processed per batch */
+    S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS;
+
+    /* Find resampler with the right sampling ratio */
+    up2x = 0;
+    if( Fs_Hz_out > Fs_Hz_in ) {
+        /* Upsample */
+        if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) {                            /* Fs_out : Fs_in = 2 : 1 */
+            /* Special case: directly use 2x upsampler */
+            S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper;
+        } else {
+            /* Default resampler */
+            S->resampler_function = USE_silk_resampler_private_IIR_FIR;
+            up2x = 1;
+        }
+    } else if ( Fs_Hz_out < Fs_Hz_in ) {
+        /* Downsample */
+         S->resampler_function = USE_silk_resampler_private_down_FIR;
+        if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) {             /* Fs_out : Fs_in = 3 : 4 */
+            S->FIR_Fracs = 3;
+            S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0;
+            S->Coefs = silk_Resampler_3_4_COEFS;
+        } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) {      /* Fs_out : Fs_in = 2 : 3 */
+            S->FIR_Fracs = 2;
+            S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0;
+            S->Coefs = silk_Resampler_2_3_COEFS;
+        } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) {                     /* Fs_out : Fs_in = 1 : 2 */
+            S->FIR_Fracs = 1;
+            S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1;
+            S->Coefs = silk_Resampler_1_2_COEFS;
+        } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) {                     /* Fs_out : Fs_in = 1 : 3 */
+            S->FIR_Fracs = 1;
+            S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+            S->Coefs = silk_Resampler_1_3_COEFS;
+        } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) {                     /* Fs_out : Fs_in = 1 : 4 */
+            S->FIR_Fracs = 1;
+            S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+            S->Coefs = silk_Resampler_1_4_COEFS;
+        } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) {                     /* Fs_out : Fs_in = 1 : 6 */
+            S->FIR_Fracs = 1;
+            S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+            S->Coefs = silk_Resampler_1_6_COEFS;
+        } else {
+            /* None available */
+            silk_assert( 0 );
+            return -1;
+        }
+    } else {
+        /* Input and output sampling rates are equal: copy */
+        S->resampler_function = USE_silk_resampler_copy;
+    }
+
+    /* Ratio of input/output samples */
+    S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 );
+    /* Make sure the ratio is rounded up */
+    while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) {
+        S->invRatio_Q16++;
+    }
+
+    return 0;
+}
+
+/* Resampler: convert from one sampling rate to another */
+/* Input and output sampling rate are at most 48000 Hz  */
+opus_int silk_resampler(
+    silk_resampler_state_struct *S,                 /* I/O  Resampler state                                             */
+    opus_int16                  out[],              /* O    Output signal                                               */
+    const opus_int16            in[],               /* I    Input signal                                                */
+    opus_int32                  inLen               /* I    Number of input samples                                     */
+)
+{
+    opus_int nSamples;
+
+    /* Need at least 1 ms of input data */
+    silk_assert( inLen >= S->Fs_in_kHz );
+    /* Delay can't exceed the 1 ms of buffering */
+    silk_assert( S->inputDelay <= S->Fs_in_kHz );
+
+    nSamples = S->Fs_in_kHz - S->inputDelay;
+
+    /* Copy to delay buffer */
+    silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) );
+
+    switch( S->resampler_function ) {
+        case USE_silk_resampler_private_up2_HQ_wrapper:
+            silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz );
+            silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+            break;
+        case USE_silk_resampler_private_IIR_FIR:
+            silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz );
+            silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+            break;
+        case USE_silk_resampler_private_down_FIR:
+            silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz );
+            silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+            break;
+        default:
+            silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) );
+            silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) );
+    }
+
+    /* Copy to delay buffer */
+    silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) );
+
+    return 0;
+}
diff --git a/third_party/opus/src/silk/resampler_down2.c b/third_party/opus/src/silk/resampler_down2.c
new file mode 100644
index 0000000..cec36346
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_down2.c
@@ -0,0 +1,74 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_rom.h"
+
+/* Downsample by a factor 2 */
+void silk_resampler_down2(
+    opus_int32                  *S,                 /* I/O  State vector [ 2 ]                                          */
+    opus_int16                  *out,               /* O    Output signal [ floor(len/2) ]                              */
+    const opus_int16            *in,                /* I    Input signal [ len ]                                        */
+    opus_int32                  inLen               /* I    Number of input samples                                     */
+)
+{
+    opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 );
+    opus_int32 in32, out32, Y, X;
+
+    silk_assert( silk_resampler_down2_0 > 0 );
+    silk_assert( silk_resampler_down2_1 < 0 );
+
+    /* Internal variables and state are in Q10 format */
+    for( k = 0; k < len2; k++ ) {
+        /* Convert to Q10 */
+        in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 );
+
+        /* All-pass section for even input sample */
+        Y      = silk_SUB32( in32, S[ 0 ] );
+        X      = silk_SMLAWB( Y, Y, silk_resampler_down2_1 );
+        out32  = silk_ADD32( S[ 0 ], X );
+        S[ 0 ] = silk_ADD32( in32, X );
+
+        /* Convert to Q10 */
+        in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 );
+
+        /* All-pass section for odd input sample, and add to output of previous section */
+        Y      = silk_SUB32( in32, S[ 1 ] );
+        X      = silk_SMULWB( Y, silk_resampler_down2_0 );
+        out32  = silk_ADD32( out32, S[ 1 ] );
+        out32  = silk_ADD32( out32, X );
+        S[ 1 ] = silk_ADD32( in32, X );
+
+        /* Add, convert back to int16 and store to output */
+        out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) );
+    }
+}
+
diff --git a/third_party/opus/src/silk/resampler_down2_3.c b/third_party/opus/src/silk/resampler_down2_3.c
new file mode 100644
index 0000000..4342614d
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_down2_3.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+#include "stack_alloc.h"
+
+#define ORDER_FIR                   4
+
+/* Downsample by a factor 2/3, low quality */
+void silk_resampler_down2_3(
+    opus_int32                  *S,                 /* I/O  State vector [ 6 ]                                          */
+    opus_int16                  *out,               /* O    Output signal [ floor(2*inLen/3) ]                          */
+    const opus_int16            *in,                /* I    Input signal [ inLen ]                                      */
+    opus_int32                  inLen               /* I    Number of input samples                                     */
+)
+{
+    opus_int32 nSamplesIn, counter, res_Q6;
+    VARDECL( opus_int32, buf );
+    opus_int32 *buf_ptr;
+    SAVE_STACK;
+
+    ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 );
+
+    /* Copy buffered samples to start of buffer */
+    silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) );
+
+    /* Iterate over blocks of frameSizeIn input samples */
+    while( 1 ) {
+        nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN );
+
+        /* Second-order AR filter (output in Q8) */
+        silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in,
+            silk_Resampler_2_3_COEFS_LQ, nSamplesIn );
+
+        /* Interpolate filtered signal */
+        buf_ptr = buf;
+        counter = nSamplesIn;
+        while( counter > 2 ) {
+            /* Inner product */
+            res_Q6 = silk_SMULWB(         buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] );
+            res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] );
+            res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] );
+            res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] );
+
+            /* Scale down, saturate and store in output array */
+            *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+
+            res_Q6 = silk_SMULWB(         buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] );
+            res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] );
+            res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] );
+            res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] );
+
+            /* Scale down, saturate and store in output array */
+            *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+
+            buf_ptr += 3;
+            counter -= 3;
+        }
+
+        in += nSamplesIn;
+        inLen -= nSamplesIn;
+
+        if( inLen > 0 ) {
+            /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+            silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) );
+        } else {
+            break;
+        }
+    }
+
+    /* Copy last part of filtered signal to the state for the next call */
+    silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) );
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/resampler_private.h b/third_party/opus/src/silk/resampler_private.h
new file mode 100644
index 0000000..422a7d9d
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_private.h
@@ -0,0 +1,88 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_RESAMPLER_PRIVATE_H
+#define SILK_RESAMPLER_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_structs.h"
+#include "resampler_rom.h"
+
+/* Number of input samples to process in the inner loop */
+#define RESAMPLER_MAX_BATCH_SIZE_MS             10
+#define RESAMPLER_MAX_FS_KHZ                    48
+#define RESAMPLER_MAX_BATCH_SIZE_IN             ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ )
+
+/* Description: Hybrid IIR/FIR polyphase implementation of resampling */
+void silk_resampler_private_IIR_FIR(
+    void                            *SS,            /* I/O  Resampler state             */
+    opus_int16                      out[],          /* O    Output signal               */
+    const opus_int16                in[],           /* I    Input signal                */
+    opus_int32                      inLen           /* I    Number of input samples     */
+);
+
+/* Description: Hybrid IIR/FIR polyphase implementation of resampling */
+void silk_resampler_private_down_FIR(
+    void                            *SS,            /* I/O  Resampler state             */
+    opus_int16                      out[],          /* O    Output signal               */
+    const opus_int16                in[],           /* I    Input signal                */
+    opus_int32                      inLen           /* I    Number of input samples     */
+);
+
+/* Upsample by a factor 2, high quality */
+void silk_resampler_private_up2_HQ_wrapper(
+    void                            *SS,            /* I/O  Resampler state (unused)    */
+    opus_int16                      *out,           /* O    Output signal [ 2 * len ]   */
+    const opus_int16                *in,            /* I    Input signal [ len ]        */
+    opus_int32                      len             /* I    Number of input samples     */
+);
+
+/* Upsample by a factor 2, high quality */
+void silk_resampler_private_up2_HQ(
+    opus_int32                      *S,             /* I/O  Resampler state [ 6 ]       */
+    opus_int16                      *out,           /* O    Output signal [ 2 * len ]   */
+    const opus_int16                *in,            /* I    Input signal [ len ]        */
+    opus_int32                      len             /* I    Number of input samples     */
+);
+
+/* Second order AR filter */
+void silk_resampler_private_AR2(
+    opus_int32                      S[],            /* I/O  State vector [ 2 ]          */
+    opus_int32                      out_Q8[],       /* O    Output signal               */
+    const opus_int16                in[],           /* I    Input signal                */
+    const opus_int16                A_Q14[],        /* I    AR coefficients, Q14        */
+    opus_int32                      len             /* I    Signal length               */
+);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SILK_RESAMPLER_PRIVATE_H */
diff --git a/third_party/opus/src/silk/resampler_private_AR2.c b/third_party/opus/src/silk/resampler_private_AR2.c
new file mode 100644
index 0000000..5fff23714
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_private_AR2.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+
+/* Second order AR filter with single delay elements */
+void silk_resampler_private_AR2(
+    opus_int32                      S[],            /* I/O  State vector [ 2 ]          */
+    opus_int32                      out_Q8[],       /* O    Output signal               */
+    const opus_int16                in[],           /* I    Input signal                */
+    const opus_int16                A_Q14[],        /* I    AR coefficients, Q14        */
+    opus_int32                      len             /* I    Signal length               */
+)
+{
+    opus_int32    k;
+    opus_int32    out32;
+
+    for( k = 0; k < len; k++ ) {
+        out32       = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 );
+        out_Q8[ k ] = out32;
+        out32       = silk_LSHIFT( out32, 2 );
+        S[ 0 ]      = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] );
+        S[ 1 ]      = silk_SMULWB( out32, A_Q14[ 1 ] );
+    }
+}
+
diff --git a/third_party/opus/src/silk/resampler_private_IIR_FIR.c b/third_party/opus/src/silk/resampler_private_IIR_FIR.c
new file mode 100644
index 0000000..6b2b3a2
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_private_IIR_FIR.c
@@ -0,0 +1,107 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+#include "stack_alloc.h"
+
+static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL(
+    opus_int16  *out,
+    opus_int16  *buf,
+    opus_int32  max_index_Q16,
+    opus_int32  index_increment_Q16
+)
+{
+    opus_int32 index_Q16, res_Q15;
+    opus_int16 *buf_ptr;
+    opus_int32 table_index;
+
+    /* Interpolate upsampled signal and store in output array */
+    for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+        table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 );
+        buf_ptr = &buf[ index_Q16 >> 16 ];
+
+        res_Q15 = silk_SMULBB(          buf_ptr[ 0 ], silk_resampler_frac_FIR_12[      table_index ][ 0 ] );
+        res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[      table_index ][ 1 ] );
+        res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[      table_index ][ 2 ] );
+        res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[      table_index ][ 3 ] );
+        res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] );
+        res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] );
+        res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] );
+        res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] );
+        *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) );
+    }
+    return out;
+}
+/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */
+void silk_resampler_private_IIR_FIR(
+    void                            *SS,            /* I/O  Resampler state             */
+    opus_int16                      out[],          /* O    Output signal               */
+    const opus_int16                in[],           /* I    Input signal                */
+    opus_int32                      inLen           /* I    Number of input samples     */
+)
+{
+    silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+    opus_int32 nSamplesIn;
+    opus_int32 max_index_Q16, index_increment_Q16;
+    VARDECL( opus_int16, buf );
+    SAVE_STACK;
+
+    ALLOC( buf, 2 * S->batchSize + RESAMPLER_ORDER_FIR_12, opus_int16 );
+
+    /* Copy buffered samples to start of buffer */
+    silk_memcpy( buf, S->sFIR.i16, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+
+    /* Iterate over blocks of frameSizeIn input samples */
+    index_increment_Q16 = S->invRatio_Q16;
+    while( 1 ) {
+        nSamplesIn = silk_min( inLen, S->batchSize );
+
+        /* Upsample 2x */
+        silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn );
+
+        max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 );         /* + 1 because 2x upsampling */
+        out = silk_resampler_private_IIR_FIR_INTERPOL( out, buf, max_index_Q16, index_increment_Q16 );
+        in += nSamplesIn;
+        inLen -= nSamplesIn;
+
+        if( inLen > 0 ) {
+            /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+            silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+        } else {
+            break;
+        }
+    }
+
+    /* Copy last part of filtered signal to the state for the next call */
+    silk_memcpy( S->sFIR.i16, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/resampler_private_down_FIR.c b/third_party/opus/src/silk/resampler_private_down_FIR.c
new file mode 100644
index 0000000..783e42b
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_private_down_FIR.c
@@ -0,0 +1,194 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+#include "stack_alloc.h"
+
+static OPUS_INLINE opus_int16 *silk_resampler_private_down_FIR_INTERPOL(
+    opus_int16          *out,
+    opus_int32          *buf,
+    const opus_int16    *FIR_Coefs,
+    opus_int            FIR_Order,
+    opus_int            FIR_Fracs,
+    opus_int32          max_index_Q16,
+    opus_int32          index_increment_Q16
+)
+{
+    opus_int32 index_Q16, res_Q6;
+    opus_int32 *buf_ptr;
+    opus_int32 interpol_ind;
+    const opus_int16 *interpol_ptr;
+
+    switch( FIR_Order ) {
+        case RESAMPLER_DOWN_ORDER_FIR0:
+            for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+                /* Integer part gives pointer to buffered input */
+                buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+                /* Fractional part gives interpolation coefficients */
+                interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs );
+
+                /* Inner product */
+                interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ];
+                res_Q6 = silk_SMULWB(         buf_ptr[ 0 ], interpol_ptr[ 0 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] );
+                interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ];
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[  9 ], interpol_ptr[ 8 ] );
+
+                /* Scale down, saturate and store in output array */
+                *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+            }
+            break;
+        case RESAMPLER_DOWN_ORDER_FIR1:
+            for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+                /* Integer part gives pointer to buffered input */
+                buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+                /* Inner product */
+                res_Q6 = silk_SMULWB(         silk_ADD32( buf_ptr[  0 ], buf_ptr[ 23 ] ), FIR_Coefs[  0 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  1 ], buf_ptr[ 22 ] ), FIR_Coefs[  1 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  2 ], buf_ptr[ 21 ] ), FIR_Coefs[  2 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  3 ], buf_ptr[ 20 ] ), FIR_Coefs[  3 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  4 ], buf_ptr[ 19 ] ), FIR_Coefs[  4 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  5 ], buf_ptr[ 18 ] ), FIR_Coefs[  5 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  6 ], buf_ptr[ 17 ] ), FIR_Coefs[  6 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  7 ], buf_ptr[ 16 ] ), FIR_Coefs[  7 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  8 ], buf_ptr[ 15 ] ), FIR_Coefs[  8 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  9 ], buf_ptr[ 14 ] ), FIR_Coefs[  9 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] );
+
+                /* Scale down, saturate and store in output array */
+                *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+            }
+            break;
+        case RESAMPLER_DOWN_ORDER_FIR2:
+            for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+                /* Integer part gives pointer to buffered input */
+                buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+                /* Inner product */
+                res_Q6 = silk_SMULWB(         silk_ADD32( buf_ptr[  0 ], buf_ptr[ 35 ] ), FIR_Coefs[  0 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  1 ], buf_ptr[ 34 ] ), FIR_Coefs[  1 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  2 ], buf_ptr[ 33 ] ), FIR_Coefs[  2 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  3 ], buf_ptr[ 32 ] ), FIR_Coefs[  3 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  4 ], buf_ptr[ 31 ] ), FIR_Coefs[  4 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  5 ], buf_ptr[ 30 ] ), FIR_Coefs[  5 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  6 ], buf_ptr[ 29 ] ), FIR_Coefs[  6 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  7 ], buf_ptr[ 28 ] ), FIR_Coefs[  7 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  8 ], buf_ptr[ 27 ] ), FIR_Coefs[  8 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[  9 ], buf_ptr[ 26 ] ), FIR_Coefs[  9 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] );
+                res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] );
+
+                /* Scale down, saturate and store in output array */
+                *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+            }
+            break;
+        default:
+            silk_assert( 0 );
+    }
+    return out;
+}
+
+/* Resample with a 2nd order AR filter followed by FIR interpolation */
+void silk_resampler_private_down_FIR(
+    void                            *SS,            /* I/O  Resampler state             */
+    opus_int16                      out[],          /* O    Output signal               */
+    const opus_int16                in[],           /* I    Input signal                */
+    opus_int32                      inLen           /* I    Number of input samples     */
+)
+{
+    silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+    opus_int32 nSamplesIn;
+    opus_int32 max_index_Q16, index_increment_Q16;
+    VARDECL( opus_int32, buf );
+    const opus_int16 *FIR_Coefs;
+    SAVE_STACK;
+
+    ALLOC( buf, S->batchSize + S->FIR_Order, opus_int32 );
+
+    /* Copy buffered samples to start of buffer */
+    silk_memcpy( buf, S->sFIR.i32, S->FIR_Order * sizeof( opus_int32 ) );
+
+    FIR_Coefs = &S->Coefs[ 2 ];
+
+    /* Iterate over blocks of frameSizeIn input samples */
+    index_increment_Q16 = S->invRatio_Q16;
+    while( 1 ) {
+        nSamplesIn = silk_min( inLen, S->batchSize );
+
+        /* Second-order AR filter (output in Q8) */
+        silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn );
+
+        max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 );
+
+        /* Interpolate filtered signal */
+        out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order,
+            S->FIR_Fracs, max_index_Q16, index_increment_Q16 );
+
+        in += nSamplesIn;
+        inLen -= nSamplesIn;
+
+        if( inLen > 1 ) {
+            /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+            silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) );
+        } else {
+            break;
+        }
+    }
+
+    /* Copy last part of filtered signal to the state for the next call */
+    silk_memcpy( S->sFIR.i32, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) );
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/resampler_private_up2_HQ.c b/third_party/opus/src/silk/resampler_private_up2_HQ.c
new file mode 100644
index 0000000..c7ec8de3
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_private_up2_HQ.c
@@ -0,0 +1,113 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "resampler_private.h"
+
+/* Upsample by a factor 2, high quality */
+/* Uses 2nd order allpass filters for the 2x upsampling, followed by a      */
+/* notch filter just above Nyquist.                                         */
+void silk_resampler_private_up2_HQ(
+    opus_int32                      *S,             /* I/O  Resampler state [ 6 ]       */
+    opus_int16                      *out,           /* O    Output signal [ 2 * len ]   */
+    const opus_int16                *in,            /* I    Input signal [ len ]        */
+    opus_int32                      len             /* I    Number of input samples     */
+)
+{
+    opus_int32 k;
+    opus_int32 in32, out32_1, out32_2, Y, X;
+
+    silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 );
+    silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 );
+    silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 );
+    silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 );
+    silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 );
+    silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 );
+
+    /* Internal variables and state are in Q10 format */
+    for( k = 0; k < len; k++ ) {
+        /* Convert to Q10 */
+        in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 );
+
+        /* First all-pass section for even output sample */
+        Y       = silk_SUB32( in32, S[ 0 ] );
+        X       = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] );
+        out32_1 = silk_ADD32( S[ 0 ], X );
+        S[ 0 ]  = silk_ADD32( in32, X );
+
+        /* Second all-pass section for even output sample */
+        Y       = silk_SUB32( out32_1, S[ 1 ] );
+        X       = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] );
+        out32_2 = silk_ADD32( S[ 1 ], X );
+        S[ 1 ]  = silk_ADD32( out32_1, X );
+
+        /* Third all-pass section for even output sample */
+        Y       = silk_SUB32( out32_2, S[ 2 ] );
+        X       = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] );
+        out32_1 = silk_ADD32( S[ 2 ], X );
+        S[ 2 ]  = silk_ADD32( out32_2, X );
+
+        /* Apply gain in Q15, convert back to int16 and store to output */
+        out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) );
+
+        /* First all-pass section for odd output sample */
+        Y       = silk_SUB32( in32, S[ 3 ] );
+        X       = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] );
+        out32_1 = silk_ADD32( S[ 3 ], X );
+        S[ 3 ]  = silk_ADD32( in32, X );
+
+        /* Second all-pass section for odd output sample */
+        Y       = silk_SUB32( out32_1, S[ 4 ] );
+        X       = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] );
+        out32_2 = silk_ADD32( S[ 4 ], X );
+        S[ 4 ]  = silk_ADD32( out32_1, X );
+
+        /* Third all-pass section for odd output sample */
+        Y       = silk_SUB32( out32_2, S[ 5 ] );
+        X       = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] );
+        out32_1 = silk_ADD32( S[ 5 ], X );
+        S[ 5 ]  = silk_ADD32( out32_2, X );
+
+        /* Apply gain in Q15, convert back to int16 and store to output */
+        out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) );
+    }
+}
+
+void silk_resampler_private_up2_HQ_wrapper(
+    void                            *SS,            /* I/O  Resampler state (unused)    */
+    opus_int16                      *out,           /* O    Output signal [ 2 * len ]   */
+    const opus_int16                *in,            /* I    Input signal [ len ]        */
+    opus_int32                      len             /* I    Number of input samples     */
+)
+{
+    silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+    silk_resampler_private_up2_HQ( S->sIIR, out, in, len );
+}
diff --git a/third_party/opus/src/silk/resampler_rom.c b/third_party/opus/src/silk/resampler_rom.c
new file mode 100644
index 0000000..5e6b044
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_rom.c
@@ -0,0 +1,96 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Filter coefficients for IIR/FIR polyphase resampling     *
+ * Total size: 179 Words (358 Bytes)                        */
+
+#include "resampler_private.h"
+
+/* Matlab code for the notch filter coefficients: */
+/* B = [1, 0.147, 1];  A = [1, 0.107, 0.89]; G = 0.93; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]) */
+/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */
+/* const opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634,  -7012,   7209,  30474 }; */
+
+/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = {
+    -20694, -13867,
+       -49,     64,     17,   -157,    353,   -496,    163,  11047,  22205,
+       -39,      6,     91,   -170,    186,     23,   -896,   6336,  19928,
+       -19,    -36,    102,    -89,    -24,    328,   -951,   2568,  15909,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = {
+    -14457, -14019,
+        64,    128,   -122,     36,    310,   -768,    584,   9267,  17733,
+        12,    128,     18,   -142,    288,   -117,   -865,   4123,  14459,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = {
+       616, -14323,
+       -10,     39,     58,    -46,    -84,    120,    184,   -315,   -541,   1284,   5380,   9024,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+     16102, -15162,
+       -13,      0,     20,     26,      5,    -31,    -43,     -4,     65,     90,      7,   -157,   -248,    -44,    593,   1583,   2612,   3271,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+     22500, -15099,
+         3,    -14,    -20,    -15,      2,     25,     37,     25,    -16,    -71,   -107,    -79,     50,    292,    623,    982,   1288,   1464,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+     27540, -15257,
+        17,     12,      8,      1,    -10,    -22,    -30,    -32,    -22,      3,     44,    100,    168,    243,    317,    381,    429,    455,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = {
+     -2797,  -6507,
+      4697,  10739,
+      1567,   8276,
+};
+
+/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */
+silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = {
+    {  189,  -600,   617, 30567 },
+    {  117,  -159, -1070, 29704 },
+    {   52,   221, -2392, 28276 },
+    {   -4,   529, -3350, 26341 },
+    {  -48,   758, -3956, 23973 },
+    {  -80,   905, -4235, 21254 },
+    {  -99,   972, -4222, 18278 },
+    { -107,   967, -3957, 15143 },
+    { -103,   896, -3487, 11950 },
+    {  -91,   773, -2865,  8798 },
+    {  -71,   611, -2143,  5784 },
+    {  -46,   425, -1375,  2996 },
+};
diff --git a/third_party/opus/src/silk/resampler_rom.h b/third_party/opus/src/silk/resampler_rom.h
new file mode 100644
index 0000000..490b3388
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_rom.h
@@ -0,0 +1,68 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_FIX_RESAMPLER_ROM_H
+#define SILK_FIX_RESAMPLER_ROM_H
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+#include "typedef.h"
+#include "resampler_structs.h"
+
+#define RESAMPLER_DOWN_ORDER_FIR0               18
+#define RESAMPLER_DOWN_ORDER_FIR1               24
+#define RESAMPLER_DOWN_ORDER_FIR2               36
+#define RESAMPLER_ORDER_FIR_12                  8
+
+/* Tables for 2x downsampler */
+static const opus_int16 silk_resampler_down2_0 = 9872;
+static const opus_int16 silk_resampler_down2_1 = 39809 - 65536;
+
+/* Tables for 2x upsampler, high quality */
+static const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 };
+static const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 };
+
+/* Tables with IIR and FIR coefficients for fractional downsamplers */
+extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ];
+extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ];
+extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 +     RESAMPLER_DOWN_ORDER_FIR1 / 2 ];
+extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 +     RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 +     RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 +     RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ];
+
+/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */
+extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ];
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* SILK_FIX_RESAMPLER_ROM_H */
diff --git a/third_party/opus/src/silk/resampler_structs.h b/third_party/opus/src/silk/resampler_structs.h
new file mode 100644
index 0000000..9e9457d
--- /dev/null
+++ b/third_party/opus/src/silk/resampler_structs.h
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_RESAMPLER_STRUCTS_H
+#define SILK_RESAMPLER_STRUCTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SILK_RESAMPLER_MAX_FIR_ORDER                 36
+#define SILK_RESAMPLER_MAX_IIR_ORDER                 6
+
+typedef struct _silk_resampler_state_struct{
+    opus_int32       sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */
+    union{
+        opus_int32   i32[ SILK_RESAMPLER_MAX_FIR_ORDER ];
+        opus_int16   i16[ SILK_RESAMPLER_MAX_FIR_ORDER ];
+    }                sFIR;
+    opus_int16       delayBuf[ 48 ];
+    opus_int         resampler_function;
+    opus_int         batchSize;
+    opus_int32       invRatio_Q16;
+    opus_int         FIR_Order;
+    opus_int         FIR_Fracs;
+    opus_int         Fs_in_kHz;
+    opus_int         Fs_out_kHz;
+    opus_int         inputDelay;
+    const opus_int16 *Coefs;
+} silk_resampler_state_struct;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SILK_RESAMPLER_STRUCTS_H */
+
diff --git a/third_party/opus/src/silk/shell_coder.c b/third_party/opus/src/silk/shell_coder.c
new file mode 100644
index 0000000..4af3414
--- /dev/null
+++ b/third_party/opus/src/silk/shell_coder.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* shell coder; pulse-subframe length is hardcoded */
+
+static OPUS_INLINE void combine_pulses(
+    opus_int         *out,   /* O    combined pulses vector [len] */
+    const opus_int   *in,    /* I    input vector       [2 * len] */
+    const opus_int   len     /* I    number of OUTPUT samples     */
+)
+{
+    opus_int k;
+    for( k = 0; k < len; k++ ) {
+        out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ];
+    }
+}
+
+static OPUS_INLINE void encode_split(
+    ec_enc                      *psRangeEnc,    /* I/O  compressor data structure                   */
+    const opus_int              p_child1,       /* I    pulse amplitude of first child subframe     */
+    const opus_int              p,              /* I    pulse amplitude of current subframe         */
+    const opus_uint8            *shell_table    /* I    table of shell cdfs                         */
+)
+{
+    if( p > 0 ) {
+        ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 );
+    }
+}
+
+static OPUS_INLINE void decode_split(
+    opus_int16                  *p_child1,      /* O    pulse amplitude of first child subframe     */
+    opus_int16                  *p_child2,      /* O    pulse amplitude of second child subframe    */
+    ec_dec                      *psRangeDec,    /* I/O  Compressor data structure                   */
+    const opus_int              p,              /* I    pulse amplitude of current subframe         */
+    const opus_uint8            *shell_table    /* I    table of shell cdfs                         */
+)
+{
+    if( p > 0 ) {
+        p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 );
+        p_child2[ 0 ] = p - p_child1[ 0 ];
+    } else {
+        p_child1[ 0 ] = 0;
+        p_child2[ 0 ] = 0;
+    }
+}
+
+/* Shell encoder, operates on one shell code frame of 16 pulses */
+void silk_shell_encoder(
+    ec_enc                      *psRangeEnc,                    /* I/O  compressor data structure                   */
+    const opus_int              *pulses0                        /* I    data: nonnegative pulse amplitudes          */
+)
+{
+    opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ];
+
+    /* this function operates on one shell code frame of 16 pulses */
+    silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 );
+
+    /* tree representation per pulse-subframe */
+    combine_pulses( pulses1, pulses0, 8 );
+    combine_pulses( pulses2, pulses1, 4 );
+    combine_pulses( pulses3, pulses2, 2 );
+    combine_pulses( pulses4, pulses3, 1 );
+
+    encode_split( psRangeEnc, pulses3[  0 ], pulses4[ 0 ], silk_shell_code_table3 );
+
+    encode_split( psRangeEnc, pulses2[  0 ], pulses3[ 0 ], silk_shell_code_table2 );
+
+    encode_split( psRangeEnc, pulses1[  0 ], pulses2[ 0 ], silk_shell_code_table1 );
+    encode_split( psRangeEnc, pulses0[  0 ], pulses1[ 0 ], silk_shell_code_table0 );
+    encode_split( psRangeEnc, pulses0[  2 ], pulses1[ 1 ], silk_shell_code_table0 );
+
+    encode_split( psRangeEnc, pulses1[  2 ], pulses2[ 1 ], silk_shell_code_table1 );
+    encode_split( psRangeEnc, pulses0[  4 ], pulses1[ 2 ], silk_shell_code_table0 );
+    encode_split( psRangeEnc, pulses0[  6 ], pulses1[ 3 ], silk_shell_code_table0 );
+
+    encode_split( psRangeEnc, pulses2[  2 ], pulses3[ 1 ], silk_shell_code_table2 );
+
+    encode_split( psRangeEnc, pulses1[  4 ], pulses2[ 2 ], silk_shell_code_table1 );
+    encode_split( psRangeEnc, pulses0[  8 ], pulses1[ 4 ], silk_shell_code_table0 );
+    encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 );
+
+    encode_split( psRangeEnc, pulses1[  6 ], pulses2[ 3 ], silk_shell_code_table1 );
+    encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 );
+    encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 );
+}
+
+
+/* Shell decoder, operates on one shell code frame of 16 pulses */
+void silk_shell_decoder(
+    opus_int16                  *pulses0,                       /* O    data: nonnegative pulse amplitudes          */
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    const opus_int              pulses4                         /* I    number of pulses per pulse-subframe         */
+)
+{
+    opus_int16 pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ];
+
+    /* this function operates on one shell code frame of 16 pulses */
+    silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 );
+
+    decode_split( &pulses3[  0 ], &pulses3[  1 ], psRangeDec, pulses4,      silk_shell_code_table3 );
+
+    decode_split( &pulses2[  0 ], &pulses2[  1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 );
+
+    decode_split( &pulses1[  0 ], &pulses1[  1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 );
+    decode_split( &pulses0[  0 ], &pulses0[  1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 );
+    decode_split( &pulses0[  2 ], &pulses0[  3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 );
+
+    decode_split( &pulses1[  2 ], &pulses1[  3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 );
+    decode_split( &pulses0[  4 ], &pulses0[  5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 );
+    decode_split( &pulses0[  6 ], &pulses0[  7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 );
+
+    decode_split( &pulses2[  2 ], &pulses2[  3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 );
+
+    decode_split( &pulses1[  4 ], &pulses1[  5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 );
+    decode_split( &pulses0[  8 ], &pulses0[  9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 );
+    decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 );
+
+    decode_split( &pulses1[  6 ], &pulses1[  7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 );
+    decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 );
+    decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 );
+}
diff --git a/third_party/opus/src/silk/sigm_Q15.c b/third_party/opus/src/silk/sigm_Q15.c
new file mode 100644
index 0000000..3c507d2
--- /dev/null
+++ b/third_party/opus/src/silk/sigm_Q15.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Approximate sigmoid function */
+
+#include "SigProc_FIX.h"
+
+/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */
+static const opus_int32 sigm_LUT_slope_Q10[ 6 ] = {
+    237, 153, 73, 30, 12, 7
+};
+/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */
+static const opus_int32 sigm_LUT_pos_Q15[ 6 ] = {
+    16384, 23955, 28861, 31213, 32178, 32548
+};
+/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */
+static const opus_int32 sigm_LUT_neg_Q15[ 6 ] = {
+    16384, 8812, 3906, 1554, 589, 219
+};
+
+opus_int silk_sigm_Q15(
+    opus_int                    in_Q5               /* I                                                                */
+)
+{
+    opus_int ind;
+
+    if( in_Q5 < 0 ) {
+        /* Negative input */
+        in_Q5 = -in_Q5;
+        if( in_Q5 >= 6 * 32 ) {
+            return 0;        /* Clip */
+        } else {
+            /* Linear interpolation of look up table */
+            ind = silk_RSHIFT( in_Q5, 5 );
+            return( sigm_LUT_neg_Q15[ ind ] - silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) );
+        }
+    } else {
+        /* Positive input */
+        if( in_Q5 >= 6 * 32 ) {
+            return 32767;        /* clip */
+        } else {
+            /* Linear interpolation of look up table */
+            ind = silk_RSHIFT( in_Q5, 5 );
+            return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) );
+        }
+    }
+}
+
diff --git a/third_party/opus/src/silk/sort.c b/third_party/opus/src/silk/sort.c
new file mode 100644
index 0000000..7187c9e
--- /dev/null
+++ b/third_party/opus/src/silk/sort.c
@@ -0,0 +1,154 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Insertion sort (fast for already almost sorted arrays):   */
+/* Best case:  O(n)   for an already sorted array            */
+/* Worst case: O(n^2) for an inversely sorted array          */
+/*                                                           */
+/* Shell short:    https://en.wikipedia.org/wiki/Shell_sort  */
+
+#include "SigProc_FIX.h"
+
+void silk_insertion_sort_increasing(
+    opus_int32           *a,             /* I/O   Unsorted / Sorted vector               */
+    opus_int             *idx,           /* O     Index vector for the sorted elements   */
+    const opus_int       L,              /* I     Vector length                          */
+    const opus_int       K               /* I     Number of correctly sorted positions   */
+)
+{
+    opus_int32    value;
+    opus_int        i, j;
+
+    /* Safety checks */
+    silk_assert( K >  0 );
+    silk_assert( L >  0 );
+    silk_assert( L >= K );
+
+    /* Write start indices in index vector */
+    for( i = 0; i < K; i++ ) {
+        idx[ i ] = i;
+    }
+
+    /* Sort vector elements by value, increasing order */
+    for( i = 1; i < K; i++ ) {
+        value = a[ i ];
+        for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+            a[ j + 1 ]   = a[ j ];       /* Shift value */
+            idx[ j + 1 ] = idx[ j ];     /* Shift index */
+        }
+        a[ j + 1 ]   = value;   /* Write value */
+        idx[ j + 1 ] = i;       /* Write index */
+    }
+
+    /* If less than L values are asked for, check the remaining values, */
+    /* but only spend CPU to ensure that the K first values are correct */
+    for( i = K; i < L; i++ ) {
+        value = a[ i ];
+        if( value < a[ K - 1 ] ) {
+            for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+                a[ j + 1 ]   = a[ j ];       /* Shift value */
+                idx[ j + 1 ] = idx[ j ];     /* Shift index */
+            }
+            a[ j + 1 ]   = value;   /* Write value */
+            idx[ j + 1 ] = i;       /* Write index */
+        }
+    }
+}
+
+#ifdef FIXED_POINT
+/* This function is only used by the fixed-point build */
+void silk_insertion_sort_decreasing_int16(
+    opus_int16                  *a,                 /* I/O   Unsorted / Sorted vector                                   */
+    opus_int                    *idx,               /* O     Index vector for the sorted elements                       */
+    const opus_int              L,                  /* I     Vector length                                              */
+    const opus_int              K                   /* I     Number of correctly sorted positions                       */
+)
+{
+    opus_int i, j;
+    opus_int value;
+
+    /* Safety checks */
+    silk_assert( K >  0 );
+    silk_assert( L >  0 );
+    silk_assert( L >= K );
+
+    /* Write start indices in index vector */
+    for( i = 0; i < K; i++ ) {
+        idx[ i ] = i;
+    }
+
+    /* Sort vector elements by value, decreasing order */
+    for( i = 1; i < K; i++ ) {
+        value = a[ i ];
+        for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+            a[ j + 1 ]   = a[ j ];     /* Shift value */
+            idx[ j + 1 ] = idx[ j ];   /* Shift index */
+        }
+        a[ j + 1 ]   = value;   /* Write value */
+        idx[ j + 1 ] = i;       /* Write index */
+    }
+
+    /* If less than L values are asked for, check the remaining values, */
+    /* but only spend CPU to ensure that the K first values are correct */
+    for( i = K; i < L; i++ ) {
+        value = a[ i ];
+        if( value > a[ K - 1 ] ) {
+            for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+                a[ j + 1 ]   = a[ j ];     /* Shift value */
+                idx[ j + 1 ] = idx[ j ];   /* Shift index */
+            }
+            a[ j + 1 ]   = value;   /* Write value */
+            idx[ j + 1 ] = i;       /* Write index */
+        }
+    }
+}
+#endif
+
+void silk_insertion_sort_increasing_all_values_int16(
+     opus_int16                 *a,                 /* I/O   Unsorted / Sorted vector                                   */
+     const opus_int             L                   /* I     Vector length                                              */
+)
+{
+    opus_int    value;
+    opus_int    i, j;
+
+    /* Safety checks */
+    silk_assert( L >  0 );
+
+    /* Sort vector elements by value, increasing order */
+    for( i = 1; i < L; i++ ) {
+        value = a[ i ];
+        for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+            a[ j + 1 ] = a[ j ]; /* Shift value */
+        }
+        a[ j + 1 ] = value; /* Write value */
+    }
+}
diff --git a/third_party/opus/src/silk/stereo_LR_to_MS.c b/third_party/opus/src/silk/stereo_LR_to_MS.c
new file mode 100644
index 0000000..dda0298
--- /dev/null
+++ b/third_party/opus/src/silk/stereo_LR_to_MS.c
@@ -0,0 +1,229 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Convert Left/Right stereo signal to adaptive Mid/Side representation */
+void silk_stereo_LR_to_MS(
+    stereo_enc_state            *state,                         /* I/O  State                                       */
+    opus_int16                  x1[],                           /* I/O  Left input signal, becomes mid signal       */
+    opus_int16                  x2[],                           /* I/O  Right input signal, becomes side signal     */
+    opus_int8                   ix[ 2 ][ 3 ],                   /* O    Quantization indices                        */
+    opus_int8                   *mid_only_flag,                 /* O    Flag: only mid signal coded                 */
+    opus_int32                  mid_side_rates_bps[],           /* O    Bitrates for mid and side signals           */
+    opus_int32                  total_rate_bps,                 /* I    Total bitrate                               */
+    opus_int                    prev_speech_act_Q8,             /* I    Speech activity level in previous frame     */
+    opus_int                    toMono,                         /* I    Last frame before a stereo->mono transition */
+    opus_int                    fs_kHz,                         /* I    Sample rate (kHz)                           */
+    opus_int                    frame_length                    /* I    Number of samples                           */
+)
+{
+    opus_int   n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13;
+    opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13;
+    opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24;
+    VARDECL( opus_int16, side );
+    VARDECL( opus_int16, LP_mid );
+    VARDECL( opus_int16, HP_mid );
+    VARDECL( opus_int16, LP_side );
+    VARDECL( opus_int16, HP_side );
+    opus_int16 *mid = &x1[ -2 ];
+    SAVE_STACK;
+
+    ALLOC( side, frame_length + 2, opus_int16 );
+    /* Convert to basic mid/side signals */
+    for( n = 0; n < frame_length + 2; n++ ) {
+        sum  = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ];
+        diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ];
+        mid[  n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
+        side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) );
+    }
+
+    /* Buffering */
+    silk_memcpy( mid,  state->sMid,  2 * sizeof( opus_int16 ) );
+    silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) );
+    silk_memcpy( state->sMid,  &mid[  frame_length ], 2 * sizeof( opus_int16 ) );
+    silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) );
+
+    /* LP and HP filter mid signal */
+    ALLOC( LP_mid, frame_length, opus_int16 );
+    ALLOC( HP_mid, frame_length, opus_int16 );
+    for( n = 0; n < frame_length; n++ ) {
+        sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 );
+        LP_mid[ n ] = sum;
+        HP_mid[ n ] = mid[ n + 1 ] - sum;
+    }
+
+    /* LP and HP filter side signal */
+    ALLOC( LP_side, frame_length, opus_int16 );
+    ALLOC( HP_side, frame_length, opus_int16 );
+    for( n = 0; n < frame_length; n++ ) {
+        sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + (opus_int32)side[ n + 2 ], side[ n + 1 ], 1 ), 2 );
+        LP_side[ n ] = sum;
+        HP_side[ n ] = side[ n + 1 ] - sum;
+    }
+
+    /* Find energies and predictors */
+    is10msFrame = frame_length == 10 * fs_kHz;
+    smooth_coef_Q16 = is10msFrame ?
+        SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) :
+        SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF,     16 );
+    smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 );
+
+    pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 );
+    pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 );
+    /* Ratio of the norms of residual and mid signals */
+    frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 );
+    frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) );
+
+    /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */
+    total_rate_bps -= is10msFrame ? 1200 : 600;      /* Subtract approximate bitrate for coding stereo parameters */
+    if( total_rate_bps < 1 ) {
+        total_rate_bps = 1;
+    }
+    min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 900 );
+    silk_assert( min_mid_rate_bps < 32767 );
+    /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */
+    frac_3_Q16 = silk_MUL( 3, frac_Q16 );
+    mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 );
+    /* If Mid bitrate below minimum, reduce stereo width */
+    if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) {
+        mid_side_rates_bps[ 0 ] = min_mid_rate_bps;
+        mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
+        /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */
+        width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps,
+            silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 );
+        width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) );
+    } else {
+        mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
+        width_Q14 = SILK_FIX_CONST( 1, 14 );
+    }
+
+    /* Smoother */
+    state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 );
+
+    /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */
+    *mid_only_flag = 0;
+    if( toMono ) {
+        /* Last frame before stereo->mono transition; collapse stereo width */
+        width_Q14 = 0;
+        pred_Q13[ 0 ] = 0;
+        pred_Q13[ 1 ] = 0;
+        silk_stereo_quant_pred( pred_Q13, ix );
+    } else if( state->width_prev_Q14 == 0 &&
+        ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) )
+    {
+        /* Code as panned-mono; previous frame already had zero width */
+        /* Scale down and quantize predictors */
+        pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+        pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+        silk_stereo_quant_pred( pred_Q13, ix );
+        /* Collapse stereo width */
+        width_Q14 = 0;
+        pred_Q13[ 0 ] = 0;
+        pred_Q13[ 1 ] = 0;
+        mid_side_rates_bps[ 0 ] = total_rate_bps;
+        mid_side_rates_bps[ 1 ] = 0;
+        *mid_only_flag = 1;
+    } else if( state->width_prev_Q14 != 0 &&
+        ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) )
+    {
+        /* Transition to zero-width stereo */
+        /* Scale down and quantize predictors */
+        pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+        pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+        silk_stereo_quant_pred( pred_Q13, ix );
+        /* Collapse stereo width */
+        width_Q14 = 0;
+        pred_Q13[ 0 ] = 0;
+        pred_Q13[ 1 ] = 0;
+    } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) {
+        /* Full-width stereo coding */
+        silk_stereo_quant_pred( pred_Q13, ix );
+        width_Q14 = SILK_FIX_CONST( 1, 14 );
+    } else {
+        /* Reduced-width stereo coding; scale down and quantize predictors */
+        pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+        pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+        silk_stereo_quant_pred( pred_Q13, ix );
+        width_Q14 = state->smth_width_Q14;
+    }
+
+    /* Make sure to keep on encoding until the tapered output has been transmitted */
+    if( *mid_only_flag == 1 ) {
+        state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz;
+        if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) {
+            *mid_only_flag = 0;
+        } else {
+            /* Limit to avoid wrapping around */
+            state->silent_side_len = 10000;
+        }
+    } else {
+        state->silent_side_len = 0;
+    }
+
+    if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) {
+        mid_side_rates_bps[ 1 ] = 1;
+        mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]);
+    }
+
+    /* Interpolate predictors and subtract prediction from side channel */
+    pred0_Q13  = -state->pred_prev_Q13[ 0 ];
+    pred1_Q13  = -state->pred_prev_Q13[ 1 ];
+    w_Q24      =  silk_LSHIFT( state->width_prev_Q14, 10 );
+    denom_Q16  = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz );
+    delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 );
+    delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 );
+    deltaw_Q24 =  silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 );
+    for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) {
+        pred0_Q13 += delta0_Q13;
+        pred1_Q13 += delta1_Q13;
+        w_Q24   += deltaw_Q24;
+        sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 );    /* Q11 */
+        sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 );               /* Q8  */
+        sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 );       /* Q8  */
+        x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+    }
+
+    pred0_Q13 = -pred_Q13[ 0 ];
+    pred1_Q13 = -pred_Q13[ 1 ];
+    w_Q24     =  silk_LSHIFT( width_Q14, 10 );
+    for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) {
+        sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 );    /* Q11 */
+        sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 );               /* Q8  */
+        sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 );       /* Q8  */
+        x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+    }
+    state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ];
+    state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ];
+    state->width_prev_Q14     = (opus_int16)width_Q14;
+    RESTORE_STACK;
+}
diff --git a/third_party/opus/src/silk/stereo_MS_to_LR.c b/third_party/opus/src/silk/stereo_MS_to_LR.c
new file mode 100644
index 0000000..62521a4
--- /dev/null
+++ b/third_party/opus/src/silk/stereo_MS_to_LR.c
@@ -0,0 +1,85 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Convert adaptive Mid/Side representation to Left/Right stereo signal */
+void silk_stereo_MS_to_LR(
+    stereo_dec_state            *state,                         /* I/O  State                                       */
+    opus_int16                  x1[],                           /* I/O  Left input signal, becomes mid signal       */
+    opus_int16                  x2[],                           /* I/O  Right input signal, becomes side signal     */
+    const opus_int32            pred_Q13[],                     /* I    Predictors                                  */
+    opus_int                    fs_kHz,                         /* I    Samples rate (kHz)                          */
+    opus_int                    frame_length                    /* I    Number of samples                           */
+)
+{
+    opus_int   n, denom_Q16, delta0_Q13, delta1_Q13;
+    opus_int32 sum, diff, pred0_Q13, pred1_Q13;
+
+    /* Buffering */
+    silk_memcpy( x1, state->sMid,  2 * sizeof( opus_int16 ) );
+    silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) );
+    silk_memcpy( state->sMid,  &x1[ frame_length ], 2 * sizeof( opus_int16 ) );
+    silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) );
+
+    /* Interpolate predictors and add prediction to side channel */
+    pred0_Q13  = state->pred_prev_Q13[ 0 ];
+    pred1_Q13  = state->pred_prev_Q13[ 1 ];
+    denom_Q16  = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz );
+    delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 );
+    delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 );
+    for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) {
+        pred0_Q13 += delta0_Q13;
+        pred1_Q13 += delta1_Q13;
+        sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 );       /* Q11 */
+        sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 );         /* Q8  */
+        sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 );        /* Q8  */
+        x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+    }
+    pred0_Q13 = pred_Q13[ 0 ];
+    pred1_Q13 = pred_Q13[ 1 ];
+    for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) {
+        sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 );       /* Q11 */
+        sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 );         /* Q8  */
+        sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 );        /* Q8  */
+        x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+    }
+    state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ];
+    state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ];
+
+    /* Convert to left/right signals */
+    for( n = 0; n < frame_length; n++ ) {
+        sum  = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ];
+        diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ];
+        x1[ n + 1 ] = (opus_int16)silk_SAT16( sum );
+        x2[ n + 1 ] = (opus_int16)silk_SAT16( diff );
+    }
+}
diff --git a/third_party/opus/src/silk/stereo_decode_pred.c b/third_party/opus/src/silk/stereo_decode_pred.c
new file mode 100644
index 0000000..56ba392
--- /dev/null
+++ b/third_party/opus/src/silk/stereo_decode_pred.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Decode mid/side predictors */
+void silk_stereo_decode_pred(
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int32                  pred_Q13[]                      /* O    Predictors                                  */
+)
+{
+    opus_int   n, ix[ 2 ][ 3 ];
+    opus_int32 low_Q13, step_Q13;
+
+    /* Entropy decoding */
+    n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 );
+    ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 );
+    ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ];
+    for( n = 0; n < 2; n++ ) {
+        ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 );
+        ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 );
+    }
+
+    /* Dequantize */
+    for( n = 0; n < 2; n++ ) {
+        ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ];
+        low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ];
+        step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13,
+            SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) );
+        pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 );
+    }
+
+    /* Subtract second from first predictor (helps when actually applying these) */
+    pred_Q13[ 0 ] -= pred_Q13[ 1 ];
+}
+
+/* Decode mid-only flag */
+void silk_stereo_decode_mid_only(
+    ec_dec                      *psRangeDec,                    /* I/O  Compressor data structure                   */
+    opus_int                    *decode_only_mid                /* O    Flag that only mid channel has been coded   */
+)
+{
+    /* Decode flag that only mid channel is coded */
+    *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 );
+}
diff --git a/third_party/opus/src/silk/stereo_encode_pred.c b/third_party/opus/src/silk/stereo_encode_pred.c
new file mode 100644
index 0000000..e6dd1950
--- /dev/null
+++ b/third_party/opus/src/silk/stereo_encode_pred.c
@@ -0,0 +1,62 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Entropy code the mid/side quantization indices */
+void silk_stereo_encode_pred(
+    ec_enc                      *psRangeEnc,                    /* I/O  Compressor data structure                   */
+    opus_int8                   ix[ 2 ][ 3 ]                    /* I    Quantization indices                        */
+)
+{
+    opus_int   n;
+
+    /* Entropy coding */
+    n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ];
+    silk_assert( n < 25 );
+    ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 );
+    for( n = 0; n < 2; n++ ) {
+        silk_assert( ix[ n ][ 0 ] < 3 );
+        silk_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS );
+        ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 );
+        ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 );
+    }
+}
+
+/* Entropy code the mid-only flag */
+void silk_stereo_encode_mid_only(
+    ec_enc                      *psRangeEnc,                    /* I/O  Compressor data structure                   */
+    opus_int8                   mid_only_flag
+)
+{
+    /* Encode flag that only mid channel is coded */
+    ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 );
+}
diff --git a/third_party/opus/src/silk/stereo_find_predictor.c b/third_party/opus/src/silk/stereo_find_predictor.c
new file mode 100644
index 0000000..e30e90b
--- /dev/null
+++ b/third_party/opus/src/silk/stereo_find_predictor.c
@@ -0,0 +1,79 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Find least-squares prediction gain for one signal based on another and quantize it */
+opus_int32 silk_stereo_find_predictor(                          /* O    Returns predictor in Q13                    */
+    opus_int32                  *ratio_Q14,                     /* O    Ratio of residual and mid energies          */
+    const opus_int16            x[],                            /* I    Basis signal                                */
+    const opus_int16            y[],                            /* I    Target signal                               */
+    opus_int32                  mid_res_amp_Q0[],               /* I/O  Smoothed mid, residual norms                */
+    opus_int                    length,                         /* I    Number of samples                           */
+    opus_int                    smooth_coef_Q16                 /* I    Smoothing coefficient                       */
+)
+{
+    opus_int   scale, scale1, scale2;
+    opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10;
+
+    /* Find  predictor */
+    silk_sum_sqr_shift( &nrgx, &scale1, x, length );
+    silk_sum_sqr_shift( &nrgy, &scale2, y, length );
+    scale = silk_max_int( scale1, scale2 );
+    scale = scale + ( scale & 1 );          /* make even */
+    nrgy = silk_RSHIFT32( nrgy, scale - scale2 );
+    nrgx = silk_RSHIFT32( nrgx, scale - scale1 );
+    nrgx = silk_max_int( nrgx, 1 );
+    corr = silk_inner_prod_aligned_scale( x, y, scale, length );
+    pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 );
+    pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 );
+    pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 );
+
+    /* Faster update for signals with large prediction parameters */
+    smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) );
+
+    /* Smoothed mid and residual norms */
+    silk_assert( smooth_coef_Q16 < 32768 );
+    scale = silk_RSHIFT( scale, 1 );
+    mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ],
+        smooth_coef_Q16 );
+    /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */
+    nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 );
+    nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 );
+    mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ],
+        smooth_coef_Q16 );
+
+    /* Ratio of smoothed residual and mid norms */
+    *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 );
+    *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 );
+
+    return pred_Q13;
+}
diff --git a/third_party/opus/src/silk/stereo_quant_pred.c b/third_party/opus/src/silk/stereo_quant_pred.c
new file mode 100644
index 0000000..d4ced6c3
--- /dev/null
+++ b/third_party/opus/src/silk/stereo_quant_pred.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Quantize mid/side predictors */
+void silk_stereo_quant_pred(
+    opus_int32                  pred_Q13[],                     /* I/O  Predictors (out: quantized)                 */
+    opus_int8                   ix[ 2 ][ 3 ]                    /* O    Quantization indices                        */
+)
+{
+    opus_int   i, j, n;
+    opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0;
+
+    /* Quantize */
+    for( n = 0; n < 2; n++ ) {
+        /* Brute-force search over quantization levels */
+        err_min_Q13 = silk_int32_MAX;
+        for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) {
+            low_Q13 = silk_stereo_pred_quant_Q13[ i ];
+            step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13,
+                SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) );
+            for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) {
+                lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 );
+                err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 );
+                if( err_Q13 < err_min_Q13 ) {
+                    err_min_Q13 = err_Q13;
+                    quant_pred_Q13 = lvl_Q13;
+                    ix[ n ][ 0 ] = i;
+                    ix[ n ][ 1 ] = j;
+                } else {
+                    /* Error increasing, so we're past the optimum */
+                    goto done;
+                }
+            }
+        }
+        done:
+        ix[ n ][ 2 ]  = silk_DIV32_16( ix[ n ][ 0 ], 3 );
+        ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3;
+        pred_Q13[ n ] = quant_pred_Q13;
+    }
+
+    /* Subtract second from first predictor (helps when actually applying these) */
+    pred_Q13[ 0 ] -= pred_Q13[ 1 ];
+}
diff --git a/third_party/opus/src/silk/structs.h b/third_party/opus/src/silk/structs.h
new file mode 100644
index 0000000..827829d
--- /dev/null
+++ b/third_party/opus/src/silk/structs.h
@@ -0,0 +1,327 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_H
+#define SILK_STRUCTS_H
+
+#include "typedef.h"
+#include "SigProc_FIX.h"
+#include "define.h"
+#include "entenc.h"
+#include "entdec.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/************************************/
+/* Noise shaping quantization state */
+/************************************/
+typedef struct {
+    opus_int16                  xq[           2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal                             */
+    opus_int32                  sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ];
+    opus_int32                  sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+    opus_int32                  sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+    opus_int32                  sLF_AR_shp_Q14;
+    opus_int                    lagPrev;
+    opus_int                    sLTP_buf_idx;
+    opus_int                    sLTP_shp_buf_idx;
+    opus_int32                  rand_seed;
+    opus_int32                  prev_gain_Q16;
+    opus_int                    rewhite_flag;
+} silk_nsq_state;
+
+/********************************/
+/* VAD state                    */
+/********************************/
+typedef struct {
+    opus_int32                  AnaState[ 2 ];                  /* Analysis filterbank state: 0-8 kHz                                   */
+    opus_int32                  AnaState1[ 2 ];                 /* Analysis filterbank state: 0-4 kHz                                   */
+    opus_int32                  AnaState2[ 2 ];                 /* Analysis filterbank state: 0-2 kHz                                   */
+    opus_int32                  XnrgSubfr[ VAD_N_BANDS ];       /* Subframe energies                                                    */
+    opus_int32                  NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band                                   */
+    opus_int16                  HPstate;                        /* State of differentiator in the lowest band                           */
+    opus_int32                  NL[ VAD_N_BANDS ];              /* Noise energy level in each band                                      */
+    opus_int32                  inv_NL[ VAD_N_BANDS ];          /* Inverse noise energy level in each band                              */
+    opus_int32                  NoiseLevelBias[ VAD_N_BANDS ];  /* Noise level estimator bias/offset                                    */
+    opus_int32                  counter;                        /* Frame counter used in the initial phase                              */
+} silk_VAD_state;
+
+/* Variable cut-off low-pass filter state */
+typedef struct {
+    opus_int32                   In_LP_State[ 2 ];           /* Low pass filter state */
+    opus_int32                   transition_frame_no;        /* Counter which is mapped to a cut-off frequency */
+    opus_int                     mode;                       /* Operating mode, <0: switch down, >0: switch up; 0: do nothing           */
+} silk_LP_state;
+
+/* Structure containing NLSF codebook */
+typedef struct {
+    const opus_int16             nVectors;
+    const opus_int16             order;
+    const opus_int16             quantStepSize_Q16;
+    const opus_int16             invQuantStepSize_Q6;
+    const opus_uint8             *CB1_NLSF_Q8;
+    const opus_uint8             *CB1_iCDF;
+    const opus_uint8             *pred_Q8;
+    const opus_uint8             *ec_sel;
+    const opus_uint8             *ec_iCDF;
+    const opus_uint8             *ec_Rates_Q5;
+    const opus_int16             *deltaMin_Q15;
+} silk_NLSF_CB_struct;
+
+typedef struct {
+    opus_int16                   pred_prev_Q13[ 2 ];
+    opus_int16                   sMid[ 2 ];
+    opus_int16                   sSide[ 2 ];
+    opus_int32                   mid_side_amp_Q0[ 4 ];
+    opus_int16                   smth_width_Q14;
+    opus_int16                   width_prev_Q14;
+    opus_int16                   silent_side_len;
+    opus_int8                    predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ];
+    opus_int8                    mid_only_flags[ MAX_FRAMES_PER_PACKET ];
+} stereo_enc_state;
+
+typedef struct {
+    opus_int16                   pred_prev_Q13[ 2 ];
+    opus_int16                   sMid[ 2 ];
+    opus_int16                   sSide[ 2 ];
+} stereo_dec_state;
+
+typedef struct {
+    opus_int8                    GainsIndices[ MAX_NB_SUBFR ];
+    opus_int8                    LTPIndex[ MAX_NB_SUBFR ];
+    opus_int8                    NLSFIndices[ MAX_LPC_ORDER + 1 ];
+    opus_int16                   lagIndex;
+    opus_int8                    contourIndex;
+    opus_int8                    signalType;
+    opus_int8                    quantOffsetType;
+    opus_int8                    NLSFInterpCoef_Q2;
+    opus_int8                    PERIndex;
+    opus_int8                    LTP_scaleIndex;
+    opus_int8                    Seed;
+} SideInfoIndices;
+
+/********************************/
+/* Encoder state                */
+/********************************/
+typedef struct {
+    opus_int32                   In_HP_State[ 2 ];                  /* High pass filter state                                           */
+    opus_int32                   variable_HP_smth1_Q15;             /* State of first smoother                                          */
+    opus_int32                   variable_HP_smth2_Q15;             /* State of second smoother                                         */
+    silk_LP_state                sLP;                               /* Low pass filter state                                            */
+    silk_VAD_state               sVAD;                              /* Voice activity detector state                                    */
+    silk_nsq_state               sNSQ;                              /* Noise Shape Quantizer State                                      */
+    opus_int16                   prev_NLSFq_Q15[ MAX_LPC_ORDER ];   /* Previously quantized NLSF vector                                 */
+    opus_int                     speech_activity_Q8;                /* Speech activity                                                  */
+    opus_int                     allow_bandwidth_switch;            /* Flag indicating that switching of internal bandwidth is allowed  */
+    opus_int8                    LBRRprevLastGainIndex;
+    opus_int8                    prevSignalType;
+    opus_int                     prevLag;
+    opus_int                     pitch_LPC_win_length;
+    opus_int                     max_pitch_lag;                     /* Highest possible pitch lag (samples)                             */
+    opus_int32                   API_fs_Hz;                         /* API sampling frequency (Hz)                                      */
+    opus_int32                   prev_API_fs_Hz;                    /* Previous API sampling frequency (Hz)                             */
+    opus_int                     maxInternal_fs_Hz;                 /* Maximum internal sampling frequency (Hz)                         */
+    opus_int                     minInternal_fs_Hz;                 /* Minimum internal sampling frequency (Hz)                         */
+    opus_int                     desiredInternal_fs_Hz;             /* Soft request for internal sampling frequency (Hz)                */
+    opus_int                     fs_kHz;                            /* Internal sampling frequency (kHz)                                */
+    opus_int                     nb_subfr;                          /* Number of 5 ms subframes in a frame                              */
+    opus_int                     frame_length;                      /* Frame length (samples)                                           */
+    opus_int                     subfr_length;                      /* Subframe length (samples)                                        */
+    opus_int                     ltp_mem_length;                    /* Length of LTP memory                                             */
+    opus_int                     la_pitch;                          /* Look-ahead for pitch analysis (samples)                          */
+    opus_int                     la_shape;                          /* Look-ahead for noise shape analysis (samples)                    */
+    opus_int                     shapeWinLength;                    /* Window length for noise shape analysis (samples)                 */
+    opus_int32                   TargetRate_bps;                    /* Target bitrate (bps)                                             */
+    opus_int                     PacketSize_ms;                     /* Number of milliseconds to put in each packet                     */
+    opus_int                     PacketLoss_perc;                   /* Packet loss rate measured by farend                              */
+    opus_int32                   frameCounter;
+    opus_int                     Complexity;                        /* Complexity setting                                               */
+    opus_int                     nStatesDelayedDecision;            /* Number of states in delayed decision quantization                */
+    opus_int                     useInterpolatedNLSFs;              /* Flag for using NLSF interpolation                                */
+    opus_int                     shapingLPCOrder;                   /* Filter order for noise shaping filters                           */
+    opus_int                     predictLPCOrder;                   /* Filter order for prediction filters                              */
+    opus_int                     pitchEstimationComplexity;         /* Complexity level for pitch estimator                             */
+    opus_int                     pitchEstimationLPCOrder;           /* Whitening filter order for pitch estimator                       */
+    opus_int32                   pitchEstimationThreshold_Q16;      /* Threshold for pitch estimator                                    */
+    opus_int                     LTPQuantLowComplexity;             /* Flag for low complexity LTP quantization                         */
+    opus_int                     mu_LTP_Q9;                         /* Rate-distortion tradeoff in LTP quantization                     */
+    opus_int32                   sum_log_gain_Q7;                   /* Cumulative max prediction gain                                   */
+    opus_int                     NLSF_MSVQ_Survivors;               /* Number of survivors in NLSF MSVQ                                 */
+    opus_int                     first_frame_after_reset;           /* Flag for deactivating NLSF interpolation, pitch prediction       */
+    opus_int                     controlled_since_last_payload;     /* Flag for ensuring codec_control only runs once per packet        */
+    opus_int                     warping_Q16;                       /* Warping parameter for warped noise shaping                       */
+    opus_int                     useCBR;                            /* Flag to enable constant bitrate                                  */
+    opus_int                     prefillFlag;                       /* Flag to indicate that only buffers are prefilled, no coding      */
+    const opus_uint8             *pitch_lag_low_bits_iCDF;          /* Pointer to iCDF table for low bits of pitch lag index            */
+    const opus_uint8             *pitch_contour_iCDF;               /* Pointer to iCDF table for pitch contour index                    */
+    const silk_NLSF_CB_struct    *psNLSF_CB;                        /* Pointer to NLSF codebook                                         */
+    opus_int                     input_quality_bands_Q15[ VAD_N_BANDS ];
+    opus_int                     input_tilt_Q15;
+    opus_int                     SNR_dB_Q7;                         /* Quality setting                                                  */
+
+    opus_int8                    VAD_flags[ MAX_FRAMES_PER_PACKET ];
+    opus_int8                    LBRR_flag;
+    opus_int                     LBRR_flags[ MAX_FRAMES_PER_PACKET ];
+
+    SideInfoIndices              indices;
+    opus_int8                    pulses[ MAX_FRAME_LENGTH ];
+
+    int                          arch;
+
+    /* Input/output buffering */
+    opus_int16                   inputBuf[ MAX_FRAME_LENGTH + 2 ];  /* Buffer containing input signal                                   */
+    opus_int                     inputBufIx;
+    opus_int                     nFramesPerPacket;
+    opus_int                     nFramesEncoded;                    /* Number of frames analyzed in current packet                      */
+
+    opus_int                     nChannelsAPI;
+    opus_int                     nChannelsInternal;
+    opus_int                     channelNb;
+
+    /* Parameters For LTP scaling Control */
+    opus_int                     frames_since_onset;
+
+    /* Specifically for entropy coding */
+    opus_int                     ec_prevSignalType;
+    opus_int16                   ec_prevLagIndex;
+
+    silk_resampler_state_struct resampler_state;
+
+    /* DTX */
+    opus_int                     useDTX;                            /* Flag to enable DTX                                               */
+    opus_int                     inDTX;                             /* Flag to signal DTX period                                        */
+    opus_int                     noSpeechCounter;                   /* Counts concecutive nonactive frames, used by DTX                 */
+
+    /* Inband Low Bitrate Redundancy (LBRR) data */
+    opus_int                     useInBandFEC;                      /* Saves the API setting for query                                  */
+    opus_int                     LBRR_enabled;                      /* Depends on useInBandFRC, bitrate and packet loss rate            */
+    opus_int                     LBRR_GainIncreases;                /* Gains increment for coding LBRR frames                           */
+    SideInfoIndices              indices_LBRR[ MAX_FRAMES_PER_PACKET ];
+    opus_int8                    pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ];
+} silk_encoder_state;
+
+
+/* Struct for Packet Loss Concealment */
+typedef struct {
+    opus_int32                  pitchL_Q8;                          /* Pitch lag to use for voiced concealment                          */
+    opus_int16                  LTPCoef_Q14[ LTP_ORDER ];           /* LTP coeficients to use for voiced concealment                    */
+    opus_int16                  prevLPC_Q12[ MAX_LPC_ORDER ];
+    opus_int                    last_frame_lost;                    /* Was previous frame lost                                          */
+    opus_int32                  rand_seed;                          /* Seed for unvoiced signal generation                              */
+    opus_int16                  randScale_Q14;                      /* Scaling of unvoiced random signal                                */
+    opus_int32                  conc_energy;
+    opus_int                    conc_energy_shift;
+    opus_int16                  prevLTP_scale_Q14;
+    opus_int32                  prevGain_Q16[ 2 ];
+    opus_int                    fs_kHz;
+    opus_int                    nb_subfr;
+    opus_int                    subfr_length;
+} silk_PLC_struct;
+
+/* Struct for CNG */
+typedef struct {
+    opus_int32                  CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ];
+    opus_int16                  CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ];
+    opus_int32                  CNG_synth_state[ MAX_LPC_ORDER ];
+    opus_int32                  CNG_smth_Gain_Q16;
+    opus_int32                  rand_seed;
+    opus_int                    fs_kHz;
+} silk_CNG_struct;
+
+/********************************/
+/* Decoder state                */
+/********************************/
+typedef struct {
+    opus_int32                  prev_gain_Q16;
+    opus_int32                  exc_Q14[ MAX_FRAME_LENGTH ];
+    opus_int32                  sLPC_Q14_buf[ MAX_LPC_ORDER ];
+    opus_int16                  outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ];  /* Buffer for output signal                     */
+    opus_int                    lagPrev;                            /* Previous Lag                                                     */
+    opus_int8                   LastGainIndex;                      /* Previous gain index                                              */
+    opus_int                    fs_kHz;                             /* Sampling frequency in kHz                                        */
+    opus_int32                  fs_API_hz;                          /* API sample frequency (Hz)                                        */
+    opus_int                    nb_subfr;                           /* Number of 5 ms subframes in a frame                              */
+    opus_int                    frame_length;                       /* Frame length (samples)                                           */
+    opus_int                    subfr_length;                       /* Subframe length (samples)                                        */
+    opus_int                    ltp_mem_length;                     /* Length of LTP memory                                             */
+    opus_int                    LPC_order;                          /* LPC order                                                        */
+    opus_int16                  prevNLSF_Q15[ MAX_LPC_ORDER ];      /* Used to interpolate LSFs                                         */
+    opus_int                    first_frame_after_reset;            /* Flag for deactivating NLSF interpolation                         */
+    const opus_uint8            *pitch_lag_low_bits_iCDF;           /* Pointer to iCDF table for low bits of pitch lag index            */
+    const opus_uint8            *pitch_contour_iCDF;                /* Pointer to iCDF table for pitch contour index                    */
+
+    /* For buffering payload in case of more frames per packet */
+    opus_int                    nFramesDecoded;
+    opus_int                    nFramesPerPacket;
+
+    /* Specifically for entropy coding */
+    opus_int                    ec_prevSignalType;
+    opus_int16                  ec_prevLagIndex;
+
+    opus_int                    VAD_flags[ MAX_FRAMES_PER_PACKET ];
+    opus_int                    LBRR_flag;
+    opus_int                    LBRR_flags[ MAX_FRAMES_PER_PACKET ];
+
+    silk_resampler_state_struct resampler_state;
+
+    const silk_NLSF_CB_struct   *psNLSF_CB;                         /* Pointer to NLSF codebook                                         */
+
+    /* Quantization indices */
+    SideInfoIndices             indices;
+
+    /* CNG state */
+    silk_CNG_struct             sCNG;
+
+    /* Stuff used for PLC */
+    opus_int                    lossCnt;
+    opus_int                    prevSignalType;
+
+    silk_PLC_struct sPLC;
+
+} silk_decoder_state;
+
+/************************/
+/* Decoder control      */
+/************************/
+typedef struct {
+    /* Prediction and coding parameters */
+    opus_int                    pitchL[ MAX_NB_SUBFR ];
+    opus_int32                  Gains_Q16[ MAX_NB_SUBFR ];
+    /* Holds interpolated and final coefficients, 4-byte aligned */
+    silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+    opus_int16                  LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+    opus_int                    LTP_scale_Q14;
+} silk_decoder_control;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/sum_sqr_shift.c b/third_party/opus/src/silk/sum_sqr_shift.c
new file mode 100644
index 0000000..129df19
--- /dev/null
+++ b/third_party/opus/src/silk/sum_sqr_shift.c
@@ -0,0 +1,86 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Compute number of bits to right shift the sum of squares of a vector */
+/* of int16s to make it fit in an int32                                 */
+void silk_sum_sqr_shift(
+    opus_int32                  *energy,            /* O   Energy of x, after shifting to the right                     */
+    opus_int                    *shift,             /* O   Number of bits right shift applied to energy                 */
+    const opus_int16            *x,                 /* I   Input vector                                                 */
+    opus_int                    len                 /* I   Length of input vector                                       */
+)
+{
+    opus_int   i, shft;
+    opus_int32 nrg_tmp, nrg;
+
+    nrg  = 0;
+    shft = 0;
+    len--;
+    for( i = 0; i < len; i += 2 ) {
+        nrg = silk_SMLABB_ovflw( nrg, x[ i ], x[ i ] );
+        nrg = silk_SMLABB_ovflw( nrg, x[ i + 1 ], x[ i + 1 ] );
+        if( nrg < 0 ) {
+            /* Scale down */
+            nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+            shft = 2;
+            i+=2;
+            break;
+        }
+    }
+    for( ; i < len; i += 2 ) {
+        nrg_tmp = silk_SMULBB( x[ i ], x[ i ] );
+        nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] );
+        nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, (opus_uint32)nrg_tmp, shft );
+        if( nrg < 0 ) {
+            /* Scale down */
+            nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+            shft += 2;
+        }
+    }
+    if( i == len ) {
+        /* One sample left to process */
+        nrg_tmp = silk_SMULBB( x[ i ], x[ i ] );
+        nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft );
+    }
+
+    /* Make sure to have at least one extra leading zero (two leading zeros in total) */
+    if( nrg & 0xC0000000 ) {
+        nrg = silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+        shft += 2;
+    }
+
+    /* Output arguments */
+    *shift  = shft;
+    *energy = nrg;
+}
+
diff --git a/third_party/opus/src/silk/table_LSF_cos.c b/third_party/opus/src/silk/table_LSF_cos.c
new file mode 100644
index 0000000..ec9dc639
--- /dev/null
+++ b/third_party/opus/src/silk/table_LSF_cos.c
@@ -0,0 +1,70 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+/* Cosine approximation table for LSF conversion */
+/* Q12 values (even) */
+const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ] = {
+            8192,             8190,             8182,             8170,
+            8152,             8130,             8104,             8072,
+            8034,             7994,             7946,             7896,
+            7840,             7778,             7714,             7644,
+            7568,             7490,             7406,             7318,
+            7226,             7128,             7026,             6922,
+            6812,             6698,             6580,             6458,
+            6332,             6204,             6070,             5934,
+            5792,             5648,             5502,             5352,
+            5198,             5040,             4880,             4718,
+            4552,             4382,             4212,             4038,
+            3862,             3684,             3502,             3320,
+            3136,             2948,             2760,             2570,
+            2378,             2186,             1990,             1794,
+            1598,             1400,             1202,             1002,
+             802,              602,              402,              202,
+               0,             -202,             -402,             -602,
+            -802,            -1002,            -1202,            -1400,
+           -1598,            -1794,            -1990,            -2186,
+           -2378,            -2570,            -2760,            -2948,
+           -3136,            -3320,            -3502,            -3684,
+           -3862,            -4038,            -4212,            -4382,
+           -4552,            -4718,            -4880,            -5040,
+           -5198,            -5352,            -5502,            -5648,
+           -5792,            -5934,            -6070,            -6204,
+           -6332,            -6458,            -6580,            -6698,
+           -6812,            -6922,            -7026,            -7128,
+           -7226,            -7318,            -7406,            -7490,
+           -7568,            -7644,            -7714,            -7778,
+           -7840,            -7896,            -7946,            -7994,
+           -8034,            -8072,            -8104,            -8130,
+           -8152,            -8170,            -8182,            -8190,
+           -8192
+};
diff --git a/third_party/opus/src/silk/tables.h b/third_party/opus/src/silk/tables.h
new file mode 100644
index 0000000..7fea6fd
--- /dev/null
+++ b/third_party/opus/src/silk/tables.h
@@ -0,0 +1,122 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_TABLES_H
+#define SILK_TABLES_H
+
+#include "define.h"
+#include "structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Entropy coding tables (with size in bytes indicated) */
+extern const opus_uint8  silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ];                                 /* 24 */
+extern const opus_uint8  silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ];   /* 41 */
+
+extern const opus_uint8  silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */
+extern const opus_uint8  silk_pitch_delta_iCDF[ 21 ];                                               /*  21 */
+extern const opus_uint8  silk_pitch_contour_iCDF[ 34 ];                                             /*  34 */
+extern const opus_uint8  silk_pitch_contour_NB_iCDF[ 11 ];                                          /*  11 */
+extern const opus_uint8  silk_pitch_contour_10_ms_iCDF[ 12 ];                                       /*  12 */
+extern const opus_uint8  silk_pitch_contour_10_ms_NB_iCDF[ 3 ];                                     /*   3 */
+
+extern const opus_uint8  silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ SILK_MAX_PULSES + 2 ];        /* 180 */
+extern const opus_uint8  silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ SILK_MAX_PULSES + 2 ]; /* 162 */
+
+extern const opus_uint8  silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ];                           /*  18 */
+extern const opus_uint8  silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ];                        /*  18 */
+
+extern const opus_uint8  silk_max_pulses_table[ 4 ];                                                /*   4 */
+
+extern const opus_uint8  silk_shell_code_table0[ 152 ];                                             /* 152 */
+extern const opus_uint8  silk_shell_code_table1[ 152 ];                                             /* 152 */
+extern const opus_uint8  silk_shell_code_table2[ 152 ];                                             /* 152 */
+extern const opus_uint8  silk_shell_code_table3[ 152 ];                                             /* 152 */
+extern const opus_uint8  silk_shell_code_table_offsets[ SILK_MAX_PULSES + 1 ];                      /*  17 */
+
+extern const opus_uint8  silk_lsb_iCDF[ 2 ];                                                        /*   2 */
+
+extern const opus_uint8  silk_sign_iCDF[ 42 ];                                                      /*  42 */
+
+extern const opus_uint8  silk_uniform3_iCDF[ 3 ];                                                   /*   3 */
+extern const opus_uint8  silk_uniform4_iCDF[ 4 ];                                                   /*   4 */
+extern const opus_uint8  silk_uniform5_iCDF[ 5 ];                                                   /*   5 */
+extern const opus_uint8  silk_uniform6_iCDF[ 6 ];                                                   /*   6 */
+extern const opus_uint8  silk_uniform8_iCDF[ 8 ];                                                   /*   8 */
+
+extern const opus_uint8  silk_NLSF_EXT_iCDF[ 7 ];                                                   /*   7 */
+
+extern const opus_uint8  silk_LTP_per_index_iCDF[ 3 ];                                              /*   3 */
+extern const opus_uint8  * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ];                            /*   3 */
+extern const opus_uint8  * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ];                         /*   3 */
+extern const opus_int16  silk_LTP_gain_middle_avg_RD_Q14;
+extern const opus_int8   * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ];                                /* 168 */
+extern const opus_uint8  * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS];
+
+extern const opus_int8   silk_LTP_vq_sizes[ NB_LTP_CBKS ];                                          /*   3 */
+
+extern const opus_uint8  silk_LTPscale_iCDF[ 3 ];                                                   /*   4 */
+extern const opus_int16  silk_LTPScales_table_Q14[ 3 ];                                             /*   6 */
+
+extern const opus_uint8  silk_type_offset_VAD_iCDF[ 4 ];                                            /*   4 */
+extern const opus_uint8  silk_type_offset_no_VAD_iCDF[ 2 ];                                         /*   2 */
+
+extern const opus_int16  silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ];                       /*  32 */
+extern const opus_uint8  silk_stereo_pred_joint_iCDF[ 25 ];                                         /*  25 */
+extern const opus_uint8  silk_stereo_only_code_mid_iCDF[ 2 ];                                       /*   2 */
+
+extern const opus_uint8  * const silk_LBRR_flags_iCDF_ptr[ 2 ];                                     /*  10 */
+
+extern const opus_uint8  silk_NLSF_interpolation_factor_iCDF[ 5 ];                                  /*   5 */
+
+extern const silk_NLSF_CB_struct silk_NLSF_CB_WB;                                                   /* 1040 */
+extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB;                                                /* 728 */
+
+/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */
+extern const opus_int32  silk_TargetRate_table_NB[  TARGET_RATE_TAB_SZ ];                           /*  32 */
+extern const opus_int32  silk_TargetRate_table_MB[  TARGET_RATE_TAB_SZ ];                           /*  32 */
+extern const opus_int32  silk_TargetRate_table_WB[  TARGET_RATE_TAB_SZ ];                           /*  32 */
+extern const opus_int16  silk_SNR_table_Q1[         TARGET_RATE_TAB_SZ ];                           /*  32 */
+
+/* Quantization offsets */
+extern const opus_int16  silk_Quantization_Offsets_Q10[ 2 ][ 2 ];                                   /*   8 */
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+extern const opus_int32  silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ];           /*  60 */
+extern const opus_int32  silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ];           /*  60 */
+
+/* Rom table with cosine values */
+extern const opus_int16  silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ];                          /* 258 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/opus/src/silk/tables_LTP.c b/third_party/opus/src/silk/tables_LTP.c
new file mode 100644
index 0000000..0e6a0254
--- /dev/null
+++ b/third_party/opus/src/silk/tables_LTP.c
@@ -0,0 +1,296 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+const opus_uint8 silk_LTP_per_index_iCDF[3] = {
+       179,     99,      0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_0[8] = {
+        71,     56,     43,     30,     21,     12,      6,      0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_1[16] = {
+       199,    165,    144,    124,    109,     96,     84,     71,
+        61,     51,     42,     32,     23,     15,      8,      0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_2[32] = {
+       241,    225,    211,    199,    187,    175,    164,    153,
+       142,    132,    123,    114,    105,     96,     88,     80,
+        72,     64,     57,     50,     44,     38,     33,     29,
+        24,     20,     16,     12,      9,      5,      2,      0
+};
+
+const opus_int16 silk_LTP_gain_middle_avg_RD_Q14 = 12304;
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = {
+        15,    131,    138,    138,    155,    155,    173,    173
+};
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = {
+        69,     93,    115,    118,    131,    138,    141,    138,
+       150,    150,    155,    150,    155,    160,    166,    160
+};
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = {
+       131,    128,    134,    141,    141,    141,    145,    145,
+       145,    150,    155,    155,    155,    155,    160,    160,
+       160,    160,    166,    166,    173,    173,    182,    192,
+       182,    192,    192,    192,    205,    192,    205,    224
+};
+
+const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = {
+    silk_LTP_gain_iCDF_0,
+    silk_LTP_gain_iCDF_1,
+    silk_LTP_gain_iCDF_2
+};
+
+const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = {
+    silk_LTP_gain_BITS_Q5_0,
+    silk_LTP_gain_BITS_Q5_1,
+    silk_LTP_gain_BITS_Q5_2
+};
+
+static const opus_int8 silk_LTP_gain_vq_0[8][5] =
+{
+{
+         4,      6,     24,      7,      5
+},
+{
+         0,      0,      2,      0,      0
+},
+{
+        12,     28,     41,     13,     -4
+},
+{
+        -9,     15,     42,     25,     14
+},
+{
+         1,     -2,     62,     41,     -9
+},
+{
+       -10,     37,     65,     -4,      3
+},
+{
+        -6,      4,     66,      7,     -8
+},
+{
+        16,     14,     38,     -3,     33
+}
+};
+
+static const opus_int8 silk_LTP_gain_vq_1[16][5] =
+{
+{
+        13,     22,     39,     23,     12
+},
+{
+        -1,     36,     64,     27,     -6
+},
+{
+        -7,     10,     55,     43,     17
+},
+{
+         1,      1,      8,      1,      1
+},
+{
+         6,    -11,     74,     53,     -9
+},
+{
+       -12,     55,     76,    -12,      8
+},
+{
+        -3,      3,     93,     27,     -4
+},
+{
+        26,     39,     59,      3,     -8
+},
+{
+         2,      0,     77,     11,      9
+},
+{
+        -8,     22,     44,     -6,      7
+},
+{
+        40,      9,     26,      3,      9
+},
+{
+        -7,     20,    101,     -7,      4
+},
+{
+         3,     -8,     42,     26,      0
+},
+{
+       -15,     33,     68,      2,     23
+},
+{
+        -2,     55,     46,     -2,     15
+},
+{
+         3,     -1,     21,     16,     41
+}
+};
+
+static const opus_int8 silk_LTP_gain_vq_2[32][5] =
+{
+{
+        -6,     27,     61,     39,      5
+},
+{
+       -11,     42,     88,      4,      1
+},
+{
+        -2,     60,     65,      6,     -4
+},
+{
+        -1,     -5,     73,     56,      1
+},
+{
+        -9,     19,     94,     29,     -9
+},
+{
+         0,     12,     99,      6,      4
+},
+{
+         8,    -19,    102,     46,    -13
+},
+{
+         3,      2,     13,      3,      2
+},
+{
+         9,    -21,     84,     72,    -18
+},
+{
+       -11,     46,    104,    -22,      8
+},
+{
+        18,     38,     48,     23,      0
+},
+{
+       -16,     70,     83,    -21,     11
+},
+{
+         5,    -11,    117,     22,     -8
+},
+{
+        -6,     23,    117,    -12,      3
+},
+{
+         3,     -8,     95,     28,      4
+},
+{
+       -10,     15,     77,     60,    -15
+},
+{
+        -1,      4,    124,      2,     -4
+},
+{
+         3,     38,     84,     24,    -25
+},
+{
+         2,     13,     42,     13,     31
+},
+{
+        21,     -4,     56,     46,     -1
+},
+{
+        -1,     35,     79,    -13,     19
+},
+{
+        -7,     65,     88,     -9,    -14
+},
+{
+        20,      4,     81,     49,    -29
+},
+{
+        20,      0,     75,      3,    -17
+},
+{
+         5,     -9,     44,     92,     -8
+},
+{
+         1,     -3,     22,     69,     31
+},
+{
+        -6,     95,     41,    -12,      5
+},
+{
+        39,     67,     16,     -4,      1
+},
+{
+         0,     -6,    120,     55,    -36
+},
+{
+       -13,     44,    122,      4,    -24
+},
+{
+        81,      5,     11,      3,      7
+},
+{
+         2,      0,      9,     10,     88
+}
+};
+
+const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = {
+    (opus_int8 *)&silk_LTP_gain_vq_0[0][0],
+    (opus_int8 *)&silk_LTP_gain_vq_1[0][0],
+    (opus_int8 *)&silk_LTP_gain_vq_2[0][0]
+};
+
+/* Maximum frequency-dependent response of the pitch taps above,
+   computed as max(abs(freqz(taps))) */
+static const opus_uint8 silk_LTP_gain_vq_0_gain[8] = {
+      46,      2,     90,     87,     93,     91,     82,     98
+};
+
+static const opus_uint8 silk_LTP_gain_vq_1_gain[16] = {
+     109,    120,    118,     12,    113,    115,    117,    119,
+      99,     59,     87,    111,     63,    111,    112,     80
+};
+
+static const opus_uint8 silk_LTP_gain_vq_2_gain[32] = {
+     126,    124,    125,    124,    129,    121,    126,     23,
+     132,    127,    127,    127,    126,    127,    122,    133,
+     130,    134,    101,    118,    119,    145,    126,     86,
+     124,    120,    123,    119,    170,    173,    107,    109
+};
+
+const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS] = {
+    &silk_LTP_gain_vq_0_gain[0],
+    &silk_LTP_gain_vq_1_gain[0],
+    &silk_LTP_gain_vq_2_gain[0]
+};
+
+const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = {
+    8, 16, 32
+};
diff --git a/third_party/opus/src/silk/tables_NLSF_CB_NB_MB.c b/third_party/opus/src/silk/tables_NLSF_CB_NB_MB.c
new file mode 100644
index 0000000..8c59d20
--- /dev/null
+++ b/third_party/opus/src/silk/tables_NLSF_CB_NB_MB.c
@@ -0,0 +1,159 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = {
+        12,     35,     60,     83,    108,    132,    157,    180,
+       206,    228,     15,     32,     55,     77,    101,    125,
+       151,    175,    201,    225,     19,     42,     66,     89,
+       114,    137,    162,    184,    209,    230,     12,     25,
+        50,     72,     97,    120,    147,    172,    200,    223,
+        26,     44,     69,     90,    114,    135,    159,    180,
+       205,    225,     13,     22,     53,     80,    106,    130,
+       156,    180,    205,    228,     15,     25,     44,     64,
+        90,    115,    142,    168,    196,    222,     19,     24,
+        62,     82,    100,    120,    145,    168,    190,    214,
+        22,     31,     50,     79,    103,    120,    151,    170,
+       203,    227,     21,     29,     45,     65,    106,    124,
+       150,    171,    196,    224,     30,     49,     75,     97,
+       121,    142,    165,    186,    209,    229,     19,     25,
+        52,     70,     93,    116,    143,    166,    192,    219,
+        26,     34,     62,     75,     97,    118,    145,    167,
+       194,    217,     25,     33,     56,     70,     91,    113,
+       143,    165,    196,    223,     21,     34,     51,     72,
+        97,    117,    145,    171,    196,    222,     20,     29,
+        50,     67,     90,    117,    144,    168,    197,    221,
+        22,     31,     48,     66,     95,    117,    146,    168,
+       196,    222,     24,     33,     51,     77,    116,    134,
+       158,    180,    200,    224,     21,     28,     70,     87,
+       106,    124,    149,    170,    194,    217,     26,     33,
+        53,     64,     83,    117,    152,    173,    204,    225,
+        27,     34,     65,     95,    108,    129,    155,    174,
+       210,    225,     20,     26,     72,     99,    113,    131,
+       154,    176,    200,    219,     34,     43,     61,     78,
+        93,    114,    155,    177,    205,    229,     23,     29,
+        54,     97,    124,    138,    163,    179,    209,    229,
+        30,     38,     56,     89,    118,    129,    158,    178,
+       200,    231,     21,     29,     49,     63,     85,    111,
+       142,    163,    193,    222,     27,     48,     77,    103,
+       133,    158,    179,    196,    215,    232,     29,     47,
+        74,     99,    124,    151,    176,    198,    220,    237,
+        33,     42,     61,     76,     93,    121,    155,    174,
+       207,    225,     29,     53,     87,    112,    136,    154,
+       170,    188,    208,    227,     24,     30,     52,     84,
+       131,    150,    166,    186,    203,    229,     37,     48,
+        64,     84,    104,    118,    156,    177,    201,    230
+};
+
+static const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = {
+       212,    178,    148,    129,    108,     96,     85,     82,
+        79,     77,     61,     59,     57,     56,     51,     49,
+        48,     45,     42,     41,     40,     38,     36,     34,
+        31,     30,     21,     12,     10,      3,      1,      0,
+       255,    245,    244,    236,    233,    225,    217,    203,
+       190,    176,    175,    161,    149,    136,    125,    114,
+       102,     91,     81,     71,     60,     52,     43,     35,
+        28,     20,     19,     18,     12,     11,      5,      0
+};
+
+static const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = {
+        16,      0,      0,      0,      0,     99,     66,     36,
+        36,     34,     36,     34,     34,     34,     34,     83,
+        69,     36,     52,     34,    116,    102,     70,     68,
+        68,    176,    102,     68,     68,     34,     65,     85,
+        68,     84,     36,    116,    141,    152,    139,    170,
+       132,    187,    184,    216,    137,    132,    249,    168,
+       185,    139,    104,    102,    100,     68,     68,    178,
+       218,    185,    185,    170,    244,    216,    187,    187,
+       170,    244,    187,    187,    219,    138,    103,    155,
+       184,    185,    137,    116,    183,    155,    152,    136,
+       132,    217,    184,    184,    170,    164,    217,    171,
+       155,    139,    244,    169,    184,    185,    170,    164,
+       216,    223,    218,    138,    214,    143,    188,    218,
+       168,    244,    141,    136,    155,    170,    168,    138,
+       220,    219,    139,    164,    219,    202,    216,    137,
+       168,    186,    246,    185,    139,    116,    185,    219,
+       185,    138,    100,    100,    134,    100,    102,     34,
+        68,     68,    100,     68,    168,    203,    221,    218,
+       168,    167,    154,    136,    104,     70,    164,    246,
+       171,    137,    139,    137,    155,    218,    219,    139
+};
+
+static const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = {
+       255,    254,    253,    238,     14,      3,      2,      1,
+         0,    255,    254,    252,    218,     35,      3,      2,
+         1,      0,    255,    254,    250,    208,     59,      4,
+         2,      1,      0,    255,    254,    246,    194,     71,
+        10,      2,      1,      0,    255,    252,    236,    183,
+        82,      8,      2,      1,      0,    255,    252,    235,
+       180,     90,     17,      2,      1,      0,    255,    248,
+       224,    171,     97,     30,      4,      1,      0,    255,
+       254,    236,    173,     95,     37,      7,      1,      0
+};
+
+static const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = {
+       255,    255,    255,    131,      6,    145,    255,    255,
+       255,    255,    255,    236,     93,     15,     96,    255,
+       255,    255,    255,    255,    194,     83,     25,     71,
+       221,    255,    255,    255,    255,    162,     73,     34,
+        66,    162,    255,    255,    255,    210,    126,     73,
+        43,     57,    173,    255,    255,    255,    201,    125,
+        71,     48,     58,    130,    255,    255,    255,    166,
+       110,     73,     57,     62,    104,    210,    255,    255,
+       251,    123,     65,     55,     68,    100,    171,    255
+};
+
+static const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = {
+       179,    138,    140,    148,    151,    149,    153,    151,
+       163,    116,     67,     82,     59,     92,     72,    100,
+        89,     92
+};
+
+static const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = {
+       250,      3,      6,      3,      3,      3,      4,      3,
+         3,      3,    461
+};
+
+const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB =
+{
+    32,
+    10,
+    SILK_FIX_CONST( 0.18, 16 ),
+    SILK_FIX_CONST( 1.0 / 0.18, 6 ),
+    silk_NLSF_CB1_NB_MB_Q8,
+    silk_NLSF_CB1_iCDF_NB_MB,
+    silk_NLSF_PRED_NB_MB_Q8,
+    silk_NLSF_CB2_SELECT_NB_MB,
+    silk_NLSF_CB2_iCDF_NB_MB,
+    silk_NLSF_CB2_BITS_NB_MB_Q5,
+    silk_NLSF_DELTA_MIN_NB_MB_Q15,
+};
diff --git a/third_party/opus/src/silk/tables_NLSF_CB_WB.c b/third_party/opus/src/silk/tables_NLSF_CB_WB.c
new file mode 100644
index 0000000..50af87e
--- /dev/null
+++ b/third_party/opus/src/silk/tables_NLSF_CB_WB.c
@@ -0,0 +1,198 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = {
+         7,     23,     38,     54,     69,     85,    100,    116,
+       131,    147,    162,    178,    193,    208,    223,    239,
+        13,     25,     41,     55,     69,     83,     98,    112,
+       127,    142,    157,    171,    187,    203,    220,    236,
+        15,     21,     34,     51,     61,     78,     92,    106,
+       126,    136,    152,    167,    185,    205,    225,    240,
+        10,     21,     36,     50,     63,     79,     95,    110,
+       126,    141,    157,    173,    189,    205,    221,    237,
+        17,     20,     37,     51,     59,     78,     89,    107,
+       123,    134,    150,    164,    184,    205,    224,    240,
+        10,     15,     32,     51,     67,     81,     96,    112,
+       129,    142,    158,    173,    189,    204,    220,    236,
+         8,     21,     37,     51,     65,     79,     98,    113,
+       126,    138,    155,    168,    179,    192,    209,    218,
+        12,     15,     34,     55,     63,     78,     87,    108,
+       118,    131,    148,    167,    185,    203,    219,    236,
+        16,     19,     32,     36,     56,     79,     91,    108,
+       118,    136,    154,    171,    186,    204,    220,    237,
+        11,     28,     43,     58,     74,     89,    105,    120,
+       135,    150,    165,    180,    196,    211,    226,    241,
+         6,     16,     33,     46,     60,     75,     92,    107,
+       123,    137,    156,    169,    185,    199,    214,    225,
+        11,     19,     30,     44,     57,     74,     89,    105,
+       121,    135,    152,    169,    186,    202,    218,    234,
+        12,     19,     29,     46,     57,     71,     88,    100,
+       120,    132,    148,    165,    182,    199,    216,    233,
+        17,     23,     35,     46,     56,     77,     92,    106,
+       123,    134,    152,    167,    185,    204,    222,    237,
+        14,     17,     45,     53,     63,     75,     89,    107,
+       115,    132,    151,    171,    188,    206,    221,    240,
+         9,     16,     29,     40,     56,     71,     88,    103,
+       119,    137,    154,    171,    189,    205,    222,    237,
+        16,     19,     36,     48,     57,     76,     87,    105,
+       118,    132,    150,    167,    185,    202,    218,    236,
+        12,     17,     29,     54,     71,     81,     94,    104,
+       126,    136,    149,    164,    182,    201,    221,    237,
+        15,     28,     47,     62,     79,     97,    115,    129,
+       142,    155,    168,    180,    194,    208,    223,    238,
+         8,     14,     30,     45,     62,     78,     94,    111,
+       127,    143,    159,    175,    192,    207,    223,    239,
+        17,     30,     49,     62,     79,     92,    107,    119,
+       132,    145,    160,    174,    190,    204,    220,    235,
+        14,     19,     36,     45,     61,     76,     91,    108,
+       121,    138,    154,    172,    189,    205,    222,    238,
+        12,     18,     31,     45,     60,     76,     91,    107,
+       123,    138,    154,    171,    187,    204,    221,    236,
+        13,     17,     31,     43,     53,     70,     83,    103,
+       114,    131,    149,    167,    185,    203,    220,    237,
+        17,     22,     35,     42,     58,     78,     93,    110,
+       125,    139,    155,    170,    188,    206,    224,    240,
+         8,     15,     34,     50,     67,     83,     99,    115,
+       131,    146,    162,    178,    193,    209,    224,    239,
+        13,     16,     41,     66,     73,     86,     95,    111,
+       128,    137,    150,    163,    183,    206,    225,    241,
+        17,     25,     37,     52,     63,     75,     92,    102,
+       119,    132,    144,    160,    175,    191,    212,    231,
+        19,     31,     49,     65,     83,    100,    117,    133,
+       147,    161,    174,    187,    200,    213,    227,    242,
+        18,     31,     52,     68,     88,    103,    117,    126,
+       138,    149,    163,    177,    192,    207,    223,    239,
+        16,     29,     47,     61,     76,     90,    106,    119,
+       133,    147,    161,    176,    193,    209,    224,    240,
+        15,     21,     35,     50,     61,     73,     86,     97,
+       110,    119,    129,    141,    175,    198,    218,    237
+};
+
+static const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = {
+       225,    204,    201,    184,    183,    175,    158,    154,
+       153,    135,    119,    115,    113,    110,    109,     99,
+        98,     95,     79,     68,     52,     50,     48,     45,
+        43,     32,     31,     27,     18,     10,      3,      0,
+       255,    251,    235,    230,    212,    201,    196,    182,
+       167,    166,    163,    151,    138,    124,    110,    104,
+        90,     78,     76,     70,     69,     57,     45,     34,
+        24,     21,     11,      6,      5,      4,      3,      0
+};
+
+static const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = {
+         0,      0,      0,      0,      0,      0,      0,      1,
+       100,    102,    102,     68,     68,     36,     34,     96,
+       164,    107,    158,    185,    180,    185,    139,    102,
+        64,     66,     36,     34,     34,      0,      1,     32,
+       208,    139,    141,    191,    152,    185,    155,    104,
+        96,    171,    104,    166,    102,    102,    102,    132,
+         1,      0,      0,      0,      0,     16,     16,      0,
+        80,    109,     78,    107,    185,    139,    103,    101,
+       208,    212,    141,    139,    173,    153,    123,    103,
+        36,      0,      0,      0,      0,      0,      0,      1,
+        48,      0,      0,      0,      0,      0,      0,     32,
+        68,    135,    123,    119,    119,    103,     69,     98,
+        68,    103,    120,    118,    118,    102,     71,     98,
+       134,    136,    157,    184,    182,    153,    139,    134,
+       208,    168,    248,     75,    189,    143,    121,    107,
+        32,     49,     34,     34,     34,      0,     17,      2,
+       210,    235,    139,    123,    185,    137,    105,    134,
+        98,    135,    104,    182,    100,    183,    171,    134,
+       100,     70,     68,     70,     66,     66,     34,    131,
+        64,    166,    102,     68,     36,      2,      1,      0,
+       134,    166,    102,     68,     34,     34,     66,    132,
+       212,    246,    158,    139,    107,    107,     87,    102,
+       100,    219,    125,    122,    137,    118,    103,    132,
+       114,    135,    137,    105,    171,    106,     50,     34,
+       164,    214,    141,    143,    185,    151,    121,    103,
+       192,     34,      0,      0,      0,      0,      0,      1,
+       208,    109,     74,    187,    134,    249,    159,    137,
+       102,    110,    154,    118,     87,    101,    119,    101,
+         0,      2,      0,     36,     36,     66,     68,     35,
+        96,    164,    102,    100,     36,      0,      2,     33,
+       167,    138,    174,    102,    100,     84,      2,      2,
+       100,    107,    120,    119,     36,    197,     24,      0
+};
+
+static const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = {
+       255,    254,    253,    244,     12,      3,      2,      1,
+         0,    255,    254,    252,    224,     38,      3,      2,
+         1,      0,    255,    254,    251,    209,     57,      4,
+         2,      1,      0,    255,    254,    244,    195,     69,
+         4,      2,      1,      0,    255,    251,    232,    184,
+        84,      7,      2,      1,      0,    255,    254,    240,
+       186,     86,     14,      2,      1,      0,    255,    254,
+       239,    178,     91,     30,      5,      1,      0,    255,
+       248,    227,    177,    100,     19,      2,      1,      0
+};
+
+static const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = {
+       255,    255,    255,    156,      4,    154,    255,    255,
+       255,    255,    255,    227,    102,     15,     92,    255,
+       255,    255,    255,    255,    213,     83,     24,     72,
+       236,    255,    255,    255,    255,    150,     76,     33,
+        63,    214,    255,    255,    255,    190,    121,     77,
+        43,     55,    185,    255,    255,    255,    245,    137,
+        71,     43,     59,    139,    255,    255,    255,    255,
+       131,     66,     50,     66,    107,    194,    255,    255,
+       166,    116,     76,     55,     53,    125,    255,    255
+};
+
+static const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = {
+       175,    148,    160,    176,    178,    173,    174,    164,
+       177,    174,    196,    182,    198,    192,    182,     68,
+        62,     66,     60,     72,    117,     85,     90,    118,
+       136,    151,    142,    160,    142,    155
+};
+
+static const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = {
+       100,      3,     40,      3,      3,      3,      5,     14,
+        14,     10,     11,      3,      8,      9,      7,      3,
+       347
+};
+
+const silk_NLSF_CB_struct silk_NLSF_CB_WB =
+{
+    32,
+    16,
+    SILK_FIX_CONST( 0.15, 16 ),
+    SILK_FIX_CONST( 1.0 / 0.15, 6 ),
+    silk_NLSF_CB1_WB_Q8,
+    silk_NLSF_CB1_iCDF_WB,
+    silk_NLSF_PRED_WB_Q8,
+    silk_NLSF_CB2_SELECT_WB,
+    silk_NLSF_CB2_iCDF_WB,
+    silk_NLSF_CB2_BITS_WB_Q5,
+    silk_NLSF_DELTA_MIN_WB_Q15,
+};
+
diff --git a/third_party/opus/src/silk/tables_gain.c b/third_party/opus/src/silk/tables_gain.c
new file mode 100644
index 0000000..37e41d8
--- /dev/null
+++ b/third_party/opus/src/silk/tables_gain.c
@@ -0,0 +1,63 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] =
+{
+{
+       224,    112,     44,     15,      3,      2,      1,      0
+},
+{
+       254,    237,    192,    132,     70,     23,      4,      0
+},
+{
+       255,    252,    226,    155,     61,     11,      2,      0
+}
+};
+
+const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = {
+       250,    245,    234,    203,     71,     50,     42,     38,
+        35,     33,     31,     29,     28,     27,     26,     25,
+        24,     23,     22,     21,     20,     19,     18,     17,
+        16,     15,     14,     13,     12,     11,     10,      9,
+         8,      7,      6,      5,      4,      3,      2,      1,
+         0
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/third_party/opus/src/silk/tables_other.c b/third_party/opus/src/silk/tables_other.c
new file mode 100644
index 0000000..398686b
--- /dev/null
+++ b/third_party/opus/src/silk/tables_other.c
@@ -0,0 +1,138 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "structs.h"
+#include "define.h"
+#include "tables.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */
+const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ] = {
+    0,      8000,   9400,   11500,  13500,  17500,  25000,  MAX_TARGET_RATE_BPS
+};
+const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ] = {
+    0,      9000,   12000,  14500,  18500,  24500,  35500,  MAX_TARGET_RATE_BPS
+};
+const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ] = {
+    0,      10500,  14000,  17000,  21500,  28500,  42000,  MAX_TARGET_RATE_BPS
+};
+const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ] = {
+    18,     29,     38,     40,     46,     52,     62,     84
+};
+
+/* Tables for stereo predictor coding */
+const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = {
+    -13732, -10050, -8266, -7526, -6500, -5000, -2950,  -820,
+       820,   2950,  5000,  6500,  7526,  8266, 10050, 13732
+};
+const opus_uint8  silk_stereo_pred_joint_iCDF[ 25 ] = {
+    249, 247, 246, 245, 244,
+    234, 210, 202, 201, 200,
+    197, 174,  82,  59,  56,
+     55,  54,  46,  22,  12,
+     11,  10,   9,   7,   0
+};
+const opus_uint8  silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 };
+
+/* Tables for LBRR flags */
+static const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 };
+static const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 };
+const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = {
+    silk_LBRR_flags_2_iCDF,
+    silk_LBRR_flags_3_iCDF
+};
+
+/* Table for LSB coding */
+const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 };
+
+/* Tables for LTPScale */
+const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 };
+
+/* Tables for signal type and offset coding */
+const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = {
+       232,    158,    10,      0
+};
+const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = {
+       230,      0
+};
+
+/* Tables for NLSF interpolation factor */
+const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 };
+
+/* Quantization offsets */
+const opus_int16  silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = {
+    { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 }
+};
+
+/* Table for LTPScale */
+const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 };
+
+/* Uniform entropy tables */
+const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 };
+const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 };
+const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 };
+const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 };
+const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 };
+
+const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 };
+
+/*  Elliptic/Cauer filters designed with 0.1 dB passband ripple,
+        80 dB minimum stopband attenuation, and
+        [0.95 : 0.15 : 0.35] normalized cut off frequencies. */
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] =
+{
+{    250767114,  501534038,  250767114  },
+{    209867381,  419732057,  209867381  },
+{    170987846,  341967853,  170987846  },
+{    131531482,  263046905,  131531482  },
+{     89306658,  178584282,   89306658  }
+};
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] =
+{
+{    506393414,  239854379  },
+{    411067935,  169683996  },
+{    306733530,  116694253  },
+{    185807084,   77959395  },
+{     35497197,   57401098  }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/third_party/opus/src/silk/tables_pitch_lag.c b/third_party/opus/src/silk/tables_pitch_lag.c
new file mode 100644
index 0000000..e80cc59a
--- /dev/null
+++ b/third_party/opus/src/silk/tables_pitch_lag.c
@@ -0,0 +1,69 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = {
+       253,    250,    244,    233,    212,    182,    150,    131,
+       120,    110,     98,     85,     72,     60,     49,     40,
+        32,     25,     19,     15,     13,     11,      9,      8,
+         7,      6,      5,      4,      3,      2,      1,      0
+};
+
+const opus_uint8 silk_pitch_delta_iCDF[21] = {
+       210,    208,    206,    203,    199,    193,    183,    168,
+       142,    104,     74,     52,     37,     27,     20,     14,
+        10,      6,      4,      2,      0
+};
+
+const opus_uint8 silk_pitch_contour_iCDF[34] = {
+       223,    201,    183,    167,    152,    138,    124,    111,
+        98,     88,     79,     70,     62,     56,     50,     44,
+        39,     35,     31,     27,     24,     21,     18,     16,
+        14,     12,     10,      8,      6,      4,      3,      2,
+         1,      0
+};
+
+const opus_uint8 silk_pitch_contour_NB_iCDF[11] = {
+       188,    176,    155,    138,    119,     97,     67,     43,
+        26,     10,      0
+};
+
+const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = {
+       165,    119,     80,     61,     47,     35,     27,     20,
+        14,      9,      4,      0
+};
+
+const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = {
+       113,     63,      0
+};
+
+
diff --git a/third_party/opus/src/silk/tables_pulses_per_block.c b/third_party/opus/src/silk/tables_pulses_per_block.c
new file mode 100644
index 0000000..c7c01c88
--- /dev/null
+++ b/third_party/opus/src/silk/tables_pulses_per_block.c
@@ -0,0 +1,264 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tables.h"
+
+const opus_uint8 silk_max_pulses_table[ 4 ] = {
+         8,     10,     12,     16
+};
+
+const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = {
+{
+       125,     51,     26,     18,     15,     12,     11,     10,
+         9,      8,      7,      6,      5,      4,      3,      2,
+         1,      0
+},
+{
+       198,    105,     45,     22,     15,     12,     11,     10,
+         9,      8,      7,      6,      5,      4,      3,      2,
+         1,      0
+},
+{
+       213,    162,    116,     83,     59,     43,     32,     24,
+        18,     15,     12,      9,      7,      6,      5,      3,
+         2,      0
+},
+{
+       239,    187,    116,     59,     28,     16,     11,     10,
+         9,      8,      7,      6,      5,      4,      3,      2,
+         1,      0
+},
+{
+       250,    229,    188,    135,     86,     51,     30,     19,
+        13,     10,      8,      6,      5,      4,      3,      2,
+         1,      0
+},
+{
+       249,    235,    213,    185,    156,    128,    103,     83,
+        66,     53,     42,     33,     26,     21,     17,     13,
+        10,      0
+},
+{
+       254,    249,    235,    206,    164,    118,     77,     46,
+        27,     16,     10,      7,      5,      4,      3,      2,
+         1,      0
+},
+{
+       255,    253,    249,    239,    220,    191,    156,    119,
+        85,     57,     37,     23,     15,     10,      6,      4,
+         2,      0
+},
+{
+       255,    253,    251,    246,    237,    223,    203,    179,
+       152,    124,     98,     75,     55,     40,     29,     21,
+        15,      0
+},
+{
+       255,    254,    253,    247,    220,    162,    106,     67,
+        42,     28,     18,     12,      9,      6,      4,      3,
+         2,      0
+}
+};
+
+const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = {
+{
+        31,     57,    107,    160,    205,    205,    255,    255,
+       255,    255,    255,    255,    255,    255,    255,    255,
+       255,    255
+},
+{
+        69,     47,     67,    111,    166,    205,    255,    255,
+       255,    255,    255,    255,    255,    255,    255,    255,
+       255,    255
+},
+{
+        82,     74,     79,     95,    109,    128,    145,    160,
+       173,    205,    205,    205,    224,    255,    255,    224,
+       255,    224
+},
+{
+       125,     74,     59,     69,     97,    141,    182,    255,
+       255,    255,    255,    255,    255,    255,    255,    255,
+       255,    255
+},
+{
+       173,    115,     85,     73,     76,     92,    115,    145,
+       173,    205,    224,    224,    255,    255,    255,    255,
+       255,    255
+},
+{
+       166,    134,    113,    102,    101,    102,    107,    118,
+       125,    138,    145,    155,    166,    182,    192,    192,
+       205,    150
+},
+{
+       224,    182,    134,    101,     83,     79,     85,     97,
+       120,    145,    173,    205,    224,    255,    255,    255,
+       255,    255
+},
+{
+       255,    224,    192,    150,    120,    101,     92,     89,
+        93,    102,    118,    134,    160,    182,    192,    224,
+       224,    224
+},
+{
+       255,    224,    224,    182,    155,    134,    118,    109,
+       104,    102,    106,    111,    118,    131,    145,    160,
+       173,    131
+}
+};
+
+const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] =
+{
+{
+       241,    190,    178,    132,     87,     74,     41,     14,
+         0
+},
+{
+       223,    193,    157,    140,    106,     57,     39,     18,
+         0
+}
+};
+
+const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] =
+{
+{
+       131,     74,    141,     79,     80,    138,     95,    104,
+       134
+},
+{
+        95,     99,     91,    125,     93,     76,    123,    115,
+       123
+}
+};
+
+const opus_uint8 silk_shell_code_table0[ 152 ] = {
+       128,      0,    214,     42,      0,    235,    128,     21,
+         0,    244,    184,     72,     11,      0,    248,    214,
+       128,     42,      7,      0,    248,    225,    170,     80,
+        25,      5,      0,    251,    236,    198,    126,     54,
+        18,      3,      0,    250,    238,    211,    159,     82,
+        35,     15,      5,      0,    250,    231,    203,    168,
+       128,     88,     53,     25,      6,      0,    252,    238,
+       216,    185,    148,    108,     71,     40,     18,      4,
+         0,    253,    243,    225,    199,    166,    128,     90,
+        57,     31,     13,      3,      0,    254,    246,    233,
+       212,    183,    147,    109,     73,     44,     23,     10,
+         2,      0,    255,    250,    240,    223,    198,    166,
+       128,     90,     58,     33,     16,      6,      1,      0,
+       255,    251,    244,    231,    210,    181,    146,    110,
+        75,     46,     25,     12,      5,      1,      0,    255,
+       253,    248,    238,    221,    196,    164,    128,     92,
+        60,     35,     18,      8,      3,      1,      0,    255,
+       253,    249,    242,    229,    208,    180,    146,    110,
+        76,     48,     27,     14,      7,      3,      1,      0
+};
+
+const opus_uint8 silk_shell_code_table1[ 152 ] = {
+       129,      0,    207,     50,      0,    236,    129,     20,
+         0,    245,    185,     72,     10,      0,    249,    213,
+       129,     42,      6,      0,    250,    226,    169,     87,
+        27,      4,      0,    251,    233,    194,    130,     62,
+        20,      4,      0,    250,    236,    207,    160,     99,
+        47,     17,      3,      0,    255,    240,    217,    182,
+       131,     81,     41,     11,      1,      0,    255,    254,
+       233,    201,    159,    107,     61,     20,      2,      1,
+         0,    255,    249,    233,    206,    170,    128,     86,
+        50,     23,      7,      1,      0,    255,    250,    238,
+       217,    186,    148,    108,     70,     39,     18,      6,
+         1,      0,    255,    252,    243,    226,    200,    166,
+       128,     90,     56,     30,     13,      4,      1,      0,
+       255,    252,    245,    231,    209,    180,    146,    110,
+        76,     47,     25,     11,      4,      1,      0,    255,
+       253,    248,    237,    219,    194,    163,    128,     93,
+        62,     37,     19,      8,      3,      1,      0,    255,
+       254,    250,    241,    226,    205,    177,    145,    111,
+        79,     51,     30,     15,      6,      2,      1,      0
+};
+
+const opus_uint8 silk_shell_code_table2[ 152 ] = {
+       129,      0,    203,     54,      0,    234,    129,     23,
+         0,    245,    184,     73,     10,      0,    250,    215,
+       129,     41,      5,      0,    252,    232,    173,     86,
+        24,      3,      0,    253,    240,    200,    129,     56,
+        15,      2,      0,    253,    244,    217,    164,     94,
+        38,     10,      1,      0,    253,    245,    226,    189,
+       132,     71,     27,      7,      1,      0,    253,    246,
+       231,    203,    159,    105,     56,     23,      6,      1,
+         0,    255,    248,    235,    213,    179,    133,     85,
+        47,     19,      5,      1,      0,    255,    254,    243,
+       221,    194,    159,    117,     70,     37,     12,      2,
+         1,      0,    255,    254,    248,    234,    208,    171,
+       128,     85,     48,     22,      8,      2,      1,      0,
+       255,    254,    250,    240,    220,    189,    149,    107,
+        67,     36,     16,      6,      2,      1,      0,    255,
+       254,    251,    243,    227,    201,    166,    128,     90,
+        55,     29,     13,      5,      2,      1,      0,    255,
+       254,    252,    246,    234,    213,    183,    147,    109,
+        73,     43,     22,     10,      4,      2,      1,      0
+};
+
+const opus_uint8 silk_shell_code_table3[ 152 ] = {
+       130,      0,    200,     58,      0,    231,    130,     26,
+         0,    244,    184,     76,     12,      0,    249,    214,
+       130,     43,      6,      0,    252,    232,    173,     87,
+        24,      3,      0,    253,    241,    203,    131,     56,
+        14,      2,      0,    254,    246,    221,    167,     94,
+        35,      8,      1,      0,    254,    249,    232,    193,
+       130,     65,     23,      5,      1,      0,    255,    251,
+       239,    211,    162,     99,     45,     15,      4,      1,
+         0,    255,    251,    243,    223,    186,    131,     74,
+        33,     11,      3,      1,      0,    255,    252,    245,
+       230,    202,    158,    105,     57,     24,      8,      2,
+         1,      0,    255,    253,    247,    235,    214,    179,
+       132,     84,     44,     19,      7,      2,      1,      0,
+       255,    254,    250,    240,    223,    196,    159,    112,
+        69,     36,     15,      6,      2,      1,      0,    255,
+       254,    253,    245,    231,    209,    176,    136,     93,
+        55,     27,     11,      3,      2,      1,      0,    255,
+       254,    253,    252,    239,    221,    194,    158,    117,
+        76,     42,     18,      4,      3,      2,      1,      0
+};
+
+const opus_uint8 silk_shell_code_table_offsets[ 17 ] = {
+         0,      0,      2,      5,      9,     14,     20,     27,
+        35,     44,     54,     65,     77,     90,    104,    119,
+       135
+};
+
+const opus_uint8 silk_sign_iCDF[ 42 ] = {
+       254,     49,     67,     77,     82,     93,     99,
+       198,     11,     18,     24,     31,     36,     45,
+       255,     46,     66,     78,     87,     94,    104,
+       208,     14,     21,     32,     42,     51,     66,
+       255,     94,    104,    109,    112,    115,    118,
+       248,     53,     69,     80,     88,     95,    102
+};
diff --git a/third_party/opus/src/silk/tuning_parameters.h b/third_party/opus/src/silk/tuning_parameters.h
new file mode 100644
index 0000000..5b8f404
--- /dev/null
+++ b/third_party/opus/src/silk/tuning_parameters.h
@@ -0,0 +1,171 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_TUNING_PARAMETERS_H
+#define SILK_TUNING_PARAMETERS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Decay time for bitreservoir */
+#define BITRESERVOIR_DECAY_TIME_MS                      500
+
+/*******************/
+/* Pitch estimator */
+/*******************/
+
+/* Level of noise floor for whitening filter LPC analysis in pitch analysis */
+#define FIND_PITCH_WHITE_NOISE_FRACTION                 1e-3f
+
+/* Bandwidth expansion for whitening filter in pitch analysis */
+#define FIND_PITCH_BANDWIDTH_EXPANSION                  0.99f
+
+/*********************/
+/* Linear prediction */
+/*********************/
+
+/* LPC analysis regularization */
+#define FIND_LPC_COND_FAC                               1e-5f
+
+/* LTP analysis defines */
+#define FIND_LTP_COND_FAC                               1e-5f
+#define LTP_DAMPING                                     0.05f
+#define LTP_SMOOTHING                                   0.1f
+
+/* LTP quantization settings */
+#define MU_LTP_QUANT_NB                                 0.03f
+#define MU_LTP_QUANT_MB                                 0.025f
+#define MU_LTP_QUANT_WB                                 0.02f
+
+/* Max cumulative LTP gain */
+#define MAX_SUM_LOG_GAIN_DB                             250.0f
+
+/***********************/
+/* High pass filtering */
+/***********************/
+
+/* Smoothing parameters for low end of pitch frequency range estimation */
+#define VARIABLE_HP_SMTH_COEF1                          0.1f
+#define VARIABLE_HP_SMTH_COEF2                          0.015f
+#define VARIABLE_HP_MAX_DELTA_FREQ                      0.4f
+
+/* Min and max cut-off frequency values (-3 dB points) */
+#define VARIABLE_HP_MIN_CUTOFF_HZ                       60
+#define VARIABLE_HP_MAX_CUTOFF_HZ                       100
+
+/***********/
+/* Various */
+/***********/
+
+/* VAD threshold */
+#define SPEECH_ACTIVITY_DTX_THRES                       0.05f
+
+/* Speech Activity LBRR enable threshold */
+#define LBRR_SPEECH_ACTIVITY_THRES                      0.3f
+
+/*************************/
+/* Perceptual parameters */
+/*************************/
+
+/* reduction in coding SNR during low speech activity */
+#define BG_SNR_DECR_dB                                  2.0f
+
+/* factor for reducing quantization noise during voiced speech */
+#define HARM_SNR_INCR_dB                                2.0f
+
+/* factor for reducing quantization noise for unvoiced sparse signals */
+#define SPARSE_SNR_INCR_dB                              2.0f
+
+/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */
+#define SPARSENESS_THRESHOLD_QNT_OFFSET                 0.75f
+
+/* warping control */
+#define WARPING_MULTIPLIER                              0.015f
+
+/* fraction added to first autocorrelation value */
+#define SHAPE_WHITE_NOISE_FRACTION                      5e-5f
+
+/* noise shaping filter chirp factor */
+#define BANDWIDTH_EXPANSION                             0.95f
+
+/* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */
+#define LOW_RATE_BANDWIDTH_EXPANSION_DELTA              0.01f
+
+/* extra harmonic boosting (signal shaping) at low bitrates */
+#define LOW_RATE_HARMONIC_BOOST                         0.1f
+
+/* extra harmonic boosting (signal shaping) for noisy input signals */
+#define LOW_INPUT_QUALITY_HARMONIC_BOOST                0.1f
+
+/* harmonic noise shaping */
+#define HARMONIC_SHAPING                                0.3f
+
+/* extra harmonic noise shaping for high bitrates or noisy input */
+#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING       0.2f
+
+/* parameter for shaping noise towards higher frequencies */
+#define HP_NOISE_COEF                                   0.25f
+
+/* parameter for shaping noise even more towards higher frequencies during voiced speech */
+#define HARM_HP_NOISE_COEF                              0.35f
+
+/* parameter for applying a high-pass tilt to the input signal */
+#define INPUT_TILT                                      0.05f
+
+/* parameter for extra high-pass tilt to the input signal at high rates */
+#define HIGH_RATE_INPUT_TILT                            0.1f
+
+/* parameter for reducing noise at the very low frequencies */
+#define LOW_FREQ_SHAPING                                4.0f
+
+/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */
+#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR               0.5f
+
+/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */
+#define SUBFR_SMTH_COEF                                 0.4f
+
+/* parameters defining the R/D tradeoff in the residual quantizer */
+#define LAMBDA_OFFSET                                   1.2f
+#define LAMBDA_SPEECH_ACT                               -0.2f
+#define LAMBDA_DELAYED_DECISIONS                        -0.05f
+#define LAMBDA_INPUT_QUALITY                            -0.1f
+#define LAMBDA_CODING_QUALITY                           -0.2f
+#define LAMBDA_QUANT_OFFSET                             0.8f
+
+/* Compensation in bitrate calculations for 10 ms modes */
+#define REDUCE_BITRATE_10_MS_BPS                        2200
+
+/* Maximum time before allowing a bandwidth transition */
+#define MAX_BANDWIDTH_SWITCH_DELAY_MS                   5000
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_TUNING_PARAMETERS_H */
diff --git a/third_party/opus/src/silk/typedef.h b/third_party/opus/src/silk/typedef.h
new file mode 100644
index 0000000..97b7e70
--- /dev/null
+++ b/third_party/opus/src/silk/typedef.h
@@ -0,0 +1,78 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_TYPEDEF_H
+#define SILK_TYPEDEF_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#ifndef FIXED_POINT
+# include <float.h>
+# define silk_float      float
+# define silk_float_MAX  FLT_MAX
+#endif
+
+#define silk_int64_MAX   ((opus_int64)0x7FFFFFFFFFFFFFFFLL)   /*  2^63 - 1 */
+#define silk_int64_MIN   ((opus_int64)0x8000000000000000LL)   /* -2^63 */
+#define silk_int32_MAX   0x7FFFFFFF                           /*  2^31 - 1 =  2147483647 */
+#define silk_int32_MIN   ((opus_int32)0x80000000)             /* -2^31     = -2147483648 */
+#define silk_int16_MAX   0x7FFF                               /*  2^15 - 1 =  32767 */
+#define silk_int16_MIN   ((opus_int16)0x8000)                 /* -2^15     = -32768 */
+#define silk_int8_MAX    0x7F                                 /*  2^7 - 1  =  127 */
+#define silk_int8_MIN    ((opus_int8)0x80)                    /* -2^7      = -128 */
+#define silk_uint8_MAX   0xFF                                 /*  2^8 - 1 = 255 */
+
+#define silk_TRUE        1
+#define silk_FALSE       0
+
+/* assertions */
+#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS))
+# ifndef silk_assert
+#  include <crtdbg.h>      /* ASSERTE() */
+#  define silk_assert(COND)   _ASSERTE(COND)
+# endif
+#else
+# ifdef ENABLE_ASSERTIONS
+#  include <stdio.h>
+#  include <stdlib.h>
+#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__);
+#ifdef __GNUC__
+__attribute__((noreturn))
+#endif
+static OPUS_INLINE void _silk_fatal(const char *str, const char *file, int line)
+{
+   fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
+   abort();
+}
+#  define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}}
+# else
+#  define silk_assert(COND)
+# endif
+#endif
+
+#endif /* SILK_TYPEDEF_H */
diff --git a/third_party/opus/src/silk/x86/NSQ_del_dec_sse.c b/third_party/opus/src/silk/x86/NSQ_del_dec_sse.c
new file mode 100644
index 0000000..21d4a8bc
--- /dev/null
+++ b/third_party/opus/src/silk/x86/NSQ_del_dec_sse.c
@@ -0,0 +1,857 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "main.h"
+#include "celt/x86/x86cpu.h"
+
+#include "stack_alloc.h"
+
+typedef struct {
+    opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+    opus_int32 RandState[ DECISION_DELAY ];
+    opus_int32 Q_Q10[     DECISION_DELAY ];
+    opus_int32 Xq_Q14[    DECISION_DELAY ];
+    opus_int32 Pred_Q15[  DECISION_DELAY ];
+    opus_int32 Shape_Q14[ DECISION_DELAY ];
+    opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+    opus_int32 LF_AR_Q14;
+    opus_int32 Seed;
+    opus_int32 SeedInit;
+    opus_int32 RD_Q10;
+} NSQ_del_dec_struct;
+
+typedef struct {
+    opus_int32 Q_Q10;
+    opus_int32 RD_Q10;
+    opus_int32 xq_Q14;
+    opus_int32 LF_AR_Q14;
+    opus_int32 sLTP_shp_Q14;
+    opus_int32 LPC_exc_Q14;
+} NSQ_sample_struct;
+
+typedef NSQ_sample_struct  NSQ_sample_pair[ 2 ];
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1(
+    const silk_encoder_state *psEncC,               /* I    Encoder State                       */
+    silk_nsq_state      *NSQ,                       /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],                 /* I/O  Delayed decision states             */
+    const opus_int32    x_Q3[],                     /* I    Input in Q3                         */
+    opus_int32          x_sc_Q10[],                 /* O    Input scaled with 1/Gain in Q10     */
+    const opus_int16    sLTP[],                     /* I    Re-whitened LTP state in Q0         */
+    opus_int32          sLTP_Q15[],                 /* O    LTP state matching scaled input     */
+    opus_int            subfr,                      /* I    Subframe number                     */
+    opus_int            nStatesDelayedDecision,     /* I    Number of del dec states            */
+    const opus_int      LTP_scale_Q14,              /* I    LTP state scaling                   */
+    const opus_int32    Gains_Q16[ MAX_NB_SUBFR ],  /* I                                        */
+    const opus_int      pitchL[ MAX_NB_SUBFR ],     /* I    Pitch lag                           */
+    const opus_int      signal_type,                /* I    Signal type                         */
+    const opus_int      decisionDelay               /* I    Decision delay                      */
+);
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],             /* I/O  Delayed decision states             */
+    opus_int            signalType,             /* I    Signal type                         */
+    const opus_int32    x_Q10[],                /* I                                        */
+    opus_int8           pulses[],               /* O                                        */
+    opus_int16          xq[],                   /* O                                        */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP filter state                    */
+    opus_int32          delayedGain_Q10[],      /* I/O  Gain delay buffer                   */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs         */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs          */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping coefs                 */
+    opus_int            lag,                    /* I    Pitch lag                           */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                        */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                       */
+    opus_int32          LF_shp_Q14,             /* I                                        */
+    opus_int32          Gain_Q16,               /* I                                        */
+    opus_int            Lambda_Q10,             /* I                                        */
+    opus_int            offset_Q10,             /* I                                        */
+    opus_int            length,                 /* I    Input length                        */
+    opus_int            subfr,                  /* I    Subframe number                     */
+    opus_int            shapingLPCOrder,        /* I    Shaping LPC filter order            */
+    opus_int            predictLPCOrder,        /* I    Prediction filter order             */
+    opus_int            warping_Q16,            /* I                                        */
+    opus_int            nStatesDelayedDecision, /* I    Number of states in decision tree   */
+    opus_int            *smpl_buf_idx,          /* I    Index to newest samples in buffers  */
+    opus_int            decisionDelay           /* I                                        */
+);
+
+void silk_NSQ_del_dec_sse4_1(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+)
+{
+    opus_int            i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr;
+    opus_int            last_smple_idx, smpl_buf_idx, decisionDelay;
+    const opus_int16    *A_Q12, *B_Q14, *AR_shp_Q13;
+    opus_int16          *pxq;
+    VARDECL( opus_int32, sLTP_Q15 );
+    VARDECL( opus_int16, sLTP );
+    opus_int32          HarmShapeFIRPacked_Q14;
+    opus_int            offset_Q10;
+    opus_int32          RDmin_Q10, Gain_Q10;
+    VARDECL( opus_int32, x_sc_Q10 );
+    VARDECL( opus_int32, delayedGain_Q10 );
+    VARDECL( NSQ_del_dec_struct, psDelDec );
+    NSQ_del_dec_struct  *psDD;
+    SAVE_STACK;
+
+    /* Set unvoiced lag to the previous one, overwrite later for voiced */
+    lag = NSQ->lagPrev;
+
+    silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+    /* Initialize delayed decision states */
+    ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct );
+    silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) );
+    for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) {
+        psDD                 = &psDelDec[ k ];
+        psDD->Seed           = ( k + psIndices->Seed ) & 3;
+        psDD->SeedInit       = psDD->Seed;
+        psDD->RD_Q10         = 0;
+        psDD->LF_AR_Q14      = NSQ->sLF_AR_shp_Q14;
+        psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ];
+        silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+        silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) );
+    }
+
+    offset_Q10   = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+    smpl_buf_idx = 0; /* index of oldest samples */
+
+    decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length );
+
+    /* For voiced frames limit the decision delay to lower than the pitch lag */
+    if( psIndices->signalType == TYPE_VOICED ) {
+        for( k = 0; k < psEncC->nb_subfr; k++ ) {
+            decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 );
+        }
+    } else {
+        if( lag > 0 ) {
+            decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 );
+        }
+    }
+
+    if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+        LSF_interpolation_flag = 0;
+    } else {
+        LSF_interpolation_flag = 1;
+    }
+
+    ALLOC( sLTP_Q15,
+           psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+    ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+    ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+    ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 );
+    /* Set up pointers to start of sub frame */
+    pxq                   = &NSQ->xq[ psEncC->ltp_mem_length ];
+    NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+    NSQ->sLTP_buf_idx     = psEncC->ltp_mem_length;
+    subfr = 0;
+    for( k = 0; k < psEncC->nb_subfr; k++ ) {
+        A_Q12      = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ];
+        B_Q14      = &LTPCoef_Q14[ k * LTP_ORDER           ];
+        AR_shp_Q13 = &AR2_Q13[     k * MAX_SHAPE_LPC_ORDER ];
+
+        /* Noise shape parameters */
+        silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+        HarmShapeFIRPacked_Q14  =                          silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+        HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+        NSQ->rewhite_flag = 0;
+        if( psIndices->signalType == TYPE_VOICED ) {
+            /* Voiced */
+            lag = pitchL[ k ];
+
+            /* Re-whitening */
+            if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+                if( k == 2 ) {
+                    /* RESET DELAYED DECISIONS */
+                    /* Find winner */
+                    RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+                    Winner_ind = 0;
+                    for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) {
+                        if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) {
+                            RDmin_Q10 = psDelDec[ i ].RD_Q10;
+                            Winner_ind = i;
+                        }
+                    }
+                    for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) {
+                        if( i != Winner_ind ) {
+                            psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 );
+                            silk_assert( psDelDec[ i ].RD_Q10 >= 0 );
+                        }
+                    }
+
+                    /* Copy final part of signals from winner state to output and long-term filter states */
+                    psDD = &psDelDec[ Winner_ind ];
+                    last_smple_idx = smpl_buf_idx + decisionDelay;
+                    for( i = 0; i < decisionDelay; i++ ) {
+                        last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+                        pulses[   i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+                        pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+                            silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) );
+                        NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+                    }
+
+                    subfr = 0;
+                }
+
+                /* Rewhiten with new A coefs */
+                start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+                silk_assert( start_idx > 0 );
+
+                silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+                    A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+                NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+                NSQ->rewhite_flag = 1;
+            }
+        }
+
+        silk_nsq_del_dec_scale_states_sse4_1( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k,
+            psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay );
+
+        silk_noise_shape_quantizer_del_dec_sse4_1( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15,
+            delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ],
+            Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder,
+            psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay );
+
+        x_Q3   += psEncC->subfr_length;
+        pulses += psEncC->subfr_length;
+        pxq    += psEncC->subfr_length;
+    }
+
+    /* Find winner */
+    RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+    Winner_ind = 0;
+    for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) {
+        if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) {
+            RDmin_Q10 = psDelDec[ k ].RD_Q10;
+            Winner_ind = k;
+        }
+    }
+
+    /* Copy final part of signals from winner state to output and long-term filter states */
+    psDD = &psDelDec[ Winner_ind ];
+    psIndices->Seed = psDD->SeedInit;
+    last_smple_idx = smpl_buf_idx + decisionDelay;
+    Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 );
+    for( i = 0; i < decisionDelay; i++ ) {
+        last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+        pulses[   i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+        pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+            silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) );
+        NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+    }
+    silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+    silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) );
+
+    /* Update states */
+    NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14;
+    NSQ->lagPrev        = pitchL[ psEncC->nb_subfr - 1 ];
+
+    /* Save quantized speech signal */
+    /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */
+    silk_memmove( NSQ->xq,           &NSQ->xq[           psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+    silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+    RESTORE_STACK;
+}
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],             /* I/O  Delayed decision states             */
+    opus_int            signalType,             /* I    Signal type                         */
+    const opus_int32    x_Q10[],                /* I                                        */
+    opus_int8           pulses[],               /* O                                        */
+    opus_int16          xq[],                   /* O                                        */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP filter state                    */
+    opus_int32          delayedGain_Q10[],      /* I/O  Gain delay buffer                   */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs         */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs          */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping coefs                 */
+    opus_int            lag,                    /* I    Pitch lag                           */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                        */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                       */
+    opus_int32          LF_shp_Q14,             /* I                                        */
+    opus_int32          Gain_Q16,               /* I                                        */
+    opus_int            Lambda_Q10,             /* I                                        */
+    opus_int            offset_Q10,             /* I                                        */
+    opus_int            length,                 /* I    Input length                        */
+    opus_int            subfr,                  /* I    Subframe number                     */
+    opus_int            shapingLPCOrder,        /* I    Shaping LPC filter order            */
+    opus_int            predictLPCOrder,        /* I    Prediction filter order             */
+    opus_int            warping_Q16,            /* I                                        */
+    opus_int            nStatesDelayedDecision, /* I    Number of states in decision tree   */
+    opus_int            *smpl_buf_idx,          /* I    Index to newest samples in buffers  */
+    opus_int            decisionDelay           /* I                                        */
+)
+{
+    opus_int     i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+    opus_int32   Winner_rand_state;
+    opus_int32   LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+    opus_int32   n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+    opus_int32   q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+    opus_int32   tmp1, tmp2, sLF_AR_shp_Q14;
+    opus_int32   *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
+    VARDECL( NSQ_sample_pair, psSampleState );
+    NSQ_del_dec_struct *psDD;
+    NSQ_sample_struct  *psSS;
+
+    __m128i a_Q12_0123, a_Q12_4567, a_Q12_89AB, a_Q12_CDEF;
+    __m128i b_Q12_0123, b_sr_Q12_0123;
+    SAVE_STACK;
+
+    silk_assert( nStatesDelayedDecision > 0 );
+    ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair );
+
+    shp_lag_ptr  = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+    pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+    Gain_Q10     = silk_RSHIFT( Gain_Q16, 6 );
+
+    a_Q12_0123 = OP_CVTEPI16_EPI32_M64( a_Q12 );
+    a_Q12_4567 = OP_CVTEPI16_EPI32_M64( a_Q12 + 4 );
+
+    if( opus_likely( predictLPCOrder == 16 ) ) {
+        a_Q12_89AB = OP_CVTEPI16_EPI32_M64( a_Q12 + 8 );
+        a_Q12_CDEF = OP_CVTEPI16_EPI32_M64( a_Q12 + 12 );
+    }
+
+    if( signalType == TYPE_VOICED ){
+        b_Q12_0123 = OP_CVTEPI16_EPI32_M64( b_Q14 );
+        b_sr_Q12_0123 = _mm_shuffle_epi32( b_Q12_0123, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+    }
+    for( i = 0; i < length; i++ ) {
+        /* Perform common calculations used in all states */
+
+        /* Long-term prediction */
+        if( signalType == TYPE_VOICED ) {
+            /* Unrolled loop */
+            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+            LTP_pred_Q14 = 2;
+            {
+                __m128i tmpa, tmpb, pred_lag_ptr_tmp;
+                pred_lag_ptr_tmp    = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) );
+                pred_lag_ptr_tmp    = _mm_shuffle_epi32( pred_lag_ptr_tmp, 0x1B );
+                tmpa                = _mm_mul_epi32( pred_lag_ptr_tmp, b_Q12_0123 );
+                tmpa                = _mm_srli_si128( tmpa, 2 );
+
+                pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) );/* equal shift right 4 bytes */
+                pred_lag_ptr_tmp    = _mm_mul_epi32( pred_lag_ptr_tmp, b_sr_Q12_0123 );
+                pred_lag_ptr_tmp    = _mm_srli_si128( pred_lag_ptr_tmp, 2 );
+                pred_lag_ptr_tmp    = _mm_add_epi32( pred_lag_ptr_tmp, tmpa );
+
+                tmpb = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 0, 3, 2 ) );/* equal shift right 8 bytes */
+                pred_lag_ptr_tmp    = _mm_add_epi32( pred_lag_ptr_tmp, tmpb );
+                LTP_pred_Q14        += _mm_cvtsi128_si32( pred_lag_ptr_tmp );
+
+                LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+                LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 );                          /* Q13 -> Q14 */
+                pred_lag_ptr++;
+            }
+        } else {
+            LTP_pred_Q14 = 0;
+        }
+
+        /* Long-term shaping */
+        if( lag > 0 ) {
+            /* Symmetric, packed FIR coefficients */
+            n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+            n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ],                      HarmShapeFIRPacked_Q14 );
+            n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 );            /* Q12 -> Q14 */
+            shp_lag_ptr++;
+        } else {
+            n_LTP_Q14 = 0;
+        }
+        {
+            __m128i tmpa, tmpb, psLPC_Q14_tmp, a_Q12_tmp;
+
+            for( k = 0; k < nStatesDelayedDecision; k++ ) {
+                /* Delayed decision state */
+                psDD = &psDelDec[ k ];
+
+                /* Sample state */
+                psSS = psSampleState[ k ];
+
+                /* Generate dither */
+                psDD->Seed = silk_RAND( psDD->Seed );
+
+                /* Pointer used in short term prediction and shaping */
+                psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
+                /* Short-term prediction */
+                silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 );
+                /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+                LPC_pred_Q14 = silk_RSHIFT( predictLPCOrder, 1 );
+
+                tmpb = _mm_setzero_si128();
+
+                /* step 1 */
+                psLPC_Q14_tmp   = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -3 ] ) ); /* -3, -2 , -1, 0 */
+                psLPC_Q14_tmp   = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B );      /* 0, -1, -2, -3 */
+                tmpa            = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_0123 );    /* 0, -1, -2, -3 * 0123 -> 0*0, 2*-2 */
+
+                tmpa            = _mm_srli_epi64( tmpa, 16 );
+                tmpb            = _mm_add_epi32( tmpb, tmpa );
+
+                psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+                a_Q12_tmp = _mm_shuffle_epi32( a_Q12_0123, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+                psLPC_Q14_tmp   = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); /* 1*-1, 3*-3 */
+                psLPC_Q14_tmp   = _mm_srli_epi64( psLPC_Q14_tmp, 16 );
+                tmpb            = _mm_add_epi32( tmpb, psLPC_Q14_tmp );
+
+                /* step 2 */
+                psLPC_Q14_tmp   = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -7 ] ) );
+                psLPC_Q14_tmp   = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B );
+                tmpa            = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_4567 );
+                tmpa            = _mm_srli_epi64( tmpa, 16 );
+                tmpb            = _mm_add_epi32( tmpb, tmpa );
+
+                psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+                a_Q12_tmp = _mm_shuffle_epi32( a_Q12_4567, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+                psLPC_Q14_tmp   = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp );
+                psLPC_Q14_tmp   = _mm_srli_epi64( psLPC_Q14_tmp, 16 );
+                tmpb            = _mm_add_epi32( tmpb, psLPC_Q14_tmp );
+
+                if ( opus_likely( predictLPCOrder == 16 ) )
+                {
+                    /* step 3 */
+                    psLPC_Q14_tmp   = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -11 ] ) );
+                    psLPC_Q14_tmp   = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B );
+                    tmpa            = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_89AB );
+                    tmpa            = _mm_srli_epi64( tmpa, 16 );
+                    tmpb            = _mm_add_epi32( tmpb, tmpa );
+
+                    psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+                    a_Q12_tmp = _mm_shuffle_epi32( a_Q12_89AB, _MM_SHUFFLE(0, 3, 2, 1 ) );/* equal shift right 4 bytes */
+                    psLPC_Q14_tmp   = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp );
+                    psLPC_Q14_tmp   = _mm_srli_epi64( psLPC_Q14_tmp, 16 );
+                    tmpb            = _mm_add_epi32( tmpb, psLPC_Q14_tmp );
+
+                    /* setp 4 */
+                    psLPC_Q14_tmp   = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -15 ] ) );
+                    psLPC_Q14_tmp   = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B );
+                    tmpa            = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_CDEF );
+                    tmpa            = _mm_srli_epi64( tmpa, 16 );
+                    tmpb            = _mm_add_epi32( tmpb, tmpa );
+
+                    psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+                    a_Q12_tmp = _mm_shuffle_epi32( a_Q12_CDEF, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */
+                    psLPC_Q14_tmp   = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp );
+                    psLPC_Q14_tmp   = _mm_srli_epi64( psLPC_Q14_tmp, 16 );
+                    tmpb            = _mm_add_epi32( tmpb, psLPC_Q14_tmp );
+
+                    /* add at last */
+                    /* equal shift right 8 bytes*/
+                    tmpa            = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) );
+                    tmpb            = _mm_add_epi32( tmpb, tmpa );
+                    LPC_pred_Q14    += _mm_cvtsi128_si32( tmpb );
+                }
+                else
+                {
+                    /* add at last */
+                    tmpa            = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) ); /* equal shift right 8 bytes*/
+                    tmpb            = _mm_add_epi32( tmpb, tmpa );
+                    LPC_pred_Q14    += _mm_cvtsi128_si32( tmpb );
+
+                    LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -8 ], a_Q12[ 8 ] );
+                    LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -9 ], a_Q12[ 9 ] );
+                }
+
+                LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */
+
+                /* Noise shape feedback */
+                silk_assert( ( shapingLPCOrder & 1 ) == 0 );   /* check that order is even */
+                /* Output of lowpass section */
+                tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 );
+                /* Output of allpass section */
+                tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 );
+                psDD->sAR2_Q14[ 0 ] = tmp2;
+                n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 );
+                n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] );
+                /* Loop over allpass sections */
+                for( j = 2; j < shapingLPCOrder; j += 2 ) {
+                    /* Output of allpass section */
+                    tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 );
+                    psDD->sAR2_Q14[ j - 1 ] = tmp1;
+                    n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] );
+                    /* Output of allpass section */
+                    tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 );
+                    psDD->sAR2_Q14[ j + 0 ] = tmp2;
+                    n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] );
+                }
+                psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+                n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+
+                n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 );                                      /* Q11 -> Q12 */
+                n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 );              /* Q12 */
+                n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 );                                      /* Q12 -> Q14 */
+
+                n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 );     /* Q12 */
+                n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 );            /* Q12 */
+                n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 );                                      /* Q12 -> Q14 */
+
+                /* Input minus prediction plus noise feedback                       */
+                /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP  */
+                tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 );                                    /* Q14 */
+                tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 );                               /* Q13 */
+                tmp1 = silk_SUB32( tmp2, tmp1 );                                            /* Q13 */
+                tmp1 = silk_RSHIFT_ROUND( tmp1, 4 );                                        /* Q10 */
+
+                r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 );                                     /* residual error Q10 */
+
+                /* Flip sign depending on dither */
+                if ( psDD->Seed < 0 ) {
+                    r_Q10 = -r_Q10;
+                }
+                r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+                /* Find two quantization level candidates and measure their rate-distortion */
+                q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+                q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+                if( q1_Q0 > 0 ) {
+                    q1_Q10  = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+                    q1_Q10  = silk_ADD32( q1_Q10, offset_Q10 );
+                    q2_Q10  = silk_ADD32( q1_Q10, 1024 );
+                    rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+                    rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+                } else if( q1_Q0 == 0 ) {
+                    q1_Q10  = offset_Q10;
+                    q2_Q10  = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+                    rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+                    rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+                } else if( q1_Q0 == -1 ) {
+                    q2_Q10  = offset_Q10;
+                    q1_Q10  = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+                    rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+                    rd2_Q10 = silk_SMULBB(  q2_Q10, Lambda_Q10 );
+                } else {            /* q1_Q0 < -1 */
+                    q1_Q10  = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+                    q1_Q10  = silk_ADD32( q1_Q10, offset_Q10 );
+                    q2_Q10  = silk_ADD32( q1_Q10, 1024 );
+                    rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+                    rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+                }
+                rr_Q10  = silk_SUB32( r_Q10, q1_Q10 );
+                rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
+                rr_Q10  = silk_SUB32( r_Q10, q2_Q10 );
+                rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
+
+                if( rd1_Q10 < rd2_Q10 ) {
+                    psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+                    psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+                    psSS[ 0 ].Q_Q10  = q1_Q10;
+                    psSS[ 1 ].Q_Q10  = q2_Q10;
+                } else {
+                    psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+                    psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+                    psSS[ 0 ].Q_Q10  = q2_Q10;
+                    psSS[ 1 ].Q_Q10  = q1_Q10;
+                }
+
+                /* Update states for best quantization */
+
+                /* Quantized excitation */
+                exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
+                if ( psDD->Seed < 0 ) {
+                    exc_Q14 = -exc_Q14;
+                }
+
+                /* Add predictions */
+                LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+                xq_Q14      = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+                /* Update states */
+                sLF_AR_shp_Q14         = silk_SUB32( xq_Q14, n_AR_Q14 );
+                psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+                psSS[ 0 ].LF_AR_Q14    = sLF_AR_shp_Q14;
+                psSS[ 0 ].LPC_exc_Q14  = LPC_exc_Q14;
+                psSS[ 0 ].xq_Q14       = xq_Q14;
+
+                /* Update states for second best quantization */
+
+                /* Quantized excitation */
+                exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
+                if ( psDD->Seed < 0 ) {
+                    exc_Q14 = -exc_Q14;
+                }
+
+
+                /* Add predictions */
+                LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+                xq_Q14      = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+                /* Update states */
+                sLF_AR_shp_Q14         = silk_SUB32( xq_Q14, n_AR_Q14 );
+                psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+                psSS[ 1 ].LF_AR_Q14    = sLF_AR_shp_Q14;
+                psSS[ 1 ].LPC_exc_Q14  = LPC_exc_Q14;
+                psSS[ 1 ].xq_Q14       = xq_Q14;
+            }
+        }
+        *smpl_buf_idx  = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK;                   /* Index to newest samples              */
+        last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK;       /* Index to decisionDelay old samples   */
+
+        /* Find winner */
+        RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+        Winner_ind = 0;
+        for( k = 1; k < nStatesDelayedDecision; k++ ) {
+            if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
+                RDmin_Q10  = psSampleState[ k ][ 0 ].RD_Q10;
+                Winner_ind = k;
+            }
+        }
+
+        /* Increase RD values of expired states */
+        Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
+                psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
+                psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
+                silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
+            }
+        }
+
+        /* Find worst in first set and best in second set */
+        RDmax_Q10  = psSampleState[ 0 ][ 0 ].RD_Q10;
+        RDmin_Q10  = psSampleState[ 0 ][ 1 ].RD_Q10;
+        RDmax_ind = 0;
+        RDmin_ind = 0;
+        for( k = 1; k < nStatesDelayedDecision; k++ ) {
+            /* find worst in first set */
+            if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
+                RDmax_Q10  = psSampleState[ k ][ 0 ].RD_Q10;
+                RDmax_ind = k;
+            }
+            /* find best in second set */
+            if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
+                RDmin_Q10  = psSampleState[ k ][ 1 ].RD_Q10;
+                RDmin_ind = k;
+            }
+        }
+
+        /* Replace a state if best from second set outperforms worst in first set */
+        if( RDmin_Q10 < RDmax_Q10 ) {
+            silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
+                         ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
+            silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
+        }
+
+        /* Write samples from winner to output and long-term filter states */
+        psDD = &psDelDec[ Winner_ind ];
+        if( subfr > 0 || i >= decisionDelay ) {
+            pulses[  i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+            xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+                silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
+            NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
+            sLTP_Q15[          NSQ->sLTP_buf_idx     - decisionDelay ] = psDD->Pred_Q15[  last_smple_idx ];
+        }
+        NSQ->sLTP_shp_buf_idx++;
+        NSQ->sLTP_buf_idx++;
+
+        /* Update states */
+        for( k = 0; k < nStatesDelayedDecision; k++ ) {
+            psDD                                     = &psDelDec[ k ];
+            psSS                                     = &psSampleState[ k ][ 0 ];
+            psDD->LF_AR_Q14                          = psSS->LF_AR_Q14;
+            psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
+            psDD->Xq_Q14[    *smpl_buf_idx ]         = psSS->xq_Q14;
+            psDD->Q_Q10[     *smpl_buf_idx ]         = psSS->Q_Q10;
+            psDD->Pred_Q15[  *smpl_buf_idx ]         = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
+            psDD->Shape_Q14[ *smpl_buf_idx ]         = psSS->sLTP_shp_Q14;
+            psDD->Seed                               = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
+            psDD->RandState[ *smpl_buf_idx ]         = psDD->Seed;
+            psDD->RD_Q10                             = psSS->RD_Q10;
+        }
+        delayedGain_Q10[     *smpl_buf_idx ]         = Gain_Q10;
+    }
+    /* Update LPC states */
+    for( k = 0; k < nStatesDelayedDecision; k++ ) {
+        psDD = &psDelDec[ k ];
+        silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+    }
+    RESTORE_STACK;
+}
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1(
+    const silk_encoder_state *psEncC,               /* I    Encoder State                       */
+    silk_nsq_state      *NSQ,                       /* I/O  NSQ state                           */
+    NSQ_del_dec_struct  psDelDec[],                 /* I/O  Delayed decision states             */
+    const opus_int32    x_Q3[],                     /* I    Input in Q3                         */
+    opus_int32          x_sc_Q10[],                 /* O    Input scaled with 1/Gain in Q10     */
+    const opus_int16    sLTP[],                     /* I    Re-whitened LTP state in Q0         */
+    opus_int32          sLTP_Q15[],                 /* O    LTP state matching scaled input     */
+    opus_int            subfr,                      /* I    Subframe number                     */
+    opus_int            nStatesDelayedDecision,     /* I    Number of del dec states            */
+    const opus_int      LTP_scale_Q14,              /* I    LTP state scaling                   */
+    const opus_int32    Gains_Q16[ MAX_NB_SUBFR ],  /* I                                        */
+    const opus_int      pitchL[ MAX_NB_SUBFR ],     /* I    Pitch lag                           */
+    const opus_int      signal_type,                /* I    Signal type                         */
+    const opus_int      decisionDelay               /* I    Decision delay                      */
+)
+{
+    opus_int            i, k, lag;
+    opus_int32          gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+    NSQ_del_dec_struct  *psDD;
+    __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1;
+
+    lag          = pitchL[ subfr ];
+    inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+
+    silk_assert( inv_gain_Q31 != 0 );
+
+    /* Calculate gain adjustment factor */
+    if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+        gain_adj_Q16 =  silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+    } else {
+        gain_adj_Q16 = (opus_int32)1 << 16;
+    }
+
+    /* Scale input */
+    inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+
+    /* prepare inv_gain_Q23 in packed 4 32-bits */
+    xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23);
+
+    for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) {
+        xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) );
+        /* equal shift right 4 bytes*/
+        xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+        xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 );
+        xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 );
+
+        xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 );
+        xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 );
+
+        xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC );
+
+        _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ])), xmm_x_Q3_x2x0 );
+    }
+
+    for( ; i < psEncC->subfr_length; i++ ) {
+        x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+    }
+
+    /* Save inverse gain */
+    NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+    /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+    if( NSQ->rewhite_flag ) {
+        if( subfr == 0 ) {
+            /* Do LTP downscaling */
+            inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+        }
+        for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+            silk_assert( i < MAX_FRAME_LENGTH );
+            sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+        }
+    }
+
+    /* Adjust for changing gain */
+    if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+        /* Scale long-term shaping state */
+        {
+            __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1;
+
+            /* prepare gain_adj_Q16 in packed 4 32-bits */
+            xmm_gain_adj_Q16 = _mm_set1_epi32( gain_adj_Q16 );
+
+            for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 )
+            {
+                xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) );
+                /* equal shift right 4 bytes*/
+                xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+                xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 );
+                xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 );
+
+                xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 );
+                xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 );
+
+                xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC );
+
+                _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 );
+            }
+
+            for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+                NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+            }
+
+            /* Scale long-term prediction state */
+            if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+                for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) {
+                    sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+                }
+            }
+
+            for( k = 0; k < nStatesDelayedDecision; k++ ) {
+                psDD = &psDelDec[ k ];
+
+                /* Scale scalar states */
+                psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 );
+
+                /* Scale short-term prediction and shaping states */
+                for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+                    psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] );
+                }
+                for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+                    psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] );
+                }
+                for( i = 0; i < DECISION_DELAY; i++ ) {
+                    psDD->Pred_Q15[  i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[  i ] );
+                    psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] );
+                }
+            }
+        }
+    }
+}
diff --git a/third_party/opus/src/silk/x86/NSQ_sse.c b/third_party/opus/src/silk/x86/NSQ_sse.c
new file mode 100644
index 0000000..bb3c5f19
--- /dev/null
+++ b/third_party/opus/src/silk/x86/NSQ_sse.c
@@ -0,0 +1,720 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "main.h"
+#include "celt/x86/x86cpu.h"
+#include "stack_alloc.h"
+
+static OPUS_INLINE void silk_nsq_scale_states_sse4_1(
+    const silk_encoder_state *psEncC,           /* I    Encoder State                   */
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    const opus_int32    x_Q3[],                 /* I    input in Q3                     */
+    opus_int32          x_sc_Q10[],             /* O    input scaled with 1/Gain        */
+    const opus_int16    sLTP[],                 /* I    re-whitened LTP state in Q0     */
+    opus_int32          sLTP_Q15[],             /* O    LTP state matching scaled input */
+    opus_int            subfr,                  /* I    subframe number                 */
+    const opus_int      LTP_scale_Q14,          /* I                                    */
+    const opus_int32    Gains_Q16[ MAX_NB_SUBFR ], /* I                                 */
+    const opus_int      pitchL[ MAX_NB_SUBFR ], /* I    Pitch lag                       */
+    const opus_int      signal_type             /* I    Signal type                     */
+);
+
+static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    opus_int            signalType,             /* I    Signal type                     */
+    const opus_int32    x_sc_Q10[],             /* I                                    */
+    opus_int8           pulses[],               /* O                                    */
+    opus_int16          xq[],                   /* O                                    */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP state                       */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs     */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs      */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping AR coefs          */
+    opus_int            lag,                    /* I    Pitch lag                       */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                    */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                   */
+    opus_int32          LF_shp_Q14,             /* I                                    */
+    opus_int32          Gain_Q16,               /* I                                    */
+    opus_int            offset_Q10,             /* I                                    */
+    opus_int            length,                 /* I    Input length                    */
+    opus_int32          table[][4]              /* I                                    */
+);
+
+void silk_NSQ_sse4_1(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+)
+{
+    opus_int            k, lag, start_idx, LSF_interpolation_flag;
+    const opus_int16    *A_Q12, *B_Q14, *AR_shp_Q13;
+    opus_int16          *pxq;
+    VARDECL( opus_int32, sLTP_Q15 );
+    VARDECL( opus_int16, sLTP );
+    opus_int32          HarmShapeFIRPacked_Q14;
+    opus_int            offset_Q10;
+    VARDECL( opus_int32, x_sc_Q10 );
+
+    opus_int32   table[ 64 ][ 4 ];
+    opus_int32   tmp1;
+    opus_int32   q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
+
+    SAVE_STACK;
+
+    NSQ->rand_seed = psIndices->Seed;
+
+    /* Set unvoiced lag to the previous one, overwrite later for voiced */
+    lag = NSQ->lagPrev;
+
+    silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+    offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+
+    /* 0 */
+    q1_Q10  = offset_Q10;
+    q2_Q10  = offset_Q10 + ( 1024 - QUANT_LEVEL_ADJUST_Q10 );
+    rd1_Q20 = q1_Q10 * Lambda_Q10;
+    rd2_Q20 = q2_Q10 * Lambda_Q10;
+
+    table[ 32 ][ 0 ] = q1_Q10;
+    table[ 32 ][ 1 ] = q2_Q10;
+    table[ 32 ][ 2 ] = 2 * (q1_Q10 - q2_Q10);
+    table[ 32 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10);
+
+    /* -1 */
+    q1_Q10  = offset_Q10 - ( 1024 - QUANT_LEVEL_ADJUST_Q10 );
+    q2_Q10  = offset_Q10;
+    rd1_Q20 = - q1_Q10 * Lambda_Q10;
+    rd2_Q20 = q2_Q10 * Lambda_Q10;
+
+    table[ 31 ][ 0 ] = q1_Q10;
+    table[ 31 ][ 1 ] = q2_Q10;
+    table[ 31 ][ 2 ] = 2 * (q1_Q10 - q2_Q10);
+    table[ 31 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10);
+
+    /* > 0 */
+    for (k = 1; k <= 31; k++)
+    {
+        tmp1 = offset_Q10 + silk_LSHIFT( k, 10 );
+
+        q1_Q10  = tmp1 - QUANT_LEVEL_ADJUST_Q10;
+        q2_Q10  = tmp1 - QUANT_LEVEL_ADJUST_Q10 + 1024;
+        rd1_Q20 = q1_Q10 * Lambda_Q10;
+        rd2_Q20 = q2_Q10 * Lambda_Q10;
+
+        table[ 32 + k ][ 0 ] = q1_Q10;
+        table[ 32 + k ][ 1 ] = q2_Q10;
+        table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10);
+        table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10);
+    }
+
+    /* < -1 */
+    for (k = -32; k <= -2; k++)
+    {
+        tmp1 = offset_Q10 + silk_LSHIFT( k, 10 );
+
+        q1_Q10  = tmp1 + QUANT_LEVEL_ADJUST_Q10;
+        q2_Q10  = tmp1 + QUANT_LEVEL_ADJUST_Q10 + 1024;
+        rd1_Q20 = - q1_Q10 * Lambda_Q10;
+        rd2_Q20 = - q2_Q10 * Lambda_Q10;
+
+        table[ 32 + k ][ 0 ] = q1_Q10;
+        table[ 32 + k ][ 1 ] = q2_Q10;
+        table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10);
+        table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10);
+    }
+
+    if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+        LSF_interpolation_flag = 0;
+    } else {
+        LSF_interpolation_flag = 1;
+    }
+
+    ALLOC( sLTP_Q15,
+           psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+    ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+    ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+    /* Set up pointers to start of sub frame */
+    NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+    NSQ->sLTP_buf_idx     = psEncC->ltp_mem_length;
+    pxq                   = &NSQ->xq[ psEncC->ltp_mem_length ];
+    for( k = 0; k < psEncC->nb_subfr; k++ ) {
+        A_Q12      = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ];
+        B_Q14      = &LTPCoef_Q14[ k * LTP_ORDER ];
+        AR_shp_Q13 = &AR2_Q13[     k * MAX_SHAPE_LPC_ORDER ];
+
+        /* Noise shape parameters */
+        silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+        HarmShapeFIRPacked_Q14  =                          silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+        HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+        NSQ->rewhite_flag = 0;
+        if( psIndices->signalType == TYPE_VOICED ) {
+            /* Voiced */
+            lag = pitchL[ k ];
+
+            /* Re-whitening */
+            if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+                /* Rewhiten with new A coefs */
+                start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+                silk_assert( start_idx > 0 );
+
+                silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+                    A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+                NSQ->rewhite_flag = 1;
+                NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+            }
+        }
+
+        silk_nsq_scale_states_sse4_1( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType );
+
+        if ( opus_likely( ( 10 == psEncC->shapingLPCOrder ) && ( 16 == psEncC->predictLPCOrder) ) )
+        {
+            silk_noise_shape_quantizer_10_16_sse4_1( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
+                AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ],
+                offset_Q10, psEncC->subfr_length, &(table[32]) );
+        }
+        else
+        {
+            silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
+                AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10,
+                offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch );
+        }
+
+        x_Q3   += psEncC->subfr_length;
+        pulses += psEncC->subfr_length;
+        pxq    += psEncC->subfr_length;
+    }
+
+    /* Update lagPrev for next frame */
+    NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+    /* Save quantized speech and noise shaping signals */
+    /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */
+    silk_memmove( NSQ->xq,           &NSQ->xq[           psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+    silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+    RESTORE_STACK;
+}
+
+/***********************************/
+/* silk_noise_shape_quantizer_10_16  */
+/***********************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    opus_int            signalType,             /* I    Signal type                     */
+    const opus_int32    x_sc_Q10[],             /* I                                    */
+    opus_int8           pulses[],               /* O                                    */
+    opus_int16          xq[],                   /* O                                    */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP state                       */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs     */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs      */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping AR coefs          */
+    opus_int            lag,                    /* I    Pitch lag                       */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                    */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                   */
+    opus_int32          LF_shp_Q14,             /* I                                    */
+    opus_int32          Gain_Q16,               /* I                                    */
+    opus_int            offset_Q10,             /* I                                    */
+    opus_int            length,                 /* I    Input length                    */
+    opus_int32          table[][4]              /* I                                    */
+)
+{
+    opus_int     i;
+    opus_int32   LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
+    opus_int32   n_LF_Q12, r_Q10, q1_Q0, q1_Q10, q2_Q10;
+    opus_int32   exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+    opus_int32   tmp1, tmp2, sLF_AR_shp_Q14;
+    opus_int32   *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr;
+
+    __m128i xmm_tempa, xmm_tempb;
+
+    __m128i xmm_one;
+
+    __m128i psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF;
+    __m128i psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF;
+    __m128i a_Q12_01234567,        a_Q12_89ABCDEF;
+
+    __m128i sAR2_Q14_hi_76543210, sAR2_Q14_lo_76543210;
+    __m128i AR_shp_Q13_76543210;
+
+    shp_lag_ptr  = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+    pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+    Gain_Q10     = silk_RSHIFT( Gain_Q16, 6 );
+
+    /* Set up short term AR state */
+    psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ];
+
+    sLF_AR_shp_Q14 = NSQ->sLF_AR_shp_Q14;
+    xq_Q14         = psLPC_Q14[ 0 ];
+    LTP_pred_Q13   = 0;
+
+    /* load a_Q12 */
+    xmm_one = _mm_set_epi8( 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 );
+
+    /* load a_Q12[0] - a_Q12[7] */
+    a_Q12_01234567 = _mm_loadu_si128( (__m128i *)(&a_Q12[ 0 ] ) );
+    /* load a_Q12[ 8 ] - a_Q12[ 15 ] */
+    a_Q12_89ABCDEF = _mm_loadu_si128( (__m128i *)(&a_Q12[ 8 ] ) );
+
+    a_Q12_01234567 = _mm_shuffle_epi8( a_Q12_01234567, xmm_one );
+    a_Q12_89ABCDEF = _mm_shuffle_epi8( a_Q12_89ABCDEF, xmm_one );
+
+    /* load AR_shp_Q13 */
+    AR_shp_Q13_76543210 = _mm_loadu_si128( (__m128i *)(&AR_shp_Q13[0] ) );
+
+    /* load psLPC_Q14 */
+    xmm_one = _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0 );
+
+    xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-16]) );
+    xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-12]) );
+
+    xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one );
+    xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one );
+
+    psLPC_Q14_hi_89ABCDEF = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb );
+    psLPC_Q14_lo_89ABCDEF = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb );
+
+    xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -8 ]) );
+    xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -4 ]) );
+
+    xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one );
+    xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one );
+
+    psLPC_Q14_hi_01234567 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb );
+    psLPC_Q14_lo_01234567 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb );
+
+    /* load sAR2_Q14 */
+    xmm_tempa = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 0 ]) ) );
+    xmm_tempb = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 4 ]) ) );
+
+    xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one );
+    xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one );
+
+    sAR2_Q14_hi_76543210 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb );
+    sAR2_Q14_lo_76543210 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb );
+
+    /* prepare 1 in 8 * 16bit */
+    xmm_one = _mm_set1_epi16(1);
+
+    for( i = 0; i < length; i++ )
+    {
+        /* Short-term prediction */
+        __m128i xmm_hi_07, xmm_hi_8F, xmm_lo_07, xmm_lo_8F;
+
+        /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+        LPC_pred_Q10 = 8; /* silk_RSHIFT( predictLPCOrder, 1 ); */
+
+        /* shift psLPC_Q14 */
+        psLPC_Q14_hi_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF, 2 );
+        psLPC_Q14_lo_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF, 2 );
+
+        psLPC_Q14_hi_01234567 = _mm_srli_si128( psLPC_Q14_hi_01234567, 2 );
+        psLPC_Q14_lo_01234567 = _mm_srli_si128( psLPC_Q14_lo_01234567, 2 );
+
+        psLPC_Q14_hi_01234567 = _mm_insert_epi16( psLPC_Q14_hi_01234567, (xq_Q14 >> 16), 7 );
+        psLPC_Q14_lo_01234567 = _mm_insert_epi16( psLPC_Q14_lo_01234567, (xq_Q14),       7 );
+
+        /* high part, use pmaddwd, results in 4 32-bit */
+        xmm_hi_07 = _mm_madd_epi16( psLPC_Q14_hi_01234567, a_Q12_01234567 );
+        xmm_hi_8F = _mm_madd_epi16( psLPC_Q14_hi_89ABCDEF, a_Q12_89ABCDEF );
+
+        /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed, _mm_srai_epi16(psLPC_Q14_lo_01234567, 15) */
+        xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_01234567 );
+        xmm_tempb = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_89ABCDEF );
+
+        xmm_tempa = _mm_and_si128( xmm_tempa, a_Q12_01234567 );
+        xmm_tempb = _mm_and_si128( xmm_tempb, a_Q12_89ABCDEF );
+
+        xmm_lo_07 = _mm_mulhi_epi16( psLPC_Q14_lo_01234567, a_Q12_01234567 );
+        xmm_lo_8F = _mm_mulhi_epi16( psLPC_Q14_lo_89ABCDEF, a_Q12_89ABCDEF );
+
+        xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa );
+        xmm_lo_8F = _mm_add_epi16( xmm_lo_8F, xmm_tempb );
+
+        xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one );
+        xmm_lo_8F = _mm_madd_epi16( xmm_lo_8F, xmm_one );
+
+        /* accumulate */
+        xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_hi_8F );
+        xmm_lo_07 = _mm_add_epi32( xmm_lo_07, xmm_lo_8F );
+
+        xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 );
+
+        xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) );
+        xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) );
+
+        LPC_pred_Q10 += _mm_cvtsi128_si32( xmm_hi_07 );
+
+        /* Long-term prediction */
+        if ( opus_likely( signalType == TYPE_VOICED ) ) {
+            /* Unrolled loop */
+            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+            LTP_pred_Q13 = 2;
+            {
+                __m128i b_Q14_3210, b_Q14_0123, pred_lag_ptr_0123;
+
+                b_Q14_3210 = OP_CVTEPI16_EPI32_M64( b_Q14 );
+                b_Q14_0123 = _mm_shuffle_epi32( b_Q14_3210, 0x1B );
+
+                /* loaded: [0] [-1] [-2] [-3] */
+                pred_lag_ptr_0123 = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) );
+                /* shuffle to [-3] [-2] [-1] [0] and to new xmm */
+                xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, 0x1B );
+                /*64-bit multiply, a[2] * b[-2], a[0] * b[0] */
+                xmm_tempa = _mm_mul_epi32( xmm_tempa, b_Q14_3210 );
+                /* right shift 2 bytes (16 bits), zero extended */
+                xmm_tempa = _mm_srli_si128( xmm_tempa, 2 );
+
+                /* a[1] * b[-1], a[3] * b[-3] */
+                pred_lag_ptr_0123 = _mm_mul_epi32( pred_lag_ptr_0123, b_Q14_0123 );
+                pred_lag_ptr_0123 = _mm_srli_si128( pred_lag_ptr_0123, 2 );
+
+                pred_lag_ptr_0123 = _mm_add_epi32( pred_lag_ptr_0123, xmm_tempa );
+                /* equal shift right 8 bytes*/
+                xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, _MM_SHUFFLE( 0, 0, 3, 2 ) );
+                xmm_tempa = _mm_add_epi32( xmm_tempa, pred_lag_ptr_0123 );
+
+                LTP_pred_Q13 += _mm_cvtsi128_si32( xmm_tempa );
+
+                LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+                pred_lag_ptr++;
+            }
+        }
+
+        /* Noise shape feedback */
+        NSQ->sAR2_Q14[ 9 ] = NSQ->sAR2_Q14[ 8 ];
+        NSQ->sAR2_Q14[ 8 ] = _mm_cvtsi128_si32( _mm_srli_si128(_mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ), 12 ) );
+
+        sAR2_Q14_hi_76543210 = _mm_slli_si128( sAR2_Q14_hi_76543210, 2 );
+        sAR2_Q14_lo_76543210 = _mm_slli_si128( sAR2_Q14_lo_76543210, 2 );
+
+        sAR2_Q14_hi_76543210 = _mm_insert_epi16( sAR2_Q14_hi_76543210, (xq_Q14 >> 16), 0 );
+        sAR2_Q14_lo_76543210 = _mm_insert_epi16( sAR2_Q14_lo_76543210, (xq_Q14),       0 );
+
+        /* high part, use pmaddwd, results in 4 32-bit */
+        xmm_hi_07 = _mm_madd_epi16( sAR2_Q14_hi_76543210, AR_shp_Q13_76543210 );
+
+        /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed,_mm_srai_epi16(sAR2_Q14_lo_76543210, 15) */
+        xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), sAR2_Q14_lo_76543210 );
+        xmm_tempa = _mm_and_si128( xmm_tempa, AR_shp_Q13_76543210 );
+
+        xmm_lo_07 = _mm_mulhi_epi16( sAR2_Q14_lo_76543210, AR_shp_Q13_76543210 );
+        xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa );
+
+        xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one );
+
+        /* accumulate */
+        xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 );
+
+        xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) );
+        xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) );
+
+        n_AR_Q12 = 5 + _mm_cvtsi128_si32( xmm_hi_07 );
+
+        n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 8 ], AR_shp_Q13[ 8 ] );
+        n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 9 ], AR_shp_Q13[ 9 ] );
+
+        n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 );                                /* Q11 -> Q12 */
+        n_AR_Q12 = silk_SMLAWB( n_AR_Q12, sLF_AR_shp_Q14, Tilt_Q14 );
+
+        n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 );
+        n_LF_Q12 = silk_SMLAWT( n_LF_Q12, sLF_AR_shp_Q14, LF_shp_Q14 );
+
+        silk_assert( lag > 0 || signalType != TYPE_VOICED );
+
+        /* Combine prediction and noise shaping signals */
+        tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 );        /* Q12 */
+        tmp1 = silk_SUB32( tmp1, n_LF_Q12 );                                    /* Q12 */
+        if( lag > 0 ) {
+            /* Symmetric, packed FIR coefficients */
+            n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+            n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ],                      HarmShapeFIRPacked_Q14 );
+            n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 );
+            shp_lag_ptr++;
+
+            tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 );                       /* Q13 */
+            tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 );                          /* Q13 */
+            tmp1 = silk_RSHIFT_ROUND( tmp1, 3 );                                /* Q10 */
+        } else {
+            tmp1 = silk_RSHIFT_ROUND( tmp1, 2 );                                /* Q10 */
+        }
+
+        r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 );                              /* residual error Q10 */
+
+        /* Generate dither */
+        NSQ->rand_seed = silk_RAND( NSQ->rand_seed );
+
+        /* Flip sign depending on dither */
+        tmp2 = -r_Q10;
+        if ( NSQ->rand_seed < 0 ) r_Q10 = tmp2;
+
+        r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+        /* Find two quantization level candidates and measure their rate-distortion */
+        q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+        q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+
+        q1_Q10 = table[q1_Q0][0];
+        q2_Q10 = table[q1_Q0][1];
+
+        if (r_Q10 * table[q1_Q0][2] - table[q1_Q0][3] < 0)
+        {
+            q1_Q10 = q2_Q10;
+        }
+
+        pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 );
+
+        /* Excitation */
+        exc_Q14 = silk_LSHIFT( q1_Q10, 4 );
+
+        tmp2 = -exc_Q14;
+        if ( NSQ->rand_seed < 0 ) exc_Q14 = tmp2;
+
+        /* Add predictions */
+        LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 );
+        xq_Q14      = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 );
+
+        /* Update states */
+        psLPC_Q14++;
+        *psLPC_Q14 = xq_Q14;
+        sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 );
+
+        NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 );
+        sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 );
+        NSQ->sLTP_shp_buf_idx++;
+        NSQ->sLTP_buf_idx++;
+
+        /* Make dither dependent on quantized signal */
+        NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] );
+    }
+
+    NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14;
+
+    /* Scale XQ back to normal level before saving */
+    psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH ];
+
+    /* write back sAR2_Q14 */
+    xmm_tempa = _mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 );
+    xmm_tempb = _mm_unpacklo_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 );
+    _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 4 ]), xmm_tempa );
+    _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 0 ]), xmm_tempb );
+
+    /* xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) ); */
+    {
+        __m128i xmm_Gain_Q10;
+        __m128i xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, xmm_xq_Q14_7654, xmm_xq_Q14_x7x5;
+
+        /* prepare (1 << 7) in packed 4 32-bits */
+        xmm_tempa = _mm_set1_epi32( (1 << 7) );
+
+        /* prepare Gain_Q10 in packed 4 32-bits */
+        xmm_Gain_Q10 = _mm_set1_epi32( Gain_Q10 );
+
+        /* process xq */
+        for (i = 0; i < length - 7; i += 8)
+        {
+            xmm_xq_Q14_3210 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 0 ] ) ) );
+            xmm_xq_Q14_7654 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 4 ] ) ) );
+
+            /* equal shift right 4 bytes*/
+            xmm_xq_Q14_x3x1 = _mm_shuffle_epi32( xmm_xq_Q14_3210, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+            /* equal shift right 4 bytes*/
+            xmm_xq_Q14_x7x5 = _mm_shuffle_epi32( xmm_xq_Q14_7654, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+            xmm_xq_Q14_3210 = _mm_mul_epi32( xmm_xq_Q14_3210, xmm_Gain_Q10 );
+            xmm_xq_Q14_x3x1 = _mm_mul_epi32( xmm_xq_Q14_x3x1, xmm_Gain_Q10 );
+            xmm_xq_Q14_7654 = _mm_mul_epi32( xmm_xq_Q14_7654, xmm_Gain_Q10 );
+            xmm_xq_Q14_x7x5 = _mm_mul_epi32( xmm_xq_Q14_x7x5, xmm_Gain_Q10 );
+
+            xmm_xq_Q14_3210 = _mm_srli_epi64( xmm_xq_Q14_3210, 16 );
+            xmm_xq_Q14_x3x1 = _mm_slli_epi64( xmm_xq_Q14_x3x1, 16 );
+            xmm_xq_Q14_7654 = _mm_srli_epi64( xmm_xq_Q14_7654, 16 );
+            xmm_xq_Q14_x7x5 = _mm_slli_epi64( xmm_xq_Q14_x7x5, 16 );
+
+            xmm_xq_Q14_3210 = _mm_blend_epi16( xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, 0xCC );
+            xmm_xq_Q14_7654 = _mm_blend_epi16( xmm_xq_Q14_7654, xmm_xq_Q14_x7x5, 0xCC );
+
+            /* silk_RSHIFT_ROUND(xq, 8) */
+            xmm_xq_Q14_3210 = _mm_add_epi32( xmm_xq_Q14_3210, xmm_tempa );
+            xmm_xq_Q14_7654 = _mm_add_epi32( xmm_xq_Q14_7654, xmm_tempa );
+
+            xmm_xq_Q14_3210 = _mm_srai_epi32( xmm_xq_Q14_3210, 8 );
+            xmm_xq_Q14_7654 = _mm_srai_epi32( xmm_xq_Q14_7654, 8 );
+
+            /* silk_SAT16 */
+            xmm_xq_Q14_3210 = _mm_packs_epi32( xmm_xq_Q14_3210, xmm_xq_Q14_7654 );
+
+            /* save to xq */
+            _mm_storeu_si128( (__m128i *)(&xq[ i ] ), xmm_xq_Q14_3210 );
+        }
+    }
+    for ( ; i < length; i++)
+    {
+        xq[i] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) );
+    }
+
+    /* Update LPC synth buffer */
+    silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+}
+
+static OPUS_INLINE void silk_nsq_scale_states_sse4_1(
+    const silk_encoder_state *psEncC,           /* I    Encoder State                   */
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    const opus_int32    x_Q3[],                 /* I    input in Q3                     */
+    opus_int32          x_sc_Q10[],             /* O    input scaled with 1/Gain        */
+    const opus_int16    sLTP[],                 /* I    re-whitened LTP state in Q0     */
+    opus_int32          sLTP_Q15[],             /* O    LTP state matching scaled input */
+    opus_int            subfr,                  /* I    subframe number                 */
+    const opus_int      LTP_scale_Q14,          /* I                                    */
+    const opus_int32    Gains_Q16[ MAX_NB_SUBFR ], /* I                                 */
+    const opus_int      pitchL[ MAX_NB_SUBFR ], /* I    Pitch lag                       */
+    const opus_int      signal_type             /* I    Signal type                     */
+)
+{
+    opus_int   i, lag;
+    opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+    __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1;
+
+    lag          = pitchL[ subfr ];
+    inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+    silk_assert( inv_gain_Q31 != 0 );
+
+    /* Calculate gain adjustment factor */
+    if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+        gain_adj_Q16 =  silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+    } else {
+        gain_adj_Q16 = (opus_int32)1 << 16;
+    }
+
+    /* Scale input */
+    inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+
+    /* prepare inv_gain_Q23 in packed 4 32-bits */
+    xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23);
+
+    for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) {
+        xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) );
+
+        /* equal shift right 4 bytes*/
+        xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+        xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 );
+        xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 );
+
+        xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 );
+        xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 );
+
+        xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC );
+
+        _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ] ) ), xmm_x_Q3_x2x0 );
+    }
+
+    for( ; i < psEncC->subfr_length; i++ ) {
+        x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+    }
+
+    /* Save inverse gain */
+    NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+    /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+    if( NSQ->rewhite_flag ) {
+        if( subfr == 0 ) {
+            /* Do LTP downscaling */
+            inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+        }
+        for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+            silk_assert( i < MAX_FRAME_LENGTH );
+            sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+        }
+    }
+
+    /* Adjust for changing gain */
+    if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+        /* Scale long-term shaping state */
+        __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1;
+
+        /* prepare gain_adj_Q16 in packed 4 32-bits */
+        xmm_gain_adj_Q16 = _mm_set1_epi32(gain_adj_Q16);
+
+        for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 )
+        {
+            xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) );
+            /* equal shift right 4 bytes*/
+            xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+            xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 );
+            xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 );
+
+            xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 );
+            xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 );
+
+            xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC );
+
+            _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 );
+        }
+
+        for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+            NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+        }
+
+        /* Scale long-term prediction state */
+        if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+            for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+                sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+            }
+        }
+
+        NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 );
+
+        /* Scale short-term prediction and shaping states */
+        for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+            NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] );
+        }
+        for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+            NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] );
+        }
+    }
+}
diff --git a/third_party/opus/src/silk/x86/SigProc_FIX_sse.h b/third_party/opus/src/silk/x86/SigProc_FIX_sse.h
new file mode 100644
index 0000000..61efa8d
--- /dev/null
+++ b/third_party/opus/src/silk/x86/SigProc_FIX_sse.h
@@ -0,0 +1,94 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SIGPROC_FIX_SSE_H
+#define SIGPROC_FIX_SSE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+void silk_burg_modified_sse4_1(
+    opus_int32                  *res_nrg,           /* O    Residual energy                                             */
+    opus_int                    *res_nrg_Q,         /* O    Residual energy Q value                                     */
+    opus_int32                  A_Q16[],            /* O    Prediction coefficients (length order)                      */
+    const opus_int16            x[],                /* I    Input signal, length: nb_subfr * ( D + subfr_length )       */
+    const opus_int32            minInvGain_Q30,     /* I    Inverse of max prediction gain                              */
+    const opus_int              subfr_length,       /* I    Input signal subframe length (incl. D preceding samples)    */
+    const opus_int              nb_subfr,           /* I    Number of subframes stacked in x                            */
+    const opus_int              D,                  /* I    Order                                                       */
+    int                         arch                /* I    Run-time architecture                                       */
+);
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \
+    ((void)(arch), silk_burg_modified_sse4_1(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch))
+
+#else
+
+extern void (*const SILK_BURG_MODIFIED_IMPL[OPUS_ARCHMASK + 1])(
+    opus_int32                  *res_nrg,           /* O    Residual energy                                             */
+    opus_int                    *res_nrg_Q,         /* O    Residual energy Q value                                     */
+    opus_int32                  A_Q16[],            /* O    Prediction coefficients (length order)                      */
+    const opus_int16            x[],                /* I    Input signal, length: nb_subfr * ( D + subfr_length )       */
+    const opus_int32            minInvGain_Q30,     /* I    Inverse of max prediction gain                              */
+    const opus_int              subfr_length,       /* I    Input signal subframe length (incl. D preceding samples)    */
+    const opus_int              nb_subfr,           /* I    Number of subframes stacked in x                            */
+    const opus_int              D,                  /* I    Order                                                       */
+    int                         arch                /* I    Run-time architecture                                       */);
+
+#  define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \
+    ((*SILK_BURG_MODIFIED_IMPL[(arch) & OPUS_ARCHMASK])(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch))
+
+#endif
+
+opus_int64 silk_inner_prod16_aligned_64_sse4_1(
+    const opus_int16 *inVec1,
+    const opus_int16 *inVec2,
+    const opus_int   len
+);
+
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+
+#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \
+    ((void)(arch),silk_inner_prod16_aligned_64_sse4_1(inVec1, inVec2, len))
+
+#else
+
+extern opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[OPUS_ARCHMASK + 1])(
+                    const opus_int16 *inVec1,
+                    const opus_int16 *inVec2,
+                    const opus_int   len);
+
+#  define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \
+    ((*SILK_INNER_PROD16_ALIGNED_64_IMPL[(arch) & OPUS_ARCHMASK])(inVec1, inVec2, len))
+
+#endif
+#endif
+#endif
diff --git a/third_party/opus/src/silk/x86/VAD_sse.c b/third_party/opus/src/silk/x86/VAD_sse.c
new file mode 100644
index 0000000..4e90f44
--- /dev/null
+++ b/third_party/opus/src/silk/x86/VAD_sse.c
@@ -0,0 +1,277 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Weighting factors for tilt measure */
+static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 };
+
+/***************************************/
+/* Get the speech activity level in Q8 */
+/***************************************/
+opus_int silk_VAD_GetSA_Q8_sse4_1(                  /* O    Return value, 0 if success                  */
+    silk_encoder_state          *psEncC,            /* I/O  Encoder state                               */
+    const opus_int16            pIn[]               /* I    PCM input                                   */
+)
+{
+    opus_int   SA_Q15, pSNR_dB_Q7, input_tilt;
+    opus_int   decimated_framelength1, decimated_framelength2;
+    opus_int   decimated_framelength;
+    opus_int   dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
+    opus_int32 sumSquared, smooth_coef_Q16;
+    opus_int16 HPstateTmp;
+    VARDECL( opus_int16, X );
+    opus_int32 Xnrg[ VAD_N_BANDS ];
+    opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ];
+    opus_int32 speech_nrg, x_tmp;
+    opus_int   X_offset[ VAD_N_BANDS ];
+    opus_int   ret = 0;
+    silk_VAD_state *psSilk_VAD = &psEncC->sVAD;
+
+    SAVE_STACK;
+
+    /* Safety checks */
+    silk_assert( VAD_N_BANDS == 4 );
+    silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length );
+    silk_assert( psEncC->frame_length <= 512 );
+    silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) );
+
+    /***********************/
+    /* Filter and Decimate */
+    /***********************/
+    decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 );
+    decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 );
+    decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 );
+    /* Decimate into 4 bands:
+       0       L      3L       L              3L                             5L
+               -      --       -              --                             --
+               8       8       2               4                              4
+
+       [0-1 kHz| temp. |1-2 kHz|    2-4 kHz    |            4-8 kHz           |
+
+       They're arranged to allow the minimal ( frame_length / 4 ) extra
+       scratch space during the downsampling process */
+    X_offset[ 0 ] = 0;
+    X_offset[ 1 ] = decimated_framelength + decimated_framelength2;
+    X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength;
+    X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2;
+    ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 );
+
+    /* 0-8 kHz to 0-4 kHz and 4-8 kHz */
+    silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[  0 ],
+        X, &X[ X_offset[ 3 ] ], psEncC->frame_length );
+
+    /* 0-4 kHz to 0-2 kHz and 2-4 kHz */
+    silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ],
+        X, &X[ X_offset[ 2 ] ], decimated_framelength1 );
+
+    /* 0-2 kHz to 0-1 kHz and 1-2 kHz */
+    silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ],
+        X, &X[ X_offset[ 1 ] ], decimated_framelength2 );
+
+    /*********************************************/
+    /* HP filter on lowest band (differentiator) */
+    /*********************************************/
+    X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 );
+    HPstateTmp = X[ decimated_framelength - 1 ];
+    for( i = decimated_framelength - 1; i > 0; i-- ) {
+        X[ i - 1 ]  = silk_RSHIFT( X[ i - 1 ], 1 );
+        X[ i ]     -= X[ i - 1 ];
+    }
+    X[ 0 ] -= psSilk_VAD->HPstate;
+    psSilk_VAD->HPstate = HPstateTmp;
+
+    /*************************************/
+    /* Calculate the energy in each band */
+    /*************************************/
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        /* Find the decimated framelength in the non-uniformly divided bands */
+        decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) );
+
+        /* Split length into subframe lengths */
+        dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 );
+        dec_subframe_offset = 0;
+
+        /* Compute energy per sub-frame */
+        /* initialize with summed energy of last subframe */
+        Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ];
+        for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) {
+            __m128i xmm_X, xmm_acc;
+            sumSquared = 0;
+
+            xmm_acc = _mm_setzero_si128();
+
+            for( i = 0; i < dec_subframe_length - 7; i += 8 )
+            {
+                xmm_X   = _mm_loadu_si128( (__m128i *)&(X[ X_offset[ b ] + i + dec_subframe_offset ] ) );
+                xmm_X   = _mm_srai_epi16( xmm_X, 3 );
+                xmm_X   = _mm_madd_epi16( xmm_X, xmm_X );
+                xmm_acc = _mm_add_epi32( xmm_acc, xmm_X );
+            }
+
+            xmm_acc = _mm_add_epi32( xmm_acc, _mm_unpackhi_epi64( xmm_acc, xmm_acc ) );
+            xmm_acc = _mm_add_epi32( xmm_acc, _mm_shufflelo_epi16( xmm_acc, 0x0E ) );
+
+            sumSquared += _mm_cvtsi128_si32( xmm_acc );
+
+            for( ; i < dec_subframe_length; i++ ) {
+                /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2.            */
+                /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128)  */
+                x_tmp = silk_RSHIFT(
+                    X[ X_offset[ b ] + i + dec_subframe_offset ], 3 );
+                sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp );
+
+                /* Safety check */
+                silk_assert( sumSquared >= 0 );
+            }
+
+            /* Add/saturate summed energy of current subframe */
+            if( s < VAD_INTERNAL_SUBFRAMES - 1 ) {
+                Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared );
+            } else {
+                /* Look-ahead subframe */
+                Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) );
+            }
+
+            dec_subframe_offset += dec_subframe_length;
+        }
+        psSilk_VAD->XnrgSubfr[ b ] = sumSquared;
+    }
+
+    /********************/
+    /* Noise estimation */
+    /********************/
+    silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD );
+
+    /***********************************************/
+    /* Signal-plus-noise to noise ratio estimation */
+    /***********************************************/
+    sumSquared = 0;
+    input_tilt = 0;
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ];
+        if( speech_nrg > 0 ) {
+            /* Divide, with sufficient resolution */
+            if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) {
+                NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 );
+            } else {
+                NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 );
+            }
+
+            /* Convert to log domain */
+            SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128;
+
+            /* Sum-of-squares */
+            sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 );          /* Q14 */
+
+            /* Tilt measure */
+            if( speech_nrg < ( (opus_int32)1 << 20 ) ) {
+                /* Scale down SNR value for small subband speech energies */
+                SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 );
+            }
+            input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 );
+        } else {
+            NrgToNoiseRatio_Q8[ b ] = 256;
+        }
+    }
+
+    /* Mean-of-squares */
+    sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */
+
+    /* Root-mean-square approximation, scale to dBs, and write to output pointer */
+    pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */
+
+    /*********************************/
+    /* Speech Probability Estimation */
+    /*********************************/
+    SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 );
+
+    /**************************/
+    /* Frequency Tilt Measure */
+    /**************************/
+    psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 );
+
+    /**************************************************/
+    /* Scale the sigmoid output based on power levels */
+    /**************************************************/
+    speech_nrg = 0;
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        /* Accumulate signal-without-noise energies, higher frequency bands have more weight */
+        speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 );
+    }
+
+    /* Power scaling */
+    if( speech_nrg <= 0 ) {
+        SA_Q15 = silk_RSHIFT( SA_Q15, 1 );
+    } else if( speech_nrg < 32768 ) {
+        if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+            speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 );
+        } else {
+            speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 );
+        }
+
+        /* square-root */
+        speech_nrg = silk_SQRT_APPROX( speech_nrg );
+        SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 );
+    }
+
+    /* Copy the resulting speech activity in Q8 */
+    psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX );
+
+    /***********************************/
+    /* Energy Level and SNR estimation */
+    /***********************************/
+    /* Smoothing coefficient */
+    smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) );
+
+    if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+        smooth_coef_Q16 >>= 1;
+    }
+
+    for( b = 0; b < VAD_N_BANDS; b++ ) {
+        /* compute smoothed energy-to-noise ratio per band */
+        psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ],
+            NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 );
+
+        /* signal to noise ratio in dB per band */
+        SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 );
+        /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
+        psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) );
+    }
+
+    RESTORE_STACK;
+    return( ret );
+}
diff --git a/third_party/opus/src/silk/x86/VQ_WMat_EC_sse.c b/third_party/opus/src/silk/x86/VQ_WMat_EC_sse.c
new file mode 100644
index 0000000..74d6c6d0
--- /dev/null
+++ b/third_party/opus/src/silk/x86/VQ_WMat_EC_sse.c
@@ -0,0 +1,142 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#include "main.h"
+#include "celt/x86/x86cpu.h"
+
+/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
+void silk_VQ_WMat_EC_sse4_1(
+    opus_int8                   *ind,                           /* O    index of best codebook vector               */
+    opus_int32                  *rate_dist_Q14,                 /* O    best weighted quant error + mu * rate       */
+    opus_int                    *gain_Q7,                       /* O    sum of absolute LTP coefficients            */
+    const opus_int16            *in_Q14,                        /* I    input vector to be quantized                */
+    const opus_int32            *W_Q18,                         /* I    weighting matrix                            */
+    const opus_int8             *cb_Q7,                         /* I    codebook                                    */
+    const opus_uint8            *cb_gain_Q7,                    /* I    codebook effective gain                     */
+    const opus_uint8            *cl_Q5,                         /* I    code length for each codebook vector        */
+    const opus_int              mu_Q9,                          /* I    tradeoff betw. weighted error and rate      */
+    const opus_int32            max_gain_Q7,                    /* I    maximum sum of absolute LTP coefficients    */
+    opus_int                    L                               /* I    number of vectors in codebook               */
+)
+{
+    opus_int   k, gain_tmp_Q7;
+    const opus_int8 *cb_row_Q7;
+    opus_int16 diff_Q14[ 5 ];
+    opus_int32 sum1_Q14, sum2_Q16;
+
+    __m128i C_tmp1, C_tmp2, C_tmp3, C_tmp4, C_tmp5;
+    /* Loop over codebook */
+    *rate_dist_Q14 = silk_int32_MAX;
+    cb_row_Q7 = cb_Q7;
+    for( k = 0; k < L; k++ ) {
+        gain_tmp_Q7 = cb_gain_Q7[k];
+
+        diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 );
+
+        C_tmp1 = OP_CVTEPI16_EPI32_M64( &in_Q14[ 1 ] );
+        C_tmp2 = OP_CVTEPI8_EPI32_M32( &cb_row_Q7[ 1 ] );
+        C_tmp2 = _mm_slli_epi32( C_tmp2, 7 );
+        C_tmp1 = _mm_sub_epi32( C_tmp1, C_tmp2 );
+
+        diff_Q14[ 1 ] = _mm_extract_epi16( C_tmp1, 0 );
+        diff_Q14[ 2 ] = _mm_extract_epi16( C_tmp1, 2 );
+        diff_Q14[ 3 ] = _mm_extract_epi16( C_tmp1, 4 );
+        diff_Q14[ 4 ] = _mm_extract_epi16( C_tmp1, 6 );
+
+        /* Weighted rate */
+        sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] );
+
+        /* Penalty for too large gain */
+        sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 );
+
+        silk_assert( sum1_Q14 >= 0 );
+
+        /* first row of W_Q18 */
+        C_tmp3 = _mm_loadu_si128( (__m128i *)(&W_Q18[ 1 ] ) );
+        C_tmp4 = _mm_mul_epi32( C_tmp3, C_tmp1 );
+        C_tmp4 = _mm_srli_si128( C_tmp4, 2 );
+
+        C_tmp1 = _mm_shuffle_epi32( C_tmp1, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */
+        C_tmp3 = _mm_shuffle_epi32( C_tmp3, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */
+
+        C_tmp5 = _mm_mul_epi32( C_tmp3, C_tmp1 );
+        C_tmp5 = _mm_srli_si128( C_tmp5, 2 );
+
+        C_tmp5 = _mm_add_epi32( C_tmp4, C_tmp5 );
+        C_tmp5 = _mm_slli_epi32( C_tmp5, 1 );
+
+        C_tmp5 = _mm_add_epi32( C_tmp5, _mm_shuffle_epi32( C_tmp5, _MM_SHUFFLE( 0, 0, 0, 2 ) ) );
+        sum2_Q16 = _mm_cvtsi128_si32( C_tmp5 );
+
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  0 ], diff_Q14[ 0 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 0 ] );
+
+        /* second row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[  7 ], diff_Q14[ 2 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  8 ], diff_Q14[ 3 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  9 ], diff_Q14[ 4 ] );
+        sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[  6 ], diff_Q14[ 1 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 1 ] );
+
+        /* third row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[ 13 ], diff_Q14[ 3 ] );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] );
+        sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 2 ] );
+
+        /* fourth row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[ 19 ], diff_Q14[ 4 ] );
+        sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+        sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 3 ] );
+
+        /* last row of W_Q18 */
+        sum2_Q16 = silk_SMULWB(           W_Q18[ 24 ], diff_Q14[ 4 ] );
+        sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16,    diff_Q14[ 4 ] );
+
+        silk_assert( sum1_Q14 >= 0 );
+
+        /* find best */
+        if( sum1_Q14 < *rate_dist_Q14 ) {
+            *rate_dist_Q14 = sum1_Q14;
+            *ind = (opus_int8)k;
+            *gain_Q7 = gain_tmp_Q7;
+        }
+
+        /* Go to next cbk vector */
+        cb_row_Q7 += LTP_ORDER;
+    }
+}
diff --git a/third_party/opus/src/silk/x86/main_sse.h b/third_party/opus/src/silk/x86/main_sse.h
new file mode 100644
index 0000000..d8d6131
--- /dev/null
+++ b/third_party/opus/src/silk/x86/main_sse.h
@@ -0,0 +1,277 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MAIN_SSE_H
+#define MAIN_SSE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+# if defined(OPUS_X86_MAY_HAVE_SSE4_1)
+
+#  define OVERRIDE_silk_VQ_WMat_EC
+
+void silk_VQ_WMat_EC_sse4_1(
+    opus_int8                   *ind,                           /* O    index of best codebook vector               */
+    opus_int32                  *rate_dist_Q14,                 /* O    best weighted quant error + mu * rate       */
+    opus_int                    *gain_Q7,                       /* O    sum of absolute LTP coefficients            */
+    const opus_int16            *in_Q14,                        /* I    input vector to be quantized                */
+    const opus_int32            *W_Q18,                         /* I    weighting matrix                            */
+    const opus_int8             *cb_Q7,                         /* I    codebook                                    */
+    const opus_uint8            *cb_gain_Q7,                    /* I    codebook effective gain                     */
+    const opus_uint8            *cl_Q5,                         /* I    code length for each codebook vector        */
+    const opus_int              mu_Q9,                          /* I    tradeoff betw. weighted error and rate      */
+    const opus_int32            max_gain_Q7,                    /* I    maximum sum of absolute LTP coefficients    */
+    opus_int                    L                               /* I    number of vectors in codebook               */
+);
+
+#if defined OPUS_X86_PRESUME_SSE4_1
+
+#define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+                          mu_Q9, max_gain_Q7, L, arch) \
+    ((void)(arch),silk_VQ_WMat_EC_sse4_1(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+                          mu_Q9, max_gain_Q7, L))
+
+#else
+
+extern void (*const SILK_VQ_WMAT_EC_IMPL[OPUS_ARCHMASK + 1])(
+    opus_int8                   *ind,                           /* O    index of best codebook vector               */
+    opus_int32                  *rate_dist_Q14,                 /* O    best weighted quant error + mu * rate       */
+    opus_int                    *gain_Q7,                       /* O    sum of absolute LTP coefficients            */
+    const opus_int16            *in_Q14,                        /* I    input vector to be quantized                */
+    const opus_int32            *W_Q18,                         /* I    weighting matrix                            */
+    const opus_int8             *cb_Q7,                         /* I    codebook                                    */
+    const opus_uint8            *cb_gain_Q7,                    /* I    codebook effective gain                     */
+    const opus_uint8            *cl_Q5,                         /* I    code length for each codebook vector        */
+    const opus_int              mu_Q9,                          /* I    tradeoff betw. weighted error and rate      */
+    const opus_int32            max_gain_Q7,                    /* I    maximum sum of absolute LTP coefficients    */
+    opus_int                    L                               /* I    number of vectors in codebook               */
+);
+
+#  define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+                          mu_Q9, max_gain_Q7, L, arch) \
+    ((*SILK_VQ_WMAT_EC_IMPL[(arch) & OPUS_ARCHMASK])(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \
+                          mu_Q9, max_gain_Q7, L))
+
+#endif
+
+#  define OVERRIDE_silk_NSQ
+
+void silk_NSQ_sse4_1(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+);
+
+#if defined OPUS_X86_PRESUME_SSE4_1
+
+#define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                   HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+    ((void)(arch),silk_NSQ_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                   HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+
+#else
+
+extern void (*const SILK_NSQ_IMPL[OPUS_ARCHMASK + 1])(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+);
+
+#  define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                   HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+    ((*SILK_NSQ_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                   HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+
+#endif
+
+#  define OVERRIDE_silk_NSQ_del_dec
+
+void silk_NSQ_del_dec_sse4_1(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+);
+
+#if defined OPUS_X86_PRESUME_SSE4_1
+
+#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                           HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+    ((void)(arch),silk_NSQ_del_dec_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                           HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+
+#else
+
+extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+);
+
+#  define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                           HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \
+    ((*SILK_NSQ_DEL_DEC_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \
+                           HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14))
+
+#endif
+
+void silk_noise_shape_quantizer(
+    silk_nsq_state      *NSQ,                   /* I/O  NSQ state                       */
+    opus_int            signalType,             /* I    Signal type                     */
+    const opus_int32    x_sc_Q10[],             /* I                                    */
+    opus_int8           pulses[],               /* O                                    */
+    opus_int16          xq[],                   /* O                                    */
+    opus_int32          sLTP_Q15[],             /* I/O  LTP state                       */
+    const opus_int16    a_Q12[],                /* I    Short term prediction coefs     */
+    const opus_int16    b_Q14[],                /* I    Long term prediction coefs      */
+    const opus_int16    AR_shp_Q13[],           /* I    Noise shaping AR coefs          */
+    opus_int            lag,                    /* I    Pitch lag                       */
+    opus_int32          HarmShapeFIRPacked_Q14, /* I                                    */
+    opus_int            Tilt_Q14,               /* I    Spectral tilt                   */
+    opus_int32          LF_shp_Q14,             /* I                                    */
+    opus_int32          Gain_Q16,               /* I                                    */
+    opus_int            Lambda_Q10,             /* I                                    */
+    opus_int            offset_Q10,             /* I                                    */
+    opus_int            length,                 /* I    Input length                    */
+    opus_int            shapingLPCOrder,        /* I    Noise shaping AR filter order   */
+    opus_int            predictLPCOrder,        /* I    Prediction filter order         */
+    int                 arch                    /* I    Architecture                    */
+);
+
+/**************************/
+/* Noise level estimation */
+/**************************/
+void silk_VAD_GetNoiseLevels(
+    const opus_int32            pX[ VAD_N_BANDS ],  /* I    subband energies                            */
+    silk_VAD_state              *psSilk_VAD         /* I/O  Pointer to Silk VAD state                   */
+);
+
+#  define OVERRIDE_silk_VAD_GetSA_Q8
+
+opus_int silk_VAD_GetSA_Q8_sse4_1(
+    silk_encoder_state *psEnC,
+    const opus_int16   pIn[]
+);
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_sse4_1(psEnC, pIn))
+
+#else
+
+#  define silk_VAD_GetSA_Q8(psEnC, pIn, arch) \
+     ((*SILK_VAD_GETSA_Q8_IMPL[(arch) & OPUS_ARCHMASK])(psEnC, pIn))
+
+extern opus_int (*const SILK_VAD_GETSA_Q8_IMPL[OPUS_ARCHMASK + 1])(
+     silk_encoder_state *psEnC,
+     const opus_int16   pIn[]);
+
+#  define OVERRIDE_silk_warped_LPC_analysis_filter_FIX
+
+#endif
+
+void silk_warped_LPC_analysis_filter_FIX_sse4_1(
+          opus_int32            state[],                    /* I/O  State [order + 1]                   */
+          opus_int32            res_Q2[],                   /* O    Residual signal [length]            */
+    const opus_int16            coef_Q13[],                 /* I    Coefficients [order]                */
+    const opus_int16            input[],                    /* I    Input signal [length]               */
+    const opus_int16            lambda_Q16,                 /* I    Warping factor                      */
+    const opus_int              length,                     /* I    Length of input signal              */
+    const opus_int              order                       /* I    Filter order (even)                 */
+);
+
+#if defined(OPUS_X86_PRESUME_SSE4_1)
+#define silk_warped_LPC_analysis_filter_FIX(state, res_Q2, coef_Q13, input, lambda_Q16, length, order, arch) \
+    ((void)(arch),silk_warped_LPC_analysis_filter_FIX_c(state, res_Q2, coef_Q13, input, lambda_Q16, length, order))
+
+#else
+
+extern void (*const SILK_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[OPUS_ARCHMASK + 1])(
+          opus_int32            state[],                    /* I/O  State [order + 1]                   */
+          opus_int32            res_Q2[],                   /* O    Residual signal [length]            */
+    const opus_int16            coef_Q13[],                 /* I    Coefficients [order]                */
+    const opus_int16            input[],                    /* I    Input signal [length]               */
+    const opus_int16            lambda_Q16,                 /* I    Warping factor                      */
+    const opus_int              length,                     /* I    Length of input signal              */
+    const opus_int              order                       /* I    Filter order (even)                 */
+);
+
+#  define silk_warped_LPC_analysis_filter_FIX(state, res_Q2, coef_Q13, input, lambda_Q16, length, order, arch) \
+    ((*SILK_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[(arch) & OPUS_ARCHMASK])(state, res_Q2, coef_Q13, input, lambda_Q16, length, order))
+
+#endif
+
+# endif
+#endif
diff --git a/third_party/opus/src/silk/x86/x86_silk_map.c b/third_party/opus/src/silk/x86/x86_silk_map.c
new file mode 100644
index 0000000..818841f2
--- /dev/null
+++ b/third_party/opus/src/silk/x86/x86_silk_map.c
@@ -0,0 +1,174 @@
+/* Copyright (c) 2014, Cisco Systems, INC
+   Written by XiangMingZhu WeiZhou MinPeng YanWang
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include "celt/x86/x86cpu.h"
+#include "structs.h"
+#include "SigProc_FIX.h"
+#include "pitch.h"
+#include "main.h"
+
+#if !defined(OPUS_X86_PRESUME_SSE4_1)
+
+#if defined(FIXED_POINT)
+
+#include "fixed/main_FIX.h"
+
+opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[ OPUS_ARCHMASK + 1 ] )(
+    const opus_int16 *inVec1,
+    const opus_int16 *inVec2,
+    const opus_int   len
+) = {
+  silk_inner_prod16_aligned_64_c,                  /* non-sse */
+  silk_inner_prod16_aligned_64_c,
+  silk_inner_prod16_aligned_64_c,
+  MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ), /* sse4.1 */
+  MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 )  /* avx */
+};
+
+#endif
+
+opus_int (*const SILK_VAD_GETSA_Q8_IMPL[ OPUS_ARCHMASK + 1 ] )(
+    silk_encoder_state *psEncC,
+    const opus_int16   pIn[]
+) = {
+  silk_VAD_GetSA_Q8_c,                  /* non-sse */
+  silk_VAD_GetSA_Q8_c,
+  silk_VAD_GetSA_Q8_c,
+  MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ), /* sse4.1 */
+  MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 )  /* avx */
+};
+
+void (*const SILK_NSQ_IMPL[ OPUS_ARCHMASK + 1 ] )(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+) = {
+  silk_NSQ_c,                  /* non-sse */
+  silk_NSQ_c,
+  silk_NSQ_c,
+  MAY_HAVE_SSE4_1( silk_NSQ ), /* sse4.1 */
+  MAY_HAVE_SSE4_1( silk_NSQ )  /* avx */
+};
+
+void (*const SILK_VQ_WMAT_EC_IMPL[ OPUS_ARCHMASK + 1 ] )(
+    opus_int8                   *ind,                           /* O    index of best codebook vector               */
+    opus_int32                  *rate_dist_Q14,                 /* O    best weighted quant error + mu * rate       */
+    opus_int                    *gain_Q7,                       /* O    sum of absolute LTP coefficients            */
+    const opus_int16            *in_Q14,                        /* I    input vector to be quantized                */
+    const opus_int32            *W_Q18,                         /* I    weighting matrix                            */
+    const opus_int8             *cb_Q7,                         /* I    codebook                                    */
+    const opus_uint8            *cb_gain_Q7,                    /* I    codebook effective gain                     */
+    const opus_uint8            *cl_Q5,                         /* I    code length for each codebook vector        */
+    const opus_int              mu_Q9,                          /* I    tradeoff betw. weighted error and rate      */
+    const opus_int32            max_gain_Q7,                    /* I    maximum sum of absolute LTP coefficients    */
+    opus_int                    L                               /* I    number of vectors in codebook               */
+) = {
+  silk_VQ_WMat_EC_c,                  /* non-sse */
+  silk_VQ_WMat_EC_c,
+  silk_VQ_WMat_EC_c,
+  MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ), /* sse4.1 */
+  MAY_HAVE_SSE4_1( silk_VQ_WMat_EC )  /* avx */
+};
+
+void (*const SILK_NSQ_DEL_DEC_IMPL[ OPUS_ARCHMASK + 1 ] )(
+    const silk_encoder_state    *psEncC,                                    /* I/O  Encoder State                   */
+    silk_nsq_state              *NSQ,                                       /* I/O  NSQ state                       */
+    SideInfoIndices             *psIndices,                                 /* I/O  Quantization Indices            */
+    const opus_int32            x_Q3[],                                     /* I    Prefiltered input signal        */
+    opus_int8                   pulses[],                                   /* O    Quantized pulse signal          */
+    const opus_int16            PredCoef_Q12[ 2 * MAX_LPC_ORDER ],          /* I    Short term prediction coefs     */
+    const opus_int16            LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],    /* I    Long term prediction coefs      */
+    const opus_int16            AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs             */
+    const opus_int              HarmShapeGain_Q14[ MAX_NB_SUBFR ],          /* I    Long term shaping coefs         */
+    const opus_int              Tilt_Q14[ MAX_NB_SUBFR ],                   /* I    Spectral tilt                   */
+    const opus_int32            LF_shp_Q14[ MAX_NB_SUBFR ],                 /* I    Low frequency shaping coefs     */
+    const opus_int32            Gains_Q16[ MAX_NB_SUBFR ],                  /* I    Quantization step sizes         */
+    const opus_int              pitchL[ MAX_NB_SUBFR ],                     /* I    Pitch lags                      */
+    const opus_int              Lambda_Q10,                                 /* I    Rate/distortion tradeoff        */
+    const opus_int              LTP_scale_Q14                               /* I    LTP state scaling               */
+) = {
+  silk_NSQ_del_dec_c,                  /* non-sse */
+  silk_NSQ_del_dec_c,
+  silk_NSQ_del_dec_c,
+  MAY_HAVE_SSE4_1( silk_NSQ_del_dec ), /* sse4.1 */
+  MAY_HAVE_SSE4_1( silk_NSQ_del_dec )  /* avx */
+};
+
+#if defined(FIXED_POINT)
+
+void (*const SILK_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[ OPUS_ARCHMASK + 1 ] )(
+    opus_int32                  state[],                    /* I/O  State [order + 1]                   */
+    opus_int32                  res_Q2[],                   /* O    Residual signal [length]            */
+    const opus_int16            coef_Q13[],                 /* I    Coefficients [order]                */
+    const opus_int16            input[],                    /* I    Input signal [length]               */
+    const opus_int16            lambda_Q16,                 /* I    Warping factor                      */
+    const opus_int              length,                     /* I    Length of input signal              */
+    const opus_int              order                       /* I    Filter order (even)                 */
+) = {
+  silk_warped_LPC_analysis_filter_FIX_c,                  /* non-sse */
+  silk_warped_LPC_analysis_filter_FIX_c,
+  silk_warped_LPC_analysis_filter_FIX_c,
+  MAY_HAVE_SSE4_1( silk_warped_LPC_analysis_filter_FIX ), /* sse4.1 */
+  MAY_HAVE_SSE4_1( silk_warped_LPC_analysis_filter_FIX )  /* avx */
+};
+
+void (*const SILK_BURG_MODIFIED_IMPL[ OPUS_ARCHMASK + 1 ] )(
+    opus_int32                  *res_nrg,           /* O    Residual energy                                             */
+    opus_int                    *res_nrg_Q,         /* O    Residual energy Q value                                     */
+    opus_int32                  A_Q16[],            /* O    Prediction coefficients (length order)                      */
+    const opus_int16            x[],                /* I    Input signal, length: nb_subfr * ( D + subfr_length )       */
+    const opus_int32            minInvGain_Q30,     /* I    Inverse of max prediction gain                              */
+    const opus_int              subfr_length,       /* I    Input signal subframe length (incl. D preceding samples)    */
+    const opus_int              nb_subfr,           /* I    Number of subframes stacked in x                            */
+    const opus_int              D,                  /* I    Order                                                       */
+    int                         arch                /* I    Run-time architecture                                       */
+) = {
+  silk_burg_modified_c,                  /* non-sse */
+  silk_burg_modified_c,
+  silk_burg_modified_c,
+  MAY_HAVE_SSE4_1( silk_burg_modified ), /* sse4.1 */
+  MAY_HAVE_SSE4_1( silk_burg_modified )  /* avx */
+};
+
+#endif
+#endif
diff --git a/third_party/opus/src/src/analysis.c b/third_party/opus/src/src/analysis.c
new file mode 100644
index 0000000..663431a
--- /dev/null
+++ b/third_party/opus/src/src/analysis.c
@@ -0,0 +1,672 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "kiss_fft.h"
+#include "celt.h"
+#include "modes.h"
+#include "arch.h"
+#include "quant_bands.h"
+#include <stdio.h>
+#include "analysis.h"
+#include "mlp.h"
+#include "stack_alloc.h"
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+static const float dct_table[128] = {
+        0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+        0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+        0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f,
+       -0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f,
+        0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f,
+       -0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f,
+        0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f,
+        0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f,
+        0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
+        0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
+        0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f,
+       -0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f,
+        0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f,
+       -0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f,
+        0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f,
+        0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f,
+};
+
+static const float analysis_window[240] = {
+      0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f,
+      0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f,
+      0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f,
+      0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f,
+      0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
+      0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f,
+      0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f,
+      0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f,
+      0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f,
+      0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f,
+      0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f,
+      0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f,
+      0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f,
+      0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f,
+      0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f,
+      0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f,
+      0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f,
+      0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f,
+      0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f,
+      0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f,
+      0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f,
+      0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f,
+      0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f,
+      0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f,
+      0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f,
+      0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f,
+      0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f,
+      0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f,
+      0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f,
+      0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f,
+};
+
+static const int tbands[NB_TBANDS+1] = {
+       2,  4,  6,  8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120
+};
+
+static const int extra_bands[NB_TOT_BANDS+1] = {
+      1, 2,  4,  6,  8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200
+};
+
+/*static const float tweight[NB_TBANDS+1] = {
+      .3, .4, .5, .6, .7, .8, .9, 1., 1., 1., 1., 1., 1., 1., .8, .7, .6, .5
+};*/
+
+#define NB_TONAL_SKIP_BANDS 9
+
+#define cA 0.43157974f
+#define cB 0.67848403f
+#define cC 0.08595542f
+#define cE ((float)M_PI/2)
+static OPUS_INLINE float fast_atan2f(float y, float x) {
+   float x2, y2;
+   /* Should avoid underflow on the values we'll get */
+   if (ABS16(x)+ABS16(y)<1e-9f)
+   {
+      x*=1e12f;
+      y*=1e12f;
+   }
+   x2 = x*x;
+   y2 = y*y;
+   if(x2<y2){
+      float den = (y2 + cB*x2) * (y2 + cC*x2);
+      if (den!=0)
+         return -x*y*(y2 + cA*x2) / den + (y<0 ? -cE : cE);
+      else
+         return (y<0 ? -cE : cE);
+   }else{
+      float den = (x2 + cB*y2) * (x2 + cC*y2);
+      if (den!=0)
+         return  x*y*(x2 + cA*y2) / den + (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
+      else
+         return (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
+   }
+}
+
+void tonality_analysis_init(TonalityAnalysisState *tonal)
+{
+  /* Initialize reusable fields. */
+  tonal->arch = opus_select_arch();
+  /* Clear remaining fields. */
+  tonality_analysis_reset(tonal);
+}
+
+void tonality_analysis_reset(TonalityAnalysisState *tonal)
+{
+  /* Clear non-reusable fields. */
+  char *start = (char*)&tonal->TONALITY_ANALYSIS_RESET_START;
+  OPUS_CLEAR(start, sizeof(TonalityAnalysisState) - (start - (char*)tonal));
+}
+
+void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len)
+{
+   int pos;
+   int curr_lookahead;
+   float psum;
+   int i;
+
+   pos = tonal->read_pos;
+   curr_lookahead = tonal->write_pos-tonal->read_pos;
+   if (curr_lookahead<0)
+      curr_lookahead += DETECT_SIZE;
+
+   if (len > 480 && pos != tonal->write_pos)
+   {
+      pos++;
+      if (pos==DETECT_SIZE)
+         pos=0;
+   }
+   if (pos == tonal->write_pos)
+      pos--;
+   if (pos<0)
+      pos = DETECT_SIZE-1;
+   OPUS_COPY(info_out, &tonal->info[pos], 1);
+   tonal->read_subframe += len/120;
+   while (tonal->read_subframe>=4)
+   {
+      tonal->read_subframe -= 4;
+      tonal->read_pos++;
+   }
+   if (tonal->read_pos>=DETECT_SIZE)
+      tonal->read_pos-=DETECT_SIZE;
+
+   /* Compensate for the delay in the features themselves.
+      FIXME: Need a better estimate the 10 I just made up */
+   curr_lookahead = IMAX(curr_lookahead-10, 0);
+
+   psum=0;
+   /* Summing the probability of transition patterns that involve music at
+      time (DETECT_SIZE-curr_lookahead-1) */
+   for (i=0;i<DETECT_SIZE-curr_lookahead;i++)
+      psum += tonal->pmusic[i];
+   for (;i<DETECT_SIZE;i++)
+      psum += tonal->pspeech[i];
+   psum = psum*tonal->music_confidence + (1-psum)*tonal->speech_confidence;
+   /*printf("%f %f %f\n", psum, info_out->music_prob, info_out->tonality);*/
+
+   info_out->music_prob = psum;
+}
+
+static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix)
+{
+    int i, b;
+    const kiss_fft_state *kfft;
+    VARDECL(kiss_fft_cpx, in);
+    VARDECL(kiss_fft_cpx, out);
+    int N = 480, N2=240;
+    float * OPUS_RESTRICT A = tonal->angle;
+    float * OPUS_RESTRICT dA = tonal->d_angle;
+    float * OPUS_RESTRICT d2A = tonal->d2_angle;
+    VARDECL(float, tonality);
+    VARDECL(float, noisiness);
+    float band_tonality[NB_TBANDS];
+    float logE[NB_TBANDS];
+    float BFCC[8];
+    float features[25];
+    float frame_tonality;
+    float max_frame_tonality;
+    /*float tw_sum=0;*/
+    float frame_noisiness;
+    const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI);
+    float slope=0;
+    float frame_stationarity;
+    float relativeE;
+    float frame_probs[2];
+    float alpha, alphaE, alphaE2;
+    float frame_loudness;
+    float bandwidth_mask;
+    int bandwidth=0;
+    float maxE = 0;
+    float noise_floor;
+    int remaining;
+    AnalysisInfo *info;
+    SAVE_STACK;
+
+    tonal->last_transition++;
+    alpha = 1.f/IMIN(20, 1+tonal->count);
+    alphaE = 1.f/IMIN(50, 1+tonal->count);
+    alphaE2 = 1.f/IMIN(1000, 1+tonal->count);
+
+    if (tonal->count<4)
+       tonal->music_prob = .5;
+    kfft = celt_mode->mdct.kfft[0];
+    if (tonal->count==0)
+       tonal->mem_fill = 240;
+    downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C);
+    if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE)
+    {
+       tonal->mem_fill += len;
+       /* Don't have enough to update the analysis */
+       RESTORE_STACK;
+       return;
+    }
+    info = &tonal->info[tonal->write_pos++];
+    if (tonal->write_pos>=DETECT_SIZE)
+       tonal->write_pos-=DETECT_SIZE;
+
+    ALLOC(in, 480, kiss_fft_cpx);
+    ALLOC(out, 480, kiss_fft_cpx);
+    ALLOC(tonality, 240, float);
+    ALLOC(noisiness, 240, float);
+    for (i=0;i<N2;i++)
+    {
+       float w = analysis_window[i];
+       in[i].r = (kiss_fft_scalar)(w*tonal->inmem[i]);
+       in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]);
+       in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]);
+       in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]);
+    }
+    OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240);
+    remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill);
+    downmix(x, &tonal->inmem[240], remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C);
+    tonal->mem_fill = 240 + remaining;
+    opus_fft(kfft, in, out, tonal->arch);
+#ifndef FIXED_POINT
+    /* If there's any NaN on the input, the entire output will be NaN, so we only need to check one value. */
+    if (celt_isnan(out[0].r))
+    {
+       info->valid = 0;
+       RESTORE_STACK;
+       return;
+    }
+#endif
+
+    for (i=1;i<N2;i++)
+    {
+       float X1r, X2r, X1i, X2i;
+       float angle, d_angle, d2_angle;
+       float angle2, d_angle2, d2_angle2;
+       float mod1, mod2, avg_mod;
+       X1r = (float)out[i].r+out[N-i].r;
+       X1i = (float)out[i].i-out[N-i].i;
+       X2r = (float)out[i].i+out[N-i].i;
+       X2i = (float)out[N-i].r-out[i].r;
+
+       angle = (float)(.5f/M_PI)*fast_atan2f(X1i, X1r);
+       d_angle = angle - A[i];
+       d2_angle = d_angle - dA[i];
+
+       angle2 = (float)(.5f/M_PI)*fast_atan2f(X2i, X2r);
+       d_angle2 = angle2 - angle;
+       d2_angle2 = d_angle2 - d_angle;
+
+       mod1 = d2_angle - (float)floor(.5+d2_angle);
+       noisiness[i] = ABS16(mod1);
+       mod1 *= mod1;
+       mod1 *= mod1;
+
+       mod2 = d2_angle2 - (float)floor(.5+d2_angle2);
+       noisiness[i] += ABS16(mod2);
+       mod2 *= mod2;
+       mod2 *= mod2;
+
+       avg_mod = .25f*(d2A[i]+2.f*mod1+mod2);
+       tonality[i] = 1.f/(1.f+40.f*16.f*pi4*avg_mod)-.015f;
+
+       A[i] = angle2;
+       dA[i] = d_angle2;
+       d2A[i] = mod2;
+    }
+
+    frame_tonality = 0;
+    max_frame_tonality = 0;
+    /*tw_sum = 0;*/
+    info->activity = 0;
+    frame_noisiness = 0;
+    frame_stationarity = 0;
+    if (!tonal->count)
+    {
+       for (b=0;b<NB_TBANDS;b++)
+       {
+          tonal->lowE[b] = 1e10;
+          tonal->highE[b] = -1e10;
+       }
+    }
+    relativeE = 0;
+    frame_loudness = 0;
+    for (b=0;b<NB_TBANDS;b++)
+    {
+       float E=0, tE=0, nE=0;
+       float L1, L2;
+       float stationarity;
+       for (i=tbands[b];i<tbands[b+1];i++)
+       {
+          float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
+                     + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
+#ifdef FIXED_POINT
+          /* FIXME: It's probably best to change the BFCC filter initial state instead */
+          binE *= 5.55e-17f;
+#endif
+          E += binE;
+          tE += binE*tonality[i];
+          nE += binE*2.f*(.5f-noisiness[i]);
+       }
+#ifndef FIXED_POINT
+       /* Check for extreme band energies that could cause NaNs later. */
+       if (!(E<1e9f) || celt_isnan(E))
+       {
+          info->valid = 0;
+          RESTORE_STACK;
+          return;
+       }
+#endif
+
+       tonal->E[tonal->E_count][b] = E;
+       frame_noisiness += nE/(1e-15f+E);
+
+       frame_loudness += (float)sqrt(E+1e-10f);
+       logE[b] = (float)log(E+1e-10f);
+       tonal->lowE[b] = MIN32(logE[b], tonal->lowE[b]+.01f);
+       tonal->highE[b] = MAX32(logE[b], tonal->highE[b]-.1f);
+       if (tonal->highE[b] < tonal->lowE[b]+1.f)
+       {
+          tonal->highE[b]+=.5f;
+          tonal->lowE[b]-=.5f;
+       }
+       relativeE += (logE[b]-tonal->lowE[b])/(1e-15f+tonal->highE[b]-tonal->lowE[b]);
+
+       L1=L2=0;
+       for (i=0;i<NB_FRAMES;i++)
+       {
+          L1 += (float)sqrt(tonal->E[i][b]);
+          L2 += tonal->E[i][b];
+       }
+
+       stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2));
+       stationarity *= stationarity;
+       stationarity *= stationarity;
+       frame_stationarity += stationarity;
+       /*band_tonality[b] = tE/(1e-15+E)*/;
+       band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]);
+#if 0
+       if (b>=NB_TONAL_SKIP_BANDS)
+       {
+          frame_tonality += tweight[b]*band_tonality[b];
+          tw_sum += tweight[b];
+       }
+#else
+       frame_tonality += band_tonality[b];
+       if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS)
+          frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS];
+#endif
+       max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality);
+       slope += band_tonality[b]*(b-8);
+       /*printf("%f %f ", band_tonality[b], stationarity);*/
+       tonal->prev_band_tonality[b] = band_tonality[b];
+    }
+
+    bandwidth_mask = 0;
+    bandwidth = 0;
+    maxE = 0;
+    noise_floor = 5.7e-4f/(1<<(IMAX(0,lsb_depth-8)));
+#ifdef FIXED_POINT
+    noise_floor *= 1<<(15+SIG_SHIFT);
+#endif
+    noise_floor *= noise_floor;
+    for (b=0;b<NB_TOT_BANDS;b++)
+    {
+       float E=0;
+       int band_start, band_end;
+       /* Keep a margin of 300 Hz for aliasing */
+       band_start = extra_bands[b];
+       band_end = extra_bands[b+1];
+       for (i=band_start;i<band_end;i++)
+       {
+          float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
+                     + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
+          E += binE;
+       }
+       maxE = MAX32(maxE, E);
+       tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E);
+       E = MAX32(E, tonal->meanE[b]);
+       /* Use a simple follower with 13 dB/Bark slope for spreading function */
+       bandwidth_mask = MAX32(.05f*bandwidth_mask, E);
+       /* Consider the band "active" only if all these conditions are met:
+          1) less than 10 dB below the simple follower
+          2) less than 90 dB below the peak band (maximal masking possible considering
+             both the ATH and the loudness-dependent slope of the spreading function)
+          3) above the PCM quantization noise floor
+       */
+       if (E>.1*bandwidth_mask && E*1e9f > maxE && E > noise_floor*(band_end-band_start))
+          bandwidth = b;
+    }
+    if (tonal->count<=2)
+       bandwidth = 20;
+    frame_loudness = 20*(float)log10(frame_loudness);
+    tonal->Etracker = MAX32(tonal->Etracker-.03f, frame_loudness);
+    tonal->lowECount *= (1-alphaE);
+    if (frame_loudness < tonal->Etracker-30)
+       tonal->lowECount += alphaE;
+
+    for (i=0;i<8;i++)
+    {
+       float sum=0;
+       for (b=0;b<16;b++)
+          sum += dct_table[i*16+b]*logE[b];
+       BFCC[i] = sum;
+    }
+
+    frame_stationarity /= NB_TBANDS;
+    relativeE /= NB_TBANDS;
+    if (tonal->count<10)
+       relativeE = .5;
+    frame_noisiness /= NB_TBANDS;
+#if 1
+    info->activity = frame_noisiness + (1-frame_noisiness)*relativeE;
+#else
+    info->activity = .5*(1+frame_noisiness-frame_stationarity);
+#endif
+    frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS));
+    frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f);
+    tonal->prev_tonality = frame_tonality;
+
+    slope /= 8*8;
+    info->tonality_slope = slope;
+
+    tonal->E_count = (tonal->E_count+1)%NB_FRAMES;
+    tonal->count++;
+    info->tonality = frame_tonality;
+
+    for (i=0;i<4;i++)
+       features[i] = -0.12299f*(BFCC[i]+tonal->mem[i+24]) + 0.49195f*(tonal->mem[i]+tonal->mem[i+16]) + 0.69693f*tonal->mem[i+8] - 1.4349f*tonal->cmean[i];
+
+    for (i=0;i<4;i++)
+       tonal->cmean[i] = (1-alpha)*tonal->cmean[i] + alpha*BFCC[i];
+
+    for (i=0;i<4;i++)
+        features[4+i] = 0.63246f*(BFCC[i]-tonal->mem[i+24]) + 0.31623f*(tonal->mem[i]-tonal->mem[i+16]);
+    for (i=0;i<3;i++)
+        features[8+i] = 0.53452f*(BFCC[i]+tonal->mem[i+24]) - 0.26726f*(tonal->mem[i]+tonal->mem[i+16]) -0.53452f*tonal->mem[i+8];
+
+    if (tonal->count > 5)
+    {
+       for (i=0;i<9;i++)
+          tonal->std[i] = (1-alpha)*tonal->std[i] + alpha*features[i]*features[i];
+    }
+
+    for (i=0;i<8;i++)
+    {
+       tonal->mem[i+24] = tonal->mem[i+16];
+       tonal->mem[i+16] = tonal->mem[i+8];
+       tonal->mem[i+8] = tonal->mem[i];
+       tonal->mem[i] = BFCC[i];
+    }
+    for (i=0;i<9;i++)
+       features[11+i] = (float)sqrt(tonal->std[i]);
+    features[20] = info->tonality;
+    features[21] = info->activity;
+    features[22] = frame_stationarity;
+    features[23] = info->tonality_slope;
+    features[24] = tonal->lowECount;
+
+#ifndef DISABLE_FLOAT_API
+    mlp_process(&net, features, frame_probs);
+    frame_probs[0] = .5f*(frame_probs[0]+1);
+    /* Curve fitting between the MLP probability and the actual probability */
+    frame_probs[0] = .01f + 1.21f*frame_probs[0]*frame_probs[0] - .23f*(float)pow(frame_probs[0], 10);
+    /* Probability of active audio (as opposed to silence) */
+    frame_probs[1] = .5f*frame_probs[1]+.5f;
+    /* Consider that silence has a 50-50 probability. */
+    frame_probs[0] = frame_probs[1]*frame_probs[0] + (1-frame_probs[1])*.5f;
+
+    /*printf("%f %f ", frame_probs[0], frame_probs[1]);*/
+    {
+       /* Probability of state transition */
+       float tau;
+       /* Represents independence of the MLP probabilities, where
+          beta=1 means fully independent. */
+       float beta;
+       /* Denormalized probability of speech (p0) and music (p1) after update */
+       float p0, p1;
+       /* Probabilities for "all speech" and "all music" */
+       float s0, m0;
+       /* Probability sum for renormalisation */
+       float psum;
+       /* Instantaneous probability of speech and music, with beta pre-applied. */
+       float speech0;
+       float music0;
+       float p, q;
+
+       /* One transition every 3 minutes of active audio */
+       tau = .00005f*frame_probs[1];
+       /* Adapt beta based on how "unexpected" the new prob is */
+       p = MAX16(.05f,MIN16(.95f,frame_probs[0]));
+       q = MAX16(.05f,MIN16(.95f,tonal->music_prob));
+       beta = .01f+.05f*ABS16(p-q)/(p*(1-q)+q*(1-p));
+       /* p0 and p1 are the probabilities of speech and music at this frame
+          using only information from previous frame and applying the
+          state transition model */
+       p0 = (1-tonal->music_prob)*(1-tau) +    tonal->music_prob *tau;
+       p1 =    tonal->music_prob *(1-tau) + (1-tonal->music_prob)*tau;
+       /* We apply the current probability with exponent beta to work around
+          the fact that the probability estimates aren't independent. */
+       p0 *= (float)pow(1-frame_probs[0], beta);
+       p1 *= (float)pow(frame_probs[0], beta);
+       /* Normalise the probabilities to get the Marokv probability of music. */
+       tonal->music_prob = p1/(p0+p1);
+       info->music_prob = tonal->music_prob;
+
+       /* This chunk of code deals with delayed decision. */
+       psum=1e-20f;
+       /* Instantaneous probability of speech and music, with beta pre-applied. */
+       speech0 = (float)pow(1-frame_probs[0], beta);
+       music0  = (float)pow(frame_probs[0], beta);
+       if (tonal->count==1)
+       {
+          tonal->pspeech[0]=.5;
+          tonal->pmusic [0]=.5;
+       }
+       /* Updated probability of having only speech (s0) or only music (m0),
+          before considering the new observation. */
+       s0 = tonal->pspeech[0] + tonal->pspeech[1];
+       m0 = tonal->pmusic [0] + tonal->pmusic [1];
+       /* Updates s0 and m0 with instantaneous probability. */
+       tonal->pspeech[0] = s0*(1-tau)*speech0;
+       tonal->pmusic [0] = m0*(1-tau)*music0;
+       /* Propagate the transition probabilities */
+       for (i=1;i<DETECT_SIZE-1;i++)
+       {
+          tonal->pspeech[i] = tonal->pspeech[i+1]*speech0;
+          tonal->pmusic [i] = tonal->pmusic [i+1]*music0;
+       }
+       /* Probability that the latest frame is speech, when all the previous ones were music. */
+       tonal->pspeech[DETECT_SIZE-1] = m0*tau*speech0;
+       /* Probability that the latest frame is music, when all the previous ones were speech. */
+       tonal->pmusic [DETECT_SIZE-1] = s0*tau*music0;
+
+       /* Renormalise probabilities to 1 */
+       for (i=0;i<DETECT_SIZE;i++)
+          psum += tonal->pspeech[i] + tonal->pmusic[i];
+       psum = 1.f/psum;
+       for (i=0;i<DETECT_SIZE;i++)
+       {
+          tonal->pspeech[i] *= psum;
+          tonal->pmusic [i] *= psum;
+       }
+       psum = tonal->pmusic[0];
+       for (i=1;i<DETECT_SIZE;i++)
+          psum += tonal->pspeech[i];
+
+       /* Estimate our confidence in the speech/music decisions */
+       if (frame_probs[1]>.75)
+       {
+          if (tonal->music_prob>.9)
+          {
+             float adapt;
+             adapt = 1.f/(++tonal->music_confidence_count);
+             tonal->music_confidence_count = IMIN(tonal->music_confidence_count, 500);
+             tonal->music_confidence += adapt*MAX16(-.2f,frame_probs[0]-tonal->music_confidence);
+          }
+          if (tonal->music_prob<.1)
+          {
+             float adapt;
+             adapt = 1.f/(++tonal->speech_confidence_count);
+             tonal->speech_confidence_count = IMIN(tonal->speech_confidence_count, 500);
+             tonal->speech_confidence += adapt*MIN16(.2f,frame_probs[0]-tonal->speech_confidence);
+          }
+       } else {
+          if (tonal->music_confidence_count==0)
+             tonal->music_confidence = .9f;
+          if (tonal->speech_confidence_count==0)
+             tonal->speech_confidence = .1f;
+       }
+    }
+    if (tonal->last_music != (tonal->music_prob>.5f))
+       tonal->last_transition=0;
+    tonal->last_music = tonal->music_prob>.5f;
+#else
+    info->music_prob = 0;
+#endif
+    /*for (i=0;i<25;i++)
+       printf("%f ", features[i]);
+    printf("\n");*/
+
+    info->bandwidth = bandwidth;
+    /*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/
+    info->noisiness = frame_noisiness;
+    info->valid = 1;
+    RESTORE_STACK;
+}
+
+void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
+                 int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
+                 int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info)
+{
+   int offset;
+   int pcm_len;
+
+   if (analysis_pcm != NULL)
+   {
+      /* Avoid overflow/wrap-around of the analysis buffer */
+      analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/100, analysis_frame_size);
+
+      pcm_len = analysis_frame_size - analysis->analysis_offset;
+      offset = analysis->analysis_offset;
+      do {
+         tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
+         offset += 480;
+         pcm_len -= 480;
+      } while (pcm_len>0);
+      analysis->analysis_offset = analysis_frame_size;
+
+      analysis->analysis_offset -= frame_size;
+   }
+
+   analysis_info->valid = 0;
+   tonality_get_info(analysis, analysis_info, frame_size);
+}
diff --git a/third_party/opus/src/src/analysis.h b/third_party/opus/src/src/analysis.h
new file mode 100644
index 0000000..9eae56a
--- /dev/null
+++ b/third_party/opus/src/src/analysis.h
@@ -0,0 +1,103 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ANALYSIS_H
+#define ANALYSIS_H
+
+#include "celt.h"
+#include "opus_private.h"
+
+#define NB_FRAMES 8
+#define NB_TBANDS 18
+#define NB_TOT_BANDS 21
+#define ANALYSIS_BUF_SIZE 720 /* 15 ms at 48 kHz */
+
+#define DETECT_SIZE 200
+
+typedef struct {
+   int arch;
+#define TONALITY_ANALYSIS_RESET_START angle
+   float angle[240];
+   float d_angle[240];
+   float d2_angle[240];
+   opus_val32 inmem[ANALYSIS_BUF_SIZE];
+   int   mem_fill;                      /* number of usable samples in the buffer */
+   float prev_band_tonality[NB_TBANDS];
+   float prev_tonality;
+   float E[NB_FRAMES][NB_TBANDS];
+   float lowE[NB_TBANDS];
+   float highE[NB_TBANDS];
+   float meanE[NB_TOT_BANDS];
+   float mem[32];
+   float cmean[8];
+   float std[9];
+   float music_prob;
+   float Etracker;
+   float lowECount;
+   int E_count;
+   int last_music;
+   int last_transition;
+   int count;
+   float subframe_mem[3];
+   int analysis_offset;
+   /** Probability of having speech for time i to DETECT_SIZE-1 (and music before).
+       pspeech[0] is the probability that all frames in the window are speech. */
+   float pspeech[DETECT_SIZE];
+   /** Probability of having music for time i to DETECT_SIZE-1 (and speech before).
+       pmusic[0] is the probability that all frames in the window are music. */
+   float pmusic[DETECT_SIZE];
+   float speech_confidence;
+   float music_confidence;
+   int speech_confidence_count;
+   int music_confidence_count;
+   int write_pos;
+   int read_pos;
+   int read_subframe;
+   AnalysisInfo info[DETECT_SIZE];
+} TonalityAnalysisState;
+
+/** Initialize a TonalityAnalysisState struct.
+ *
+ * This performs some possibly slow initialization steps which should
+ * not be repeated every analysis step. No allocated memory is retained
+ * by the state struct, so no cleanup call is required.
+ */
+void tonality_analysis_init(TonalityAnalysisState *analysis);
+
+/** Reset a TonalityAnalysisState stuct.
+ *
+ * Call this when there's a discontinuity in the data.
+ */
+void tonality_analysis_reset(TonalityAnalysisState *analysis);
+
+void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len);
+
+void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
+                 int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
+                 int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info);
+
+#endif
diff --git a/third_party/opus/src/src/mlp.c b/third_party/opus/src/src/mlp.c
new file mode 100644
index 0000000..ff9e50d
--- /dev/null
+++ b/third_party/opus/src/src/mlp.c
@@ -0,0 +1,145 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#include <math.h>
+#include "mlp.h"
+#include "arch.h"
+#include "tansig_table.h"
+#define MAX_NEURONS 100
+
+#if 0
+static OPUS_INLINE opus_val16 tansig_approx(opus_val32 _x) /* Q19 */
+{
+    int i;
+    opus_val16 xx; /* Q11 */
+    /*double x, y;*/
+    opus_val16 dy, yy; /* Q14 */
+    /*x = 1.9073e-06*_x;*/
+    if (_x>=QCONST32(8,19))
+        return QCONST32(1.,14);
+    if (_x<=-QCONST32(8,19))
+        return -QCONST32(1.,14);
+    xx = EXTRACT16(SHR32(_x, 8));
+    /*i = lrint(25*x);*/
+    i = SHR32(ADD32(1024,MULT16_16(25, xx)),11);
+    /*x -= .04*i;*/
+    xx -= EXTRACT16(SHR32(MULT16_16(20972,i),8));
+    /*x = xx*(1./2048);*/
+    /*y = tansig_table[250+i];*/
+    yy = tansig_table[250+i];
+    /*y = yy*(1./16384);*/
+    dy = 16384-MULT16_16_Q14(yy,yy);
+    yy = yy + MULT16_16_Q14(MULT16_16_Q11(xx,dy),(16384 - MULT16_16_Q11(yy,xx)));
+    return yy;
+}
+#else
+/*extern const float tansig_table[501];*/
+static OPUS_INLINE float tansig_approx(float x)
+{
+    int i;
+    float y, dy;
+    float sign=1;
+    /* Tests are reversed to catch NaNs */
+    if (!(x<8))
+        return 1;
+    if (!(x>-8))
+        return -1;
+#ifndef FIXED_POINT
+    /* Another check in case of -ffast-math */
+    if (celt_isnan(x))
+       return 0;
+#endif
+    if (x<0)
+    {
+       x=-x;
+       sign=-1;
+    }
+    i = (int)floor(.5f+25*x);
+    x -= .04f*i;
+    y = tansig_table[i];
+    dy = 1-y*y;
+    y = y + x*dy*(1 - y*x);
+    return sign*y;
+}
+#endif
+
+#if 0
+void mlp_process(const MLP *m, const opus_val16 *in, opus_val16 *out)
+{
+    int j;
+    opus_val16 hidden[MAX_NEURONS];
+    const opus_val16 *W = m->weights;
+    /* Copy to tmp_in */
+    for (j=0;j<m->topo[1];j++)
+    {
+        int k;
+        opus_val32 sum = SHL32(EXTEND32(*W++),8);
+        for (k=0;k<m->topo[0];k++)
+            sum = MAC16_16(sum, in[k],*W++);
+        hidden[j] = tansig_approx(sum);
+    }
+    for (j=0;j<m->topo[2];j++)
+    {
+        int k;
+        opus_val32 sum = SHL32(EXTEND32(*W++),14);
+        for (k=0;k<m->topo[1];k++)
+            sum = MAC16_16(sum, hidden[k], *W++);
+        out[j] = tansig_approx(EXTRACT16(PSHR32(sum,17)));
+    }
+}
+#else
+void mlp_process(const MLP *m, const float *in, float *out)
+{
+    int j;
+    float hidden[MAX_NEURONS];
+    const float *W = m->weights;
+    /* Copy to tmp_in */
+    for (j=0;j<m->topo[1];j++)
+    {
+        int k;
+        float sum = *W++;
+        for (k=0;k<m->topo[0];k++)
+            sum = sum + in[k]**W++;
+        hidden[j] = tansig_approx(sum);
+    }
+    for (j=0;j<m->topo[2];j++)
+    {
+        int k;
+        float sum = *W++;
+        for (k=0;k<m->topo[1];k++)
+            sum = sum + hidden[k]**W++;
+        out[j] = tansig_approx(sum);
+    }
+}
+#endif
diff --git a/third_party/opus/src/src/mlp.h b/third_party/opus/src/src/mlp.h
new file mode 100644
index 0000000..618e246
--- /dev/null
+++ b/third_party/opus/src/src/mlp.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MLP_H_
+#define _MLP_H_
+
+#include "arch.h"
+
+typedef struct {
+    int layers;
+    const int *topo;
+    const float *weights;
+} MLP;
+
+extern const MLP net;
+
+void mlp_process(const MLP *m, const float *in, float *out);
+
+#endif /* _MLP_H_ */
diff --git a/third_party/opus/src/src/mlp_data.c b/third_party/opus/src/src/mlp_data.c
new file mode 100644
index 0000000..c2fda4e
--- /dev/null
+++ b/third_party/opus/src/src/mlp_data.c
@@ -0,0 +1,109 @@
+/* The contents of this file was automatically generated by mlp_train.c
+   It contains multi-layer perceptron (MLP) weights. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mlp.h"
+
+/* RMS error was 0.138320, seed was 1361535663 */
+
+static const float weights[422] = {
+
+/* hidden layer */
+-0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f,
+-0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f,
+-0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f,
+0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f,
+0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f,
+24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f,
+-0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f,
+-0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f,
+-0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f,
+1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f,
+15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f,
+0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f,
+-0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f,
+0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f,
+0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f,
+-1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f,
+-0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f,
+-0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f,
+0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f,
+-0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f,
+2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f,
+0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f,
+-0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f,
+0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f,
+0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f,
+-4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f,
+5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f,
+-0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f,
+-0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f,
+-0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f,
+1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f,
+-7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f,
+-0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f,
+0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f,
+0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f,
+-0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f,
+10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f,
+-0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f,
+-0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f,
+-0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f,
+0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f,
+-0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f,
+0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f,
+0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f,
+-0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f,
+0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f,
+-0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f,
+-0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f,
+-0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f,
+-0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f,
+-0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f,
+5.8427f, -0.38075f, 0.221894f, -1.41934f, -1.87943e+06f,
+1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f,
+0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f,
+-0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f,
+0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f,
+-0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f,
+-975268.f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f,
+0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f,
+-0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f,
+-2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f,
+0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f,
+-6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f,
+0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f,
+-0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f,
+-0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f,
+0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f,
+-0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f,
+0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f,
+-0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f,
+0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f,
+-2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f,
+4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f,
+0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f,
+-0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f,
+0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f,
+0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f,
+3.95279f, 1.89068f, 0.486087f, -11.3343f, 3.9416e+06f,
+
+/* output layer */
+-0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f,
+0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f,
+0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f,
+0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f,
+4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f,
+-1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f,
+3.87308f, 3.52558f};
+
+static const int topo[3] = {25, 15, 2};
+
+const MLP net = {
+    3,
+    topo,
+    weights
+};
diff --git a/third_party/opus/src/src/opus.c b/third_party/opus/src/src/opus.c
new file mode 100644
index 0000000..f76f125
--- /dev/null
+++ b/third_party/opus/src/src/opus.c
@@ -0,0 +1,356 @@
+/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited
+   Written by Jean-Marc Valin and Koen Vos */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus.h"
+#include "opus_private.h"
+
+#ifndef DISABLE_FLOAT_API
+OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem)
+{
+   int c;
+   int i;
+   float *x;
+
+   if (C<1 || N<1 || !_x || !declip_mem) return;
+
+   /* First thing: saturate everything to +/- 2 which is the highest level our
+      non-linearity can handle. At the point where the signal reaches +/-2,
+      the derivative will be zero anyway, so this doesn't introduce any
+      discontinuity in the derivative. */
+   for (i=0;i<N*C;i++)
+      _x[i] = MAX16(-2.f, MIN16(2.f, _x[i]));
+   for (c=0;c<C;c++)
+   {
+      float a;
+      float x0;
+      int curr;
+
+      x = _x+c;
+      a = declip_mem[c];
+      /* Continue applying the non-linearity from the previous frame to avoid
+         any discontinuity. */
+      for (i=0;i<N;i++)
+      {
+         if (x[i*C]*a>=0)
+            break;
+         x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
+      }
+
+      curr=0;
+      x0 = x[0];
+      while(1)
+      {
+         int start, end;
+         float maxval;
+         int special=0;
+         int peak_pos;
+         for (i=curr;i<N;i++)
+         {
+            if (x[i*C]>1 || x[i*C]<-1)
+               break;
+         }
+         if (i==N)
+         {
+            a=0;
+            break;
+         }
+         peak_pos = i;
+         start=end=i;
+         maxval=ABS16(x[i*C]);
+         /* Look for first zero crossing before clipping */
+         while (start>0 && x[i*C]*x[(start-1)*C]>=0)
+            start--;
+         /* Look for first zero crossing after clipping */
+         while (end<N && x[i*C]*x[end*C]>=0)
+         {
+            /* Look for other peaks until the next zero-crossing. */
+            if (ABS16(x[end*C])>maxval)
+            {
+               maxval = ABS16(x[end*C]);
+               peak_pos = end;
+            }
+            end++;
+         }
+         /* Detect the special case where we clip before the first zero crossing */
+         special = (start==0 && x[i*C]*x[0]>=0);
+
+         /* Compute a such that maxval + a*maxval^2 = 1 */
+         a=(maxval-1)/(maxval*maxval);
+         /* Slightly boost "a" by 2^-22. This is just enough to ensure -ffast-math
+            does not cause output values larger than +/-1, but small enough not
+            to matter even for 24-bit output.  */
+         a += a*2.4e-7;
+         if (x[i*C]>0)
+            a = -a;
+         /* Apply soft clipping */
+         for (i=start;i<end;i++)
+            x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
+
+         if (special && peak_pos>=2)
+         {
+            /* Add a linear ramp from the first sample to the signal peak.
+               This avoids a discontinuity at the beginning of the frame. */
+            float delta;
+            float offset = x0-x[0];
+            delta = offset / peak_pos;
+            for (i=curr;i<peak_pos;i++)
+            {
+               offset -= delta;
+               x[i*C] += offset;
+               x[i*C] = MAX16(-1.f, MIN16(1.f, x[i*C]));
+            }
+         }
+         curr = end;
+         if (curr==N)
+            break;
+      }
+      declip_mem[c] = a;
+   }
+}
+#endif
+
+int encode_size(int size, unsigned char *data)
+{
+   if (size < 252)
+   {
+      data[0] = size;
+      return 1;
+   } else {
+      data[0] = 252+(size&0x3);
+      data[1] = (size-(int)data[0])>>2;
+      return 2;
+   }
+}
+
+static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size)
+{
+   if (len<1)
+   {
+      *size = -1;
+      return -1;
+   } else if (data[0]<252)
+   {
+      *size = data[0];
+      return 1;
+   } else if (len<2)
+   {
+      *size = -1;
+      return -1;
+   } else {
+      *size = 4*data[1] + data[0];
+      return 2;
+   }
+}
+
+int opus_packet_get_samples_per_frame(const unsigned char *data,
+      opus_int32 Fs)
+{
+   int audiosize;
+   if (data[0]&0x80)
+   {
+      audiosize = ((data[0]>>3)&0x3);
+      audiosize = (Fs<<audiosize)/400;
+   } else if ((data[0]&0x60) == 0x60)
+   {
+      audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
+   } else {
+      audiosize = ((data[0]>>3)&0x3);
+      if (audiosize == 3)
+         audiosize = Fs*60/1000;
+      else
+         audiosize = (Fs<<audiosize)/100;
+   }
+   return audiosize;
+}
+
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+      int self_delimited, unsigned char *out_toc,
+      const unsigned char *frames[48], opus_int16 size[48],
+      int *payload_offset, opus_int32 *packet_offset)
+{
+   int i, bytes;
+   int count;
+   int cbr;
+   unsigned char ch, toc;
+   int framesize;
+   opus_int32 last_size;
+   opus_int32 pad = 0;
+   const unsigned char *data0 = data;
+
+   if (size==NULL || len<0)
+      return OPUS_BAD_ARG;
+   if (len==0)
+      return OPUS_INVALID_PACKET;
+
+   framesize = opus_packet_get_samples_per_frame(data, 48000);
+
+   cbr = 0;
+   toc = *data++;
+   len--;
+   last_size = len;
+   switch (toc&0x3)
+   {
+   /* One frame */
+   case 0:
+      count=1;
+      break;
+   /* Two CBR frames */
+   case 1:
+      count=2;
+      cbr = 1;
+      if (!self_delimited)
+      {
+         if (len&0x1)
+            return OPUS_INVALID_PACKET;
+         last_size = len/2;
+         /* If last_size doesn't fit in size[0], we'll catch it later */
+         size[0] = (opus_int16)last_size;
+      }
+      break;
+   /* Two VBR frames */
+   case 2:
+      count = 2;
+      bytes = parse_size(data, len, size);
+      len -= bytes;
+      if (size[0]<0 || size[0] > len)
+         return OPUS_INVALID_PACKET;
+      data += bytes;
+      last_size = len-size[0];
+      break;
+   /* Multiple CBR/VBR frames (from 0 to 120 ms) */
+   default: /*case 3:*/
+      if (len<1)
+         return OPUS_INVALID_PACKET;
+      /* Number of frames encoded in bits 0 to 5 */
+      ch = *data++;
+      count = ch&0x3F;
+      if (count <= 0 || framesize*count > 5760)
+         return OPUS_INVALID_PACKET;
+      len--;
+      /* Padding flag is bit 6 */
+      if (ch&0x40)
+      {
+         int p;
+         do {
+            int tmp;
+            if (len<=0)
+               return OPUS_INVALID_PACKET;
+            p = *data++;
+            len--;
+            tmp = p==255 ? 254: p;
+            len -= tmp;
+            pad += tmp;
+         } while (p==255);
+      }
+      if (len<0)
+         return OPUS_INVALID_PACKET;
+      /* VBR flag is bit 7 */
+      cbr = !(ch&0x80);
+      if (!cbr)
+      {
+         /* VBR case */
+         last_size = len;
+         for (i=0;i<count-1;i++)
+         {
+            bytes = parse_size(data, len, size+i);
+            len -= bytes;
+            if (size[i]<0 || size[i] > len)
+               return OPUS_INVALID_PACKET;
+            data += bytes;
+            last_size -= bytes+size[i];
+         }
+         if (last_size<0)
+            return OPUS_INVALID_PACKET;
+      } else if (!self_delimited)
+      {
+         /* CBR case */
+         last_size = len/count;
+         if (last_size*count!=len)
+            return OPUS_INVALID_PACKET;
+         for (i=0;i<count-1;i++)
+            size[i] = (opus_int16)last_size;
+      }
+      break;
+   }
+   /* Self-delimited framing has an extra size for the last frame. */
+   if (self_delimited)
+   {
+      bytes = parse_size(data, len, size+count-1);
+      len -= bytes;
+      if (size[count-1]<0 || size[count-1] > len)
+         return OPUS_INVALID_PACKET;
+      data += bytes;
+      /* For CBR packets, apply the size to all the frames. */
+      if (cbr)
+      {
+         if (size[count-1]*count > len)
+            return OPUS_INVALID_PACKET;
+         for (i=0;i<count-1;i++)
+            size[i] = size[count-1];
+      } else if (bytes+size[count-1] > last_size)
+         return OPUS_INVALID_PACKET;
+   } else
+   {
+      /* Because it's not encoded explicitly, it's possible the size of the
+         last packet (or all the packets, for the CBR case) is larger than
+         1275. Reject them here.*/
+      if (last_size > 1275)
+         return OPUS_INVALID_PACKET;
+      size[count-1] = (opus_int16)last_size;
+   }
+
+   if (payload_offset)
+      *payload_offset = (int)(data-data0);
+
+   for (i=0;i<count;i++)
+   {
+      if (frames)
+         frames[i] = data;
+      data += size[i];
+   }
+
+   if (packet_offset)
+      *packet_offset = pad+(opus_int32)(data-data0);
+
+   if (out_toc)
+      *out_toc = toc;
+
+   return count;
+}
+
+int opus_packet_parse(const unsigned char *data, opus_int32 len,
+      unsigned char *out_toc, const unsigned char *frames[48],
+      opus_int16 size[48], int *payload_offset)
+{
+   return opus_packet_parse_impl(data, len, 0, out_toc,
+                                 frames, size, payload_offset, NULL);
+}
+
diff --git a/third_party/opus/src/src/opus_compare.c b/third_party/opus/src/src/opus_compare.c
new file mode 100644
index 0000000..06c67d75
--- /dev/null
+++ b/third_party/opus/src/src/opus_compare.c
@@ -0,0 +1,379 @@
+/* Copyright (c) 2011-2012 Xiph.Org Foundation, Mozilla Corporation
+   Written by Jean-Marc Valin and Timothy B. Terriberry */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#define OPUS_PI (3.14159265F)
+
+#define OPUS_COSF(_x)        ((float)cos(_x))
+#define OPUS_SINF(_x)        ((float)sin(_x))
+
+static void *check_alloc(void *_ptr){
+  if(_ptr==NULL){
+    fprintf(stderr,"Out of memory.\n");
+    exit(EXIT_FAILURE);
+  }
+  return _ptr;
+}
+
+static void *opus_malloc(size_t _size){
+  return check_alloc(malloc(_size));
+}
+
+static void *opus_realloc(void *_ptr,size_t _size){
+  return check_alloc(realloc(_ptr,_size));
+}
+
+static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){
+  unsigned char  buf[1024];
+  float         *samples;
+  size_t         nsamples;
+  size_t         csamples;
+  size_t         xi;
+  size_t         nread;
+  samples=NULL;
+  nsamples=csamples=0;
+  for(;;){
+    nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin);
+    if(nread<=0)break;
+    if(nsamples+nread>csamples){
+      do csamples=csamples<<1|1;
+      while(nsamples+nread>csamples);
+      samples=(float *)opus_realloc(samples,
+       _nchannels*csamples*sizeof(*samples));
+    }
+    for(xi=0;xi<nread;xi++){
+      int ci;
+      for(ci=0;ci<_nchannels;ci++){
+        int s;
+        s=buf[2*(xi*_nchannels+ci)+1]<<8|buf[2*(xi*_nchannels+ci)];
+        s=((s&0xFFFF)^0x8000)-0x8000;
+        samples[(nsamples+xi)*_nchannels+ci]=s;
+      }
+    }
+    nsamples+=nread;
+  }
+  *_samples=(float *)opus_realloc(samples,
+   _nchannels*nsamples*sizeof(*samples));
+  return nsamples;
+}
+
+static void band_energy(float *_out,float *_ps,const int *_bands,int _nbands,
+ const float *_in,int _nchannels,size_t _nframes,int _window_sz,
+ int _step,int _downsample){
+  float *window;
+  float *x;
+  float *c;
+  float *s;
+  size_t xi;
+  int    xj;
+  int    ps_sz;
+  window=(float *)opus_malloc((3+_nchannels)*_window_sz*sizeof(*window));
+  c=window+_window_sz;
+  s=c+_window_sz;
+  x=s+_window_sz;
+  ps_sz=_window_sz/2;
+  for(xj=0;xj<_window_sz;xj++){
+    window[xj]=0.5F-0.5F*OPUS_COSF((2*OPUS_PI/(_window_sz-1))*xj);
+  }
+  for(xj=0;xj<_window_sz;xj++){
+    c[xj]=OPUS_COSF((2*OPUS_PI/_window_sz)*xj);
+  }
+  for(xj=0;xj<_window_sz;xj++){
+    s[xj]=OPUS_SINF((2*OPUS_PI/_window_sz)*xj);
+  }
+  for(xi=0;xi<_nframes;xi++){
+    int ci;
+    int xk;
+    int bi;
+    for(ci=0;ci<_nchannels;ci++){
+      for(xk=0;xk<_window_sz;xk++){
+        x[ci*_window_sz+xk]=window[xk]*_in[(xi*_step+xk)*_nchannels+ci];
+      }
+    }
+    for(bi=xj=0;bi<_nbands;bi++){
+      float p[2]={0};
+      for(;xj<_bands[bi+1];xj++){
+        for(ci=0;ci<_nchannels;ci++){
+          float re;
+          float im;
+          int   ti;
+          ti=0;
+          re=im=0;
+          for(xk=0;xk<_window_sz;xk++){
+            re+=c[ti]*x[ci*_window_sz+xk];
+            im-=s[ti]*x[ci*_window_sz+xk];
+            ti+=xj;
+            if(ti>=_window_sz)ti-=_window_sz;
+          }
+          re*=_downsample;
+          im*=_downsample;
+          _ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000;
+          p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci];
+        }
+      }
+      if(_out){
+        _out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]);
+        if(_nchannels==2){
+          _out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]);
+        }
+      }
+    }
+  }
+  free(window);
+}
+
+#define NBANDS (21)
+#define NFREQS (240)
+
+/*Bands on which we compute the pseudo-NMR (Bark-derived
+  CELT bands).*/
+static const int BANDS[NBANDS+1]={
+  0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200
+};
+
+#define TEST_WIN_SIZE (480)
+#define TEST_WIN_STEP (120)
+
+int main(int _argc,const char **_argv){
+  FILE    *fin1;
+  FILE    *fin2;
+  float   *x;
+  float   *y;
+  float   *xb;
+  float   *X;
+  float   *Y;
+  double    err;
+  float    Q;
+  size_t   xlength;
+  size_t   ylength;
+  size_t   nframes;
+  size_t   xi;
+  int      ci;
+  int      xj;
+  int      bi;
+  int      nchannels;
+  unsigned rate;
+  int      downsample;
+  int      ybands;
+  int      yfreqs;
+  int      max_compare;
+  if(_argc<3||_argc>6){
+    fprintf(stderr,"Usage: %s [-s] [-r rate2] <file1.sw> <file2.sw>\n",
+     _argv[0]);
+    return EXIT_FAILURE;
+  }
+  nchannels=1;
+  if(strcmp(_argv[1],"-s")==0){
+    nchannels=2;
+    _argv++;
+  }
+  rate=48000;
+  ybands=NBANDS;
+  yfreqs=NFREQS;
+  downsample=1;
+  if(strcmp(_argv[1],"-r")==0){
+    rate=atoi(_argv[2]);
+    if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){
+      fprintf(stderr,
+       "Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n");
+      return EXIT_FAILURE;
+    }
+    downsample=48000/rate;
+    switch(rate){
+      case  8000:ybands=13;break;
+      case 12000:ybands=15;break;
+      case 16000:ybands=17;break;
+      case 24000:ybands=19;break;
+    }
+    yfreqs=NFREQS/downsample;
+    _argv+=2;
+  }
+  fin1=fopen(_argv[1],"rb");
+  if(fin1==NULL){
+    fprintf(stderr,"Error opening '%s'.\n",_argv[1]);
+    return EXIT_FAILURE;
+  }
+  fin2=fopen(_argv[2],"rb");
+  if(fin2==NULL){
+    fprintf(stderr,"Error opening '%s'.\n",_argv[2]);
+    fclose(fin1);
+    return EXIT_FAILURE;
+  }
+  /*Read in the data and allocate scratch space.*/
+  xlength=read_pcm16(&x,fin1,2);
+  if(nchannels==1){
+    for(xi=0;xi<xlength;xi++)x[xi]=.5*(x[2*xi]+x[2*xi+1]);
+  }
+  fclose(fin1);
+  ylength=read_pcm16(&y,fin2,nchannels);
+  fclose(fin2);
+  if(xlength!=ylength*downsample){
+    fprintf(stderr,"Sample counts do not match (%lu!=%lu).\n",
+     (unsigned long)xlength,(unsigned long)ylength*downsample);
+    return EXIT_FAILURE;
+  }
+  if(xlength<TEST_WIN_SIZE){
+    fprintf(stderr,"Insufficient sample data (%lu<%i).\n",
+     (unsigned long)xlength,TEST_WIN_SIZE);
+    return EXIT_FAILURE;
+  }
+  nframes=(xlength-TEST_WIN_SIZE+TEST_WIN_STEP)/TEST_WIN_STEP;
+  xb=(float *)opus_malloc(nframes*NBANDS*nchannels*sizeof(*xb));
+  X=(float *)opus_malloc(nframes*NFREQS*nchannels*sizeof(*X));
+  Y=(float *)opus_malloc(nframes*yfreqs*nchannels*sizeof(*Y));
+  /*Compute the per-band spectral energy of the original signal
+     and the error.*/
+  band_energy(xb,X,BANDS,NBANDS,x,nchannels,nframes,
+   TEST_WIN_SIZE,TEST_WIN_STEP,1);
+  free(x);
+  band_energy(NULL,Y,BANDS,ybands,y,nchannels,nframes,
+   TEST_WIN_SIZE/downsample,TEST_WIN_STEP/downsample,downsample);
+  free(y);
+  for(xi=0;xi<nframes;xi++){
+    /*Frequency masking (low to high): 10 dB/Bark slope.*/
+    for(bi=1;bi<NBANDS;bi++){
+      for(ci=0;ci<nchannels;ci++){
+        xb[(xi*NBANDS+bi)*nchannels+ci]+=
+         0.1F*xb[(xi*NBANDS+bi-1)*nchannels+ci];
+      }
+    }
+    /*Frequency masking (high to low): 15 dB/Bark slope.*/
+    for(bi=NBANDS-1;bi-->0;){
+      for(ci=0;ci<nchannels;ci++){
+        xb[(xi*NBANDS+bi)*nchannels+ci]+=
+         0.03F*xb[(xi*NBANDS+bi+1)*nchannels+ci];
+      }
+    }
+    if(xi>0){
+      /*Temporal masking: -3 dB/2.5ms slope.*/
+      for(bi=0;bi<NBANDS;bi++){
+        for(ci=0;ci<nchannels;ci++){
+          xb[(xi*NBANDS+bi)*nchannels+ci]+=
+           0.5F*xb[((xi-1)*NBANDS+bi)*nchannels+ci];
+        }
+      }
+    }
+    /* Allowing some cross-talk */
+    if(nchannels==2){
+      for(bi=0;bi<NBANDS;bi++){
+        float l,r;
+        l=xb[(xi*NBANDS+bi)*nchannels+0];
+        r=xb[(xi*NBANDS+bi)*nchannels+1];
+        xb[(xi*NBANDS+bi)*nchannels+0]+=0.01F*r;
+        xb[(xi*NBANDS+bi)*nchannels+1]+=0.01F*l;
+      }
+    }
+
+    /* Apply masking */
+    for(bi=0;bi<ybands;bi++){
+      for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
+        for(ci=0;ci<nchannels;ci++){
+          X[(xi*NFREQS+xj)*nchannels+ci]+=
+           0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
+          Y[(xi*yfreqs+xj)*nchannels+ci]+=
+           0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
+        }
+      }
+    }
+  }
+
+  /* Average of consecutive frames to make comparison slightly less sensitive */
+  for(bi=0;bi<ybands;bi++){
+    for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
+      for(ci=0;ci<nchannels;ci++){
+         float xtmp;
+         float ytmp;
+         xtmp = X[xj*nchannels+ci];
+         ytmp = Y[xj*nchannels+ci];
+         for(xi=1;xi<nframes;xi++){
+           float xtmp2;
+           float ytmp2;
+           xtmp2 = X[(xi*NFREQS+xj)*nchannels+ci];
+           ytmp2 = Y[(xi*yfreqs+xj)*nchannels+ci];
+           X[(xi*NFREQS+xj)*nchannels+ci] += xtmp;
+           Y[(xi*yfreqs+xj)*nchannels+ci] += ytmp;
+           xtmp = xtmp2;
+           ytmp = ytmp2;
+         }
+      }
+    }
+  }
+
+  /*If working at a lower sampling rate, don't take into account the last
+     300 Hz to allow for different transition bands.
+    For 12 kHz, we don't skip anything, because the last band already skips
+     400 Hz.*/
+  if(rate==48000)max_compare=BANDS[NBANDS];
+  else if(rate==12000)max_compare=BANDS[ybands];
+  else max_compare=BANDS[ybands]-3;
+  err=0;
+  for(xi=0;xi<nframes;xi++){
+    double Ef;
+    Ef=0;
+    for(bi=0;bi<ybands;bi++){
+      double Eb;
+      Eb=0;
+      for(xj=BANDS[bi];xj<BANDS[bi+1]&&xj<max_compare;xj++){
+        for(ci=0;ci<nchannels;ci++){
+          float re;
+          float im;
+          re=Y[(xi*yfreqs+xj)*nchannels+ci]/X[(xi*NFREQS+xj)*nchannels+ci];
+          im=re-log(re)-1;
+          /*Make comparison less sensitive around the SILK/CELT cross-over to
+            allow for mode freedom in the filters.*/
+          if(xj>=79&&xj<=81)im*=0.1F;
+          if(xj==80)im*=0.1F;
+          Eb+=im;
+        }
+      }
+      Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels;
+      Ef += Eb*Eb;
+    }
+    /*Using a fixed normalization value means we're willing to accept slightly
+       lower quality for lower sampling rates.*/
+    Ef/=NBANDS;
+    Ef*=Ef;
+    err+=Ef*Ef;
+  }
+  err=pow(err/nframes,1.0/16);
+  Q=100*(1-0.5*log(1+err)/log(1.13));
+  if(Q<0){
+    fprintf(stderr,"Test vector FAILS\n");
+    fprintf(stderr,"Internal weighted error is %f\n",err);
+    return EXIT_FAILURE;
+  }
+  else{
+    fprintf(stderr,"Test vector PASSES\n");
+    fprintf(stderr,
+     "Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err);
+    return EXIT_SUCCESS;
+  }
+}
diff --git a/third_party/opus/src/src/opus_decoder.c b/third_party/opus/src/src/opus_decoder.c
new file mode 100644
index 0000000..080bec50
--- /dev/null
+++ b/third_party/opus/src/src/opus_decoder.c
@@ -0,0 +1,981 @@
+/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited
+   Written by Jean-Marc Valin and Koen Vos */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef OPUS_BUILD
+# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details."
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(OPUS_WILL_BE_SLOW)
+# pragma message "You appear to be compiling without optimization, if so opus will be very slow."
+#endif
+
+#include <stdarg.h>
+#include "celt.h"
+#include "opus.h"
+#include "entdec.h"
+#include "modes.h"
+#include "API.h"
+#include "stack_alloc.h"
+#include "float_cast.h"
+#include "opus_private.h"
+#include "os_support.h"
+#include "structs.h"
+#include "define.h"
+#include "mathops.h"
+#include "cpu_support.h"
+
+struct OpusDecoder {
+   int          celt_dec_offset;
+   int          silk_dec_offset;
+   int          channels;
+   opus_int32   Fs;          /** Sampling rate (at the API level) */
+   silk_DecControlStruct DecControl;
+   int          decode_gain;
+   int          arch;
+
+   /* Everything beyond this point gets cleared on a reset */
+#define OPUS_DECODER_RESET_START stream_channels
+   int          stream_channels;
+
+   int          bandwidth;
+   int          mode;
+   int          prev_mode;
+   int          frame_size;
+   int          prev_redundancy;
+   int          last_packet_duration;
+#ifndef FIXED_POINT
+   opus_val16   softclip_mem[2];
+#endif
+
+   opus_uint32  rangeFinal;
+};
+
+
+int opus_decoder_get_size(int channels)
+{
+   int silkDecSizeBytes, celtDecSizeBytes;
+   int ret;
+   if (channels<1 || channels > 2)
+      return 0;
+   ret = silk_Get_Decoder_Size( &silkDecSizeBytes );
+   if(ret)
+      return 0;
+   silkDecSizeBytes = align(silkDecSizeBytes);
+   celtDecSizeBytes = celt_decoder_get_size(channels);
+   return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes;
+}
+
+int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
+{
+   void *silk_dec;
+   CELTDecoder *celt_dec;
+   int ret, silkDecSizeBytes;
+
+   if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
+    || (channels!=1&&channels!=2))
+      return OPUS_BAD_ARG;
+
+   OPUS_CLEAR((char*)st, opus_decoder_get_size(channels));
+   /* Initialize SILK encoder */
+   ret = silk_Get_Decoder_Size(&silkDecSizeBytes);
+   if (ret)
+      return OPUS_INTERNAL_ERROR;
+
+   silkDecSizeBytes = align(silkDecSizeBytes);
+   st->silk_dec_offset = align(sizeof(OpusDecoder));
+   st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes;
+   silk_dec = (char*)st+st->silk_dec_offset;
+   celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+   st->stream_channels = st->channels = channels;
+
+   st->Fs = Fs;
+   st->DecControl.API_sampleRate = st->Fs;
+   st->DecControl.nChannelsAPI      = st->channels;
+
+   /* Reset decoder */
+   ret = silk_InitDecoder( silk_dec );
+   if(ret)return OPUS_INTERNAL_ERROR;
+
+   /* Initialize CELT decoder */
+   ret = celt_decoder_init(celt_dec, Fs, channels);
+   if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+
+   celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0));
+
+   st->prev_mode = 0;
+   st->frame_size = Fs/400;
+   st->arch = opus_select_arch();
+   return OPUS_OK;
+}
+
+OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error)
+{
+   int ret;
+   OpusDecoder *st;
+   if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
+    || (channels!=1&&channels!=2))
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+   st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels));
+   if (st == NULL)
+   {
+      if (error)
+         *error = OPUS_ALLOC_FAIL;
+      return NULL;
+   }
+   ret = opus_decoder_init(st, Fs, channels);
+   if (error)
+      *error = ret;
+   if (ret != OPUS_OK)
+   {
+      opus_free(st);
+      st = NULL;
+   }
+   return st;
+}
+
+static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2,
+      opus_val16 *out, int overlap, int channels,
+      const opus_val16 *window, opus_int32 Fs)
+{
+   int i, c;
+   int inc = 48000/Fs;
+   for (c=0;c<channels;c++)
+   {
+      for (i=0;i<overlap;i++)
+      {
+         opus_val16 w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+         out[i*channels+c] = SHR32(MAC16_16(MULT16_16(w,in2[i*channels+c]),
+                                   Q15ONE-w, in1[i*channels+c]), 15);
+      }
+   }
+}
+
+static int opus_packet_get_mode(const unsigned char *data)
+{
+   int mode;
+   if (data[0]&0x80)
+   {
+      mode = MODE_CELT_ONLY;
+   } else if ((data[0]&0x60) == 0x60)
+   {
+      mode = MODE_HYBRID;
+   } else {
+      mode = MODE_SILK_ONLY;
+   }
+   return mode;
+}
+
+static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
+      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+   void *silk_dec;
+   CELTDecoder *celt_dec;
+   int i, silk_ret=0, celt_ret=0;
+   ec_dec dec;
+   opus_int32 silk_frame_size;
+   int pcm_silk_size;
+   VARDECL(opus_int16, pcm_silk);
+   int pcm_transition_silk_size;
+   VARDECL(opus_val16, pcm_transition_silk);
+   int pcm_transition_celt_size;
+   VARDECL(opus_val16, pcm_transition_celt);
+   opus_val16 *pcm_transition=NULL;
+   int redundant_audio_size;
+   VARDECL(opus_val16, redundant_audio);
+
+   int audiosize;
+   int mode;
+   int transition=0;
+   int start_band;
+   int redundancy=0;
+   int redundancy_bytes = 0;
+   int celt_to_silk=0;
+   int c;
+   int F2_5, F5, F10, F20;
+   const opus_val16 *window;
+   opus_uint32 redundant_rng = 0;
+   int celt_accum;
+   ALLOC_STACK;
+
+   silk_dec = (char*)st+st->silk_dec_offset;
+   celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+   F20 = st->Fs/50;
+   F10 = F20>>1;
+   F5 = F10>>1;
+   F2_5 = F5>>1;
+   if (frame_size < F2_5)
+   {
+      RESTORE_STACK;
+      return OPUS_BUFFER_TOO_SMALL;
+   }
+   /* Limit frame_size to avoid excessive stack allocations. */
+   frame_size = IMIN(frame_size, st->Fs/25*3);
+   /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
+   if (len<=1)
+   {
+      data = NULL;
+      /* In that case, don't conceal more than what the ToC says */
+      frame_size = IMIN(frame_size, st->frame_size);
+   }
+   if (data != NULL)
+   {
+      audiosize = st->frame_size;
+      mode = st->mode;
+      ec_dec_init(&dec,(unsigned char*)data,len);
+   } else {
+      audiosize = frame_size;
+      mode = st->prev_mode;
+
+      if (mode == 0)
+      {
+         /* If we haven't got any packet yet, all we can do is return zeros */
+         for (i=0;i<audiosize*st->channels;i++)
+            pcm[i] = 0;
+         RESTORE_STACK;
+         return audiosize;
+      }
+
+      /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
+         10, or 20 (e.g. 12.5 or 30 ms). */
+      if (audiosize > F20)
+      {
+         do {
+            int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0);
+            if (ret<0)
+            {
+               RESTORE_STACK;
+               return ret;
+            }
+            pcm += ret*st->channels;
+            audiosize -= ret;
+         } while (audiosize > 0);
+         RESTORE_STACK;
+         return frame_size;
+      } else if (audiosize < F20)
+      {
+         if (audiosize > F10)
+            audiosize = F10;
+         else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10)
+            audiosize = F5;
+      }
+   }
+
+   /* In fixed-point, we can tell CELT to do the accumulation on top of the
+      SILK PCM buffer. This saves some stack space. */
+#ifdef FIXED_POINT
+   celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10);
+#else
+   celt_accum = 0;
+#endif
+
+   pcm_transition_silk_size = ALLOC_NONE;
+   pcm_transition_celt_size = ALLOC_NONE;
+   if (data!=NULL && st->prev_mode > 0 && (
+       (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy)
+    || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) )
+      )
+   {
+      transition = 1;
+      /* Decide where to allocate the stack memory for pcm_transition */
+      if (mode == MODE_CELT_ONLY)
+         pcm_transition_celt_size = F5*st->channels;
+      else
+         pcm_transition_silk_size = F5*st->channels;
+   }
+   ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16);
+   if (transition && mode == MODE_CELT_ONLY)
+   {
+      pcm_transition = pcm_transition_celt;
+      opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
+   }
+   if (audiosize > frame_size)
+   {
+      /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   } else {
+      frame_size = audiosize;
+   }
+
+   /* Don't allocate any memory when in CELT-only mode */
+   pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE;
+   ALLOC(pcm_silk, pcm_silk_size, opus_int16);
+
+   /* SILK processing */
+   if (mode != MODE_CELT_ONLY)
+   {
+      int lost_flag, decoded_samples;
+      opus_int16 *pcm_ptr;
+#ifdef FIXED_POINT
+      if (celt_accum)
+         pcm_ptr = pcm;
+      else
+#endif
+         pcm_ptr = pcm_silk;
+
+      if (st->prev_mode==MODE_CELT_ONLY)
+         silk_InitDecoder( silk_dec );
+
+      /* The SILK PLC cannot produce frames of less than 10 ms */
+      st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs);
+
+      if (data != NULL)
+      {
+        st->DecControl.nChannelsInternal = st->stream_channels;
+        if( mode == MODE_SILK_ONLY ) {
+           if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
+              st->DecControl.internalSampleRate = 8000;
+           } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
+              st->DecControl.internalSampleRate = 12000;
+           } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
+              st->DecControl.internalSampleRate = 16000;
+           } else {
+              st->DecControl.internalSampleRate = 16000;
+              silk_assert( 0 );
+           }
+        } else {
+           /* Hybrid mode */
+           st->DecControl.internalSampleRate = 16000;
+        }
+     }
+
+     lost_flag = data == NULL ? 1 : 2 * decode_fec;
+     decoded_samples = 0;
+     do {
+        /* Call SILK decoder */
+        int first_frame = decoded_samples == 0;
+        silk_ret = silk_Decode( silk_dec, &st->DecControl,
+                                lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch );
+        if( silk_ret ) {
+           if (lost_flag) {
+              /* PLC failure should not be fatal */
+              silk_frame_size = frame_size;
+              for (i=0;i<frame_size*st->channels;i++)
+                 pcm_ptr[i] = 0;
+           } else {
+             RESTORE_STACK;
+             return OPUS_INTERNAL_ERROR;
+           }
+        }
+        pcm_ptr += silk_frame_size * st->channels;
+        decoded_samples += silk_frame_size;
+      } while( decoded_samples < frame_size );
+   }
+
+   start_band = 0;
+   if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL
+    && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len)
+   {
+      /* Check if we have a redundant 0-8 kHz band */
+      if (mode == MODE_HYBRID)
+         redundancy = ec_dec_bit_logp(&dec, 12);
+      else
+         redundancy = 1;
+      if (redundancy)
+      {
+         celt_to_silk = ec_dec_bit_logp(&dec, 1);
+         /* redundancy_bytes will be at least two, in the non-hybrid
+            case due to the ec_tell() check above */
+         redundancy_bytes = mode==MODE_HYBRID ?
+               (opus_int32)ec_dec_uint(&dec, 256)+2 :
+               len-((ec_tell(&dec)+7)>>3);
+         len -= redundancy_bytes;
+         /* This is a sanity check. It should never happen for a valid
+            packet, so the exact behaviour is not normative. */
+         if (len*8 < ec_tell(&dec))
+         {
+            len = 0;
+            redundancy_bytes = 0;
+            redundancy = 0;
+         }
+         /* Shrink decoder because of raw bits */
+         dec.storage -= redundancy_bytes;
+      }
+   }
+   if (mode != MODE_CELT_ONLY)
+      start_band = 17;
+
+   {
+      int endband=21;
+
+      switch(st->bandwidth)
+      {
+      case OPUS_BANDWIDTH_NARROWBAND:
+         endband = 13;
+         break;
+      case OPUS_BANDWIDTH_MEDIUMBAND:
+      case OPUS_BANDWIDTH_WIDEBAND:
+         endband = 17;
+         break;
+      case OPUS_BANDWIDTH_SUPERWIDEBAND:
+         endband = 19;
+         break;
+      case OPUS_BANDWIDTH_FULLBAND:
+         endband = 21;
+         break;
+      }
+      celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband));
+      celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels));
+   }
+
+   if (redundancy)
+   {
+      transition = 0;
+      pcm_transition_silk_size=ALLOC_NONE;
+   }
+
+   ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16);
+
+   if (transition && mode != MODE_CELT_ONLY)
+   {
+      pcm_transition = pcm_transition_silk;
+      opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
+   }
+
+   /* Only allocation memory for redundancy if/when needed */
+   redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE;
+   ALLOC(redundant_audio, redundant_audio_size, opus_val16);
+
+   /* 5 ms redundant frame for CELT->SILK*/
+   if (redundancy && celt_to_silk)
+   {
+      celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+      celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
+                          redundant_audio, F5, NULL, 0);
+      celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
+   }
+
+   /* MUST be after PLC */
+   celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band));
+
+   if (mode != MODE_SILK_ONLY)
+   {
+      int celt_frame_size = IMIN(F20, frame_size);
+      /* Make sure to discard any previous CELT state */
+      if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy)
+         celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+      /* Decode CELT */
+      celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
+                                     len, pcm, celt_frame_size, &dec, celt_accum);
+   } else {
+      unsigned char silence[2] = {0xFF, 0xFF};
+      if (!celt_accum)
+      {
+         for (i=0;i<frame_size*st->channels;i++)
+            pcm[i] = 0;
+      }
+      /* For hybrid -> SILK transitions, we let the CELT MDCT
+         do a fade-out by decoding a silence frame */
+      if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
+      {
+         celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+         celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum);
+      }
+   }
+
+   if (mode != MODE_CELT_ONLY && !celt_accum)
+   {
+#ifdef FIXED_POINT
+      for (i=0;i<frame_size*st->channels;i++)
+         pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i]));
+#else
+      for (i=0;i<frame_size*st->channels;i++)
+         pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]);
+#endif
+   }
+
+   {
+      const CELTMode *celt_mode;
+      celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode));
+      window = celt_mode->window;
+   }
+
+   /* 5 ms redundant frame for SILK->CELT */
+   if (redundancy && !celt_to_silk)
+   {
+      celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+      celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+
+      celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0);
+      celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
+      smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5,
+                  pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
+   }
+   if (redundancy && celt_to_silk)
+   {
+      for (c=0;c<st->channels;c++)
+      {
+         for (i=0;i<F2_5;i++)
+            pcm[st->channels*i+c] = redundant_audio[st->channels*i+c];
+      }
+      smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5,
+                  pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs);
+   }
+   if (transition)
+   {
+      if (audiosize >= F5)
+      {
+         for (i=0;i<st->channels*F2_5;i++)
+            pcm[i] = pcm_transition[i];
+         smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5,
+                     pcm+st->channels*F2_5, F2_5,
+                     st->channels, window, st->Fs);
+      } else {
+         /* Not enough time to do a clean transition, but we do it anyway
+            This will not preserve amplitude perfectly and may introduce
+            a bit of temporal aliasing, but it shouldn't be too bad and
+            that's pretty much the best we can do. In any case, generating this
+            transition it pretty silly in the first place */
+         smooth_fade(pcm_transition, pcm,
+                     pcm, F2_5,
+                     st->channels, window, st->Fs);
+      }
+   }
+
+   if(st->decode_gain)
+   {
+      opus_val32 gain;
+      gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain));
+      for (i=0;i<frame_size*st->channels;i++)
+      {
+         opus_val32 x;
+         x = MULT16_32_P16(pcm[i],gain);
+         pcm[i] = SATURATE(x, 32767);
+      }
+   }
+
+   if (len <= 1)
+      st->rangeFinal = 0;
+   else
+      st->rangeFinal = dec.rng ^ redundant_rng;
+
+   st->prev_mode = mode;
+   st->prev_redundancy = redundancy && !celt_to_silk;
+
+   if (celt_ret>=0)
+   {
+      if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels))
+         OPUS_PRINT_INT(audiosize);
+   }
+
+   RESTORE_STACK;
+   return celt_ret < 0 ? celt_ret : audiosize;
+
+}
+
+int opus_decode_native(OpusDecoder *st, const unsigned char *data,
+      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec,
+      int self_delimited, opus_int32 *packet_offset, int soft_clip)
+{
+   int i, nb_samples;
+   int count, offset;
+   unsigned char toc;
+   int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
+   /* 48 x 2.5 ms = 120 ms */
+   opus_int16 size[48];
+   if (decode_fec<0 || decode_fec>1)
+      return OPUS_BAD_ARG;
+   /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
+   if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
+      return OPUS_BAD_ARG;
+   if (len==0 || data==NULL)
+   {
+      int pcm_count=0;
+      do {
+         int ret;
+         ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0);
+         if (ret<0)
+            return ret;
+         pcm_count += ret;
+      } while (pcm_count < frame_size);
+      celt_assert(pcm_count == frame_size);
+      if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels))
+         OPUS_PRINT_INT(pcm_count);
+      st->last_packet_duration = pcm_count;
+      return pcm_count;
+   } else if (len<0)
+      return OPUS_BAD_ARG;
+
+   packet_mode = opus_packet_get_mode(data);
+   packet_bandwidth = opus_packet_get_bandwidth(data);
+   packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
+   packet_stream_channels = opus_packet_get_nb_channels(data);
+
+   count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
+                                  size, &offset, packet_offset);
+   if (count<0)
+      return count;
+
+   data += offset;
+
+   if (decode_fec)
+   {
+      int duration_copy;
+      int ret;
+      /* If no FEC can be present, run the PLC (recursive call) */
+      if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
+         return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip);
+      /* Otherwise, run the PLC on everything except the size for which we might have FEC */
+      duration_copy = st->last_packet_duration;
+      if (frame_size-packet_frame_size!=0)
+      {
+         ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip);
+         if (ret<0)
+         {
+            st->last_packet_duration = duration_copy;
+            return ret;
+         }
+         celt_assert(ret==frame_size-packet_frame_size);
+      }
+      /* Complete with FEC */
+      st->mode = packet_mode;
+      st->bandwidth = packet_bandwidth;
+      st->frame_size = packet_frame_size;
+      st->stream_channels = packet_stream_channels;
+      ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
+            packet_frame_size, 1);
+      if (ret<0)
+         return ret;
+      else {
+         if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels))
+            OPUS_PRINT_INT(frame_size);
+         st->last_packet_duration = frame_size;
+         return frame_size;
+      }
+   }
+
+   if (count*packet_frame_size > frame_size)
+      return OPUS_BUFFER_TOO_SMALL;
+
+   /* Update the state as the last step to avoid updating it on an invalid packet */
+   st->mode = packet_mode;
+   st->bandwidth = packet_bandwidth;
+   st->frame_size = packet_frame_size;
+   st->stream_channels = packet_stream_channels;
+
+   nb_samples=0;
+   for (i=0;i<count;i++)
+   {
+      int ret;
+      ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0);
+      if (ret<0)
+         return ret;
+      celt_assert(ret==packet_frame_size);
+      data += size[i];
+      nb_samples += ret;
+   }
+   st->last_packet_duration = nb_samples;
+   if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels))
+      OPUS_PRINT_INT(nb_samples);
+#ifndef FIXED_POINT
+   if (soft_clip)
+      opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem);
+   else
+      st->softclip_mem[0]=st->softclip_mem[1]=0;
+#endif
+   return nb_samples;
+}
+
+#ifdef FIXED_POINT
+
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+   if(frame_size<=0)
+      return OPUS_BAD_ARG;
+   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+      opus_int32 len, float *pcm, int frame_size, int decode_fec)
+{
+   VARDECL(opus_int16, out);
+   int ret, i;
+   int nb_samples;
+   ALLOC_STACK;
+
+   if(frame_size<=0)
+   {
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   }
+   if (data != NULL && len > 0 && !decode_fec)
+   {
+      nb_samples = opus_decoder_get_nb_samples(st, data, len);
+      if (nb_samples>0)
+         frame_size = IMIN(frame_size, nb_samples);
+      else
+         return OPUS_INVALID_PACKET;
+   }
+   ALLOC(out, frame_size*st->channels, opus_int16);
+
+   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0);
+   if (ret > 0)
+   {
+      for (i=0;i<ret*st->channels;i++)
+         pcm[i] = (1.f/32768.f)*(out[i]);
+   }
+   RESTORE_STACK;
+   return ret;
+}
+#endif
+
+
+#else
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+      opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
+{
+   VARDECL(float, out);
+   int ret, i;
+   int nb_samples;
+   ALLOC_STACK;
+
+   if(frame_size<=0)
+   {
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   }
+
+   if (data != NULL && len > 0 && !decode_fec)
+   {
+      nb_samples = opus_decoder_get_nb_samples(st, data, len);
+      if (nb_samples>0)
+         frame_size = IMIN(frame_size, nb_samples);
+      else
+         return OPUS_INVALID_PACKET;
+   }
+   ALLOC(out, frame_size*st->channels, float);
+
+   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1);
+   if (ret > 0)
+   {
+      for (i=0;i<ret*st->channels;i++)
+         pcm[i] = FLOAT2INT16(out[i]);
+   }
+   RESTORE_STACK;
+   return ret;
+}
+
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+   if(frame_size<=0)
+      return OPUS_BAD_ARG;
+   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
+}
+
+#endif
+
+int opus_decoder_ctl(OpusDecoder *st, int request, ...)
+{
+   int ret = OPUS_OK;
+   va_list ap;
+   void *silk_dec;
+   CELTDecoder *celt_dec;
+
+   silk_dec = (char*)st+st->silk_dec_offset;
+   celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+
+
+   va_start(ap, request);
+
+   switch (request)
+   {
+   case OPUS_GET_BANDWIDTH_REQUEST:
+   {
+      opus_int32 *value = va_arg(ap, opus_int32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      *value = st->bandwidth;
+   }
+   break;
+   case OPUS_GET_FINAL_RANGE_REQUEST:
+   {
+      opus_uint32 *value = va_arg(ap, opus_uint32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      *value = st->rangeFinal;
+   }
+   break;
+   case OPUS_RESET_STATE:
+   {
+      OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START,
+            sizeof(OpusDecoder)-
+            ((char*)&st->OPUS_DECODER_RESET_START - (char*)st));
+
+      celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+      silk_InitDecoder( silk_dec );
+      st->stream_channels = st->channels;
+      st->frame_size = st->Fs/400;
+   }
+   break;
+   case OPUS_GET_SAMPLE_RATE_REQUEST:
+   {
+      opus_int32 *value = va_arg(ap, opus_int32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      *value = st->Fs;
+   }
+   break;
+   case OPUS_GET_PITCH_REQUEST:
+   {
+      opus_int32 *value = va_arg(ap, opus_int32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      if (st->prev_mode == MODE_CELT_ONLY)
+         celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
+      else
+         *value = st->DecControl.prevPitchLag;
+   }
+   break;
+   case OPUS_GET_GAIN_REQUEST:
+   {
+      opus_int32 *value = va_arg(ap, opus_int32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      *value = st->decode_gain;
+   }
+   break;
+   case OPUS_SET_GAIN_REQUEST:
+   {
+       opus_int32 value = va_arg(ap, opus_int32);
+       if (value<-32768 || value>32767)
+       {
+          goto bad_arg;
+       }
+       st->decode_gain = value;
+   }
+   break;
+   case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
+   {
+      opus_uint32 *value = va_arg(ap, opus_uint32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      *value = st->last_packet_duration;
+   }
+   break;
+   default:
+      /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
+      ret = OPUS_UNIMPLEMENTED;
+      break;
+   }
+
+   va_end(ap);
+   return ret;
+bad_arg:
+   va_end(ap);
+   return OPUS_BAD_ARG;
+}
+
+void opus_decoder_destroy(OpusDecoder *st)
+{
+   opus_free(st);
+}
+
+
+int opus_packet_get_bandwidth(const unsigned char *data)
+{
+   int bandwidth;
+   if (data[0]&0x80)
+   {
+      bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3);
+      if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+         bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+   } else if ((data[0]&0x60) == 0x60)
+   {
+      bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND :
+                                   OPUS_BANDWIDTH_SUPERWIDEBAND;
+   } else {
+      bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3);
+   }
+   return bandwidth;
+}
+
+int opus_packet_get_nb_channels(const unsigned char *data)
+{
+   return (data[0]&0x4) ? 2 : 1;
+}
+
+int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len)
+{
+   int count;
+   if (len<1)
+      return OPUS_BAD_ARG;
+   count = packet[0]&0x3;
+   if (count==0)
+      return 1;
+   else if (count!=3)
+      return 2;
+   else if (len<2)
+      return OPUS_INVALID_PACKET;
+   else
+      return packet[1]&0x3F;
+}
+
+int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len,
+      opus_int32 Fs)
+{
+   int samples;
+   int count = opus_packet_get_nb_frames(packet, len);
+
+   if (count<0)
+      return count;
+
+   samples = count*opus_packet_get_samples_per_frame(packet, Fs);
+   /* Can't have more than 120 ms */
+   if (samples*25 > Fs*3)
+      return OPUS_INVALID_PACKET;
+   else
+      return samples;
+}
+
+int opus_decoder_get_nb_samples(const OpusDecoder *dec,
+      const unsigned char packet[], opus_int32 len)
+{
+   return opus_packet_get_nb_samples(packet, len, dec->Fs);
+}
diff --git a/third_party/opus/src/src/opus_demo.c b/third_party/opus/src/src/opus_demo.c
new file mode 100644
index 0000000..7c930699
--- /dev/null
+++ b/third_party/opus/src/src/opus_demo.c
@@ -0,0 +1,887 @@
+/* Copyright (c) 2007-2008 CSIRO
+   Copyright (c) 2007-2009 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "opus.h"
+#include "debug.h"
+#include "opus_types.h"
+#include "opus_private.h"
+#include "opus_multistream.h"
+
+#define MAX_PACKET 1500
+
+void print_usage( char* argv[] )
+{
+    fprintf(stderr, "Usage: %s [-e] <application> <sampling rate (Hz)> <channels (1/2)> "
+        "<bits per second>  [options] <input> <output>\n", argv[0]);
+    fprintf(stderr, "       %s -d <sampling rate (Hz)> <channels (1/2)> "
+        "[options] <input> <output>\n\n", argv[0]);
+    fprintf(stderr, "application: voip | audio | restricted-lowdelay\n" );
+    fprintf(stderr, "options:\n" );
+    fprintf(stderr, "-e                   : only runs the encoder (output the bit-stream)\n" );
+    fprintf(stderr, "-d                   : only runs the decoder (reads the bit-stream as input)\n" );
+    fprintf(stderr, "-cbr                 : enable constant bitrate; default: variable bitrate\n" );
+    fprintf(stderr, "-cvbr                : enable constrained variable bitrate; default: unconstrained\n" );
+    fprintf(stderr, "-variable-duration   : enable frames of variable duration (experts only); default: disabled\n" );
+    fprintf(stderr, "-bandwidth <NB|MB|WB|SWB|FB> : audio bandwidth (from narrowband to fullband); default: sampling rate\n" );
+    fprintf(stderr, "-framesize <2.5|5|10|20|40|60> : frame size in ms; default: 20 \n" );
+    fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
+    fprintf(stderr, "-complexity <comp>   : complexity, 0 (lowest) ... 10 (highest); default: 10\n" );
+    fprintf(stderr, "-inbandfec           : enable SILK inband FEC\n" );
+    fprintf(stderr, "-forcemono           : force mono encoding, even for stereo input\n" );
+    fprintf(stderr, "-dtx                 : enable SILK DTX\n" );
+    fprintf(stderr, "-loss <perc>         : simulate packet loss, in percent (0-100); default: 0\n" );
+}
+
+static void int_to_char(opus_uint32 i, unsigned char ch[4])
+{
+    ch[0] = i>>24;
+    ch[1] = (i>>16)&0xFF;
+    ch[2] = (i>>8)&0xFF;
+    ch[3] = i&0xFF;
+}
+
+static opus_uint32 char_to_int(unsigned char ch[4])
+{
+    return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16)
+         | ((opus_uint32)ch[2]<< 8) |  (opus_uint32)ch[3];
+}
+
+static void check_encoder_option(int decode_only, const char *opt)
+{
+   if (decode_only)
+   {
+      fprintf(stderr, "option %s is only for encoding\n", opt);
+      exit(EXIT_FAILURE);
+   }
+}
+
+static const int silk8_test[][4] = {
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960,   1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480,   1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960,   2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480,   2}
+};
+
+static const int silk12_test[][4] = {
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960,   1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480,   1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960,   2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480,   2}
+};
+
+static const int silk16_test[][4] = {
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960,   1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480,   1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960,   2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480,   2}
+};
+
+static const int hybrid24_test[][4] = {
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2}
+};
+
+static const int hybrid48_test[][4] = {
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2},
+      {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}
+};
+
+static const int celt_test[][4] = {
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      960, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND,      960, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND,    960, 1},
+
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      480, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND,      480, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND,    480, 1},
+
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      240, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND,      240, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND,    240, 1},
+
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      120, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND,      120, 1},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND,    120, 1},
+
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      960, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND,      960, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND,    960, 2},
+
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      480, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND,      480, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND,    480, 2},
+
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      240, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND,      240, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND,    240, 2},
+
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      120, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND,      120, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND,    120, 2},
+
+};
+
+static const int celt_hq_test[][4] = {
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      960, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      480, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      240, 2},
+      {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND,      120, 2},
+};
+
+#if 0 /* This is a hack that replaces the normal encoder/decoder with the multistream version */
+#define OpusEncoder OpusMSEncoder
+#define OpusDecoder OpusMSDecoder
+#define opus_encode opus_multistream_encode
+#define opus_decode opus_multistream_decode
+#define opus_encoder_ctl opus_multistream_encoder_ctl
+#define opus_decoder_ctl opus_multistream_decoder_ctl
+#define opus_encoder_create ms_opus_encoder_create
+#define opus_decoder_create ms_opus_decoder_create
+#define opus_encoder_destroy opus_multistream_encoder_destroy
+#define opus_decoder_destroy opus_multistream_decoder_destroy
+
+static OpusEncoder *ms_opus_encoder_create(opus_int32 Fs, int channels, int application, int *error)
+{
+   int streams, coupled_streams;
+   unsigned char mapping[256];
+   return (OpusEncoder *)opus_multistream_surround_encoder_create(Fs, channels, 1, &streams, &coupled_streams, mapping, application, error);
+}
+static OpusDecoder *ms_opus_decoder_create(opus_int32 Fs, int channels, int *error)
+{
+   int streams;
+   int coupled_streams;
+   unsigned char mapping[256]={0,1};
+   streams = 1;
+   coupled_streams = channels==2;
+   return (OpusDecoder *)opus_multistream_decoder_create(Fs, channels, streams, coupled_streams, mapping, error);
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+    int err;
+    char *inFile, *outFile;
+    FILE *fin, *fout;
+    OpusEncoder *enc=NULL;
+    OpusDecoder *dec=NULL;
+    int args;
+    int len[2];
+    int frame_size, channels;
+    opus_int32 bitrate_bps=0;
+    unsigned char *data[2];
+    unsigned char *fbytes;
+    opus_int32 sampling_rate;
+    int use_vbr;
+    int max_payload_bytes;
+    int complexity;
+    int use_inbandfec;
+    int use_dtx;
+    int forcechannels;
+    int cvbr = 0;
+    int packet_loss_perc;
+    opus_int32 count=0, count_act=0;
+    int k;
+    opus_int32 skip=0;
+    int stop=0;
+    short *in, *out;
+    int application=OPUS_APPLICATION_AUDIO;
+    double bits=0.0, bits_max=0.0, bits_act=0.0, bits2=0.0, nrg;
+    double tot_samples=0;
+    opus_uint64 tot_in, tot_out;
+    int bandwidth=OPUS_AUTO;
+    const char *bandwidth_string;
+    int lost = 0, lost_prev = 1;
+    int toggle = 0;
+    opus_uint32 enc_final_range[2];
+    opus_uint32 dec_final_range;
+    int encode_only=0, decode_only=0;
+    int max_frame_size = 48000*2;
+    int curr_read=0;
+    int sweep_bps = 0;
+    int random_framesize=0, newsize=0, delayed_celt=0;
+    int sweep_max=0, sweep_min=0;
+    int random_fec=0;
+    const int (*mode_list)[4]=NULL;
+    int nb_modes_in_list=0;
+    int curr_mode=0;
+    int curr_mode_count=0;
+    int mode_switch_time = 48000;
+    int nb_encoded=0;
+    int remaining=0;
+    int variable_duration=OPUS_FRAMESIZE_ARG;
+    int delayed_decision=0;
+
+    if (argc < 5 )
+    {
+       print_usage( argv );
+       return EXIT_FAILURE;
+    }
+
+    tot_in=tot_out=0;
+    fprintf(stderr, "%s\n", opus_get_version_string());
+
+    args = 1;
+    if (strcmp(argv[args], "-e")==0)
+    {
+        encode_only = 1;
+        args++;
+    } else if (strcmp(argv[args], "-d")==0)
+    {
+        decode_only = 1;
+        args++;
+    }
+    if (!decode_only && argc < 7 )
+    {
+       print_usage( argv );
+       return EXIT_FAILURE;
+    }
+
+    if (!decode_only)
+    {
+       if (strcmp(argv[args], "voip")==0)
+          application = OPUS_APPLICATION_VOIP;
+       else if (strcmp(argv[args], "restricted-lowdelay")==0)
+          application = OPUS_APPLICATION_RESTRICTED_LOWDELAY;
+       else if (strcmp(argv[args], "audio")!=0) {
+          fprintf(stderr, "unknown application: %s\n", argv[args]);
+          print_usage(argv);
+          return EXIT_FAILURE;
+       }
+       args++;
+    }
+    sampling_rate = (opus_int32)atol(argv[args]);
+    args++;
+
+    if (sampling_rate != 8000 && sampling_rate != 12000
+     && sampling_rate != 16000 && sampling_rate != 24000
+     && sampling_rate != 48000)
+    {
+        fprintf(stderr, "Supported sampling rates are 8000, 12000, "
+                "16000, 24000 and 48000.\n");
+        return EXIT_FAILURE;
+    }
+    frame_size = sampling_rate/50;
+
+    channels = atoi(argv[args]);
+    args++;
+
+    if (channels < 1 || channels > 2)
+    {
+        fprintf(stderr, "Opus_demo supports only 1 or 2 channels.\n");
+        return EXIT_FAILURE;
+    }
+
+    if (!decode_only)
+    {
+       bitrate_bps = (opus_int32)atol(argv[args]);
+       args++;
+    }
+
+    /* defaults: */
+    use_vbr = 1;
+    max_payload_bytes = MAX_PACKET;
+    complexity = 10;
+    use_inbandfec = 0;
+    forcechannels = OPUS_AUTO;
+    use_dtx = 0;
+    packet_loss_perc = 0;
+
+    while( args < argc - 2 ) {
+        /* process command line options */
+        if( strcmp( argv[ args ], "-cbr" ) == 0 ) {
+            check_encoder_option(decode_only, "-cbr");
+            use_vbr = 0;
+            args++;
+        } else if( strcmp( argv[ args ], "-bandwidth" ) == 0 ) {
+            check_encoder_option(decode_only, "-bandwidth");
+            if (strcmp(argv[ args + 1 ], "NB")==0)
+                bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+            else if (strcmp(argv[ args + 1 ], "MB")==0)
+                bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+            else if (strcmp(argv[ args + 1 ], "WB")==0)
+                bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+            else if (strcmp(argv[ args + 1 ], "SWB")==0)
+                bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+            else if (strcmp(argv[ args + 1 ], "FB")==0)
+                bandwidth = OPUS_BANDWIDTH_FULLBAND;
+            else {
+                fprintf(stderr, "Unknown bandwidth %s. "
+                                "Supported are NB, MB, WB, SWB, FB.\n",
+                                argv[ args + 1 ]);
+                return EXIT_FAILURE;
+            }
+            args += 2;
+        } else if( strcmp( argv[ args ], "-framesize" ) == 0 ) {
+            check_encoder_option(decode_only, "-framesize");
+            if (strcmp(argv[ args + 1 ], "2.5")==0)
+                frame_size = sampling_rate/400;
+            else if (strcmp(argv[ args + 1 ], "5")==0)
+                frame_size = sampling_rate/200;
+            else if (strcmp(argv[ args + 1 ], "10")==0)
+                frame_size = sampling_rate/100;
+            else if (strcmp(argv[ args + 1 ], "20")==0)
+                frame_size = sampling_rate/50;
+            else if (strcmp(argv[ args + 1 ], "40")==0)
+                frame_size = sampling_rate/25;
+            else if (strcmp(argv[ args + 1 ], "60")==0)
+                frame_size = 3*sampling_rate/50;
+            else {
+                fprintf(stderr, "Unsupported frame size: %s ms. "
+                                "Supported are 2.5, 5, 10, 20, 40, 60.\n",
+                                argv[ args + 1 ]);
+                return EXIT_FAILURE;
+            }
+            args += 2;
+        } else if( strcmp( argv[ args ], "-max_payload" ) == 0 ) {
+            check_encoder_option(decode_only, "-max_payload");
+            max_payload_bytes = atoi( argv[ args + 1 ] );
+            args += 2;
+        } else if( strcmp( argv[ args ], "-complexity" ) == 0 ) {
+            check_encoder_option(decode_only, "-complexity");
+            complexity = atoi( argv[ args + 1 ] );
+            args += 2;
+        } else if( strcmp( argv[ args ], "-inbandfec" ) == 0 ) {
+            use_inbandfec = 1;
+            args++;
+        } else if( strcmp( argv[ args ], "-forcemono" ) == 0 ) {
+            check_encoder_option(decode_only, "-forcemono");
+            forcechannels = 1;
+            args++;
+        } else if( strcmp( argv[ args ], "-cvbr" ) == 0 ) {
+            check_encoder_option(decode_only, "-cvbr");
+            cvbr = 1;
+            args++;
+        } else if( strcmp( argv[ args ], "-variable-duration" ) == 0 ) {
+            check_encoder_option(decode_only, "-variable-duration");
+            variable_duration = OPUS_FRAMESIZE_VARIABLE;
+            args++;
+        } else if( strcmp( argv[ args ], "-delayed-decision" ) == 0 ) {
+            check_encoder_option(decode_only, "-delayed-decision");
+            delayed_decision = 1;
+            args++;
+        } else if( strcmp( argv[ args ], "-dtx") == 0 ) {
+            check_encoder_option(decode_only, "-dtx");
+            use_dtx = 1;
+            args++;
+        } else if( strcmp( argv[ args ], "-loss" ) == 0 ) {
+            packet_loss_perc = atoi( argv[ args + 1 ] );
+            args += 2;
+        } else if( strcmp( argv[ args ], "-sweep" ) == 0 ) {
+            check_encoder_option(decode_only, "-sweep");
+            sweep_bps = atoi( argv[ args + 1 ] );
+            args += 2;
+        } else if( strcmp( argv[ args ], "-random_framesize" ) == 0 ) {
+            check_encoder_option(decode_only, "-random_framesize");
+            random_framesize = 1;
+            args++;
+        } else if( strcmp( argv[ args ], "-sweep_max" ) == 0 ) {
+            check_encoder_option(decode_only, "-sweep_max");
+            sweep_max = atoi( argv[ args + 1 ] );
+            args += 2;
+        } else if( strcmp( argv[ args ], "-random_fec" ) == 0 ) {
+            check_encoder_option(decode_only, "-random_fec");
+            random_fec = 1;
+            args++;
+        } else if( strcmp( argv[ args ], "-silk8k_test" ) == 0 ) {
+            check_encoder_option(decode_only, "-silk8k_test");
+            mode_list = silk8_test;
+            nb_modes_in_list = 8;
+            args++;
+        } else if( strcmp( argv[ args ], "-silk12k_test" ) == 0 ) {
+            check_encoder_option(decode_only, "-silk12k_test");
+            mode_list = silk12_test;
+            nb_modes_in_list = 8;
+            args++;
+        } else if( strcmp( argv[ args ], "-silk16k_test" ) == 0 ) {
+            check_encoder_option(decode_only, "-silk16k_test");
+            mode_list = silk16_test;
+            nb_modes_in_list = 8;
+            args++;
+        } else if( strcmp( argv[ args ], "-hybrid24k_test" ) == 0 ) {
+            check_encoder_option(decode_only, "-hybrid24k_test");
+            mode_list = hybrid24_test;
+            nb_modes_in_list = 4;
+            args++;
+        } else if( strcmp( argv[ args ], "-hybrid48k_test" ) == 0 ) {
+            check_encoder_option(decode_only, "-hybrid48k_test");
+            mode_list = hybrid48_test;
+            nb_modes_in_list = 4;
+            args++;
+        } else if( strcmp( argv[ args ], "-celt_test" ) == 0 ) {
+            check_encoder_option(decode_only, "-celt_test");
+            mode_list = celt_test;
+            nb_modes_in_list = 32;
+            args++;
+        } else if( strcmp( argv[ args ], "-celt_hq_test" ) == 0 ) {
+            check_encoder_option(decode_only, "-celt_hq_test");
+            mode_list = celt_hq_test;
+            nb_modes_in_list = 4;
+            args++;
+        } else {
+            printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
+            print_usage( argv );
+            return EXIT_FAILURE;
+        }
+    }
+
+    if (sweep_max)
+       sweep_min = bitrate_bps;
+
+    if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
+    {
+        fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
+                          MAX_PACKET);
+        return EXIT_FAILURE;
+    }
+
+    inFile = argv[argc-2];
+    fin = fopen(inFile, "rb");
+    if (!fin)
+    {
+        fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
+        return EXIT_FAILURE;
+    }
+    if (mode_list)
+    {
+       int size;
+       fseek(fin, 0, SEEK_END);
+       size = ftell(fin);
+       fprintf(stderr, "File size is %d bytes\n", size);
+       fseek(fin, 0, SEEK_SET);
+       mode_switch_time = size/sizeof(short)/channels/nb_modes_in_list;
+       fprintf(stderr, "Switching mode every %d samples\n", mode_switch_time);
+    }
+
+    outFile = argv[argc-1];
+    fout = fopen(outFile, "wb+");
+    if (!fout)
+    {
+        fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
+        fclose(fin);
+        return EXIT_FAILURE;
+    }
+
+    if (!decode_only)
+    {
+       enc = opus_encoder_create(sampling_rate, channels, application, &err);
+       if (err != OPUS_OK)
+       {
+          fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err));
+          fclose(fin);
+          fclose(fout);
+          return EXIT_FAILURE;
+       }
+       opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
+       opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
+       opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr));
+       opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr));
+       opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
+       opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(use_inbandfec));
+       opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels));
+       opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx));
+       opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
+
+       opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip));
+       opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16));
+       opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration));
+    }
+    if (!encode_only)
+    {
+       dec = opus_decoder_create(sampling_rate, channels, &err);
+       if (err != OPUS_OK)
+       {
+          fprintf(stderr, "Cannot create decoder: %s\n", opus_strerror(err));
+          fclose(fin);
+          fclose(fout);
+          return EXIT_FAILURE;
+       }
+    }
+
+
+    switch(bandwidth)
+    {
+    case OPUS_BANDWIDTH_NARROWBAND:
+         bandwidth_string = "narrowband";
+         break;
+    case OPUS_BANDWIDTH_MEDIUMBAND:
+         bandwidth_string = "mediumband";
+         break;
+    case OPUS_BANDWIDTH_WIDEBAND:
+         bandwidth_string = "wideband";
+         break;
+    case OPUS_BANDWIDTH_SUPERWIDEBAND:
+         bandwidth_string = "superwideband";
+         break;
+    case OPUS_BANDWIDTH_FULLBAND:
+         bandwidth_string = "fullband";
+         break;
+    case OPUS_AUTO:
+         bandwidth_string = "auto bandwidth";
+         break;
+    default:
+         bandwidth_string = "unknown";
+         break;
+    }
+
+    if (decode_only)
+       fprintf(stderr, "Decoding with %ld Hz output (%d channels)\n",
+                       (long)sampling_rate, channels);
+    else
+       fprintf(stderr, "Encoding %ld Hz input at %.3f kb/s "
+                       "in %s with %d-sample frames.\n",
+                       (long)sampling_rate, bitrate_bps*0.001,
+                       bandwidth_string, frame_size);
+
+    in = (short*)malloc(max_frame_size*channels*sizeof(short));
+    out = (short*)malloc(max_frame_size*channels*sizeof(short));
+    /* We need to allocate for 16-bit PCM data, but we store it as unsigned char. */
+    fbytes = (unsigned char*)malloc(max_frame_size*channels*sizeof(short));
+    data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char));
+    if ( use_inbandfec ) {
+        data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char));
+    }
+    if(delayed_decision)
+    {
+       if (variable_duration!=OPUS_FRAMESIZE_VARIABLE)
+       {
+          if (frame_size==sampling_rate/400)
+             variable_duration = OPUS_FRAMESIZE_2_5_MS;
+          else if (frame_size==sampling_rate/200)
+             variable_duration = OPUS_FRAMESIZE_5_MS;
+          else if (frame_size==sampling_rate/100)
+             variable_duration = OPUS_FRAMESIZE_10_MS;
+          else if (frame_size==sampling_rate/50)
+             variable_duration = OPUS_FRAMESIZE_20_MS;
+          else if (frame_size==sampling_rate/25)
+             variable_duration = OPUS_FRAMESIZE_40_MS;
+          else
+             variable_duration = OPUS_FRAMESIZE_60_MS;
+          opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration));
+       }
+       frame_size = 2*48000;
+    }
+    while (!stop)
+    {
+        if (delayed_celt)
+        {
+            frame_size = newsize;
+            delayed_celt = 0;
+        } else if (random_framesize && rand()%20==0)
+        {
+            newsize = rand()%6;
+            switch(newsize)
+            {
+            case 0: newsize=sampling_rate/400; break;
+            case 1: newsize=sampling_rate/200; break;
+            case 2: newsize=sampling_rate/100; break;
+            case 3: newsize=sampling_rate/50; break;
+            case 4: newsize=sampling_rate/25; break;
+            case 5: newsize=3*sampling_rate/50; break;
+            }
+            while (newsize < sampling_rate/25 && bitrate_bps-abs(sweep_bps) <= 3*12*sampling_rate/newsize)
+               newsize*=2;
+            if (newsize < sampling_rate/100 && frame_size >= sampling_rate/100)
+            {
+                opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+                delayed_celt=1;
+            } else {
+                frame_size = newsize;
+            }
+        }
+        if (random_fec && rand()%30==0)
+        {
+           opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rand()%4==0));
+        }
+        if (decode_only)
+        {
+            unsigned char ch[4];
+            err = fread(ch, 1, 4, fin);
+            if (feof(fin))
+                break;
+            len[toggle] = char_to_int(ch);
+            if (len[toggle]>max_payload_bytes || len[toggle]<0)
+            {
+                fprintf(stderr, "Invalid payload length: %d\n",len[toggle]);
+                break;
+            }
+            err = fread(ch, 1, 4, fin);
+            enc_final_range[toggle] = char_to_int(ch);
+            err = fread(data[toggle], 1, len[toggle], fin);
+            if (err<len[toggle])
+            {
+                fprintf(stderr, "Ran out of input, "
+                                "expecting %d bytes got %d\n",
+                                len[toggle],err);
+                break;
+            }
+        } else {
+            int i;
+            if (mode_list!=NULL)
+            {
+                opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(mode_list[curr_mode][1]));
+                opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(mode_list[curr_mode][0]));
+                opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(mode_list[curr_mode][3]));
+                frame_size = mode_list[curr_mode][2];
+            }
+            err = fread(fbytes, sizeof(short)*channels, frame_size-remaining, fin);
+            curr_read = err;
+            tot_in += curr_read;
+            for(i=0;i<curr_read*channels;i++)
+            {
+                opus_int32 s;
+                s=fbytes[2*i+1]<<8|fbytes[2*i];
+                s=((s&0xFFFF)^0x8000)-0x8000;
+                in[i+remaining*channels]=s;
+            }
+            if (curr_read+remaining < frame_size)
+            {
+                for (i=(curr_read+remaining)*channels;i<frame_size*channels;i++)
+                   in[i] = 0;
+                if (encode_only || decode_only)
+                   stop = 1;
+            }
+            len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
+            nb_encoded = opus_packet_get_samples_per_frame(data[toggle], sampling_rate)*opus_packet_get_nb_frames(data[toggle], len[toggle]);
+            remaining = frame_size-nb_encoded;
+            for(i=0;i<remaining*channels;i++)
+               in[i] = in[nb_encoded*channels+i];
+            if (sweep_bps!=0)
+            {
+               bitrate_bps += sweep_bps;
+               if (sweep_max)
+               {
+                  if (bitrate_bps > sweep_max)
+                     sweep_bps = -sweep_bps;
+                  else if (bitrate_bps < sweep_min)
+                     sweep_bps = -sweep_bps;
+               }
+               /* safety */
+               if (bitrate_bps<1000)
+                  bitrate_bps = 1000;
+               opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
+            }
+            opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range[toggle]));
+            if (len[toggle] < 0)
+            {
+                fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
+                fclose(fin);
+                fclose(fout);
+                return EXIT_FAILURE;
+            }
+            curr_mode_count += frame_size;
+            if (curr_mode_count > mode_switch_time && curr_mode < nb_modes_in_list-1)
+            {
+               curr_mode++;
+               curr_mode_count = 0;
+            }
+        }
+
+#if 0 /* This is for testing the padding code, do not enable by default */
+        if (len[toggle]<1275)
+        {
+           int new_len = len[toggle]+rand()%(max_payload_bytes-len[toggle]);
+           if ((err = opus_packet_pad(data[toggle], len[toggle], new_len)) != OPUS_OK)
+           {
+              fprintf(stderr, "padding failed: %s\n", opus_strerror(err));
+              return EXIT_FAILURE;
+           }
+           len[toggle] = new_len;
+        }
+#endif
+        if (encode_only)
+        {
+            unsigned char int_field[4];
+            int_to_char(len[toggle], int_field);
+            if (fwrite(int_field, 1, 4, fout) != 4) {
+               fprintf(stderr, "Error writing.\n");
+               return EXIT_FAILURE;
+            }
+            int_to_char(enc_final_range[toggle], int_field);
+            if (fwrite(int_field, 1, 4, fout) != 4) {
+               fprintf(stderr, "Error writing.\n");
+               return EXIT_FAILURE;
+            }
+            if (fwrite(data[toggle], 1, len[toggle], fout) != (unsigned)len[toggle]) {
+               fprintf(stderr, "Error writing.\n");
+               return EXIT_FAILURE;
+            }
+            tot_samples += nb_encoded;
+        } else {
+            int output_samples;
+            lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc);
+            if (lost)
+               opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
+            else
+               output_samples = max_frame_size;
+            if( count >= use_inbandfec ) {
+                /* delay by one packet when using in-band FEC */
+                if( use_inbandfec  ) {
+                    if( lost_prev ) {
+                        /* attempt to decode with in-band FEC from next packet */
+                        opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
+                        output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 1);
+                    } else {
+                        /* regular decode */
+                        output_samples = max_frame_size;
+                        output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, output_samples, 0);
+                    }
+                } else {
+                    output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 0);
+                }
+                if (output_samples>0)
+                {
+                    if (!decode_only && tot_out + output_samples > tot_in)
+                    {
+                       stop=1;
+                       output_samples  = tot_in-tot_out;
+                    }
+                    if (output_samples>skip) {
+                       int i;
+                       for(i=0;i<(output_samples-skip)*channels;i++)
+                       {
+                          short s;
+                          s=out[i+(skip*channels)];
+                          fbytes[2*i]=s&0xFF;
+                          fbytes[2*i+1]=(s>>8)&0xFF;
+                       }
+                       if (fwrite(fbytes, sizeof(short)*channels, output_samples-skip, fout) != (unsigned)(output_samples-skip)){
+                          fprintf(stderr, "Error writing.\n");
+                          return EXIT_FAILURE;
+                       }
+                       tot_out += output_samples-skip;
+                    }
+                    if (output_samples<skip) skip -= output_samples;
+                    else skip = 0;
+                } else {
+                   fprintf(stderr, "error decoding frame: %s\n",
+                                   opus_strerror(output_samples));
+                }
+                tot_samples += output_samples;
+            }
+        }
+
+        if (!encode_only)
+           opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
+        /* compare final range encoder rng values of encoder and decoder */
+        if( enc_final_range[toggle^use_inbandfec]!=0  && !encode_only
+         && !lost && !lost_prev
+         && dec_final_range != enc_final_range[toggle^use_inbandfec] ) {
+            fprintf (stderr, "Error: Range coder state mismatch "
+                             "between encoder and decoder "
+                             "in frame %ld: 0x%8lx vs 0x%8lx\n",
+                         (long)count,
+                         (unsigned long)enc_final_range[toggle^use_inbandfec],
+                         (unsigned long)dec_final_range);
+            fclose(fin);
+            fclose(fout);
+            return EXIT_FAILURE;
+        }
+
+        lost_prev = lost;
+        if( count >= use_inbandfec ) {
+            /* count bits */
+            bits += len[toggle]*8;
+            bits_max = ( len[toggle]*8 > bits_max ) ? len[toggle]*8 : bits_max;
+            bits2 += len[toggle]*len[toggle]*64;
+            if (!decode_only)
+            {
+                nrg = 0.0;
+                for ( k = 0; k < frame_size * channels; k++ ) {
+                    nrg += in[ k ] * (double)in[ k ];
+                }
+                nrg /= frame_size * channels;
+                if( nrg > 1e5 ) {
+                    bits_act += len[toggle]*8;
+                    count_act++;
+                }
+            }
+        }
+        count++;
+        toggle = (toggle + use_inbandfec) & 1;
+    }
+
+    /* Print out bitrate statistics */
+    if(decode_only)
+        frame_size = (int)(tot_samples / count);
+    count -= use_inbandfec;
+    fprintf (stderr, "average bitrate:             %7.3f kb/s\n",
+                     1e-3*bits*sampling_rate/tot_samples);
+    fprintf (stderr, "maximum bitrate:             %7.3f kb/s\n",
+                     1e-3*bits_max*sampling_rate/frame_size);
+    if (!decode_only)
+       fprintf (stderr, "active bitrate:              %7.3f kb/s\n",
+               1e-3*bits_act*sampling_rate/(1e-15+frame_size*(double)count_act));
+    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n",
+            1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
+    /* Close any files to which intermediate results were stored */
+    SILK_DEBUG_STORE_CLOSE_FILES
+    silk_TimerSave("opus_timing.txt");
+    opus_encoder_destroy(enc);
+    opus_decoder_destroy(dec);
+    free(data[0]);
+    if (use_inbandfec)
+        free(data[1]);
+    fclose(fin);
+    fclose(fout);
+    free(in);
+    free(out);
+    free(fbytes);
+    return EXIT_SUCCESS;
+}
diff --git a/third_party/opus/src/src/opus_encoder.c b/third_party/opus/src/src/opus_encoder.c
new file mode 100644
index 0000000..9a516a88
--- /dev/null
+++ b/third_party/opus/src/src/opus_encoder.c
@@ -0,0 +1,2536 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+   Written by Jean-Marc Valin and Koen Vos */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include "celt.h"
+#include "entenc.h"
+#include "modes.h"
+#include "API.h"
+#include "stack_alloc.h"
+#include "float_cast.h"
+#include "opus.h"
+#include "arch.h"
+#include "pitch.h"
+#include "opus_private.h"
+#include "os_support.h"
+#include "cpu_support.h"
+#include "analysis.h"
+#include "mathops.h"
+#include "tuning_parameters.h"
+#ifdef FIXED_POINT
+#include "fixed/structs_FIX.h"
+#else
+#include "float/structs_FLP.h"
+#endif
+
+#define MAX_ENCODER_BUFFER 480
+
+typedef struct {
+   opus_val32 XX, XY, YY;
+   opus_val16 smoothed_width;
+   opus_val16 max_follower;
+} StereoWidthState;
+
+struct OpusEncoder {
+    int          celt_enc_offset;
+    int          silk_enc_offset;
+    silk_EncControlStruct silk_mode;
+    int          application;
+    int          channels;
+    int          delay_compensation;
+    int          force_channels;
+    int          signal_type;
+    int          user_bandwidth;
+    int          max_bandwidth;
+    int          user_forced_mode;
+    int          voice_ratio;
+    opus_int32   Fs;
+    int          use_vbr;
+    int          vbr_constraint;
+    int          variable_duration;
+    opus_int32   bitrate_bps;
+    opus_int32   user_bitrate_bps;
+    int          lsb_depth;
+    int          encoder_buffer;
+    int          lfe;
+    int          arch;
+#ifndef DISABLE_FLOAT_API
+    TonalityAnalysisState analysis;
+#endif
+
+#define OPUS_ENCODER_RESET_START stream_channels
+    int          stream_channels;
+    opus_int16   hybrid_stereo_width_Q14;
+    opus_int32   variable_HP_smth2_Q15;
+    opus_val16   prev_HB_gain;
+    opus_val32   hp_mem[4];
+    int          mode;
+    int          prev_mode;
+    int          prev_channels;
+    int          prev_framesize;
+    int          bandwidth;
+    int          silk_bw_switch;
+    /* Sampling rate (at the API level) */
+    int          first;
+    opus_val16 * energy_masking;
+    StereoWidthState width_mem;
+    opus_val16   delay_buffer[MAX_ENCODER_BUFFER*2];
+#ifndef DISABLE_FLOAT_API
+    int          detected_bandwidth;
+#endif
+    opus_uint32  rangeFinal;
+};
+
+/* Transition tables for the voice and music. First column is the
+   middle (memoriless) threshold. The second column is the hysteresis
+   (difference with the middle) */
+static const opus_int32 mono_voice_bandwidth_thresholds[8] = {
+        11000, 1000, /* NB<->MB */
+        14000, 1000, /* MB<->WB */
+        17000, 1000, /* WB<->SWB */
+        21000, 2000, /* SWB<->FB */
+};
+static const opus_int32 mono_music_bandwidth_thresholds[8] = {
+        12000, 1000, /* NB<->MB */
+        15000, 1000, /* MB<->WB */
+        18000, 2000, /* WB<->SWB */
+        22000, 2000, /* SWB<->FB */
+};
+static const opus_int32 stereo_voice_bandwidth_thresholds[8] = {
+        11000, 1000, /* NB<->MB */
+        14000, 1000, /* MB<->WB */
+        21000, 2000, /* WB<->SWB */
+        28000, 2000, /* SWB<->FB */
+};
+static const opus_int32 stereo_music_bandwidth_thresholds[8] = {
+        12000, 1000, /* NB<->MB */
+        18000, 2000, /* MB<->WB */
+        21000, 2000, /* WB<->SWB */
+        30000, 2000, /* SWB<->FB */
+};
+/* Threshold bit-rates for switching between mono and stereo */
+static const opus_int32 stereo_voice_threshold = 30000;
+static const opus_int32 stereo_music_threshold = 30000;
+
+/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */
+static const opus_int32 mode_thresholds[2][2] = {
+      /* voice */ /* music */
+      {  64000,      16000}, /* mono */
+      {  36000,      16000}, /* stereo */
+};
+
+int opus_encoder_get_size(int channels)
+{
+    int silkEncSizeBytes, celtEncSizeBytes;
+    int ret;
+    if (channels<1 || channels > 2)
+        return 0;
+    ret = silk_Get_Encoder_Size( &silkEncSizeBytes );
+    if (ret)
+        return 0;
+    silkEncSizeBytes = align(silkEncSizeBytes);
+    celtEncSizeBytes = celt_encoder_get_size(channels);
+    return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes;
+}
+
+int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application)
+{
+    void *silk_enc;
+    CELTEncoder *celt_enc;
+    int err;
+    int ret, silkEncSizeBytes;
+
+   if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)||
+        (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO
+        && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY))
+        return OPUS_BAD_ARG;
+
+    OPUS_CLEAR((char*)st, opus_encoder_get_size(channels));
+    /* Create SILK encoder */
+    ret = silk_Get_Encoder_Size( &silkEncSizeBytes );
+    if (ret)
+        return OPUS_BAD_ARG;
+    silkEncSizeBytes = align(silkEncSizeBytes);
+    st->silk_enc_offset = align(sizeof(OpusEncoder));
+    st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes;
+    silk_enc = (char*)st+st->silk_enc_offset;
+    celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+
+    st->stream_channels = st->channels = channels;
+
+    st->Fs = Fs;
+
+    st->arch = opus_select_arch();
+
+    ret = silk_InitEncoder( silk_enc, st->arch, &st->silk_mode );
+    if(ret)return OPUS_INTERNAL_ERROR;
+
+    /* default SILK parameters */
+    st->silk_mode.nChannelsAPI              = channels;
+    st->silk_mode.nChannelsInternal         = channels;
+    st->silk_mode.API_sampleRate            = st->Fs;
+    st->silk_mode.maxInternalSampleRate     = 16000;
+    st->silk_mode.minInternalSampleRate     = 8000;
+    st->silk_mode.desiredInternalSampleRate = 16000;
+    st->silk_mode.payloadSize_ms            = 20;
+    st->silk_mode.bitRate                   = 25000;
+    st->silk_mode.packetLossPercentage      = 0;
+    st->silk_mode.complexity                = 9;
+    st->silk_mode.useInBandFEC              = 0;
+    st->silk_mode.useDTX                    = 0;
+    st->silk_mode.useCBR                    = 0;
+    st->silk_mode.reducedDependency         = 0;
+
+    /* Create CELT encoder */
+    /* Initialize CELT encoder */
+    err = celt_encoder_init(celt_enc, Fs, channels, st->arch);
+    if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+
+    celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0));
+    celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity));
+
+    st->use_vbr = 1;
+    /* Makes constrained VBR the default (safer for real-time use) */
+    st->vbr_constraint = 1;
+    st->user_bitrate_bps = OPUS_AUTO;
+    st->bitrate_bps = 3000+Fs*channels;
+    st->application = application;
+    st->signal_type = OPUS_AUTO;
+    st->user_bandwidth = OPUS_AUTO;
+    st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+    st->force_channels = OPUS_AUTO;
+    st->user_forced_mode = OPUS_AUTO;
+    st->voice_ratio = -1;
+    st->encoder_buffer = st->Fs/100;
+    st->lsb_depth = 24;
+    st->variable_duration = OPUS_FRAMESIZE_ARG;
+
+    /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead
+       + 1.5 ms for SILK resamplers and stereo prediction) */
+    st->delay_compensation = st->Fs/250;
+
+    st->hybrid_stereo_width_Q14 = 1 << 14;
+    st->prev_HB_gain = Q15ONE;
+    st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+    st->first = 1;
+    st->mode = MODE_HYBRID;
+    st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+#ifndef DISABLE_FLOAT_API
+    tonality_analysis_init(&st->analysis);
+#endif
+
+    return OPUS_OK;
+}
+
+static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels)
+{
+   int period;
+   unsigned char toc;
+   period = 0;
+   while (framerate < 400)
+   {
+       framerate <<= 1;
+       period++;
+   }
+   if (mode == MODE_SILK_ONLY)
+   {
+       toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5;
+       toc |= (period-2)<<3;
+   } else if (mode == MODE_CELT_ONLY)
+   {
+       int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND;
+       if (tmp < 0)
+           tmp = 0;
+       toc = 0x80;
+       toc |= tmp << 5;
+       toc |= period<<3;
+   } else /* Hybrid */
+   {
+       toc = 0x60;
+       toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4;
+       toc |= (period-2)<<3;
+   }
+   toc |= (channels==2)<<2;
+   return toc;
+}
+
+#ifndef FIXED_POINT
+static void silk_biquad_float(
+    const opus_val16      *in,            /* I:    Input signal                   */
+    const opus_int32      *B_Q28,         /* I:    MA coefficients [3]            */
+    const opus_int32      *A_Q28,         /* I:    AR coefficients [2]            */
+    opus_val32            *S,             /* I/O:  State vector [2]               */
+    opus_val16            *out,           /* O:    Output signal                  */
+    const opus_int32      len,            /* I:    Signal length (must be even)   */
+    int stride
+)
+{
+    /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
+    opus_int   k;
+    opus_val32 vout;
+    opus_val32 inval;
+    opus_val32 A[2], B[3];
+
+    A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28)));
+    A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28)));
+    B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28)));
+    B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28)));
+    B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28)));
+
+    /* Negate A_Q28 values and split in two parts */
+
+    for( k = 0; k < len; k++ ) {
+        /* S[ 0 ], S[ 1 ]: Q12 */
+        inval = in[ k*stride ];
+        vout = S[ 0 ] + B[0]*inval;
+
+        S[ 0 ] = S[1] - vout*A[0] + B[1]*inval;
+
+        S[ 1 ] = - vout*A[1] + B[2]*inval + VERY_SMALL;
+
+        /* Scale back to Q0 and saturate */
+        out[ k*stride ] = vout;
+    }
+}
+#endif
+
+static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+   opus_int32 B_Q28[ 3 ], A_Q28[ 2 ];
+   opus_int32 Fc_Q19, r_Q28, r_Q22;
+
+   silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) );
+   Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 );
+   silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 );
+
+   r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 );
+
+   /* b = r * [ 1; -2; 1 ]; */
+   /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */
+   B_Q28[ 0 ] = r_Q28;
+   B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 );
+   B_Q28[ 2 ] = r_Q28;
+
+   /* -r * ( 2 - Fc * Fc ); */
+   r_Q22  = silk_RSHIFT( r_Q28, 6 );
+   A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0,  22 ) );
+   A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 );
+
+#ifdef FIXED_POINT
+   silk_biquad_alt( in, B_Q28, A_Q28, hp_mem, out, len, channels );
+   if( channels == 2 ) {
+       silk_biquad_alt( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels );
+   }
+#else
+   silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels );
+   if( channels == 2 ) {
+       silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels );
+   }
+#endif
+}
+
+#ifdef FIXED_POINT
+static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+   int c, i;
+   int shift;
+
+   /* Approximates -round(log2(4.*cutoff_Hz/Fs)) */
+   shift=celt_ilog2(Fs/(cutoff_Hz*3));
+   for (c=0;c<channels;c++)
+   {
+      for (i=0;i<len;i++)
+      {
+         opus_val32 x, tmp, y;
+         x = SHL32(EXTEND32(in[channels*i+c]), 15);
+         /* First stage */
+         tmp = x-hp_mem[2*c];
+         hp_mem[2*c] = hp_mem[2*c] + PSHR32(x - hp_mem[2*c], shift);
+         /* Second stage */
+         y = tmp - hp_mem[2*c+1];
+         hp_mem[2*c+1] = hp_mem[2*c+1] + PSHR32(tmp - hp_mem[2*c+1], shift);
+         out[channels*i+c] = EXTRACT16(SATURATE(PSHR32(y, 15), 32767));
+      }
+   }
+}
+
+#else
+static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+   int c, i;
+   float coef;
+
+   coef = 4.0f*cutoff_Hz/Fs;
+   for (c=0;c<channels;c++)
+   {
+      for (i=0;i<len;i++)
+      {
+         opus_val32 x, tmp, y;
+         x = in[channels*i+c];
+         /* First stage */
+         tmp = x-hp_mem[2*c];
+         hp_mem[2*c] = hp_mem[2*c] + coef*(x - hp_mem[2*c]) + VERY_SMALL;
+         /* Second stage */
+         y = tmp - hp_mem[2*c+1];
+         hp_mem[2*c+1] = hp_mem[2*c+1] + coef*(tmp - hp_mem[2*c+1]) + VERY_SMALL;
+         out[channels*i+c] = y;
+      }
+   }
+}
+#endif
+
+static void stereo_fade(const opus_val16 *in, opus_val16 *out, opus_val16 g1, opus_val16 g2,
+        int overlap48, int frame_size, int channels, const opus_val16 *window, opus_int32 Fs)
+{
+    int i;
+    int overlap;
+    int inc;
+    inc = 48000/Fs;
+    overlap=overlap48/inc;
+    g1 = Q15ONE-g1;
+    g2 = Q15ONE-g2;
+    for (i=0;i<overlap;i++)
+    {
+       opus_val32 diff;
+       opus_val16 g, w;
+       w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+       g = SHR32(MAC16_16(MULT16_16(w,g2),
+             Q15ONE-w, g1), 15);
+       diff = EXTRACT16(HALF32((opus_val32)in[i*channels] - (opus_val32)in[i*channels+1]));
+       diff = MULT16_16_Q15(g, diff);
+       out[i*channels] = out[i*channels] - diff;
+       out[i*channels+1] = out[i*channels+1] + diff;
+    }
+    for (;i<frame_size;i++)
+    {
+       opus_val32 diff;
+       diff = EXTRACT16(HALF32((opus_val32)in[i*channels] - (opus_val32)in[i*channels+1]));
+       diff = MULT16_16_Q15(g2, diff);
+       out[i*channels] = out[i*channels] - diff;
+       out[i*channels+1] = out[i*channels+1] + diff;
+    }
+}
+
+static void gain_fade(const opus_val16 *in, opus_val16 *out, opus_val16 g1, opus_val16 g2,
+        int overlap48, int frame_size, int channels, const opus_val16 *window, opus_int32 Fs)
+{
+    int i;
+    int inc;
+    int overlap;
+    int c;
+    inc = 48000/Fs;
+    overlap=overlap48/inc;
+    if (channels==1)
+    {
+       for (i=0;i<overlap;i++)
+       {
+          opus_val16 g, w;
+          w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+          g = SHR32(MAC16_16(MULT16_16(w,g2),
+                Q15ONE-w, g1), 15);
+          out[i] = MULT16_16_Q15(g, in[i]);
+       }
+    } else {
+       for (i=0;i<overlap;i++)
+       {
+          opus_val16 g, w;
+          w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+          g = SHR32(MAC16_16(MULT16_16(w,g2),
+                Q15ONE-w, g1), 15);
+          out[i*2] = MULT16_16_Q15(g, in[i*2]);
+          out[i*2+1] = MULT16_16_Q15(g, in[i*2+1]);
+       }
+    }
+    c=0;do {
+       for (i=overlap;i<frame_size;i++)
+       {
+          out[i*channels+c] = MULT16_16_Q15(g2, in[i*channels+c]);
+       }
+    }
+    while (++c<channels);
+}
+
+OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int application, int *error)
+{
+   int ret;
+   OpusEncoder *st;
+   if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)||
+       (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO
+       && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY))
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+   st = (OpusEncoder *)opus_alloc(opus_encoder_get_size(channels));
+   if (st == NULL)
+   {
+      if (error)
+         *error = OPUS_ALLOC_FAIL;
+      return NULL;
+   }
+   ret = opus_encoder_init(st, Fs, channels, application);
+   if (error)
+      *error = ret;
+   if (ret != OPUS_OK)
+   {
+      opus_free(st);
+      st = NULL;
+   }
+   return st;
+}
+
+static opus_int32 user_bitrate_to_bitrate(OpusEncoder *st, int frame_size, int max_data_bytes)
+{
+  if(!frame_size)frame_size=st->Fs/400;
+  if (st->user_bitrate_bps==OPUS_AUTO)
+    return 60*st->Fs/frame_size + st->Fs*st->channels;
+  else if (st->user_bitrate_bps==OPUS_BITRATE_MAX)
+    return max_data_bytes*8*st->Fs/frame_size;
+  else
+    return st->user_bitrate_bps;
+}
+
+#ifndef DISABLE_FLOAT_API
+/* Don't use more than 60 ms for the frame size analysis */
+#define MAX_DYNAMIC_FRAMESIZE 24
+/* Estimates how much the bitrate will be boosted based on the sub-frame energy */
+static float transient_boost(const float *E, const float *E_1, int LM, int maxM)
+{
+   int i;
+   int M;
+   float sumE=0, sumE_1=0;
+   float metric;
+
+   M = IMIN(maxM, (1<<LM)+1);
+   for (i=0;i<M;i++)
+   {
+      sumE += E[i];
+      sumE_1 += E_1[i];
+   }
+   metric = sumE*sumE_1/(M*M);
+   /*if (LM==3)
+      printf("%f\n", metric);*/
+   /*return metric>10 ? 1 : 0;*/
+   /*return MAX16(0,1-exp(-.25*(metric-2.)));*/
+   return MIN16(1,(float)sqrt(MAX16(0,.05f*(metric-2))));
+}
+
+/* Viterbi decoding trying to find the best frame size combination using look-ahead
+
+   State numbering:
+    0: unused
+    1:  2.5 ms
+    2:  5 ms (#1)
+    3:  5 ms (#2)
+    4: 10 ms (#1)
+    5: 10 ms (#2)
+    6: 10 ms (#3)
+    7: 10 ms (#4)
+    8: 20 ms (#1)
+    9: 20 ms (#2)
+   10: 20 ms (#3)
+   11: 20 ms (#4)
+   12: 20 ms (#5)
+   13: 20 ms (#6)
+   14: 20 ms (#7)
+   15: 20 ms (#8)
+*/
+static int transient_viterbi(const float *E, const float *E_1, int N, int frame_cost, int rate)
+{
+   int i;
+   float cost[MAX_DYNAMIC_FRAMESIZE][16];
+   int states[MAX_DYNAMIC_FRAMESIZE][16];
+   float best_cost;
+   int best_state;
+   float factor;
+   /* Take into account that we damp VBR in the 32 kb/s to 64 kb/s range. */
+   if (rate<80)
+      factor=0;
+   else if (rate>160)
+      factor=1;
+   else
+      factor = (rate-80.f)/80.f;
+   /* Makes variable framesize less aggressive at lower bitrates, but I can't
+      find any valid theoretical justification for this (other than it seems
+      to help) */
+   for (i=0;i<16;i++)
+   {
+      /* Impossible state */
+      states[0][i] = -1;
+      cost[0][i] = 1e10;
+   }
+   for (i=0;i<4;i++)
+   {
+      cost[0][1<<i] = (frame_cost + rate*(1<<i))*(1+factor*transient_boost(E, E_1, i, N+1));
+      states[0][1<<i] = i;
+   }
+   for (i=1;i<N;i++)
+   {
+      int j;
+
+      /* Follow continuations */
+      for (j=2;j<16;j++)
+      {
+         cost[i][j] = cost[i-1][j-1];
+         states[i][j] = j-1;
+      }
+
+      /* New frames */
+      for(j=0;j<4;j++)
+      {
+         int k;
+         float min_cost;
+         float curr_cost;
+         states[i][1<<j] = 1;
+         min_cost = cost[i-1][1];
+         for(k=1;k<4;k++)
+         {
+            float tmp = cost[i-1][(1<<(k+1))-1];
+            if (tmp < min_cost)
+            {
+               states[i][1<<j] = (1<<(k+1))-1;
+               min_cost = tmp;
+            }
+         }
+         curr_cost = (frame_cost + rate*(1<<j))*(1+factor*transient_boost(E+i, E_1+i, j, N-i+1));
+         cost[i][1<<j] = min_cost;
+         /* If part of the frame is outside the analysis window, only count part of the cost */
+         if (N-i < (1<<j))
+            cost[i][1<<j] += curr_cost*(float)(N-i)/(1<<j);
+         else
+            cost[i][1<<j] += curr_cost;
+      }
+   }
+
+   best_state=1;
+   best_cost = cost[N-1][1];
+   /* Find best end state (doesn't force a frame to end at N-1) */
+   for (i=2;i<16;i++)
+   {
+      if (cost[N-1][i]<best_cost)
+      {
+         best_cost = cost[N-1][i];
+         best_state = i;
+      }
+   }
+
+   /* Follow transitions back */
+   for (i=N-1;i>=0;i--)
+   {
+      /*printf("%d ", best_state);*/
+      best_state = states[i][best_state];
+   }
+   /*printf("%d\n", best_state);*/
+   return best_state;
+}
+
+static int optimize_framesize(const void *x, int len, int C, opus_int32 Fs,
+                int bitrate, opus_val16 tonality, float *mem, int buffering,
+                downmix_func downmix)
+{
+   int N;
+   int i;
+   float e[MAX_DYNAMIC_FRAMESIZE+4];
+   float e_1[MAX_DYNAMIC_FRAMESIZE+3];
+   opus_val32 memx;
+   int bestLM=0;
+   int subframe;
+   int pos;
+   int offset;
+   VARDECL(opus_val32, sub);
+
+   subframe = Fs/400;
+   ALLOC(sub, subframe, opus_val32);
+   e[0]=mem[0];
+   e_1[0]=1.f/(EPSILON+mem[0]);
+   if (buffering)
+   {
+      /* Consider the CELT delay when not in restricted-lowdelay */
+      /* We assume the buffering is between 2.5 and 5 ms */
+      offset = 2*subframe - buffering;
+      celt_assert(offset>=0 && offset <= subframe);
+      len -= offset;
+      e[1]=mem[1];
+      e_1[1]=1.f/(EPSILON+mem[1]);
+      e[2]=mem[2];
+      e_1[2]=1.f/(EPSILON+mem[2]);
+      pos = 3;
+   } else {
+      pos=1;
+      offset=0;
+   }
+   N=IMIN(len/subframe, MAX_DYNAMIC_FRAMESIZE);
+   /* Just silencing a warning, it's really initialized later */
+   memx = 0;
+   for (i=0;i<N;i++)
+   {
+      float tmp;
+      opus_val32 tmpx;
+      int j;
+      tmp=EPSILON;
+
+      downmix(x, sub, subframe, i*subframe+offset, 0, -2, C);
+      if (i==0)
+         memx = sub[0];
+      for (j=0;j<subframe;j++)
+      {
+         tmpx = sub[j];
+         tmp += (tmpx-memx)*(float)(tmpx-memx);
+         memx = tmpx;
+      }
+      e[i+pos] = tmp;
+      e_1[i+pos] = 1.f/tmp;
+   }
+   /* Hack to get 20 ms working with APPLICATION_AUDIO
+      The real problem is that the corresponding memory needs to use 1.5 ms
+      from this frame and 1 ms from the next frame */
+   e[i+pos] = e[i+pos-1];
+   if (buffering)
+      N=IMIN(MAX_DYNAMIC_FRAMESIZE, N+2);
+   bestLM = transient_viterbi(e, e_1, N, (int)((1.f+.5f*tonality)*(60*C+40)), bitrate/400);
+   mem[0] = e[1<<bestLM];
+   if (buffering)
+   {
+      mem[1] = e[(1<<bestLM)+1];
+      mem[2] = e[(1<<bestLM)+2];
+   }
+   return bestLM;
+}
+
+#endif
+
+#ifndef DISABLE_FLOAT_API
+#ifdef FIXED_POINT
+#define PCM2VAL(x) FLOAT2INT16(x)
+#else
+#define PCM2VAL(x) SCALEIN(x)
+#endif
+void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C)
+{
+   const float *x;
+   opus_val32 scale;
+   int j;
+   x = (const float *)_x;
+   for (j=0;j<subframe;j++)
+      sub[j] = PCM2VAL(x[(j+offset)*C+c1]);
+   if (c2>-1)
+   {
+      for (j=0;j<subframe;j++)
+         sub[j] += PCM2VAL(x[(j+offset)*C+c2]);
+   } else if (c2==-2)
+   {
+      int c;
+      for (c=1;c<C;c++)
+      {
+         for (j=0;j<subframe;j++)
+            sub[j] += PCM2VAL(x[(j+offset)*C+c]);
+      }
+   }
+#ifdef FIXED_POINT
+   scale = (1<<SIG_SHIFT);
+#else
+   scale = 1.f;
+#endif
+   if (C==-2)
+      scale /= C;
+   else
+      scale /= 2;
+   for (j=0;j<subframe;j++)
+      sub[j] *= scale;
+}
+#endif
+
+void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C)
+{
+   const opus_int16 *x;
+   opus_val32 scale;
+   int j;
+   x = (const opus_int16 *)_x;
+   for (j=0;j<subframe;j++)
+      sub[j] = x[(j+offset)*C+c1];
+   if (c2>-1)
+   {
+      for (j=0;j<subframe;j++)
+         sub[j] += x[(j+offset)*C+c2];
+   } else if (c2==-2)
+   {
+      int c;
+      for (c=1;c<C;c++)
+      {
+         for (j=0;j<subframe;j++)
+            sub[j] += x[(j+offset)*C+c];
+      }
+   }
+#ifdef FIXED_POINT
+   scale = (1<<SIG_SHIFT);
+#else
+   scale = 1.f/32768;
+#endif
+   if (C==-2)
+      scale /= C;
+   else
+      scale /= 2;
+   for (j=0;j<subframe;j++)
+      sub[j] *= scale;
+}
+
+opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs)
+{
+   int new_size;
+   if (frame_size<Fs/400)
+      return -1;
+   if (variable_duration == OPUS_FRAMESIZE_ARG)
+      new_size = frame_size;
+   else if (variable_duration == OPUS_FRAMESIZE_VARIABLE)
+      new_size = Fs/50;
+   else if (variable_duration >= OPUS_FRAMESIZE_2_5_MS && variable_duration <= OPUS_FRAMESIZE_60_MS)
+      new_size = IMIN(3*Fs/50, (Fs/400)<<(variable_duration-OPUS_FRAMESIZE_2_5_MS));
+   else
+      return -1;
+   if (new_size>frame_size)
+      return -1;
+   if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs &&
+            50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs)
+      return -1;
+   return new_size;
+}
+
+opus_int32 compute_frame_size(const void *analysis_pcm, int frame_size,
+      int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
+      int delay_compensation, downmix_func downmix
+#ifndef DISABLE_FLOAT_API
+      , float *subframe_mem
+#endif
+      )
+{
+#ifndef DISABLE_FLOAT_API
+   if (variable_duration == OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs/200)
+   {
+      int LM = 3;
+      LM = optimize_framesize(analysis_pcm, frame_size, C, Fs, bitrate_bps,
+            0, subframe_mem, delay_compensation, downmix);
+      while ((Fs/400<<LM)>frame_size)
+         LM--;
+      frame_size = (Fs/400<<LM);
+   } else
+#else
+   (void)analysis_pcm;
+   (void)C;
+   (void)bitrate_bps;
+   (void)delay_compensation;
+   (void)downmix;
+#endif
+   {
+      frame_size = frame_size_select(frame_size, variable_duration, Fs);
+   }
+   if (frame_size<0)
+      return -1;
+   return frame_size;
+}
+
+opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem)
+{
+   opus_val32 xx, xy, yy;
+   opus_val16 sqrt_xx, sqrt_yy;
+   opus_val16 qrrt_xx, qrrt_yy;
+   int frame_rate;
+   int i;
+   opus_val16 short_alpha;
+
+   frame_rate = Fs/frame_size;
+   short_alpha = Q15ONE - MULT16_16(25, Q15ONE)/IMAX(50,frame_rate);
+   xx=xy=yy=0;
+   /* Unroll by 4. The frame size is always a multiple of 4 *except* for
+      2.5 ms frames at 12 kHz. Since this setting is very rare (and very
+      stupid), we just discard the last two samples. */
+   for (i=0;i<frame_size-3;i+=4)
+   {
+      opus_val32 pxx=0;
+      opus_val32 pxy=0;
+      opus_val32 pyy=0;
+      opus_val16 x, y;
+      x = pcm[2*i];
+      y = pcm[2*i+1];
+      pxx = SHR32(MULT16_16(x,x),2);
+      pxy = SHR32(MULT16_16(x,y),2);
+      pyy = SHR32(MULT16_16(y,y),2);
+      x = pcm[2*i+2];
+      y = pcm[2*i+3];
+      pxx += SHR32(MULT16_16(x,x),2);
+      pxy += SHR32(MULT16_16(x,y),2);
+      pyy += SHR32(MULT16_16(y,y),2);
+      x = pcm[2*i+4];
+      y = pcm[2*i+5];
+      pxx += SHR32(MULT16_16(x,x),2);
+      pxy += SHR32(MULT16_16(x,y),2);
+      pyy += SHR32(MULT16_16(y,y),2);
+      x = pcm[2*i+6];
+      y = pcm[2*i+7];
+      pxx += SHR32(MULT16_16(x,x),2);
+      pxy += SHR32(MULT16_16(x,y),2);
+      pyy += SHR32(MULT16_16(y,y),2);
+
+      xx += SHR32(pxx, 10);
+      xy += SHR32(pxy, 10);
+      yy += SHR32(pyy, 10);
+   }
+   mem->XX += MULT16_32_Q15(short_alpha, xx-mem->XX);
+   mem->XY += MULT16_32_Q15(short_alpha, xy-mem->XY);
+   mem->YY += MULT16_32_Q15(short_alpha, yy-mem->YY);
+   mem->XX = MAX32(0, mem->XX);
+   mem->XY = MAX32(0, mem->XY);
+   mem->YY = MAX32(0, mem->YY);
+   if (MAX32(mem->XX, mem->YY)>QCONST16(8e-4f, 18))
+   {
+      opus_val16 corr;
+      opus_val16 ldiff;
+      opus_val16 width;
+      sqrt_xx = celt_sqrt(mem->XX);
+      sqrt_yy = celt_sqrt(mem->YY);
+      qrrt_xx = celt_sqrt(sqrt_xx);
+      qrrt_yy = celt_sqrt(sqrt_yy);
+      /* Inter-channel correlation */
+      mem->XY = MIN32(mem->XY, sqrt_xx*sqrt_yy);
+      corr = SHR32(frac_div32(mem->XY,EPSILON+MULT16_16(sqrt_xx,sqrt_yy)),16);
+      /* Approximate loudness difference */
+      ldiff = MULT16_16(Q15ONE, ABS16(qrrt_xx-qrrt_yy))/(EPSILON+qrrt_xx+qrrt_yy);
+      width = MULT16_16_Q15(celt_sqrt(QCONST32(1.f,30)-MULT16_16(corr,corr)), ldiff);
+      /* Smoothing over one second */
+      mem->smoothed_width += (width-mem->smoothed_width)/frame_rate;
+      /* Peak follower */
+      mem->max_follower = MAX16(mem->max_follower-QCONST16(.02f,15)/frame_rate, mem->smoothed_width);
+   }
+   /*printf("%f %f %f %f %f ", corr/(float)Q15ONE, ldiff/(float)Q15ONE, width/(float)Q15ONE, mem->smoothed_width/(float)Q15ONE, mem->max_follower/(float)Q15ONE);*/
+   return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower)));
+}
+
+opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
+                unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+                const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2,
+                int analysis_channels, downmix_func downmix, int float_api)
+{
+    void *silk_enc;
+    CELTEncoder *celt_enc;
+    int i;
+    int ret=0;
+    opus_int32 nBytes;
+    ec_enc enc;
+    int bytes_target;
+    int prefill=0;
+    int start_band = 0;
+    int redundancy = 0;
+    int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */
+    int celt_to_silk = 0;
+    VARDECL(opus_val16, pcm_buf);
+    int nb_compr_bytes;
+    int to_celt = 0;
+    opus_uint32 redundant_rng = 0;
+    int cutoff_Hz, hp_freq_smth1;
+    int voice_est; /* Probability of voice in Q7 */
+    opus_int32 equiv_rate;
+    int delay_compensation;
+    int frame_rate;
+    opus_int32 max_rate; /* Max bitrate we're allowed to use */
+    int curr_bandwidth;
+    opus_val16 HB_gain;
+    opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */
+    int total_buffer;
+    opus_val16 stereo_width;
+    const CELTMode *celt_mode;
+#ifndef DISABLE_FLOAT_API
+    AnalysisInfo analysis_info;
+    int analysis_read_pos_bak=-1;
+    int analysis_read_subframe_bak=-1;
+#endif
+    VARDECL(opus_val16, tmp_prefill);
+
+    ALLOC_STACK;
+
+    max_data_bytes = IMIN(1276, out_data_bytes);
+
+    st->rangeFinal = 0;
+    if ((!st->variable_duration && 400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs &&
+         50*frame_size != st->Fs &&  25*frame_size != st->Fs &&  50*frame_size != 3*st->Fs)
+         || (400*frame_size < st->Fs)
+         || max_data_bytes<=0
+         )
+    {
+       RESTORE_STACK;
+       return OPUS_BAD_ARG;
+    }
+    silk_enc = (char*)st+st->silk_enc_offset;
+    celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+    if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+       delay_compensation = 0;
+    else
+       delay_compensation = st->delay_compensation;
+
+    lsb_depth = IMIN(lsb_depth, st->lsb_depth);
+
+    celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
+#ifndef DISABLE_FLOAT_API
+    analysis_info.valid = 0;
+#ifdef FIXED_POINT
+    if (st->silk_mode.complexity >= 10 && st->Fs==48000)
+#else
+    if (st->silk_mode.complexity >= 7 && st->Fs==48000)
+#endif
+    {
+       analysis_read_pos_bak = st->analysis.read_pos;
+       analysis_read_subframe_bak = st->analysis.read_subframe;
+       run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size,
+             c1, c2, analysis_channels, st->Fs,
+             lsb_depth, downmix, &analysis_info);
+    }
+#else
+    (void)analysis_pcm;
+    (void)analysis_size;
+#endif
+
+    st->voice_ratio = -1;
+
+#ifndef DISABLE_FLOAT_API
+    st->detected_bandwidth = 0;
+    if (analysis_info.valid)
+    {
+       int analysis_bandwidth;
+       if (st->signal_type == OPUS_AUTO)
+          st->voice_ratio = (int)floor(.5+100*(1-analysis_info.music_prob));
+
+       analysis_bandwidth = analysis_info.bandwidth;
+       if (analysis_bandwidth<=12)
+          st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+       else if (analysis_bandwidth<=14)
+          st->detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+       else if (analysis_bandwidth<=16)
+          st->detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+       else if (analysis_bandwidth<=18)
+          st->detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+       else
+          st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+    }
+#endif
+
+    if (st->channels==2 && st->force_channels!=1)
+       stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem);
+    else
+       stereo_width = 0;
+    total_buffer = delay_compensation;
+    st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes);
+
+    frame_rate = st->Fs/frame_size;
+    if (!st->use_vbr)
+    {
+       int cbrBytes;
+       /* Multiply by 3 to make sure the division is exact. */
+       int frame_rate3 = 3*st->Fs/frame_size;
+       /* We need to make sure that "int" values always fit in 16 bits. */
+       cbrBytes = IMIN( (3*st->bitrate_bps/8 + frame_rate3/2)/frame_rate3, max_data_bytes);
+       st->bitrate_bps = cbrBytes*(opus_int32)frame_rate3*8/3;
+       max_data_bytes = cbrBytes;
+    }
+    if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8
+       || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400)))
+    {
+       /*If the space is too low to do something useful, emit 'PLC' frames.*/
+       int tocmode = st->mode;
+       int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth;
+       if (tocmode==0)
+          tocmode = MODE_SILK_ONLY;
+       if (frame_rate>100)
+          tocmode = MODE_CELT_ONLY;
+       if (frame_rate < 50)
+          tocmode = MODE_SILK_ONLY;
+       if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND)
+          bw=OPUS_BANDWIDTH_WIDEBAND;
+       else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND)
+          bw=OPUS_BANDWIDTH_NARROWBAND;
+       else if (tocmode==MODE_HYBRID&&bw<=OPUS_BANDWIDTH_SUPERWIDEBAND)
+          bw=OPUS_BANDWIDTH_SUPERWIDEBAND;
+       data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels);
+       ret = 1;
+       if (!st->use_vbr)
+       {
+          ret = opus_packet_pad(data, ret, max_data_bytes);
+          if (ret == OPUS_OK)
+             ret = max_data_bytes;
+       }
+       RESTORE_STACK;
+       return ret;
+    }
+    max_rate = frame_rate*max_data_bytes*8;
+
+    /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */
+    equiv_rate = st->bitrate_bps - (40*st->channels+20)*(st->Fs/frame_size - 50);
+
+    if (st->signal_type == OPUS_SIGNAL_VOICE)
+       voice_est = 127;
+    else if (st->signal_type == OPUS_SIGNAL_MUSIC)
+       voice_est = 0;
+    else if (st->voice_ratio >= 0)
+    {
+       voice_est = st->voice_ratio*327>>8;
+       /* For AUDIO, never be more than 90% confident of having speech */
+       if (st->application == OPUS_APPLICATION_AUDIO)
+          voice_est = IMIN(voice_est, 115);
+    } else if (st->application == OPUS_APPLICATION_VOIP)
+       voice_est = 115;
+    else
+       voice_est = 48;
+
+    if (st->force_channels!=OPUS_AUTO && st->channels == 2)
+    {
+        st->stream_channels = st->force_channels;
+    } else {
+#ifdef FUZZING
+       /* Random mono/stereo decision */
+       if (st->channels == 2 && (rand()&0x1F)==0)
+          st->stream_channels = 3-st->stream_channels;
+#else
+       /* Rate-dependent mono-stereo decision */
+       if (st->channels == 2)
+       {
+          opus_int32 stereo_threshold;
+          stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14);
+          if (st->stream_channels == 2)
+             stereo_threshold -= 1000;
+          else
+             stereo_threshold += 1000;
+          st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1;
+       } else {
+          st->stream_channels = st->channels;
+       }
+#endif
+    }
+    equiv_rate = st->bitrate_bps - (40*st->stream_channels+20)*(st->Fs/frame_size - 50);
+
+    /* Mode selection depending on application and signal type */
+    if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+    {
+       st->mode = MODE_CELT_ONLY;
+    } else if (st->user_forced_mode == OPUS_AUTO)
+    {
+#ifdef FUZZING
+       /* Random mode switching */
+       if ((rand()&0xF)==0)
+       {
+          if ((rand()&0x1)==0)
+             st->mode = MODE_CELT_ONLY;
+          else
+             st->mode = MODE_SILK_ONLY;
+       } else {
+          if (st->prev_mode==MODE_CELT_ONLY)
+             st->mode = MODE_CELT_ONLY;
+          else
+             st->mode = MODE_SILK_ONLY;
+       }
+#else
+       opus_int32 mode_voice, mode_music;
+       opus_int32 threshold;
+
+       /* Interpolate based on stereo width */
+       mode_voice = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[0][0])
+             + MULT16_32_Q15(stereo_width,mode_thresholds[1][0]));
+       mode_music = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[1][1])
+             + MULT16_32_Q15(stereo_width,mode_thresholds[1][1]));
+       /* Interpolate based on speech/music probability */
+       threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14);
+       /* Bias towards SILK for VoIP because of some useful features */
+       if (st->application == OPUS_APPLICATION_VOIP)
+          threshold += 8000;
+
+       /*printf("%f %d\n", stereo_width/(float)Q15ONE, threshold);*/
+       /* Hysteresis */
+       if (st->prev_mode == MODE_CELT_ONLY)
+           threshold -= 4000;
+       else if (st->prev_mode>0)
+           threshold += 4000;
+
+       st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY;
+
+       /* When FEC is enabled and there's enough packet loss, use SILK */
+       if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4)
+          st->mode = MODE_SILK_ONLY;
+       /* When encoding voice and DTX is enabled, set the encoder to SILK mode (at least for now) */
+       if (st->silk_mode.useDTX && voice_est > 100)
+          st->mode = MODE_SILK_ONLY;
+#endif
+    } else {
+       st->mode = st->user_forced_mode;
+    }
+
+    /* Override the chosen mode to make sure we meet the requested frame size */
+    if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100)
+       st->mode = MODE_CELT_ONLY;
+    if (st->lfe)
+       st->mode = MODE_CELT_ONLY;
+    /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */
+    if (max_data_bytes < (frame_rate > 50 ? 12000 : 8000)*frame_size / (st->Fs * 8))
+       st->mode = MODE_CELT_ONLY;
+
+    if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0
+          && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY)
+    {
+       /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */
+       st->silk_mode.toMono = 1;
+       st->stream_channels = 2;
+    } else {
+       st->silk_mode.toMono = 0;
+    }
+
+    if (st->prev_mode > 0 &&
+        ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ||
+    (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY)))
+    {
+        redundancy = 1;
+        celt_to_silk = (st->mode != MODE_CELT_ONLY);
+        if (!celt_to_silk)
+        {
+            /* Switch to SILK/hybrid if frame size is 10 ms or more*/
+            if (frame_size >= st->Fs/100)
+            {
+                st->mode = st->prev_mode;
+                to_celt = 1;
+            } else {
+                redundancy=0;
+            }
+        }
+    }
+    /* For the first frame at a new SILK bandwidth */
+    if (st->silk_bw_switch)
+    {
+       redundancy = 1;
+       celt_to_silk = 1;
+       st->silk_bw_switch = 0;
+       prefill=1;
+    }
+
+    if (redundancy)
+    {
+       /* Fair share of the max size allowed */
+       redundancy_bytes = IMIN(257, max_data_bytes*(opus_int32)(st->Fs/200)/(frame_size+st->Fs/200));
+       /* For VBR, target the actual bitrate (subject to the limit above) */
+       if (st->use_vbr)
+          redundancy_bytes = IMIN(redundancy_bytes, st->bitrate_bps/1600);
+    }
+
+    if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY)
+    {
+        silk_EncControlStruct dummy;
+        silk_InitEncoder( silk_enc, st->arch, &dummy);
+        prefill=1;
+    }
+
+    /* Automatic (rate-dependent) bandwidth selection */
+    if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch)
+    {
+        const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds;
+        opus_int32 bandwidth_thresholds[8];
+        int bandwidth = OPUS_BANDWIDTH_FULLBAND;
+        opus_int32 equiv_rate2;
+
+        equiv_rate2 = equiv_rate;
+        if (st->mode != MODE_CELT_ONLY)
+        {
+           /* Adjust the threshold +/- 10% depending on complexity */
+           equiv_rate2 = equiv_rate2 * (45+st->silk_mode.complexity)/50;
+           /* CBR is less efficient by ~1 kb/s */
+           if (!st->use_vbr)
+              equiv_rate2 -= 1000;
+        }
+        if (st->channels==2 && st->force_channels!=1)
+        {
+           voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds;
+           music_bandwidth_thresholds = stereo_music_bandwidth_thresholds;
+        } else {
+           voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds;
+           music_bandwidth_thresholds = mono_music_bandwidth_thresholds;
+        }
+        /* Interpolate bandwidth thresholds depending on voice estimation */
+        for (i=0;i<8;i++)
+        {
+           bandwidth_thresholds[i] = music_bandwidth_thresholds[i]
+                    + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14);
+        }
+        do {
+            int threshold, hysteresis;
+            threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)];
+            hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1];
+            if (!st->first)
+            {
+                if (st->bandwidth >= bandwidth)
+                    threshold -= hysteresis;
+                else
+                    threshold += hysteresis;
+            }
+            if (equiv_rate2 >= threshold)
+                break;
+        } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND);
+        st->bandwidth = bandwidth;
+        /* Prevents any transition to SWB/FB until the SILK layer has fully
+           switched to WB mode and turned the variable LP filter off */
+        if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+            st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+    }
+
+    if (st->bandwidth>st->max_bandwidth)
+       st->bandwidth = st->max_bandwidth;
+
+    if (st->user_bandwidth != OPUS_AUTO)
+        st->bandwidth = st->user_bandwidth;
+
+    /* This prevents us from using hybrid at unsafe CBR/max rates */
+    if (st->mode != MODE_CELT_ONLY && max_rate < 15000)
+    {
+       st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND);
+    }
+
+    /* Prevents Opus from wasting bits on frequencies that are above
+       the Nyquist rate of the input signal */
+    if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND)
+        st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+    if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+        st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+    if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND)
+        st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+    if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND)
+        st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+#ifndef DISABLE_FLOAT_API
+    /* Use detected bandwidth to reduce the encoded bandwidth. */
+    if (st->detected_bandwidth && st->user_bandwidth == OPUS_AUTO)
+    {
+       int min_detected_bandwidth;
+       /* Makes bandwidth detection more conservative just in case the detector
+          gets it wrong when we could have coded a high bandwidth transparently.
+          When operating in SILK/hybrid mode, we don't go below wideband to avoid
+          more complicated switches that require redundancy. */
+       if (equiv_rate <= 18000*st->stream_channels && st->mode == MODE_CELT_ONLY)
+          min_detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+       else if (equiv_rate <= 24000*st->stream_channels && st->mode == MODE_CELT_ONLY)
+          min_detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+       else if (equiv_rate <= 30000*st->stream_channels)
+          min_detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+       else if (equiv_rate <= 44000*st->stream_channels)
+          min_detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+       else
+          min_detected_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+       st->detected_bandwidth = IMAX(st->detected_bandwidth, min_detected_bandwidth);
+       st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth);
+    }
+#endif
+    celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth));
+
+    /* CELT mode doesn't support mediumband, use wideband instead */
+    if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+        st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+    if (st->lfe)
+       st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+
+    /* Can't support higher than wideband for >20 ms frames */
+    if (frame_size > st->Fs/50 && (st->mode == MODE_CELT_ONLY || st->bandwidth > OPUS_BANDWIDTH_WIDEBAND))
+    {
+       VARDECL(unsigned char, tmp_data);
+       int nb_frames;
+       int bak_mode, bak_bandwidth, bak_channels, bak_to_mono;
+       VARDECL(OpusRepacketizer, rp);
+       opus_int32 bytes_per_frame;
+       opus_int32 repacketize_len;
+
+#ifndef DISABLE_FLOAT_API
+       if (analysis_read_pos_bak!= -1)
+       {
+          st->analysis.read_pos = analysis_read_pos_bak;
+          st->analysis.read_subframe = analysis_read_subframe_bak;
+       }
+#endif
+
+       nb_frames = frame_size > st->Fs/25 ? 3 : 2;
+       bytes_per_frame = IMIN(1276,(out_data_bytes-3)/nb_frames);
+
+       ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char);
+
+       ALLOC(rp, 1, OpusRepacketizer);
+       opus_repacketizer_init(rp);
+
+       bak_mode = st->user_forced_mode;
+       bak_bandwidth = st->user_bandwidth;
+       bak_channels = st->force_channels;
+
+       st->user_forced_mode = st->mode;
+       st->user_bandwidth = st->bandwidth;
+       st->force_channels = st->stream_channels;
+       bak_to_mono = st->silk_mode.toMono;
+
+       if (bak_to_mono)
+          st->force_channels = 1;
+       else
+          st->prev_channels = st->stream_channels;
+       for (i=0;i<nb_frames;i++)
+       {
+          int tmp_len;
+          st->silk_mode.toMono = 0;
+          /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */
+          if (to_celt && i==nb_frames-1)
+             st->user_forced_mode = MODE_CELT_ONLY;
+          tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50,
+                tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth,
+                NULL, 0, c1, c2, analysis_channels, downmix, float_api);
+          if (tmp_len<0)
+          {
+             RESTORE_STACK;
+             return OPUS_INTERNAL_ERROR;
+          }
+          ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len);
+          if (ret<0)
+          {
+             RESTORE_STACK;
+             return OPUS_INTERNAL_ERROR;
+          }
+       }
+       if (st->use_vbr)
+          repacketize_len = out_data_bytes;
+       else
+          repacketize_len = IMIN(3*st->bitrate_bps/(3*8*50/nb_frames), out_data_bytes);
+       ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr);
+       if (ret<0)
+       {
+          RESTORE_STACK;
+          return OPUS_INTERNAL_ERROR;
+       }
+       st->user_forced_mode = bak_mode;
+       st->user_bandwidth = bak_bandwidth;
+       st->force_channels = bak_channels;
+       st->silk_mode.toMono = bak_to_mono;
+       RESTORE_STACK;
+       return ret;
+    }
+    curr_bandwidth = st->bandwidth;
+
+    /* Chooses the appropriate mode for speech
+       *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */
+    if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+        st->mode = MODE_HYBRID;
+    if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND)
+        st->mode = MODE_SILK_ONLY;
+
+    /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */
+    bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1;
+
+    data += 1;
+
+    ec_enc_init(&enc, data, max_data_bytes-1);
+
+    ALLOC(pcm_buf, (total_buffer+frame_size)*st->channels, opus_val16);
+    OPUS_COPY(pcm_buf, &st->delay_buffer[(st->encoder_buffer-total_buffer)*st->channels], total_buffer*st->channels);
+
+    if (st->mode == MODE_CELT_ONLY)
+       hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+    else
+       hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15;
+
+    st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15,
+          hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) );
+
+    /* convert from log scale to Hertz */
+    cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) );
+
+    if (st->application == OPUS_APPLICATION_VOIP)
+    {
+       hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
+    } else {
+       dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
+    }
+#ifndef FIXED_POINT
+    if (float_api)
+    {
+       opus_val32 sum;
+       sum = celt_inner_prod(&pcm_buf[total_buffer*st->channels], &pcm_buf[total_buffer*st->channels], frame_size*st->channels, st->arch);
+       /* This should filter out both NaNs and ridiculous signals that could
+          cause NaNs further down. */
+       if (!(sum < 1e9f) || celt_isnan(sum))
+       {
+          OPUS_CLEAR(&pcm_buf[total_buffer*st->channels], frame_size*st->channels);
+          st->hp_mem[0] = st->hp_mem[1] = st->hp_mem[2] = st->hp_mem[3] = 0;
+       }
+    }
+#endif
+
+
+    /* SILK processing */
+    HB_gain = Q15ONE;
+    if (st->mode != MODE_CELT_ONLY)
+    {
+        opus_int32 total_bitRate, celt_rate;
+#ifdef FIXED_POINT
+       const opus_int16 *pcm_silk;
+#else
+       VARDECL(opus_int16, pcm_silk);
+       ALLOC(pcm_silk, st->channels*frame_size, opus_int16);
+#endif
+
+        /* Distribute bits between SILK and CELT */
+        total_bitRate = 8 * bytes_target * frame_rate;
+        if( st->mode == MODE_HYBRID ) {
+            int HB_gain_ref;
+            /* Base rate for SILK */
+            st->silk_mode.bitRate = st->stream_channels * ( 5000 + 1000 * ( st->Fs == 100 * frame_size ) );
+            if( curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND ) {
+                /* SILK gets 2/3 of the remaining bits */
+                st->silk_mode.bitRate += ( total_bitRate - st->silk_mode.bitRate ) * 2 / 3;
+            } else { /* FULLBAND */
+                /* SILK gets 3/5 of the remaining bits */
+                st->silk_mode.bitRate += ( total_bitRate - st->silk_mode.bitRate ) * 3 / 5;
+            }
+            /* Don't let SILK use more than 80% */
+            if( st->silk_mode.bitRate > total_bitRate * 4/5 ) {
+                st->silk_mode.bitRate = total_bitRate * 4/5;
+            }
+            if (!st->energy_masking)
+            {
+               /* Increasingly attenuate high band when it gets allocated fewer bits */
+               celt_rate = total_bitRate - st->silk_mode.bitRate;
+               HB_gain_ref = (curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND) ? 3000 : 3600;
+               HB_gain = SHL32((opus_val32)celt_rate, 9) / SHR32((opus_val32)celt_rate + st->stream_channels * HB_gain_ref, 6);
+               HB_gain = HB_gain < (opus_val32)Q15ONE*6/7 ? HB_gain + Q15ONE/7 : Q15ONE;
+            }
+        } else {
+            /* SILK gets all bits */
+            st->silk_mode.bitRate = total_bitRate;
+        }
+
+        /* Surround masking for SILK */
+        if (st->energy_masking && st->use_vbr && !st->lfe)
+        {
+           opus_val32 mask_sum=0;
+           opus_val16 masking_depth;
+           opus_int32 rate_offset;
+           int c;
+           int end = 17;
+           opus_int16 srate = 16000;
+           if (st->bandwidth == OPUS_BANDWIDTH_NARROWBAND)
+           {
+              end = 13;
+              srate = 8000;
+           } else if (st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+           {
+              end = 15;
+              srate = 12000;
+           }
+           for (c=0;c<st->channels;c++)
+           {
+              for(i=0;i<end;i++)
+              {
+                 opus_val16 mask;
+                 mask = MAX16(MIN16(st->energy_masking[21*c+i],
+                        QCONST16(.5f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT));
+                 if (mask > 0)
+                    mask = HALF16(mask);
+                 mask_sum += mask;
+              }
+           }
+           /* Conservative rate reduction, we cut the masking in half */
+           masking_depth = mask_sum / end*st->channels;
+           masking_depth += QCONST16(.2f, DB_SHIFT);
+           rate_offset = (opus_int32)PSHR32(MULT16_16(srate, masking_depth), DB_SHIFT);
+           rate_offset = MAX32(rate_offset, -2*st->silk_mode.bitRate/3);
+           /* Split the rate change between the SILK and CELT part for hybrid. */
+           if (st->bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND || st->bandwidth==OPUS_BANDWIDTH_FULLBAND)
+              st->silk_mode.bitRate += 3*rate_offset/5;
+           else
+              st->silk_mode.bitRate += rate_offset;
+           bytes_target += rate_offset * frame_size / (8 * st->Fs);
+        }
+
+        st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs;
+        st->silk_mode.nChannelsAPI = st->channels;
+        st->silk_mode.nChannelsInternal = st->stream_channels;
+        if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+            st->silk_mode.desiredInternalSampleRate = 8000;
+        } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+            st->silk_mode.desiredInternalSampleRate = 12000;
+        } else {
+            silk_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND );
+            st->silk_mode.desiredInternalSampleRate = 16000;
+        }
+        if( st->mode == MODE_HYBRID ) {
+            /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */
+            st->silk_mode.minInternalSampleRate = 16000;
+        } else {
+            st->silk_mode.minInternalSampleRate = 8000;
+        }
+
+        if (st->mode == MODE_SILK_ONLY)
+        {
+           opus_int32 effective_max_rate = max_rate;
+           st->silk_mode.maxInternalSampleRate = 16000;
+           if (frame_rate > 50)
+              effective_max_rate = effective_max_rate*2/3;
+           if (effective_max_rate < 13000)
+           {
+              st->silk_mode.maxInternalSampleRate = 12000;
+              st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate);
+           }
+           if (effective_max_rate < 9600)
+           {
+              st->silk_mode.maxInternalSampleRate = 8000;
+              st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate);
+           }
+        } else {
+           st->silk_mode.maxInternalSampleRate = 16000;
+        }
+
+        st->silk_mode.useCBR = !st->use_vbr;
+
+        /* Call SILK encoder for the low band */
+        nBytes = IMIN(1275, max_data_bytes-1-redundancy_bytes);
+
+        st->silk_mode.maxBits = nBytes*8;
+        /* Only allow up to 90% of the bits for hybrid mode*/
+        if (st->mode == MODE_HYBRID)
+           st->silk_mode.maxBits = (opus_int32)st->silk_mode.maxBits*9/10;
+        if (st->silk_mode.useCBR)
+        {
+           st->silk_mode.maxBits = (st->silk_mode.bitRate * frame_size / (st->Fs * 8))*8;
+           /* Reduce the initial target to make it easier to reach the CBR rate */
+           st->silk_mode.bitRate = IMAX(1, st->silk_mode.bitRate-2000);
+        }
+
+        if (prefill)
+        {
+            opus_int32 zero=0;
+            int prefill_offset;
+            /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode
+               a discontinuity. The exact location is what we need to avoid leaving any "gap"
+               in the audio when mixing with the redundant CELT frame. Here we can afford to
+               overwrite st->delay_buffer because the only thing that uses it before it gets
+               rewritten is tmp_prefill[] and even then only the part after the ramp really
+               gets used (rather than sent to the encoder and discarded) */
+            prefill_offset = st->channels*(st->encoder_buffer-st->delay_compensation-st->Fs/400);
+            gain_fade(st->delay_buffer+prefill_offset, st->delay_buffer+prefill_offset,
+                  0, Q15ONE, celt_mode->overlap, st->Fs/400, st->channels, celt_mode->window, st->Fs);
+            OPUS_CLEAR(st->delay_buffer, prefill_offset);
+#ifdef FIXED_POINT
+            pcm_silk = st->delay_buffer;
+#else
+            for (i=0;i<st->encoder_buffer*st->channels;i++)
+                pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]);
+#endif
+            silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 );
+        }
+
+#ifdef FIXED_POINT
+        pcm_silk = pcm_buf+total_buffer*st->channels;
+#else
+        for (i=0;i<frame_size*st->channels;i++)
+            pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]);
+#endif
+        ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 );
+        if( ret ) {
+            /*fprintf (stderr, "SILK encode error: %d\n", ret);*/
+            /* Handle error */
+           RESTORE_STACK;
+           return OPUS_INTERNAL_ERROR;
+        }
+        if (nBytes==0)
+        {
+           st->rangeFinal = 0;
+           data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels);
+           RESTORE_STACK;
+           return 1;
+        }
+        /* Extract SILK internal bandwidth for signaling in first byte */
+        if( st->mode == MODE_SILK_ONLY ) {
+            if( st->silk_mode.internalSampleRate == 8000 ) {
+               curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+            } else if( st->silk_mode.internalSampleRate == 12000 ) {
+               curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+            } else if( st->silk_mode.internalSampleRate == 16000 ) {
+               curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+            }
+        } else {
+            silk_assert( st->silk_mode.internalSampleRate == 16000 );
+        }
+
+        st->silk_mode.opusCanSwitch = st->silk_mode.switchReady;
+        /* FIXME: How do we allocate the redundancy for CBR? */
+        if (st->silk_mode.opusCanSwitch)
+        {
+           redundancy = 1;
+           celt_to_silk = 0;
+           st->silk_bw_switch = 1;
+        }
+    }
+
+    /* CELT processing */
+    {
+        int endband=21;
+
+        switch(curr_bandwidth)
+        {
+            case OPUS_BANDWIDTH_NARROWBAND:
+                endband = 13;
+                break;
+            case OPUS_BANDWIDTH_MEDIUMBAND:
+            case OPUS_BANDWIDTH_WIDEBAND:
+                endband = 17;
+                break;
+            case OPUS_BANDWIDTH_SUPERWIDEBAND:
+                endband = 19;
+                break;
+            case OPUS_BANDWIDTH_FULLBAND:
+                endband = 21;
+                break;
+        }
+        celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband));
+        celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels));
+    }
+    celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
+    if (st->mode != MODE_SILK_ONLY)
+    {
+        opus_val32 celt_pred=2;
+        celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+        /* We may still decide to disable prediction later */
+        if (st->silk_mode.reducedDependency)
+           celt_pred = 0;
+        celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred));
+
+        if (st->mode == MODE_HYBRID)
+        {
+            int len;
+
+            len = (ec_tell(&enc)+7)>>3;
+            if (redundancy)
+               len += st->mode == MODE_HYBRID ? 3 : 1;
+            if( st->use_vbr ) {
+                nb_compr_bytes = len + bytes_target - (st->silk_mode.bitRate * frame_size) / (8 * st->Fs);
+            } else {
+                /* check if SILK used up too much */
+                nb_compr_bytes = len > bytes_target ? len : bytes_target;
+            }
+        } else {
+            if (st->use_vbr)
+            {
+                opus_int32 bonus=0;
+#ifndef DISABLE_FLOAT_API
+                if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != st->Fs/50)
+                {
+                   bonus = (60*st->stream_channels+40)*(st->Fs/frame_size-50);
+                   if (analysis_info.valid)
+                      bonus = (opus_int32)(bonus*(1.f+.5f*analysis_info.tonality));
+                }
+#endif
+                celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1));
+                celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint));
+                celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps+bonus));
+                nb_compr_bytes = max_data_bytes-1-redundancy_bytes;
+            } else {
+                nb_compr_bytes = bytes_target;
+            }
+        }
+
+    } else {
+        nb_compr_bytes = 0;
+    }
+
+    ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16);
+    if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0)
+    {
+       OPUS_COPY(tmp_prefill, &st->delay_buffer[(st->encoder_buffer-total_buffer-st->Fs/400)*st->channels], st->channels*st->Fs/400);
+    }
+
+    if (st->channels*(st->encoder_buffer-(frame_size+total_buffer)) > 0)
+    {
+       OPUS_MOVE(st->delay_buffer, &st->delay_buffer[st->channels*frame_size], st->channels*(st->encoder_buffer-frame_size-total_buffer));
+       OPUS_COPY(&st->delay_buffer[st->channels*(st->encoder_buffer-frame_size-total_buffer)],
+             &pcm_buf[0],
+             (frame_size+total_buffer)*st->channels);
+    } else {
+       OPUS_COPY(st->delay_buffer, &pcm_buf[(frame_size+total_buffer-st->encoder_buffer)*st->channels], st->encoder_buffer*st->channels);
+    }
+    /* gain_fade() and stereo_fade() need to be after the buffer copying
+       because we don't want any of this to affect the SILK part */
+    if( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) {
+       gain_fade(pcm_buf, pcm_buf,
+             st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs);
+    }
+    st->prev_HB_gain = HB_gain;
+    if (st->mode != MODE_HYBRID || st->stream_channels==1)
+       st->silk_mode.stereoWidth_Q14 = IMIN((1<<14),2*IMAX(0,equiv_rate-30000));
+    if( !st->energy_masking && st->channels == 2 ) {
+        /* Apply stereo width reduction (at low bitrates) */
+        if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) {
+            opus_val16 g1, g2;
+            g1 = st->hybrid_stereo_width_Q14;
+            g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14);
+#ifdef FIXED_POINT
+            g1 = g1==16384 ? Q15ONE : SHL16(g1,1);
+            g2 = g2==16384 ? Q15ONE : SHL16(g2,1);
+#else
+            g1 *= (1.f/16384);
+            g2 *= (1.f/16384);
+#endif
+            stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap,
+                  frame_size, st->channels, celt_mode->window, st->Fs);
+            st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14;
+        }
+    }
+
+    if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1))
+    {
+        /* For SILK mode, the redundancy is inferred from the length */
+        if (st->mode == MODE_HYBRID && (redundancy || ec_tell(&enc)+37 <= 8*nb_compr_bytes))
+           ec_enc_bit_logp(&enc, redundancy, 12);
+        if (redundancy)
+        {
+            int max_redundancy;
+            ec_enc_bit_logp(&enc, celt_to_silk, 1);
+            if (st->mode == MODE_HYBRID)
+               max_redundancy = (max_data_bytes-1)-nb_compr_bytes;
+            else
+               max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3);
+            /* Target the same bit-rate for redundancy as for the rest,
+               up to a max of 257 bytes */
+            redundancy_bytes = IMIN(max_redundancy, st->bitrate_bps/1600);
+            redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes));
+            if (st->mode == MODE_HYBRID)
+                ec_enc_uint(&enc, redundancy_bytes-2, 256);
+        }
+    } else {
+        redundancy = 0;
+    }
+
+    if (!redundancy)
+    {
+       st->silk_bw_switch = 0;
+       redundancy_bytes = 0;
+    }
+    if (st->mode != MODE_CELT_ONLY)start_band=17;
+
+    if (st->mode == MODE_SILK_ONLY)
+    {
+        ret = (ec_tell(&enc)+7)>>3;
+        ec_enc_done(&enc);
+        nb_compr_bytes = ret;
+    } else {
+       nb_compr_bytes = IMIN((max_data_bytes-1)-redundancy_bytes, nb_compr_bytes);
+       ec_enc_shrink(&enc, nb_compr_bytes);
+    }
+
+#ifndef DISABLE_FLOAT_API
+    if (redundancy || st->mode != MODE_SILK_ONLY)
+       celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info));
+#endif
+
+    /* 5 ms redundant frame for CELT->SILK */
+    if (redundancy && celt_to_silk)
+    {
+        int err;
+        celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
+        celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+        err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL);
+        if (err < 0)
+        {
+           RESTORE_STACK;
+           return OPUS_INTERNAL_ERROR;
+        }
+        celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng));
+        celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+    }
+
+    celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band));
+
+    if (st->mode != MODE_SILK_ONLY)
+    {
+        if (st->mode != st->prev_mode && st->prev_mode > 0)
+        {
+           unsigned char dummy[2];
+           celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+
+           /* Prefilling */
+           celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL);
+           celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+        }
+        /* If false, we already busted the budget and we'll end up with a "PLC packet" */
+        if (ec_tell(&enc) <= 8*nb_compr_bytes)
+        {
+           ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc);
+           if (ret < 0)
+           {
+              RESTORE_STACK;
+              return OPUS_INTERNAL_ERROR;
+           }
+        }
+    }
+
+    /* 5 ms redundant frame for SILK->CELT */
+    if (redundancy && !celt_to_silk)
+    {
+        int err;
+        unsigned char dummy[2];
+        int N2, N4;
+        N2 = st->Fs/200;
+        N4 = st->Fs/400;
+
+        celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+        celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
+        celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+
+        /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */
+        celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL);
+
+        err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL);
+        if (err < 0)
+        {
+           RESTORE_STACK;
+           return OPUS_INTERNAL_ERROR;
+        }
+        celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng));
+    }
+
+
+
+    /* Signalling the mode in the first byte */
+    data--;
+    data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels);
+
+    st->rangeFinal = enc.rng ^ redundant_rng;
+
+    if (to_celt)
+        st->prev_mode = MODE_CELT_ONLY;
+    else
+        st->prev_mode = st->mode;
+    st->prev_channels = st->stream_channels;
+    st->prev_framesize = frame_size;
+
+    st->first = 0;
+
+    /* In the unlikely case that the SILK encoder busted its target, tell
+       the decoder to call the PLC */
+    if (ec_tell(&enc) > (max_data_bytes-1)*8)
+    {
+       if (max_data_bytes < 2)
+       {
+          RESTORE_STACK;
+          return OPUS_BUFFER_TOO_SMALL;
+       }
+       data[1] = 0;
+       ret = 1;
+       st->rangeFinal = 0;
+    } else if (st->mode==MODE_SILK_ONLY&&!redundancy)
+    {
+       /*When in LPC only mode it's perfectly
+         reasonable to strip off trailing zero bytes as
+         the required range decoder behavior is to
+         fill these in. This can't be done when the MDCT
+         modes are used because the decoder needs to know
+         the actual length for allocation purposes.*/
+       while(ret>2&&data[ret]==0)ret--;
+    }
+    /* Count ToC and redundancy */
+    ret += 1+redundancy_bytes;
+    if (!st->use_vbr)
+    {
+       if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK)
+
+       {
+          RESTORE_STACK;
+          return OPUS_INTERNAL_ERROR;
+       }
+       ret = max_data_bytes;
+    }
+    RESTORE_STACK;
+    return ret;
+}
+
+#ifdef FIXED_POINT
+
+#ifndef DISABLE_FLOAT_API
+opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size,
+      unsigned char *data, opus_int32 max_data_bytes)
+{
+   int i, ret;
+   int frame_size;
+   int delay_compensation;
+   VARDECL(opus_int16, in);
+   ALLOC_STACK;
+
+   if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+      delay_compensation = 0;
+   else
+      delay_compensation = st->delay_compensation;
+   frame_size = compute_frame_size(pcm, analysis_frame_size,
+         st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+         delay_compensation, downmix_float, st->analysis.subframe_mem);
+
+   ALLOC(in, frame_size*st->channels, opus_int16);
+
+   for (i=0;i<frame_size*st->channels;i++)
+      in[i] = FLOAT2INT16(pcm[i]);
+   ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16,
+                            pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1);
+   RESTORE_STACK;
+   return ret;
+}
+#endif
+
+opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size,
+                unsigned char *data, opus_int32 out_data_bytes)
+{
+   int frame_size;
+   int delay_compensation;
+   if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+      delay_compensation = 0;
+   else
+      delay_compensation = st->delay_compensation;
+   frame_size = compute_frame_size(pcm, analysis_frame_size,
+         st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+         delay_compensation, downmix_int
+#ifndef DISABLE_FLOAT_API
+         , st->analysis.subframe_mem
+#endif
+         );
+   return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16,
+                             pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0);
+}
+
+#else
+opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size,
+      unsigned char *data, opus_int32 max_data_bytes)
+{
+   int i, ret;
+   int frame_size;
+   int delay_compensation;
+   VARDECL(float, in);
+   ALLOC_STACK;
+
+   if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+      delay_compensation = 0;
+   else
+      delay_compensation = st->delay_compensation;
+   frame_size = compute_frame_size(pcm, analysis_frame_size,
+         st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+         delay_compensation, downmix_int, st->analysis.subframe_mem);
+
+   ALLOC(in, frame_size*st->channels, float);
+
+   for (i=0;i<frame_size*st->channels;i++)
+      in[i] = (1.0f/32768)*pcm[i];
+   ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16,
+                            pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0);
+   RESTORE_STACK;
+   return ret;
+}
+opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size,
+                      unsigned char *data, opus_int32 out_data_bytes)
+{
+   int frame_size;
+   int delay_compensation;
+   if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+      delay_compensation = 0;
+   else
+      delay_compensation = st->delay_compensation;
+   frame_size = compute_frame_size(pcm, analysis_frame_size,
+         st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+         delay_compensation, downmix_float, st->analysis.subframe_mem);
+   return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24,
+                             pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1);
+}
+#endif
+
+
+int opus_encoder_ctl(OpusEncoder *st, int request, ...)
+{
+    int ret;
+    CELTEncoder *celt_enc;
+    va_list ap;
+
+    ret = OPUS_OK;
+    va_start(ap, request);
+
+    celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+
+    switch (request)
+    {
+        case OPUS_SET_APPLICATION_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (   (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO
+                 && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+               || (!st->first && st->application != value))
+            {
+               ret = OPUS_BAD_ARG;
+               break;
+            }
+            st->application = value;
+        }
+        break;
+        case OPUS_GET_APPLICATION_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->application;
+        }
+        break;
+        case OPUS_SET_BITRATE_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX)
+            {
+                if (value <= 0)
+                    goto bad_arg;
+                else if (value <= 500)
+                    value = 500;
+                else if (value > (opus_int32)300000*st->channels)
+                    value = (opus_int32)300000*st->channels;
+            }
+            st->user_bitrate_bps = value;
+        }
+        break;
+        case OPUS_GET_BITRATE_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276);
+        }
+        break;
+        case OPUS_SET_FORCE_CHANNELS_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if((value<1 || value>st->channels) && value != OPUS_AUTO)
+            {
+               goto bad_arg;
+            }
+            st->force_channels = value;
+        }
+        break;
+        case OPUS_GET_FORCE_CHANNELS_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->force_channels;
+        }
+        break;
+        case OPUS_SET_MAX_BANDWIDTH_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND)
+            {
+               goto bad_arg;
+            }
+            st->max_bandwidth = value;
+            if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+                st->silk_mode.maxInternalSampleRate = 8000;
+            } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+                st->silk_mode.maxInternalSampleRate = 12000;
+            } else {
+                st->silk_mode.maxInternalSampleRate = 16000;
+            }
+        }
+        break;
+        case OPUS_GET_MAX_BANDWIDTH_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->max_bandwidth;
+        }
+        break;
+        case OPUS_SET_BANDWIDTH_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO)
+            {
+               goto bad_arg;
+            }
+            st->user_bandwidth = value;
+            if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+                st->silk_mode.maxInternalSampleRate = 8000;
+            } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+                st->silk_mode.maxInternalSampleRate = 12000;
+            } else {
+                st->silk_mode.maxInternalSampleRate = 16000;
+            }
+        }
+        break;
+        case OPUS_GET_BANDWIDTH_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->bandwidth;
+        }
+        break;
+        case OPUS_SET_DTX_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if(value<0 || value>1)
+            {
+               goto bad_arg;
+            }
+            st->silk_mode.useDTX = value;
+        }
+        break;
+        case OPUS_GET_DTX_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->silk_mode.useDTX;
+        }
+        break;
+        case OPUS_SET_COMPLEXITY_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if(value<0 || value>10)
+            {
+               goto bad_arg;
+            }
+            st->silk_mode.complexity = value;
+            celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value));
+        }
+        break;
+        case OPUS_GET_COMPLEXITY_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->silk_mode.complexity;
+        }
+        break;
+        case OPUS_SET_INBAND_FEC_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if(value<0 || value>1)
+            {
+               goto bad_arg;
+            }
+            st->silk_mode.useInBandFEC = value;
+        }
+        break;
+        case OPUS_GET_INBAND_FEC_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->silk_mode.useInBandFEC;
+        }
+        break;
+        case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (value < 0 || value > 100)
+            {
+               goto bad_arg;
+            }
+            st->silk_mode.packetLossPercentage = value;
+            celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value));
+        }
+        break;
+        case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->silk_mode.packetLossPercentage;
+        }
+        break;
+        case OPUS_SET_VBR_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if(value<0 || value>1)
+            {
+               goto bad_arg;
+            }
+            st->use_vbr = value;
+            st->silk_mode.useCBR = 1-value;
+        }
+        break;
+        case OPUS_GET_VBR_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->use_vbr;
+        }
+        break;
+        case OPUS_SET_VOICE_RATIO_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (value<-1 || value>100)
+            {
+               goto bad_arg;
+            }
+            st->voice_ratio = value;
+        }
+        break;
+        case OPUS_GET_VOICE_RATIO_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->voice_ratio;
+        }
+        break;
+        case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if(value<0 || value>1)
+            {
+               goto bad_arg;
+            }
+            st->vbr_constraint = value;
+        }
+        break;
+        case OPUS_GET_VBR_CONSTRAINT_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->vbr_constraint;
+        }
+        break;
+        case OPUS_SET_SIGNAL_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC)
+            {
+               goto bad_arg;
+            }
+            st->signal_type = value;
+        }
+        break;
+        case OPUS_GET_SIGNAL_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->signal_type;
+        }
+        break;
+        case OPUS_GET_LOOKAHEAD_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->Fs/400;
+            if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+                *value += st->delay_compensation;
+        }
+        break;
+        case OPUS_GET_SAMPLE_RATE_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->Fs;
+        }
+        break;
+        case OPUS_GET_FINAL_RANGE_REQUEST:
+        {
+            opus_uint32 *value = va_arg(ap, opus_uint32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->rangeFinal;
+        }
+        break;
+        case OPUS_SET_LSB_DEPTH_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (value<8 || value>24)
+            {
+               goto bad_arg;
+            }
+            st->lsb_depth=value;
+        }
+        break;
+        case OPUS_GET_LSB_DEPTH_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->lsb_depth;
+        }
+        break;
+        case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (value != OPUS_FRAMESIZE_ARG   && value != OPUS_FRAMESIZE_2_5_MS &&
+                value != OPUS_FRAMESIZE_5_MS  && value != OPUS_FRAMESIZE_10_MS  &&
+                value != OPUS_FRAMESIZE_20_MS && value != OPUS_FRAMESIZE_40_MS  &&
+                value != OPUS_FRAMESIZE_60_MS && value != OPUS_FRAMESIZE_VARIABLE)
+            {
+               goto bad_arg;
+            }
+            st->variable_duration = value;
+            celt_encoder_ctl(celt_enc, OPUS_SET_EXPERT_FRAME_DURATION(value));
+        }
+        break;
+        case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            if (!value)
+            {
+               goto bad_arg;
+            }
+            *value = st->variable_duration;
+        }
+        break;
+        case OPUS_SET_PREDICTION_DISABLED_REQUEST:
+        {
+           opus_int32 value = va_arg(ap, opus_int32);
+           if (value > 1 || value < 0)
+              goto bad_arg;
+           st->silk_mode.reducedDependency = value;
+        }
+        break;
+        case OPUS_GET_PREDICTION_DISABLED_REQUEST:
+        {
+           opus_int32 *value = va_arg(ap, opus_int32*);
+           if (!value)
+              goto bad_arg;
+           *value = st->silk_mode.reducedDependency;
+        }
+        break;
+        case OPUS_RESET_STATE:
+        {
+           void *silk_enc;
+           silk_EncControlStruct dummy;
+           char *start;
+           silk_enc = (char*)st+st->silk_enc_offset;
+#ifndef DISABLE_FLOAT_API
+           tonality_analysis_reset(&st->analysis);
+#endif
+
+           start = (char*)&st->OPUS_ENCODER_RESET_START;
+           OPUS_CLEAR(start, sizeof(OpusEncoder) - (start - (char*)st));
+
+           celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+           silk_InitEncoder( silk_enc, st->arch, &dummy );
+           st->stream_channels = st->channels;
+           st->hybrid_stereo_width_Q14 = 1 << 14;
+           st->prev_HB_gain = Q15ONE;
+           st->first = 1;
+           st->mode = MODE_HYBRID;
+           st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
+           st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+        }
+        break;
+        case OPUS_SET_FORCE_MODE_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO)
+            {
+               goto bad_arg;
+            }
+            st->user_forced_mode = value;
+        }
+        break;
+        case OPUS_SET_LFE_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            st->lfe = value;
+            ret = celt_encoder_ctl(celt_enc, OPUS_SET_LFE(value));
+        }
+        break;
+        case OPUS_SET_ENERGY_MASK_REQUEST:
+        {
+            opus_val16 *value = va_arg(ap, opus_val16*);
+            st->energy_masking = value;
+            ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value));
+        }
+        break;
+
+        case CELT_GET_MODE_REQUEST:
+        {
+           const CELTMode ** value = va_arg(ap, const CELTMode**);
+           if (!value)
+           {
+              goto bad_arg;
+           }
+           ret = celt_encoder_ctl(celt_enc, CELT_GET_MODE(value));
+        }
+        break;
+        default:
+            /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/
+            ret = OPUS_UNIMPLEMENTED;
+            break;
+    }
+    va_end(ap);
+    return ret;
+bad_arg:
+    va_end(ap);
+    return OPUS_BAD_ARG;
+}
+
+void opus_encoder_destroy(OpusEncoder *st)
+{
+    opus_free(st);
+}
diff --git a/third_party/opus/src/src/opus_multistream.c b/third_party/opus/src/src/opus_multistream.c
new file mode 100644
index 0000000..09c3639
--- /dev/null
+++ b/third_party/opus/src/src/opus_multistream.c
@@ -0,0 +1,92 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_multistream.h"
+#include "opus.h"
+#include "opus_private.h"
+#include "stack_alloc.h"
+#include <stdarg.h>
+#include "float_cast.h"
+#include "os_support.h"
+
+
+int validate_layout(const ChannelLayout *layout)
+{
+   int i, max_channel;
+
+   max_channel = layout->nb_streams+layout->nb_coupled_streams;
+   if (max_channel>255)
+      return 0;
+   for (i=0;i<layout->nb_channels;i++)
+   {
+      if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255)
+         return 0;
+   }
+   return 1;
+}
+
+
+int get_left_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+   int i;
+   i = (prev<0) ? 0 : prev+1;
+   for (;i<layout->nb_channels;i++)
+   {
+      if (layout->mapping[i]==stream_id*2)
+         return i;
+   }
+   return -1;
+}
+
+int get_right_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+   int i;
+   i = (prev<0) ? 0 : prev+1;
+   for (;i<layout->nb_channels;i++)
+   {
+      if (layout->mapping[i]==stream_id*2+1)
+         return i;
+   }
+   return -1;
+}
+
+int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+   int i;
+   i = (prev<0) ? 0 : prev+1;
+   for (;i<layout->nb_channels;i++)
+   {
+      if (layout->mapping[i]==stream_id+layout->nb_coupled_streams)
+         return i;
+   }
+   return -1;
+}
+
diff --git a/third_party/opus/src/src/opus_multistream_decoder.c b/third_party/opus/src/src/opus_multistream_decoder.c
new file mode 100644
index 0000000..b95eaa6
--- /dev/null
+++ b/third_party/opus/src/src/opus_multistream_decoder.c
@@ -0,0 +1,537 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_multistream.h"
+#include "opus.h"
+#include "opus_private.h"
+#include "stack_alloc.h"
+#include <stdarg.h>
+#include "float_cast.h"
+#include "os_support.h"
+
+struct OpusMSDecoder {
+   ChannelLayout layout;
+   /* Decoder states go here */
+};
+
+
+
+
+/* DECODER */
+
+opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams)
+{
+   int coupled_size;
+   int mono_size;
+
+   if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
+   coupled_size = opus_decoder_get_size(2);
+   mono_size = opus_decoder_get_size(1);
+   return align(sizeof(OpusMSDecoder))
+         + nb_coupled_streams * align(coupled_size)
+         + (nb_streams-nb_coupled_streams) * align(mono_size);
+}
+
+int opus_multistream_decoder_init(
+      OpusMSDecoder *st,
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping
+)
+{
+   int coupled_size;
+   int mono_size;
+   int i, ret;
+   char *ptr;
+
+   if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+       (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
+      return OPUS_BAD_ARG;
+
+   st->layout.nb_channels = channels;
+   st->layout.nb_streams = streams;
+   st->layout.nb_coupled_streams = coupled_streams;
+
+   for (i=0;i<st->layout.nb_channels;i++)
+      st->layout.mapping[i] = mapping[i];
+   if (!validate_layout(&st->layout))
+      return OPUS_BAD_ARG;
+
+   ptr = (char*)st + align(sizeof(OpusMSDecoder));
+   coupled_size = opus_decoder_get_size(2);
+   mono_size = opus_decoder_get_size(1);
+
+   for (i=0;i<st->layout.nb_coupled_streams;i++)
+   {
+      ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2);
+      if(ret!=OPUS_OK)return ret;
+      ptr += align(coupled_size);
+   }
+   for (;i<st->layout.nb_streams;i++)
+   {
+      ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1);
+      if(ret!=OPUS_OK)return ret;
+      ptr += align(mono_size);
+   }
+   return OPUS_OK;
+}
+
+
+OpusMSDecoder *opus_multistream_decoder_create(
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping,
+      int *error
+)
+{
+   int ret;
+   OpusMSDecoder *st;
+   if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+       (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+   st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams));
+   if (st==NULL)
+   {
+      if (error)
+         *error = OPUS_ALLOC_FAIL;
+      return NULL;
+   }
+   ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping);
+   if (error)
+      *error = ret;
+   if (ret != OPUS_OK)
+   {
+      opus_free(st);
+      st = NULL;
+   }
+   return st;
+}
+
+typedef void (*opus_copy_channel_out_func)(
+  void *dst,
+  int dst_stride,
+  int dst_channel,
+  const opus_val16 *src,
+  int src_stride,
+  int frame_size
+);
+
+static int opus_multistream_packet_validate(const unsigned char *data,
+      opus_int32 len, int nb_streams, opus_int32 Fs)
+{
+   int s;
+   int count;
+   unsigned char toc;
+   opus_int16 size[48];
+   int samples=0;
+   opus_int32 packet_offset;
+
+   for (s=0;s<nb_streams;s++)
+   {
+      int tmp_samples;
+      if (len<=0)
+         return OPUS_INVALID_PACKET;
+      count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL,
+                                     size, NULL, &packet_offset);
+      if (count<0)
+         return count;
+      tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs);
+      if (s!=0 && samples != tmp_samples)
+         return OPUS_INVALID_PACKET;
+      samples = tmp_samples;
+      data += packet_offset;
+      len -= packet_offset;
+   }
+   return samples;
+}
+
+static int opus_multistream_decode_native(
+      OpusMSDecoder *st,
+      const unsigned char *data,
+      opus_int32 len,
+      void *pcm,
+      opus_copy_channel_out_func copy_channel_out,
+      int frame_size,
+      int decode_fec,
+      int soft_clip
+)
+{
+   opus_int32 Fs;
+   int coupled_size;
+   int mono_size;
+   int s, c;
+   char *ptr;
+   int do_plc=0;
+   VARDECL(opus_val16, buf);
+   ALLOC_STACK;
+
+   /* Limit frame_size to avoid excessive stack allocations. */
+   opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs));
+   frame_size = IMIN(frame_size, Fs/25*3);
+   ALLOC(buf, 2*frame_size, opus_val16);
+   ptr = (char*)st + align(sizeof(OpusMSDecoder));
+   coupled_size = opus_decoder_get_size(2);
+   mono_size = opus_decoder_get_size(1);
+
+   if (len==0)
+      do_plc = 1;
+   if (len < 0)
+   {
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   }
+   if (!do_plc && len < 2*st->layout.nb_streams-1)
+   {
+      RESTORE_STACK;
+      return OPUS_INVALID_PACKET;
+   }
+   if (!do_plc)
+   {
+      int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs);
+      if (ret < 0)
+      {
+         RESTORE_STACK;
+         return ret;
+      } else if (ret > frame_size)
+      {
+         RESTORE_STACK;
+         return OPUS_BUFFER_TOO_SMALL;
+      }
+   }
+   for (s=0;s<st->layout.nb_streams;s++)
+   {
+      OpusDecoder *dec;
+      int packet_offset, ret;
+
+      dec = (OpusDecoder*)ptr;
+      ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
+
+      if (!do_plc && len<=0)
+      {
+         RESTORE_STACK;
+         return OPUS_INTERNAL_ERROR;
+      }
+      packet_offset = 0;
+      ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip);
+      data += packet_offset;
+      len -= packet_offset;
+      if (ret <= 0)
+      {
+         RESTORE_STACK;
+         return ret;
+      }
+      frame_size = ret;
+      if (s < st->layout.nb_coupled_streams)
+      {
+         int chan, prev;
+         prev = -1;
+         /* Copy "left" audio to the channel(s) where it belongs */
+         while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
+         {
+            (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+               buf, 2, frame_size);
+            prev = chan;
+         }
+         prev = -1;
+         /* Copy "right" audio to the channel(s) where it belongs */
+         while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
+         {
+            (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+               buf+1, 2, frame_size);
+            prev = chan;
+         }
+      } else {
+         int chan, prev;
+         prev = -1;
+         /* Copy audio to the channel(s) where it belongs */
+         while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
+         {
+            (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+               buf, 1, frame_size);
+            prev = chan;
+         }
+      }
+   }
+   /* Handle muted channels */
+   for (c=0;c<st->layout.nb_channels;c++)
+   {
+      if (st->layout.mapping[c] == 255)
+      {
+         (*copy_channel_out)(pcm, st->layout.nb_channels, c,
+            NULL, 0, frame_size);
+      }
+   }
+   RESTORE_STACK;
+   return frame_size;
+}
+
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_out_float(
+  void *dst,
+  int dst_stride,
+  int dst_channel,
+  const opus_val16 *src,
+  int src_stride,
+  int frame_size
+)
+{
+   float *float_dst;
+   opus_int32 i;
+   float_dst = (float*)dst;
+   if (src != NULL)
+   {
+      for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+         float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride];
+#else
+         float_dst[i*dst_stride+dst_channel] = src[i*src_stride];
+#endif
+   }
+   else
+   {
+      for (i=0;i<frame_size;i++)
+         float_dst[i*dst_stride+dst_channel] = 0;
+   }
+}
+#endif
+
+static void opus_copy_channel_out_short(
+  void *dst,
+  int dst_stride,
+  int dst_channel,
+  const opus_val16 *src,
+  int src_stride,
+  int frame_size
+)
+{
+   opus_int16 *short_dst;
+   opus_int32 i;
+   short_dst = (opus_int16*)dst;
+   if (src != NULL)
+   {
+      for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+         short_dst[i*dst_stride+dst_channel] = src[i*src_stride];
+#else
+         short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]);
+#endif
+   }
+   else
+   {
+      for (i=0;i<frame_size;i++)
+         short_dst[i*dst_stride+dst_channel] = 0;
+   }
+}
+
+
+
+#ifdef FIXED_POINT
+int opus_multistream_decode(
+      OpusMSDecoder *st,
+      const unsigned char *data,
+      opus_int32 len,
+      opus_int16 *pcm,
+      int frame_size,
+      int decode_fec
+)
+{
+   return opus_multistream_decode_native(st, data, len,
+       pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
+      opus_int32 len, float *pcm, int frame_size, int decode_fec)
+{
+   return opus_multistream_decode_native(st, data, len,
+       pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
+}
+#endif
+
+#else
+
+int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
+      opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
+{
+   return opus_multistream_decode_native(st, data, len,
+       pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1);
+}
+
+int opus_multistream_decode_float(
+      OpusMSDecoder *st,
+      const unsigned char *data,
+      opus_int32 len,
+      float *pcm,
+      int frame_size,
+      int decode_fec
+)
+{
+   return opus_multistream_decode_native(st, data, len,
+       pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
+}
+#endif
+
+int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
+{
+   va_list ap;
+   int coupled_size, mono_size;
+   char *ptr;
+   int ret = OPUS_OK;
+
+   va_start(ap, request);
+
+   coupled_size = opus_decoder_get_size(2);
+   mono_size = opus_decoder_get_size(1);
+   ptr = (char*)st + align(sizeof(OpusMSDecoder));
+   switch (request)
+   {
+       case OPUS_GET_BANDWIDTH_REQUEST:
+       case OPUS_GET_SAMPLE_RATE_REQUEST:
+       case OPUS_GET_GAIN_REQUEST:
+       case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
+       {
+          OpusDecoder *dec;
+          /* For int32* GET params, just query the first stream */
+          opus_int32 *value = va_arg(ap, opus_int32*);
+          dec = (OpusDecoder*)ptr;
+          ret = opus_decoder_ctl(dec, request, value);
+       }
+       break;
+       case OPUS_GET_FINAL_RANGE_REQUEST:
+       {
+          int s;
+          opus_uint32 *value = va_arg(ap, opus_uint32*);
+          opus_uint32 tmp;
+          if (!value)
+          {
+             goto bad_arg;
+          }
+          *value = 0;
+          for (s=0;s<st->layout.nb_streams;s++)
+          {
+             OpusDecoder *dec;
+             dec = (OpusDecoder*)ptr;
+             if (s < st->layout.nb_coupled_streams)
+                ptr += align(coupled_size);
+             else
+                ptr += align(mono_size);
+             ret = opus_decoder_ctl(dec, request, &tmp);
+             if (ret != OPUS_OK) break;
+             *value ^= tmp;
+          }
+       }
+       break;
+       case OPUS_RESET_STATE:
+       {
+          int s;
+          for (s=0;s<st->layout.nb_streams;s++)
+          {
+             OpusDecoder *dec;
+
+             dec = (OpusDecoder*)ptr;
+             if (s < st->layout.nb_coupled_streams)
+                ptr += align(coupled_size);
+             else
+                ptr += align(mono_size);
+             ret = opus_decoder_ctl(dec, OPUS_RESET_STATE);
+             if (ret != OPUS_OK)
+                break;
+          }
+       }
+       break;
+       case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST:
+       {
+          int s;
+          opus_int32 stream_id;
+          OpusDecoder **value;
+          stream_id = va_arg(ap, opus_int32);
+          if (stream_id<0 || stream_id >= st->layout.nb_streams)
+             ret = OPUS_BAD_ARG;
+          value = va_arg(ap, OpusDecoder**);
+          if (!value)
+          {
+             goto bad_arg;
+          }
+          for (s=0;s<stream_id;s++)
+          {
+             if (s < st->layout.nb_coupled_streams)
+                ptr += align(coupled_size);
+             else
+                ptr += align(mono_size);
+          }
+          *value = (OpusDecoder*)ptr;
+       }
+       break;
+       case OPUS_SET_GAIN_REQUEST:
+       {
+          int s;
+          /* This works for int32 params */
+          opus_int32 value = va_arg(ap, opus_int32);
+          for (s=0;s<st->layout.nb_streams;s++)
+          {
+             OpusDecoder *dec;
+
+             dec = (OpusDecoder*)ptr;
+             if (s < st->layout.nb_coupled_streams)
+                ptr += align(coupled_size);
+             else
+                ptr += align(mono_size);
+             ret = opus_decoder_ctl(dec, request, value);
+             if (ret != OPUS_OK)
+                break;
+          }
+       }
+       break;
+       default:
+          ret = OPUS_UNIMPLEMENTED;
+       break;
+   }
+
+   va_end(ap);
+   return ret;
+bad_arg:
+   va_end(ap);
+   return OPUS_BAD_ARG;
+}
+
+
+void opus_multistream_decoder_destroy(OpusMSDecoder *st)
+{
+    opus_free(st);
+}
diff --git a/third_party/opus/src/src/opus_multistream_encoder.c b/third_party/opus/src/src/opus_multistream_encoder.c
new file mode 100644
index 0000000..e722e31
--- /dev/null
+++ b/third_party/opus/src/src/opus_multistream_encoder.c
@@ -0,0 +1,1351 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_multistream.h"
+#include "opus.h"
+#include "opus_private.h"
+#include "stack_alloc.h"
+#include <stdarg.h>
+#include "float_cast.h"
+#include "os_support.h"
+#include "mathops.h"
+#include "mdct.h"
+#include "modes.h"
+#include "bands.h"
+#include "quant_bands.h"
+#include "pitch.h"
+
+typedef struct {
+   int nb_streams;
+   int nb_coupled_streams;
+   unsigned char mapping[8];
+} VorbisLayout;
+
+/* Index is nb_channel-1*/
+static const VorbisLayout vorbis_mappings[8] = {
+      {1, 0, {0}},                      /* 1: mono */
+      {1, 1, {0, 1}},                   /* 2: stereo */
+      {2, 1, {0, 2, 1}},                /* 3: 1-d surround */
+      {2, 2, {0, 1, 2, 3}},             /* 4: quadraphonic surround */
+      {3, 2, {0, 4, 1, 2, 3}},          /* 5: 5-channel surround */
+      {4, 2, {0, 4, 1, 2, 3, 5}},       /* 6: 5.1 surround */
+      {4, 3, {0, 4, 1, 2, 3, 5, 6}},    /* 7: 6.1 surround */
+      {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */
+};
+
+typedef void (*opus_copy_channel_in_func)(
+  opus_val16 *dst,
+  int dst_stride,
+  const void *src,
+  int src_stride,
+  int src_channel,
+  int frame_size
+);
+
+typedef enum {
+  MAPPING_TYPE_NONE,
+  MAPPING_TYPE_SURROUND
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+  ,  /* Do not include comma at end of enumerator list */
+  MAPPING_TYPE_AMBISONICS
+#endif
+} MappingType;
+
+struct OpusMSEncoder {
+   ChannelLayout layout;
+   int arch;
+   int lfe_stream;
+   int application;
+   int variable_duration;
+   MappingType mapping_type;
+   opus_int32 bitrate_bps;
+   float subframe_mem[3];
+   /* Encoder states go here */
+   /* then opus_val32 window_mem[channels*120]; */
+   /* then opus_val32 preemph_mem[channels]; */
+};
+
+static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st)
+{
+   int s;
+   char *ptr;
+   int coupled_size, mono_size;
+
+   coupled_size = opus_encoder_get_size(2);
+   mono_size = opus_encoder_get_size(1);
+   ptr = (char*)st + align(sizeof(OpusMSEncoder));
+   for (s=0;s<st->layout.nb_streams;s++)
+   {
+      if (s < st->layout.nb_coupled_streams)
+         ptr += align(coupled_size);
+      else
+         ptr += align(mono_size);
+   }
+   /* void* cast avoids clang -Wcast-align warning */
+   return (opus_val32*)(void*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32));
+}
+
+static opus_val32 *ms_get_window_mem(OpusMSEncoder *st)
+{
+   int s;
+   char *ptr;
+   int coupled_size, mono_size;
+
+   coupled_size = opus_encoder_get_size(2);
+   mono_size = opus_encoder_get_size(1);
+   ptr = (char*)st + align(sizeof(OpusMSEncoder));
+   for (s=0;s<st->layout.nb_streams;s++)
+   {
+      if (s < st->layout.nb_coupled_streams)
+         ptr += align(coupled_size);
+      else
+         ptr += align(mono_size);
+   }
+   /* void* cast avoids clang -Wcast-align warning */
+   return (opus_val32*)(void*)ptr;
+}
+
+static int validate_encoder_layout(const ChannelLayout *layout)
+{
+   int s;
+   for (s=0;s<layout->nb_streams;s++)
+   {
+      if (s < layout->nb_coupled_streams)
+      {
+         if (get_left_channel(layout, s, -1)==-1)
+            return 0;
+         if (get_right_channel(layout, s, -1)==-1)
+            return 0;
+      } else {
+         if (get_mono_channel(layout, s, -1)==-1)
+            return 0;
+      }
+   }
+   return 1;
+}
+
+static void channel_pos(int channels, int pos[8])
+{
+   /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */
+   if (channels==4)
+   {
+      pos[0]=1;
+      pos[1]=3;
+      pos[2]=1;
+      pos[3]=3;
+   } else if (channels==3||channels==5||channels==6)
+   {
+      pos[0]=1;
+      pos[1]=2;
+      pos[2]=3;
+      pos[3]=1;
+      pos[4]=3;
+      pos[5]=0;
+   } else if (channels==7)
+   {
+      pos[0]=1;
+      pos[1]=2;
+      pos[2]=3;
+      pos[3]=1;
+      pos[4]=3;
+      pos[5]=2;
+      pos[6]=0;
+   } else if (channels==8)
+   {
+      pos[0]=1;
+      pos[1]=2;
+      pos[2]=3;
+      pos[3]=1;
+      pos[4]=3;
+      pos[5]=1;
+      pos[6]=3;
+      pos[7]=0;
+   }
+}
+
+#if 1
+/* Computes a rough approximation of log2(2^a + 2^b) */
+static opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+   opus_val16 max;
+   opus_val32 diff;
+   opus_val16 frac;
+   static const opus_val16 diff_table[17] = {
+         QCONST16(0.5000000f, DB_SHIFT), QCONST16(0.2924813f, DB_SHIFT), QCONST16(0.1609640f, DB_SHIFT), QCONST16(0.0849625f, DB_SHIFT),
+         QCONST16(0.0437314f, DB_SHIFT), QCONST16(0.0221971f, DB_SHIFT), QCONST16(0.0111839f, DB_SHIFT), QCONST16(0.0056136f, DB_SHIFT),
+         QCONST16(0.0028123f, DB_SHIFT)
+   };
+   int low;
+   if (a>b)
+   {
+      max = a;
+      diff = SUB32(EXTEND32(a),EXTEND32(b));
+   } else {
+      max = b;
+      diff = SUB32(EXTEND32(b),EXTEND32(a));
+   }
+   if (!(diff < QCONST16(8.f, DB_SHIFT)))  /* inverted to catch NaNs */
+      return max;
+#ifdef FIXED_POINT
+   low = SHR32(diff, DB_SHIFT-1);
+   frac = SHL16(diff - SHL16(low, DB_SHIFT-1), 16-DB_SHIFT);
+#else
+   low = (int)floor(2*diff);
+   frac = 2*diff - low;
+#endif
+   return max + diff_table[low] + MULT16_16_Q15(frac, SUB16(diff_table[low+1], diff_table[low]));
+}
+#else
+opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+   return log2(pow(4, a)+ pow(4, b))/2;
+}
+#endif
+
+void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem,
+      int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in, int arch
+)
+{
+   int c;
+   int i;
+   int LM;
+   int pos[8] = {0};
+   int upsample;
+   int frame_size;
+   opus_val16 channel_offset;
+   opus_val32 bandE[21];
+   opus_val16 maskLogE[3][21];
+   VARDECL(opus_val32, in);
+   VARDECL(opus_val16, x);
+   VARDECL(opus_val32, freq);
+   SAVE_STACK;
+
+   upsample = resampling_factor(rate);
+   frame_size = len*upsample;
+
+   /* LM = log2(frame_size / 120) */
+   for (LM=0;LM<celt_mode->maxLM;LM++)
+      if (celt_mode->shortMdctSize<<LM==frame_size)
+         break;
+
+   ALLOC(in, frame_size+overlap, opus_val32);
+   ALLOC(x, len, opus_val16);
+   ALLOC(freq, frame_size, opus_val32);
+
+   channel_pos(channels, pos);
+
+   for (c=0;c<3;c++)
+      for (i=0;i<21;i++)
+         maskLogE[c][i] = -QCONST16(28.f, DB_SHIFT);
+
+   for (c=0;c<channels;c++)
+   {
+      OPUS_COPY(in, mem+c*overlap, overlap);
+      (*copy_channel_in)(x, 1, pcm, channels, c, len);
+      celt_preemphasis(x, in+overlap, frame_size, 1, upsample, celt_mode->preemph, preemph_mem+c, 0);
+#ifndef FIXED_POINT
+      {
+         opus_val32 sum;
+         sum = celt_inner_prod(in, in, frame_size+overlap, 0);
+         /* This should filter out both NaNs and ridiculous signals that could
+            cause NaNs further down. */
+         if (!(sum < 1e9f) || celt_isnan(sum))
+         {
+            OPUS_CLEAR(in, frame_size+overlap);
+            preemph_mem[c] = 0;
+         }
+      }
+#endif
+      clt_mdct_forward(&celt_mode->mdct, in, freq, celt_mode->window,
+            overlap, celt_mode->maxLM-LM, 1, arch);
+      if (upsample != 1)
+      {
+         int bound = len;
+         for (i=0;i<bound;i++)
+            freq[i] *= upsample;
+         for (;i<frame_size;i++)
+            freq[i] = 0;
+      }
+
+      compute_band_energies(celt_mode, freq, bandE, 21, 1, LM);
+      amp2Log2(celt_mode, 21, 21, bandE, bandLogE+21*c, 1);
+      /* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */
+      for (i=1;i<21;i++)
+         bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i-1]-QCONST16(1.f, DB_SHIFT));
+      for (i=19;i>=0;i--)
+         bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i+1]-QCONST16(2.f, DB_SHIFT));
+      if (pos[c]==1)
+      {
+         for (i=0;i<21;i++)
+            maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]);
+      } else if (pos[c]==3)
+      {
+         for (i=0;i<21;i++)
+            maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]);
+      } else if (pos[c]==2)
+      {
+         for (i=0;i<21;i++)
+         {
+            maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT));
+            maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT));
+         }
+      }
+#if 0
+      for (i=0;i<21;i++)
+         printf("%f ", bandLogE[21*c+i]);
+      float sum=0;
+      for (i=0;i<21;i++)
+         sum += bandLogE[21*c+i];
+      printf("%f ", sum/21);
+#endif
+      OPUS_COPY(mem+c*overlap, in+frame_size, overlap);
+   }
+   for (i=0;i<21;i++)
+      maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]);
+   channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1)));
+   for (c=0;c<3;c++)
+      for (i=0;i<21;i++)
+         maskLogE[c][i] += channel_offset;
+#if 0
+   for (c=0;c<3;c++)
+   {
+      for (i=0;i<21;i++)
+         printf("%f ", maskLogE[c][i]);
+   }
+#endif
+   for (c=0;c<channels;c++)
+   {
+      opus_val16 *mask;
+      if (pos[c]!=0)
+      {
+         mask = &maskLogE[pos[c]-1][0];
+         for (i=0;i<21;i++)
+            bandLogE[21*c+i] = bandLogE[21*c+i] - mask[i];
+      } else {
+         for (i=0;i<21;i++)
+            bandLogE[21*c+i] = 0;
+      }
+#if 0
+      for (i=0;i<21;i++)
+         printf("%f ", bandLogE[21*c+i]);
+      printf("\n");
+#endif
+#if 0
+      float sum=0;
+      for (i=0;i<21;i++)
+         sum += bandLogE[21*c+i];
+      printf("%f ", sum/(float)QCONST32(21.f, DB_SHIFT));
+      printf("\n");
+#endif
+   }
+   RESTORE_STACK;
+}
+
+opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
+{
+   int coupled_size;
+   int mono_size;
+
+   if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
+   coupled_size = opus_encoder_get_size(2);
+   mono_size = opus_encoder_get_size(1);
+   return align(sizeof(OpusMSEncoder))
+        + nb_coupled_streams * align(coupled_size)
+        + (nb_streams-nb_coupled_streams) * align(mono_size);
+}
+
+opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family)
+{
+   int nb_streams;
+   int nb_coupled_streams;
+   opus_int32 size;
+
+   if (mapping_family==0)
+   {
+      if (channels==1)
+      {
+         nb_streams=1;
+         nb_coupled_streams=0;
+      } else if (channels==2)
+      {
+         nb_streams=1;
+         nb_coupled_streams=1;
+      } else
+         return 0;
+   } else if (mapping_family==1 && channels<=8 && channels>=1)
+   {
+      nb_streams=vorbis_mappings[channels-1].nb_streams;
+      nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
+   } else if (mapping_family==255)
+   {
+      nb_streams=channels;
+      nb_coupled_streams=0;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+   } else if (mapping_family==254)
+   {
+      nb_streams=channels;
+      nb_coupled_streams=0;
+#endif
+   } else
+      return 0;
+   size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
+   if (channels>2)
+   {
+      size += channels*(120*sizeof(opus_val32) + sizeof(opus_val32));
+   }
+   return size;
+}
+
+static int opus_multistream_encoder_init_impl(
+      OpusMSEncoder *st,
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping,
+      int application,
+      MappingType mapping_type
+)
+{
+   int coupled_size;
+   int mono_size;
+   int i, ret;
+   char *ptr;
+
+   if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+       (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
+      return OPUS_BAD_ARG;
+
+   st->arch = opus_select_arch();
+   st->layout.nb_channels = channels;
+   st->layout.nb_streams = streams;
+   st->layout.nb_coupled_streams = coupled_streams;
+   st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0;
+   if (mapping_type != MAPPING_TYPE_SURROUND)
+      st->lfe_stream = -1;
+   st->bitrate_bps = OPUS_AUTO;
+   st->application = application;
+   st->variable_duration = OPUS_FRAMESIZE_ARG;
+   for (i=0;i<st->layout.nb_channels;i++)
+      st->layout.mapping[i] = mapping[i];
+   if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
+      return OPUS_BAD_ARG;
+   ptr = (char*)st + align(sizeof(OpusMSEncoder));
+   coupled_size = opus_encoder_get_size(2);
+   mono_size = opus_encoder_get_size(1);
+
+   for (i=0;i<st->layout.nb_coupled_streams;i++)
+   {
+      ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
+      if(ret!=OPUS_OK)return ret;
+      if (i==st->lfe_stream)
+         opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
+      ptr += align(coupled_size);
+   }
+   for (;i<st->layout.nb_streams;i++)
+   {
+      ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
+      if (i==st->lfe_stream)
+         opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
+      if(ret!=OPUS_OK)return ret;
+      ptr += align(mono_size);
+   }
+   if (mapping_type == MAPPING_TYPE_SURROUND)
+   {
+      OPUS_CLEAR(ms_get_preemph_mem(st), channels);
+      OPUS_CLEAR(ms_get_window_mem(st), channels*120);
+   }
+   st->mapping_type = mapping_type;
+   return OPUS_OK;
+}
+
+int opus_multistream_encoder_init(
+      OpusMSEncoder *st,
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping,
+      int application
+)
+{
+   return opus_multistream_encoder_init_impl(st, Fs, channels, streams,
+                                             coupled_streams, mapping,
+                                             application, MAPPING_TYPE_NONE);
+}
+
+int opus_multistream_surround_encoder_init(
+      OpusMSEncoder *st,
+      opus_int32 Fs,
+      int channels,
+      int mapping_family,
+      int *streams,
+      int *coupled_streams,
+      unsigned char *mapping,
+      int application
+)
+{
+   MappingType mapping_type;
+
+   if ((channels>255) || (channels<1))
+      return OPUS_BAD_ARG;
+   st->lfe_stream = -1;
+   if (mapping_family==0)
+   {
+      if (channels==1)
+      {
+         *streams=1;
+         *coupled_streams=0;
+         mapping[0]=0;
+      } else if (channels==2)
+      {
+         *streams=1;
+         *coupled_streams=1;
+         mapping[0]=0;
+         mapping[1]=1;
+      } else
+         return OPUS_UNIMPLEMENTED;
+   } else if (mapping_family==1 && channels<=8 && channels>=1)
+   {
+      int i;
+      *streams=vorbis_mappings[channels-1].nb_streams;
+      *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
+      for (i=0;i<channels;i++)
+         mapping[i] = vorbis_mappings[channels-1].mapping[i];
+      if (channels>=6)
+         st->lfe_stream = *streams-1;
+   } else if (mapping_family==255)
+   {
+      int i;
+      *streams=channels;
+      *coupled_streams=0;
+      for(i=0;i<channels;i++)
+         mapping[i] = i;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+   } else if (mapping_family==254)
+   {
+      int i;
+      *streams=channels;
+      *coupled_streams=0;
+      for(i=0;i<channels;i++)
+         mapping[i] = i;
+#endif
+   } else
+      return OPUS_UNIMPLEMENTED;
+
+   if (channels>2 && mapping_family==1) {
+      mapping_type = MAPPING_TYPE_SURROUND;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+   } else if (mapping_family==254)
+   {
+      mapping_type = MAPPING_TYPE_AMBISONICS;
+#endif
+   } else
+   {
+      mapping_type = MAPPING_TYPE_NONE;
+   }
+   return opus_multistream_encoder_init_impl(st, Fs, channels, *streams,
+                                             *coupled_streams, mapping,
+                                             application, mapping_type);
+}
+
+OpusMSEncoder *opus_multistream_encoder_create(
+      opus_int32 Fs,
+      int channels,
+      int streams,
+      int coupled_streams,
+      const unsigned char *mapping,
+      int application,
+      int *error
+)
+{
+   int ret;
+   OpusMSEncoder *st;
+   if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+       (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+   st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams));
+   if (st==NULL)
+   {
+      if (error)
+         *error = OPUS_ALLOC_FAIL;
+      return NULL;
+   }
+   ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
+   if (ret != OPUS_OK)
+   {
+      opus_free(st);
+      st = NULL;
+   }
+   if (error)
+      *error = ret;
+   return st;
+}
+
+OpusMSEncoder *opus_multistream_surround_encoder_create(
+      opus_int32 Fs,
+      int channels,
+      int mapping_family,
+      int *streams,
+      int *coupled_streams,
+      unsigned char *mapping,
+      int application,
+      int *error
+)
+{
+   int ret;
+   opus_int32 size;
+   OpusMSEncoder *st;
+   if ((channels>255) || (channels<1))
+   {
+      if (error)
+         *error = OPUS_BAD_ARG;
+      return NULL;
+   }
+   size = opus_multistream_surround_encoder_get_size(channels, mapping_family);
+   if (!size)
+   {
+      if (error)
+         *error = OPUS_UNIMPLEMENTED;
+      return NULL;
+   }
+   st = (OpusMSEncoder *)opus_alloc(size);
+   if (st==NULL)
+   {
+      if (error)
+         *error = OPUS_ALLOC_FAIL;
+      return NULL;
+   }
+   ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application);
+   if (ret != OPUS_OK)
+   {
+      opus_free(st);
+      st = NULL;
+   }
+   if (error)
+      *error = ret;
+   return st;
+}
+
+static void surround_rate_allocation(
+      OpusMSEncoder *st,
+      opus_int32 *rate,
+      int frame_size,
+      opus_int32 Fs
+      )
+{
+   int i;
+   opus_int32 channel_rate;
+   int stream_offset;
+   int lfe_offset;
+   int coupled_ratio; /* Q8 */
+   int lfe_ratio;     /* Q8 */
+
+   if (st->bitrate_bps > st->layout.nb_channels*40000)
+      stream_offset = 20000;
+   else
+      stream_offset = st->bitrate_bps/st->layout.nb_channels/2;
+   stream_offset += 60*(Fs/frame_size-50);
+   /* We start by giving each stream (coupled or uncoupled) the same bitrate.
+      This models the main saving of coupled channels over uncoupled. */
+   /* The LFE stream is an exception to the above and gets fewer bits. */
+   lfe_offset = 3500 + 60*(Fs/frame_size-50);
+   /* Coupled streams get twice the mono rate after the first 20 kb/s. */
+   coupled_ratio = 512;
+   /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
+   lfe_ratio = 32;
+
+   /* Compute bitrate allocation between streams */
+   if (st->bitrate_bps==OPUS_AUTO)
+   {
+      channel_rate = Fs+60*Fs/frame_size;
+   } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
+   {
+      channel_rate = 300000;
+   } else {
+      int nb_lfe;
+      int nb_uncoupled;
+      int nb_coupled;
+      int total;
+      nb_lfe = (st->lfe_stream!=-1);
+      nb_coupled = st->layout.nb_coupled_streams;
+      nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe;
+      total = (nb_uncoupled<<8)         /* mono */
+            + coupled_ratio*nb_coupled /* stereo */
+            + nb_lfe*lfe_ratio;
+      channel_rate = 256*(st->bitrate_bps-lfe_offset*nb_lfe-stream_offset*(nb_coupled+nb_uncoupled))/total;
+   }
+#ifndef FIXED_POINT
+   if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
+   {
+      opus_int32 bonus;
+      bonus = 60*(Fs/frame_size-50);
+      channel_rate += bonus;
+   }
+#endif
+
+   for (i=0;i<st->layout.nb_streams;i++)
+   {
+      if (i<st->layout.nb_coupled_streams)
+         rate[i] = stream_offset+(channel_rate*coupled_ratio>>8);
+      else if (i!=st->lfe_stream)
+         rate[i] = stream_offset+channel_rate;
+      else
+         rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8);
+   }
+}
+
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+static void ambisonics_rate_allocation(
+      OpusMSEncoder *st,
+      opus_int32 *rate,
+      int frame_size,
+      opus_int32 Fs
+      )
+{
+   int i;
+   int non_mono_rate;
+   int total_rate;
+
+   /* The mono channel gets (rate_ratio_num / rate_ratio_den) times as many bits
+    * as all other channels */
+   const int rate_ratio_num = 4;
+   const int rate_ratio_den = 3;
+   const int num_channels = st->layout.nb_streams;
+
+   if (st->bitrate_bps==OPUS_AUTO)
+   {
+      total_rate = num_channels * (20000 + st->layout.nb_streams*(Fs+60*Fs/frame_size));
+   } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
+   {
+      total_rate = num_channels * 320000;
+   } else {
+      total_rate = st->bitrate_bps;
+   }
+
+   /* Let y be the non-mono rate and let p, q be integers such that the mono
+    * channel rate is (p/q) * y.
+    * Also let T be the total bitrate to allocate. Then
+    *   (n - 1) y + (p/q) y = T
+    *   y = (T q) / (qn - q + p)
+    */
+   non_mono_rate =
+         total_rate * rate_ratio_den
+         / (rate_ratio_den*num_channels + rate_ratio_num - rate_ratio_den);
+
+#ifndef FIXED_POINT
+   if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
+   {
+      opus_int32 bonus = 60*(Fs/frame_size-50);
+      non_mono_rate += bonus;
+   }
+#endif
+
+   rate[0] = total_rate - (num_channels - 1) * non_mono_rate;
+   for (i=1;i<st->layout.nb_streams;i++)
+   {
+      rate[i] = non_mono_rate;
+   }
+}
+#endif /* ENABLE_EXPERIMENTAL_AMBISONICS */
+
+static opus_int32 rate_allocation(
+      OpusMSEncoder *st,
+      opus_int32 *rate,
+      int frame_size
+      )
+{
+   int i;
+   opus_int32 rate_sum=0;
+   opus_int32 Fs;
+   char *ptr;
+
+   ptr = (char*)st + align(sizeof(OpusMSEncoder));
+   opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+   if (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
+     ambisonics_rate_allocation(st, rate, frame_size, Fs);
+   } else
+#endif
+   {
+     surround_rate_allocation(st, rate, frame_size, Fs);
+   }
+
+   for (i=0;i<st->layout.nb_streams;i++)
+   {
+      rate[i] = IMAX(rate[i], 500);
+      rate_sum += rate[i];
+   }
+   return rate_sum;
+}
+
+/* Max size in case the encoder decides to return three frames */
+#define MS_FRAME_TMP (3*1275+7)
+static int opus_multistream_encode_native
+(
+    OpusMSEncoder *st,
+    opus_copy_channel_in_func copy_channel_in,
+    const void *pcm,
+    int analysis_frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes,
+    int lsb_depth,
+    downmix_func downmix,
+    int float_api
+)
+{
+   opus_int32 Fs;
+   int coupled_size;
+   int mono_size;
+   int s;
+   char *ptr;
+   int tot_size;
+   VARDECL(opus_val16, buf);
+   VARDECL(opus_val16, bandSMR);
+   unsigned char tmp_data[MS_FRAME_TMP];
+   OpusRepacketizer rp;
+   opus_int32 vbr;
+   const CELTMode *celt_mode;
+   opus_int32 bitrates[256];
+   opus_val16 bandLogE[42];
+   opus_val32 *mem = NULL;
+   opus_val32 *preemph_mem=NULL;
+   int frame_size;
+   opus_int32 rate_sum;
+   opus_int32 smallest_packet;
+   ALLOC_STACK;
+
+   if (st->mapping_type == MAPPING_TYPE_SURROUND)
+   {
+      preemph_mem = ms_get_preemph_mem(st);
+      mem = ms_get_window_mem(st);
+   }
+
+   ptr = (char*)st + align(sizeof(OpusMSEncoder));
+   opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+   opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr));
+   opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
+
+   {
+      opus_int32 delay_compensation;
+      int channels;
+
+      channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
+      opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
+      delay_compensation -= Fs/400;
+      frame_size = compute_frame_size(pcm, analysis_frame_size,
+            st->variable_duration, channels, Fs, st->bitrate_bps,
+            delay_compensation, downmix
+#ifndef DISABLE_FLOAT_API
+            , st->subframe_mem
+#endif
+            );
+   }
+
+   if (400*frame_size < Fs)
+   {
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   }
+   /* Validate frame_size before using it to allocate stack space.
+      This mirrors the checks in opus_encode[_float](). */
+   if (400*frame_size != Fs && 200*frame_size != Fs &&
+       100*frame_size != Fs &&  50*frame_size != Fs &&
+        25*frame_size != Fs &&  50*frame_size != 3*Fs)
+   {
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   }
+
+   /* Smallest packet the encoder can produce. */
+   smallest_packet = st->layout.nb_streams*2-1;
+   if (max_data_bytes < smallest_packet)
+   {
+      RESTORE_STACK;
+      return OPUS_BUFFER_TOO_SMALL;
+   }
+   ALLOC(buf, 2*frame_size, opus_val16);
+   coupled_size = opus_encoder_get_size(2);
+   mono_size = opus_encoder_get_size(1);
+
+   ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16);
+   if (st->mapping_type == MAPPING_TYPE_SURROUND)
+   {
+      surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in, st->arch);
+   }
+
+   /* Compute bitrate allocation between streams (this could be a lot better) */
+   rate_sum = rate_allocation(st, bitrates, frame_size);
+
+   if (!vbr)
+   {
+      if (st->bitrate_bps == OPUS_AUTO)
+      {
+         max_data_bytes = IMIN(max_data_bytes, 3*rate_sum/(3*8*Fs/frame_size));
+      } else if (st->bitrate_bps != OPUS_BITRATE_MAX)
+      {
+         max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet,
+                          3*st->bitrate_bps/(3*8*Fs/frame_size)));
+      }
+   }
+   ptr = (char*)st + align(sizeof(OpusMSEncoder));
+   for (s=0;s<st->layout.nb_streams;s++)
+   {
+      OpusEncoder *enc;
+      enc = (OpusEncoder*)ptr;
+      if (s < st->layout.nb_coupled_streams)
+         ptr += align(coupled_size);
+      else
+         ptr += align(mono_size);
+      opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s]));
+      if (st->mapping_type == MAPPING_TYPE_SURROUND)
+      {
+         opus_int32 equiv_rate;
+         equiv_rate = st->bitrate_bps;
+         if (frame_size*50 < Fs)
+            equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels;
+         if (equiv_rate > 10000*st->layout.nb_channels)
+            opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
+         else if (equiv_rate > 7000*st->layout.nb_channels)
+            opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
+         else if (equiv_rate > 5000*st->layout.nb_channels)
+            opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
+         else
+            opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
+         if (s < st->layout.nb_coupled_streams)
+         {
+            /* To preserve the spatial image, force stereo CELT on coupled streams */
+            opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+            opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2));
+         }
+      }
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+      else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
+        opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+      }
+#endif
+   }
+
+   ptr = (char*)st + align(sizeof(OpusMSEncoder));
+   /* Counting ToC */
+   tot_size = 0;
+   for (s=0;s<st->layout.nb_streams;s++)
+   {
+      OpusEncoder *enc;
+      int len;
+      int curr_max;
+      int c1, c2;
+      int ret;
+
+      opus_repacketizer_init(&rp);
+      enc = (OpusEncoder*)ptr;
+      if (s < st->layout.nb_coupled_streams)
+      {
+         int i;
+         int left, right;
+         left = get_left_channel(&st->layout, s, -1);
+         right = get_right_channel(&st->layout, s, -1);
+         (*copy_channel_in)(buf, 2,
+            pcm, st->layout.nb_channels, left, frame_size);
+         (*copy_channel_in)(buf+1, 2,
+            pcm, st->layout.nb_channels, right, frame_size);
+         ptr += align(coupled_size);
+         if (st->mapping_type == MAPPING_TYPE_SURROUND)
+         {
+            for (i=0;i<21;i++)
+            {
+               bandLogE[i] = bandSMR[21*left+i];
+               bandLogE[21+i] = bandSMR[21*right+i];
+            }
+         }
+         c1 = left;
+         c2 = right;
+      } else {
+         int i;
+         int chan = get_mono_channel(&st->layout, s, -1);
+         (*copy_channel_in)(buf, 1,
+            pcm, st->layout.nb_channels, chan, frame_size);
+         ptr += align(mono_size);
+         if (st->mapping_type == MAPPING_TYPE_SURROUND)
+         {
+            for (i=0;i<21;i++)
+               bandLogE[i] = bandSMR[21*chan+i];
+         }
+         c1 = chan;
+         c2 = -1;
+      }
+      if (st->mapping_type == MAPPING_TYPE_SURROUND)
+         opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
+      /* number of bytes left (+Toc) */
+      curr_max = max_data_bytes - tot_size;
+      /* Reserve one byte for the last stream and two for the others */
+      curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1);
+      curr_max = IMIN(curr_max,MS_FRAME_TMP);
+      /* Repacketizer will add one or two bytes for self-delimited frames */
+      if (s != st->layout.nb_streams-1) curr_max -=  curr_max>253 ? 2 : 1;
+      if (!vbr && s == st->layout.nb_streams-1)
+         opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size)));
+      len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth,
+            pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix, float_api);
+      if (len<0)
+      {
+         RESTORE_STACK;
+         return len;
+      }
+      /* We need to use the repacketizer to add the self-delimiting lengths
+         while taking into account the fact that the encoder can now return
+         more than one frame at a time (e.g. 60 ms CELT-only) */
+      ret = opus_repacketizer_cat(&rp, tmp_data, len);
+      /* If the opus_repacketizer_cat() fails, then something's seriously wrong
+         with the encoder. */
+      if (ret != OPUS_OK)
+      {
+         RESTORE_STACK;
+         return OPUS_INTERNAL_ERROR;
+      }
+      len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp),
+            data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1);
+      data += len;
+      tot_size += len;
+   }
+   /*printf("\n");*/
+   RESTORE_STACK;
+   return tot_size;
+}
+
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_in_float(
+  opus_val16 *dst,
+  int dst_stride,
+  const void *src,
+  int src_stride,
+  int src_channel,
+  int frame_size
+)
+{
+   const float *float_src;
+   opus_int32 i;
+   float_src = (const float *)src;
+   for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+      dst[i*dst_stride] = FLOAT2INT16(float_src[i*src_stride+src_channel]);
+#else
+      dst[i*dst_stride] = float_src[i*src_stride+src_channel];
+#endif
+}
+#endif
+
+static void opus_copy_channel_in_short(
+  opus_val16 *dst,
+  int dst_stride,
+  const void *src,
+  int src_stride,
+  int src_channel,
+  int frame_size
+)
+{
+   const opus_int16 *short_src;
+   opus_int32 i;
+   short_src = (const opus_int16 *)src;
+   for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+      dst[i*dst_stride] = short_src[i*src_stride+src_channel];
+#else
+      dst[i*dst_stride] = (1/32768.f)*short_src[i*src_stride+src_channel];
+#endif
+}
+
+
+#ifdef FIXED_POINT
+int opus_multistream_encode(
+    OpusMSEncoder *st,
+    const opus_val16 *pcm,
+    int frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes
+)
+{
+   return opus_multistream_encode_native(st, opus_copy_channel_in_short,
+      pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_multistream_encode_float(
+    OpusMSEncoder *st,
+    const float *pcm,
+    int frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes
+)
+{
+   return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+      pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1);
+}
+#endif
+
+#else
+
+int opus_multistream_encode_float
+(
+    OpusMSEncoder *st,
+    const opus_val16 *pcm,
+    int frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes
+)
+{
+   return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+      pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1);
+}
+
+int opus_multistream_encode(
+    OpusMSEncoder *st,
+    const opus_int16 *pcm,
+    int frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes
+)
+{
+   return opus_multistream_encode_native(st, opus_copy_channel_in_short,
+      pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0);
+}
+#endif
+
+int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
+{
+   va_list ap;
+   int coupled_size, mono_size;
+   char *ptr;
+   int ret = OPUS_OK;
+
+   va_start(ap, request);
+
+   coupled_size = opus_encoder_get_size(2);
+   mono_size = opus_encoder_get_size(1);
+   ptr = (char*)st + align(sizeof(OpusMSEncoder));
+   switch (request)
+   {
+   case OPUS_SET_BITRATE_REQUEST:
+   {
+      opus_int32 value = va_arg(ap, opus_int32);
+      if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX)
+      {
+         goto bad_arg;
+      }
+      st->bitrate_bps = value;
+   }
+   break;
+   case OPUS_GET_BITRATE_REQUEST:
+   {
+      int s;
+      opus_int32 *value = va_arg(ap, opus_int32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      *value = 0;
+      for (s=0;s<st->layout.nb_streams;s++)
+      {
+         opus_int32 rate;
+         OpusEncoder *enc;
+         enc = (OpusEncoder*)ptr;
+         if (s < st->layout.nb_coupled_streams)
+            ptr += align(coupled_size);
+         else
+            ptr += align(mono_size);
+         opus_encoder_ctl(enc, request, &rate);
+         *value += rate;
+      }
+   }
+   break;
+   case OPUS_GET_LSB_DEPTH_REQUEST:
+   case OPUS_GET_VBR_REQUEST:
+   case OPUS_GET_APPLICATION_REQUEST:
+   case OPUS_GET_BANDWIDTH_REQUEST:
+   case OPUS_GET_COMPLEXITY_REQUEST:
+   case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
+   case OPUS_GET_DTX_REQUEST:
+   case OPUS_GET_VOICE_RATIO_REQUEST:
+   case OPUS_GET_VBR_CONSTRAINT_REQUEST:
+   case OPUS_GET_SIGNAL_REQUEST:
+   case OPUS_GET_LOOKAHEAD_REQUEST:
+   case OPUS_GET_SAMPLE_RATE_REQUEST:
+   case OPUS_GET_INBAND_FEC_REQUEST:
+   case OPUS_GET_FORCE_CHANNELS_REQUEST:
+   case OPUS_GET_PREDICTION_DISABLED_REQUEST:
+   {
+      OpusEncoder *enc;
+      /* For int32* GET params, just query the first stream */
+      opus_int32 *value = va_arg(ap, opus_int32*);
+      enc = (OpusEncoder*)ptr;
+      ret = opus_encoder_ctl(enc, request, value);
+   }
+   break;
+   case OPUS_GET_FINAL_RANGE_REQUEST:
+   {
+      int s;
+      opus_uint32 *value = va_arg(ap, opus_uint32*);
+      opus_uint32 tmp;
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      *value=0;
+      for (s=0;s<st->layout.nb_streams;s++)
+      {
+         OpusEncoder *enc;
+         enc = (OpusEncoder*)ptr;
+         if (s < st->layout.nb_coupled_streams)
+            ptr += align(coupled_size);
+         else
+            ptr += align(mono_size);
+         ret = opus_encoder_ctl(enc, request, &tmp);
+         if (ret != OPUS_OK) break;
+         *value ^= tmp;
+      }
+   }
+   break;
+   case OPUS_SET_LSB_DEPTH_REQUEST:
+   case OPUS_SET_COMPLEXITY_REQUEST:
+   case OPUS_SET_VBR_REQUEST:
+   case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+   case OPUS_SET_MAX_BANDWIDTH_REQUEST:
+   case OPUS_SET_BANDWIDTH_REQUEST:
+   case OPUS_SET_SIGNAL_REQUEST:
+   case OPUS_SET_APPLICATION_REQUEST:
+   case OPUS_SET_INBAND_FEC_REQUEST:
+   case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+   case OPUS_SET_DTX_REQUEST:
+   case OPUS_SET_FORCE_MODE_REQUEST:
+   case OPUS_SET_FORCE_CHANNELS_REQUEST:
+   case OPUS_SET_PREDICTION_DISABLED_REQUEST:
+   {
+      int s;
+      /* This works for int32 params */
+      opus_int32 value = va_arg(ap, opus_int32);
+      for (s=0;s<st->layout.nb_streams;s++)
+      {
+         OpusEncoder *enc;
+
+         enc = (OpusEncoder*)ptr;
+         if (s < st->layout.nb_coupled_streams)
+            ptr += align(coupled_size);
+         else
+            ptr += align(mono_size);
+         ret = opus_encoder_ctl(enc, request, value);
+         if (ret != OPUS_OK)
+            break;
+      }
+   }
+   break;
+   case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
+   {
+      int s;
+      opus_int32 stream_id;
+      OpusEncoder **value;
+      stream_id = va_arg(ap, opus_int32);
+      if (stream_id<0 || stream_id >= st->layout.nb_streams)
+         ret = OPUS_BAD_ARG;
+      value = va_arg(ap, OpusEncoder**);
+      if (!value)
+      {
+         goto bad_arg;
+      }
+      for (s=0;s<stream_id;s++)
+      {
+         if (s < st->layout.nb_coupled_streams)
+            ptr += align(coupled_size);
+         else
+            ptr += align(mono_size);
+      }
+      *value = (OpusEncoder*)ptr;
+   }
+   break;
+   case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+   {
+       opus_int32 value = va_arg(ap, opus_int32);
+       st->variable_duration = value;
+   }
+   break;
+   case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
+   {
+       opus_int32 *value = va_arg(ap, opus_int32*);
+       if (!value)
+       {
+          goto bad_arg;
+       }
+       *value = st->variable_duration;
+   }
+   break;
+   case OPUS_RESET_STATE:
+   {
+      int s;
+      st->subframe_mem[0] = st->subframe_mem[1] = st->subframe_mem[2] = 0;
+      if (st->mapping_type == MAPPING_TYPE_SURROUND)
+      {
+         OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels);
+         OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120);
+      }
+      for (s=0;s<st->layout.nb_streams;s++)
+      {
+         OpusEncoder *enc;
+         enc = (OpusEncoder*)ptr;
+         if (s < st->layout.nb_coupled_streams)
+            ptr += align(coupled_size);
+         else
+            ptr += align(mono_size);
+         ret = opus_encoder_ctl(enc, OPUS_RESET_STATE);
+         if (ret != OPUS_OK)
+            break;
+      }
+   }
+   break;
+   default:
+      ret = OPUS_UNIMPLEMENTED;
+      break;
+   }
+
+   va_end(ap);
+   return ret;
+bad_arg:
+   va_end(ap);
+   return OPUS_BAD_ARG;
+}
+
+void opus_multistream_encoder_destroy(OpusMSEncoder *st)
+{
+    opus_free(st);
+}
diff --git a/third_party/opus/src/src/opus_private.h b/third_party/opus/src/src/opus_private.h
new file mode 100644
index 0000000..3b62eed0
--- /dev/null
+++ b/third_party/opus/src/src/opus_private.h
@@ -0,0 +1,134 @@
+/* Copyright (c) 2012 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef OPUS_PRIVATE_H
+#define OPUS_PRIVATE_H
+
+#include "arch.h"
+#include "opus.h"
+#include "celt.h"
+
+#include <stddef.h> /* offsetof */
+
+struct OpusRepacketizer {
+   unsigned char toc;
+   int nb_frames;
+   const unsigned char *frames[48];
+   opus_int16 len[48];
+   int framesize;
+};
+
+typedef struct ChannelLayout {
+   int nb_channels;
+   int nb_streams;
+   int nb_coupled_streams;
+   unsigned char mapping[256];
+} ChannelLayout;
+
+int validate_layout(const ChannelLayout *layout);
+int get_left_channel(const ChannelLayout *layout, int stream_id, int prev);
+int get_right_channel(const ChannelLayout *layout, int stream_id, int prev);
+int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev);
+
+
+
+#define MODE_SILK_ONLY          1000
+#define MODE_HYBRID             1001
+#define MODE_CELT_ONLY          1002
+
+#define OPUS_SET_VOICE_RATIO_REQUEST         11018
+#define OPUS_GET_VOICE_RATIO_REQUEST         11019
+
+/** Configures the encoder's expected percentage of voice
+  * opposed to music or other signals.
+  *
+  * @note This interface is currently more aspiration than actuality. It's
+  * ultimately expected to bias an automatic signal classifier, but it currently
+  * just shifts the static bitrate to mode mapping around a little bit.
+  *
+  * @param[in] x <tt>int</tt>:   Voice percentage in the range 0-100, inclusive.
+  * @hideinitializer */
+#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO
+  *
+  * @param[out] x <tt>int*</tt>:  Voice percentage in the range 0-100, inclusive.
+  * @hideinitializer */
+#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x)
+
+
+#define OPUS_SET_FORCE_MODE_REQUEST    11002
+#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x)
+
+typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int);
+void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C);
+void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C);
+
+int encode_size(int size, unsigned char *data);
+
+opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs);
+
+opus_int32 compute_frame_size(const void *analysis_pcm, int frame_size,
+      int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
+      int delay_compensation, downmix_func downmix
+#ifndef DISABLE_FLOAT_API
+      , float *subframe_mem
+#endif
+      );
+
+opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
+      unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+      const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2,
+      int analysis_channels, downmix_func downmix, int float_api);
+
+int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len,
+      opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited,
+      opus_int32 *packet_offset, int soft_clip);
+
+/* Make sure everything is properly aligned. */
+static OPUS_INLINE int align(int i)
+{
+    struct foo {char c; union { void* p; opus_int32 i; opus_val32 v; } u;};
+
+    unsigned int alignment = offsetof(struct foo, u);
+
+    /* Optimizing compilers should optimize div and multiply into and
+       for all sensible alignment values. */
+    return ((i + alignment - 1) / alignment) * alignment;
+}
+
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+      int self_delimited, unsigned char *out_toc,
+      const unsigned char *frames[48], opus_int16 size[48],
+      int *payload_offset, opus_int32 *packet_offset);
+
+opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
+      unsigned char *data, opus_int32 maxlen, int self_delimited, int pad);
+
+int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len);
+
+#endif /* OPUS_PRIVATE_H */
diff --git a/third_party/opus/src/src/repacketizer.c b/third_party/opus/src/src/repacketizer.c
new file mode 100644
index 0000000..c80ee7f00
--- /dev/null
+++ b/third_party/opus/src/src/repacketizer.c
@@ -0,0 +1,348 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus.h"
+#include "opus_private.h"
+#include "os_support.h"
+
+
+int opus_repacketizer_get_size(void)
+{
+   return sizeof(OpusRepacketizer);
+}
+
+OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp)
+{
+   rp->nb_frames = 0;
+   return rp;
+}
+
+OpusRepacketizer *opus_repacketizer_create(void)
+{
+   OpusRepacketizer *rp;
+   rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size());
+   if(rp==NULL)return NULL;
+   return opus_repacketizer_init(rp);
+}
+
+void opus_repacketizer_destroy(OpusRepacketizer *rp)
+{
+   opus_free(rp);
+}
+
+static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited)
+{
+   unsigned char tmp_toc;
+   int curr_nb_frames,ret;
+   /* Set of check ToC */
+   if (len<1) return OPUS_INVALID_PACKET;
+   if (rp->nb_frames == 0)
+   {
+      rp->toc = data[0];
+      rp->framesize = opus_packet_get_samples_per_frame(data, 8000);
+   } else if ((rp->toc&0xFC) != (data[0]&0xFC))
+   {
+      /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
+      return OPUS_INVALID_PACKET;
+   }
+   curr_nb_frames = opus_packet_get_nb_frames(data, len);
+   if(curr_nb_frames<1) return OPUS_INVALID_PACKET;
+
+   /* Check the 120 ms maximum packet size */
+   if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960)
+   {
+      return OPUS_INVALID_PACKET;
+   }
+
+   ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL);
+   if(ret<1)return ret;
+
+   rp->nb_frames += curr_nb_frames;
+   return OPUS_OK;
+}
+
+int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len)
+{
+   return opus_repacketizer_cat_impl(rp, data, len, 0);
+}
+
+int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
+{
+   return rp->nb_frames;
+}
+
+opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
+      unsigned char *data, opus_int32 maxlen, int self_delimited, int pad)
+{
+   int i, count;
+   opus_int32 tot_size;
+   opus_int16 *len;
+   const unsigned char **frames;
+   unsigned char * ptr;
+
+   if (begin<0 || begin>=end || end>rp->nb_frames)
+   {
+      /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/
+      return OPUS_BAD_ARG;
+   }
+   count = end-begin;
+
+   len = rp->len+begin;
+   frames = rp->frames+begin;
+   if (self_delimited)
+      tot_size = 1 + (len[count-1]>=252);
+   else
+      tot_size = 0;
+
+   ptr = data;
+   if (count==1)
+   {
+      /* Code 0 */
+      tot_size += len[0]+1;
+      if (tot_size > maxlen)
+         return OPUS_BUFFER_TOO_SMALL;
+      *ptr++ = rp->toc&0xFC;
+   } else if (count==2)
+   {
+      if (len[1] == len[0])
+      {
+         /* Code 1 */
+         tot_size += 2*len[0]+1;
+         if (tot_size > maxlen)
+            return OPUS_BUFFER_TOO_SMALL;
+         *ptr++ = (rp->toc&0xFC) | 0x1;
+      } else {
+         /* Code 2 */
+         tot_size += len[0]+len[1]+2+(len[0]>=252);
+         if (tot_size > maxlen)
+            return OPUS_BUFFER_TOO_SMALL;
+         *ptr++ = (rp->toc&0xFC) | 0x2;
+         ptr += encode_size(len[0], ptr);
+      }
+   }
+   if (count > 2 || (pad && tot_size < maxlen))
+   {
+      /* Code 3 */
+      int vbr;
+      int pad_amount=0;
+
+      /* Restart the process for the padding case */
+      ptr = data;
+      if (self_delimited)
+         tot_size = 1 + (len[count-1]>=252);
+      else
+         tot_size = 0;
+      vbr = 0;
+      for (i=1;i<count;i++)
+      {
+         if (len[i] != len[0])
+         {
+            vbr=1;
+            break;
+         }
+      }
+      if (vbr)
+      {
+         tot_size += 2;
+         for (i=0;i<count-1;i++)
+            tot_size += 1 + (len[i]>=252) + len[i];
+         tot_size += len[count-1];
+
+         if (tot_size > maxlen)
+            return OPUS_BUFFER_TOO_SMALL;
+         *ptr++ = (rp->toc&0xFC) | 0x3;
+         *ptr++ = count | 0x80;
+      } else {
+         tot_size += count*len[0]+2;
+         if (tot_size > maxlen)
+            return OPUS_BUFFER_TOO_SMALL;
+         *ptr++ = (rp->toc&0xFC) | 0x3;
+         *ptr++ = count;
+      }
+      pad_amount = pad ? (maxlen-tot_size) : 0;
+      if (pad_amount != 0)
+      {
+         int nb_255s;
+         data[1] |= 0x40;
+         nb_255s = (pad_amount-1)/255;
+         for (i=0;i<nb_255s;i++)
+            *ptr++ = 255;
+         *ptr++ = pad_amount-255*nb_255s-1;
+         tot_size += pad_amount;
+      }
+      if (vbr)
+      {
+         for (i=0;i<count-1;i++)
+            ptr += encode_size(len[i], ptr);
+      }
+   }
+   if (self_delimited) {
+      int sdlen = encode_size(len[count-1], ptr);
+      ptr += sdlen;
+   }
+   /* Copy the actual data */
+   for (i=0;i<count;i++)
+   {
+      /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
+         padding from opus_packet_pad or opus_packet_unpad(). */
+      celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]);
+      OPUS_MOVE(ptr, frames[i], len[i]);
+      ptr += len[i];
+   }
+   if (pad)
+   {
+      /* Fill padding with zeros. */
+      while (ptr<data+maxlen)
+         *ptr++=0;
+   }
+   return tot_size;
+}
+
+opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
+{
+   return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
+}
+
+opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
+{
+   return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0);
+}
+
+int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
+{
+   OpusRepacketizer rp;
+   opus_int32 ret;
+   if (len < 1)
+      return OPUS_BAD_ARG;
+   if (len==new_len)
+      return OPUS_OK;
+   else if (len > new_len)
+      return OPUS_BAD_ARG;
+   opus_repacketizer_init(&rp);
+   /* Moving payload to the end of the packet so we can do in-place padding */
+   OPUS_MOVE(data+new_len-len, data, len);
+   ret = opus_repacketizer_cat(&rp, data+new_len-len, len);
+   if (ret != OPUS_OK)
+      return ret;
+   ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
+   if (ret > 0)
+      return OPUS_OK;
+   else
+      return ret;
+}
+
+opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
+{
+   OpusRepacketizer rp;
+   opus_int32 ret;
+   if (len < 1)
+      return OPUS_BAD_ARG;
+   opus_repacketizer_init(&rp);
+   ret = opus_repacketizer_cat(&rp, data, len);
+   if (ret < 0)
+      return ret;
+   ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0);
+   celt_assert(ret > 0 && ret <= len);
+   return ret;
+}
+
+int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams)
+{
+   int s;
+   int count;
+   unsigned char toc;
+   opus_int16 size[48];
+   opus_int32 packet_offset;
+   opus_int32 amount;
+
+   if (len < 1)
+      return OPUS_BAD_ARG;
+   if (len==new_len)
+      return OPUS_OK;
+   else if (len > new_len)
+      return OPUS_BAD_ARG;
+   amount = new_len - len;
+   /* Seek to last stream */
+   for (s=0;s<nb_streams-1;s++)
+   {
+      if (len<=0)
+         return OPUS_INVALID_PACKET;
+      count = opus_packet_parse_impl(data, len, 1, &toc, NULL,
+                                     size, NULL, &packet_offset);
+      if (count<0)
+         return count;
+      data += packet_offset;
+      len -= packet_offset;
+   }
+   return opus_packet_pad(data, len, len+amount);
+}
+
+opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams)
+{
+   int s;
+   unsigned char toc;
+   opus_int16 size[48];
+   opus_int32 packet_offset;
+   OpusRepacketizer rp;
+   unsigned char *dst;
+   opus_int32 dst_len;
+
+   if (len < 1)
+      return OPUS_BAD_ARG;
+   dst = data;
+   dst_len = 0;
+   /* Unpad all frames */
+   for (s=0;s<nb_streams;s++)
+   {
+      opus_int32 ret;
+      int self_delimited = s!=nb_streams-1;
+      if (len<=0)
+         return OPUS_INVALID_PACKET;
+      opus_repacketizer_init(&rp);
+      ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
+                                     size, NULL, &packet_offset);
+      if (ret<0)
+         return ret;
+      ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
+      if (ret < 0)
+         return ret;
+      ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0);
+      if (ret < 0)
+         return ret;
+      else
+         dst_len += ret;
+      dst += ret;
+      data += packet_offset;
+      len -= packet_offset;
+   }
+   return dst_len;
+}
+
diff --git a/third_party/opus/src/src/repacketizer_demo.c b/third_party/opus/src/src/repacketizer_demo.c
new file mode 100644
index 0000000..dc05c1b
--- /dev/null
+++ b/third_party/opus/src/src/repacketizer_demo.c
@@ -0,0 +1,217 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Jean-Marc Valin */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_PACKETOUT 32000
+
+void usage(char *argv0)
+{
+   fprintf(stderr, "usage: %s [options] input_file output_file\n", argv0);
+}
+
+static void int_to_char(opus_uint32 i, unsigned char ch[4])
+{
+    ch[0] = i>>24;
+    ch[1] = (i>>16)&0xFF;
+    ch[2] = (i>>8)&0xFF;
+    ch[3] = i&0xFF;
+}
+
+static opus_uint32 char_to_int(unsigned char ch[4])
+{
+    return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16)
+         | ((opus_uint32)ch[2]<< 8) |  (opus_uint32)ch[3];
+}
+
+int main(int argc, char *argv[])
+{
+   int i, eof=0;
+   FILE *fin, *fout;
+   unsigned char packets[48][1500];
+   int len[48];
+   int rng[48];
+   OpusRepacketizer *rp;
+   unsigned char output_packet[MAX_PACKETOUT];
+   int merge = 1, split=0;
+
+   if (argc < 3)
+   {
+      usage(argv[0]);
+      return EXIT_FAILURE;
+   }
+   for (i=1;i<argc-2;i++)
+   {
+      if (strcmp(argv[i], "-merge")==0)
+      {
+         merge = atoi(argv[i+1]);
+         if(merge<1)
+         {
+            fprintf(stderr, "-merge parameter must be at least 1.\n");
+            return EXIT_FAILURE;
+         }
+         if(merge>48)
+         {
+            fprintf(stderr, "-merge parameter must be less than 48.\n");
+            return EXIT_FAILURE;
+         }
+         i++;
+      } else if (strcmp(argv[i], "-split")==0)
+         split = 1;
+      else
+      {
+         fprintf(stderr, "Unknown option: %s\n", argv[i]);
+         usage(argv[0]);
+         return EXIT_FAILURE;
+      }
+   }
+   fin = fopen(argv[argc-2], "r");
+   if(fin==NULL)
+   {
+     fprintf(stderr, "Error opening input file: %s\n", argv[argc-2]);
+     return EXIT_FAILURE;
+   }
+   fout = fopen(argv[argc-1], "w");
+   if(fout==NULL)
+   {
+     fprintf(stderr, "Error opening output file: %s\n", argv[argc-1]);
+     fclose(fin);
+     return EXIT_FAILURE;
+   }
+
+   rp = opus_repacketizer_create();
+   while (!eof)
+   {
+      int err;
+      int nb_packets=merge;
+      opus_repacketizer_init(rp);
+      for (i=0;i<nb_packets;i++)
+      {
+         unsigned char ch[4];
+         err = fread(ch, 1, 4, fin);
+         len[i] = char_to_int(ch);
+         /*fprintf(stderr, "in len = %d\n", len[i]);*/
+         if (len[i]>1500 || len[i]<0)
+         {
+             if (feof(fin))
+             {
+                eof = 1;
+             } else {
+                fprintf(stderr, "Invalid payload length\n");
+                fclose(fin);
+                fclose(fout);
+                return EXIT_FAILURE;
+             }
+             break;
+         }
+         err = fread(ch, 1, 4, fin);
+         rng[i] = char_to_int(ch);
+         err = fread(packets[i], 1, len[i], fin);
+         if (feof(fin))
+         {
+            eof = 1;
+            break;
+         }
+         err = opus_repacketizer_cat(rp, packets[i], len[i]);
+         if (err!=OPUS_OK)
+         {
+            fprintf(stderr, "opus_repacketizer_cat() failed: %s\n", opus_strerror(err));
+            break;
+         }
+      }
+      nb_packets = i;
+
+      if (eof)
+         break;
+
+      if (!split)
+      {
+         err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT);
+         if (err>0) {
+            unsigned char int_field[4];
+            int_to_char(err, int_field);
+            if(fwrite(int_field, 1, 4, fout)!=4){
+               fprintf(stderr, "Error writing.\n");
+               return EXIT_FAILURE;
+            }
+            int_to_char(rng[nb_packets-1], int_field);
+            if (fwrite(int_field, 1, 4, fout)!=4) {
+               fprintf(stderr, "Error writing.\n");
+               return EXIT_FAILURE;
+            }
+            if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) {
+               fprintf(stderr, "Error writing.\n");
+               return EXIT_FAILURE;
+            }
+            /*fprintf(stderr, "out len = %d\n", err);*/
+         } else {
+            fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err));
+         }
+      } else {
+         int nb_frames = opus_repacketizer_get_nb_frames(rp);
+         for (i=0;i<nb_frames;i++)
+         {
+            err = opus_repacketizer_out_range(rp, i, i+1, output_packet, MAX_PACKETOUT);
+            if (err>0) {
+               unsigned char int_field[4];
+               int_to_char(err, int_field);
+               if (fwrite(int_field, 1, 4, fout)!=4) {
+                  fprintf(stderr, "Error writing.\n");
+                  return EXIT_FAILURE;
+               }
+               if (i==nb_frames-1)
+                  int_to_char(rng[nb_packets-1], int_field);
+               else
+                  int_to_char(0, int_field);
+               if (fwrite(int_field, 1, 4, fout)!=4) {
+                  fprintf(stderr, "Error writing.\n");
+                  return EXIT_FAILURE;
+               }
+               if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) {
+                  fprintf(stderr, "Error writing.\n");
+                  return EXIT_FAILURE;
+               }
+               /*fprintf(stderr, "out len = %d\n", err);*/
+            } else {
+               fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err));
+            }
+
+         }
+      }
+   }
+
+   fclose(fin);
+   fclose(fout);
+   return EXIT_SUCCESS;
+}
diff --git a/third_party/opus/src/src/tansig_table.h b/third_party/opus/src/src/tansig_table.h
new file mode 100644
index 0000000..c76f844a
--- /dev/null
+++ b/third_party/opus/src/src/tansig_table.h
@@ -0,0 +1,45 @@
+/* This file is auto-generated by gen_tables */
+
+static const float tansig_table[201] = {
+0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f,
+0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f,
+0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f,
+0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f,
+0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f,
+0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
+0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f,
+0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f,
+0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f,
+0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f,
+0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f,
+0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
+0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f,
+0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f,
+0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f,
+0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f,
+0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f,
+0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
+0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f,
+0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f,
+0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f,
+0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f,
+0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f,
+0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
+0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f,
+0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
+0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f,
+0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f,
+0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f,
+0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
+0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f,
+0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f,
+0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f,
+0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f,
+0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f,
+0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
+0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+1.000000f,
+};
diff --git a/third_party/opus/src/tests/run_vectors.sh b/third_party/opus/src/tests/run_vectors.sh
new file mode 100755
index 0000000..1d447c43
--- /dev/null
+++ b/third_party/opus/src/tests/run_vectors.sh
@@ -0,0 +1,134 @@
+#!/bin/sh
+
+# Copyright (c) 2011-2012 Jean-Marc Valin
+#
+#  This file is extracted from RFC6716. Please see that RFC for additional
+#  information.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  - Redistributions of source code must retain the above copyright
+#  notice, this list of conditions and the following disclaimer.
+#
+#  - Redistributions in binary form must reproduce the above copyright
+#  notice, this list of conditions and the following disclaimer in the
+#  documentation and/or other materials provided with the distribution.
+#
+#  - Neither the name of Internet Society, IETF or IETF Trust, nor the
+#  names of specific contributors, may be used to endorse or promote
+#  products derived from this software without specific prior written
+#  permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+#  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+rm logs_mono.txt
+rm logs_stereo.txt
+
+if [ "$#" -ne "3" ]; then
+    echo "usage: run_vectors.sh <exec path> <vector path> <rate>"
+    exit 1
+fi
+
+CMD_PATH=$1
+VECTOR_PATH=$2
+RATE=$3
+
+: ${OPUS_DEMO:=$CMD_PATH/opus_demo}
+: ${OPUS_COMPARE:=$CMD_PATH/opus_compare}
+
+if [ -d $VECTOR_PATH ]; then
+    echo Test vectors found in $VECTOR_PATH
+else
+    echo No test vectors found
+    #Don't make the test fail here because the test vectors
+    #will be distributed separately
+    exit 0
+fi
+
+if [ ! -x $OPUS_COMPARE ]; then
+    echo ERROR: Compare program not found: $OPUS_COMPARE
+    exit 1
+fi
+
+if [ -x $OPUS_DEMO ]; then
+    echo Decoding with $OPUS_DEMO
+else
+    echo ERROR: Decoder not found: $OPUS_DEMO
+    exit 1
+fi
+
+echo "=============="
+echo Testing mono
+echo "=============="
+echo
+
+for file in 01 02 03 04 05 06 07 08 09 10 11 12
+do
+    if [ -e $VECTOR_PATH/testvector$file.bit ]; then
+        echo Testing testvector$file
+    else
+        echo Bitstream file not found: testvector$file.bit
+    fi
+    if $OPUS_DEMO -d $RATE 1 $VECTOR_PATH/testvector$file.bit tmp.out >> logs_mono.txt 2>&1; then
+        echo successfully decoded
+    else
+        echo ERROR: decoding failed
+        exit 1
+    fi
+    $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_mono.txt 2>&1
+    float_ret=$?
+    if [ "$float_ret" -eq "0" ]; then
+        echo output matches reference
+    else
+        echo ERROR: output does not match reference
+        exit 1
+    fi
+    echo
+done
+
+echo "=============="
+echo Testing stereo
+echo "=============="
+echo
+
+for file in 01 02 03 04 05 06 07 08 09 10 11 12
+do
+    if [ -e $VECTOR_PATH/testvector$file.bit ]; then
+        echo Testing testvector$file
+    else
+        echo Bitstream file not found: testvector$file
+    fi
+    if $OPUS_DEMO -d $RATE 2 $VECTOR_PATH/testvector$file.bit tmp.out >> logs_stereo.txt 2>&1; then
+        echo successfully decoded
+    else
+        echo ERROR: decoding failed
+        exit 1
+    fi
+    $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_stereo.txt 2>&1
+    float_ret=$?
+    if [ "$float_ret" -eq "0" ]; then
+        echo output matches reference
+    else
+        echo ERROR: output does not match reference
+        exit 1
+    fi
+    echo
+done
+
+
+
+echo All tests have passed successfully
+grep quality logs_mono.txt | awk '{sum+=$4}END{print "Average mono quality is", sum/NR, "%"}'
+grep quality logs_stereo.txt | awk '{sum+=$4}END{print "Average stereo quality is", sum/NR, "%"}'
diff --git a/third_party/opus/src/tests/test_opus_api.c b/third_party/opus/src/tests/test_opus_api.c
new file mode 100644
index 0000000..489052d
--- /dev/null
+++ b/third_party/opus/src/tests/test_opus_api.c
@@ -0,0 +1,1897 @@
+/* Copyright (c) 2011-2013 Xiph.Org Foundation
+   Written by Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This tests the API presented by the libopus system.
+   It does not attempt to extensively exercise the codec internals.
+   The strategy here is to simply the API interface invariants:
+   That sane options are accepted, insane options are rejected,
+   and that nothing blows up. In particular we don't actually test
+   that settings are heeded by the codec (though we do check that
+   get after set returns a sane value when it should). Other
+   tests check the actual codec behavior.
+   In cases where its reasonable to do so we test exhaustively,
+   but its not reasonable to do so in all cases.
+   Although these tests are simple they found several library bugs
+   when they were initially developed. */
+
+/* These tests are more sensitive if compiled with -DVALGRIND and
+   run inside valgrind. Malloc failure testing requires glibc. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "arch.h"
+#include "opus_multistream.h"
+#include "opus.h"
+#include "test_opus_common.h"
+
+#ifdef VALGRIND
+#include <valgrind/memcheck.h>
+#define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
+#define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
+#else
+#define VG_UNDEF(x,y)
+#define VG_CHECK(x,y)
+#endif
+
+#if defined(HAVE___MALLOC_HOOK)
+#define MALLOC_FAIL
+#include "os_support.h"
+#include <malloc.h>
+
+static const opus_int32 opus_apps[3] = {OPUS_APPLICATION_VOIP,
+       OPUS_APPLICATION_AUDIO,OPUS_APPLICATION_RESTRICTED_LOWDELAY};
+
+void *malloc_hook(__attribute__((unused)) size_t size,
+                  __attribute__((unused)) const void *caller)
+{
+   return 0;
+}
+#endif
+
+static const opus_int32 opus_rates[5] = {48000,24000,16000,12000,8000};
+
+opus_int32 test_dec_api(void)
+{
+   opus_uint32 dec_final_range;
+   OpusDecoder *dec;
+   OpusDecoder *dec2;
+   opus_int32 i,j,cfgs;
+   unsigned char packet[1276];
+#ifndef DISABLE_FLOAT_API
+   float fbuf[960*2];
+#endif
+   short sbuf[960*2];
+   int c,err;
+   opus_int32 *nullvalue;
+   nullvalue=0;
+
+   cfgs=0;
+   /*First test invalid configurations which should fail*/
+   fprintf(stdout,"\n  Decoder basic API tests\n");
+   fprintf(stdout,"  ---------------------------------------------------\n");
+   for(c=0;c<4;c++)
+   {
+      i=opus_decoder_get_size(c);
+      if(((c==1||c==2)&&(i<=2048||i>1<<16))||((c!=1&&c!=2)&&i!=0))test_failed();
+      fprintf(stdout,"    opus_decoder_get_size(%d)=%d ...............%s OK.\n",c,i,i>0?"":"....");
+      cfgs++;
+   }
+
+   /*Test with unsupported sample rates*/
+   for(c=0;c<4;c++)
+   {
+      for(i=-7;i<=96000;i++)
+      {
+         int fs;
+         if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue;
+         switch(i)
+         {
+           case(-5):fs=-8000;break;
+           case(-6):fs=INT32_MAX;break;
+           case(-7):fs=INT32_MIN;break;
+           default:fs=i;
+         }
+         err = OPUS_OK;
+         VG_UNDEF(&err,sizeof(err));
+         dec = opus_decoder_create(fs, c, &err);
+         if(err!=OPUS_BAD_ARG || dec!=NULL)test_failed();
+         cfgs++;
+         dec = opus_decoder_create(fs, c, 0);
+         if(dec!=NULL)test_failed();
+         cfgs++;
+         dec=malloc(opus_decoder_get_size(2));
+         if(dec==NULL)test_failed();
+         err = opus_decoder_init(dec,fs,c);
+         if(err!=OPUS_BAD_ARG)test_failed();
+         cfgs++;
+         free(dec);
+      }
+   }
+
+   VG_UNDEF(&err,sizeof(err));
+   dec = opus_decoder_create(48000, 2, &err);
+   if(err!=OPUS_OK || dec==NULL)test_failed();
+   VG_CHECK(dec,opus_decoder_get_size(2));
+   cfgs++;
+
+   fprintf(stdout,"    opus_decoder_create() ........................ OK.\n");
+   fprintf(stdout,"    opus_decoder_init() .......................... OK.\n");
+
+   err=opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE((opus_uint32 *)NULL));
+   if(err != OPUS_BAD_ARG)test_failed();
+   VG_UNDEF(&dec_final_range,sizeof(dec_final_range));
+   err=opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
+   if(err!=OPUS_OK)test_failed();
+   VG_CHECK(&dec_final_range,sizeof(dec_final_range));
+   fprintf(stdout,"    OPUS_GET_FINAL_RANGE ......................... OK.\n");
+   cfgs++;
+
+   err=opus_decoder_ctl(dec,OPUS_UNIMPLEMENTED);
+   if(err!=OPUS_UNIMPLEMENTED)test_failed();
+   fprintf(stdout,"    OPUS_UNIMPLEMENTED ........................... OK.\n");
+   cfgs++;
+
+   err=opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH((opus_int32 *)NULL));
+   if(err != OPUS_BAD_ARG)test_failed();
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&i));
+   if(err != OPUS_OK || i!=0)test_failed();
+   fprintf(stdout,"    OPUS_GET_BANDWIDTH ........................... OK.\n");
+   cfgs++;
+
+   err=opus_decoder_ctl(dec, OPUS_GET_SAMPLE_RATE((opus_int32 *)NULL));
+   if(err != OPUS_BAD_ARG)test_failed();
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_decoder_ctl(dec, OPUS_GET_SAMPLE_RATE(&i));
+   if(err != OPUS_OK || i!=48000)test_failed();
+   fprintf(stdout,"    OPUS_GET_SAMPLE_RATE ......................... OK.\n");
+   cfgs++;
+
+   /*GET_PITCH has different execution paths depending on the previously decoded frame.*/
+   err=opus_decoder_ctl(dec, OPUS_GET_PITCH(nullvalue));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i));
+   if(err != OPUS_OK || i>0 || i<-1)test_failed();
+   cfgs++;
+   VG_UNDEF(packet,sizeof(packet));
+   packet[0]=63<<2;packet[1]=packet[2]=0;
+   if(opus_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed();
+   cfgs++;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i));
+   if(err != OPUS_OK || i>0 || i<-1)test_failed();
+   cfgs++;
+   packet[0]=1;
+   if(opus_decode(dec, packet, 1, sbuf, 960, 0)!=960)test_failed();
+   cfgs++;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i));
+   if(err != OPUS_OK || i>0 || i<-1)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_GET_PITCH ............................... OK.\n");
+
+   err=opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION((opus_int32 *)NULL));
+   if(err != OPUS_BAD_ARG)test_failed();
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&i));
+   if(err != OPUS_OK || i!=960)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_GET_LAST_PACKET_DURATION ................ OK.\n");
+
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i));
+   VG_CHECK(&i,sizeof(i));
+   if(err != OPUS_OK || i!=0)test_failed();
+   cfgs++;
+   err=opus_decoder_ctl(dec, OPUS_GET_GAIN(nullvalue));
+   if(err != OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-32769));
+   if(err != OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   err=opus_decoder_ctl(dec, OPUS_SET_GAIN(32768));
+   if(err != OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-15));
+   if(err != OPUS_OK)test_failed();
+   cfgs++;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i));
+   VG_CHECK(&i,sizeof(i));
+   if(err != OPUS_OK || i!=-15)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_SET_GAIN ................................ OK.\n");
+   fprintf(stdout,"    OPUS_GET_GAIN ................................ OK.\n");
+
+   /*Reset the decoder*/
+   dec2=malloc(opus_decoder_get_size(2));
+   memcpy(dec2,dec,opus_decoder_get_size(2));
+   if(opus_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+   if(memcmp(dec2,dec,opus_decoder_get_size(2))==0)test_failed();
+   free(dec2);
+   fprintf(stdout,"    OPUS_RESET_STATE ............................. OK.\n");
+   cfgs++;
+
+   VG_UNDEF(packet,sizeof(packet));
+   packet[0]=0;
+   if(opus_decoder_get_nb_samples(dec,packet,1)!=480)test_failed();
+   if(opus_packet_get_nb_samples(packet,1,48000)!=480)test_failed();
+   if(opus_packet_get_nb_samples(packet,1,96000)!=960)test_failed();
+   if(opus_packet_get_nb_samples(packet,1,32000)!=320)test_failed();
+   if(opus_packet_get_nb_samples(packet,1,8000)!=80)test_failed();
+   packet[0]=3;
+   if(opus_packet_get_nb_samples(packet,1,24000)!=OPUS_INVALID_PACKET)test_failed();
+   packet[0]=(63<<2)|3;
+   packet[1]=63;
+   if(opus_packet_get_nb_samples(packet,0,24000)!=OPUS_BAD_ARG)test_failed();
+   if(opus_packet_get_nb_samples(packet,2,48000)!=OPUS_INVALID_PACKET)test_failed();
+   if(opus_decoder_get_nb_samples(dec,packet,2)!=OPUS_INVALID_PACKET)test_failed();
+   fprintf(stdout,"    opus_{packet,decoder}_get_nb_samples() ....... OK.\n");
+   cfgs+=9;
+
+   if(OPUS_BAD_ARG!=opus_packet_get_nb_frames(packet,0))test_failed();
+   for(i=0;i<256;i++) {
+     int l1res[4]={1,2,2,OPUS_INVALID_PACKET};
+     packet[0]=i;
+     if(l1res[packet[0]&3]!=opus_packet_get_nb_frames(packet,1))test_failed();
+     cfgs++;
+     for(j=0;j<256;j++) {
+       packet[1]=j;
+       if(((packet[0]&3)!=3?l1res[packet[0]&3]:packet[1]&63)!=opus_packet_get_nb_frames(packet,2))test_failed();
+       cfgs++;
+     }
+   }
+   fprintf(stdout,"    opus_packet_get_nb_frames() .................. OK.\n");
+
+   for(i=0;i<256;i++) {
+     int bw;
+     packet[0]=i;
+     bw=packet[0]>>4;
+     bw=OPUS_BANDWIDTH_NARROWBAND+(((((bw&7)*9)&(63-(bw&8)))+2+12*((bw&8)!=0))>>4);
+     if(bw!=opus_packet_get_bandwidth(packet))test_failed();
+     cfgs++;
+   }
+   fprintf(stdout,"    opus_packet_get_bandwidth() .................. OK.\n");
+
+   for(i=0;i<256;i++) {
+     int fp3s,rate;
+     packet[0]=i;
+     fp3s=packet[0]>>3;
+     fp3s=((((3-(fp3s&3))*13&119)+9)>>2)*((fp3s>13)*(3-((fp3s&3)==3))+1)*25;
+     for(rate=0;rate<5;rate++) {
+       if((opus_rates[rate]*3/fp3s)!=opus_packet_get_samples_per_frame(packet,opus_rates[rate]))test_failed();
+       cfgs++;
+     }
+   }
+   fprintf(stdout,"    opus_packet_get_samples_per_frame() .......... OK.\n");
+
+   packet[0]=(63<<2)+3;
+   packet[1]=49;
+   for(j=2;j<51;j++)packet[j]=0;
+   VG_UNDEF(sbuf,sizeof(sbuf));
+   if(opus_decode(dec, packet, 51, sbuf, 960, 0)!=OPUS_INVALID_PACKET)test_failed();
+   cfgs++;
+   packet[0]=(63<<2);
+   packet[1]=packet[2]=0;
+   if(opus_decode(dec, packet, -1, sbuf, 960, 0)!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   if(opus_decode(dec, packet, 3, sbuf, 60, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+   cfgs++;
+   if(opus_decode(dec, packet, 3, sbuf, 480, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+   cfgs++;
+   if(opus_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed();
+   cfgs++;
+   fprintf(stdout,"    opus_decode() ................................ OK.\n");
+#ifndef DISABLE_FLOAT_API
+   VG_UNDEF(fbuf,sizeof(fbuf));
+   if(opus_decode_float(dec, packet, 3, fbuf, 960, 0)!=960)test_failed();
+   cfgs++;
+   fprintf(stdout,"    opus_decode_float() .......................... OK.\n");
+#endif
+
+#if 0
+   /*These tests are disabled because the library crashes with null states*/
+   if(opus_decoder_ctl(0,OPUS_RESET_STATE)         !=OPUS_INVALID_STATE)test_failed();
+   if(opus_decoder_init(0,48000,1)                 !=OPUS_INVALID_STATE)test_failed();
+   if(opus_decode(0,packet,1,outbuf,2880,0)        !=OPUS_INVALID_STATE)test_failed();
+   if(opus_decode_float(0,packet,1,0,2880,0)       !=OPUS_INVALID_STATE)test_failed();
+   if(opus_decoder_get_nb_samples(0,packet,1)      !=OPUS_INVALID_STATE)test_failed();
+   if(opus_packet_get_nb_frames(NULL,1)            !=OPUS_BAD_ARG)test_failed();
+   if(opus_packet_get_bandwidth(NULL)              !=OPUS_BAD_ARG)test_failed();
+   if(opus_packet_get_samples_per_frame(NULL,48000)!=OPUS_BAD_ARG)test_failed();
+#endif
+   opus_decoder_destroy(dec);
+   cfgs++;
+   fprintf(stdout,"                   All decoder interface tests passed\n");
+   fprintf(stdout,"                             (%6d API invocations)\n",cfgs);
+   return cfgs;
+}
+
+opus_int32 test_msdec_api(void)
+{
+   opus_uint32 dec_final_range;
+   OpusMSDecoder *dec;
+   OpusDecoder *streamdec;
+   opus_int32 i,j,cfgs;
+   unsigned char packet[1276];
+   unsigned char mapping[256];
+#ifndef DISABLE_FLOAT_API
+   float fbuf[960*2];
+#endif
+   short sbuf[960*2];
+   int a,b,c,err;
+#if 0
+   /*Relevant test not enabled for multistream*/
+   int *nullvalue;
+   nullvalue=0;
+#endif
+
+   mapping[0]=0;
+   mapping[1]=1;
+   for(i=2;i<256;i++)VG_UNDEF(&mapping[i],sizeof(unsigned char));
+
+   cfgs=0;
+   /*First test invalid configurations which should fail*/
+   fprintf(stdout,"\n  Multistream decoder basic API tests\n");
+   fprintf(stdout,"  ---------------------------------------------------\n");
+   for(a=-1;a<4;a++)
+   {
+      for(b=-1;b<4;b++)
+      {
+         i=opus_multistream_decoder_get_size(a,b);
+         if(((a>0&&b<=a&&b>=0)&&(i<=2048||i>((1<<16)*a)))||((a<1||b>a||b<0)&&i!=0))test_failed();
+         fprintf(stdout,"    opus_multistream_decoder_get_size(%2d,%2d)=%d %sOK.\n",a,b,i,i>0?"":"... ");
+         cfgs++;
+      }
+   }
+
+   /*Test with unsupported sample rates*/
+   for(c=1;c<3;c++)
+   {
+      for(i=-7;i<=96000;i++)
+      {
+         int fs;
+         if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue;
+         switch(i)
+         {
+           case(-5):fs=-8000;break;
+           case(-6):fs=INT32_MAX;break;
+           case(-7):fs=INT32_MIN;break;
+           default:fs=i;
+         }
+         err = OPUS_OK;
+         VG_UNDEF(&err,sizeof(err));
+         dec = opus_multistream_decoder_create(fs, c, 1, c-1, mapping, &err);
+         if(err!=OPUS_BAD_ARG || dec!=NULL)test_failed();
+         cfgs++;
+         dec = opus_multistream_decoder_create(fs, c, 1, c-1, mapping, 0);
+         if(dec!=NULL)test_failed();
+         cfgs++;
+         dec=malloc(opus_multistream_decoder_get_size(1,1));
+         if(dec==NULL)test_failed();
+         err = opus_multistream_decoder_init(dec,fs,c,1,c-1, mapping);
+         if(err!=OPUS_BAD_ARG)test_failed();
+         cfgs++;
+         free(dec);
+      }
+   }
+
+   for(c=0;c<2;c++)
+   {
+      int *ret_err;
+      ret_err = c?0:&err;
+
+      mapping[0]=0;
+      mapping[1]=1;
+      for(i=2;i<256;i++)VG_UNDEF(&mapping[i],sizeof(unsigned char));
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 2, 1, 0, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      mapping[0]=mapping[1]=0;
+      dec = opus_multistream_decoder_create(48000, 2, 1, 0, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed();
+      cfgs++;
+      opus_multistream_decoder_destroy(dec);
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 1, 4, 1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed();
+      cfgs++;
+
+      err = opus_multistream_decoder_init(dec,48000, 1, 0, 0, mapping);
+      if(err!=OPUS_BAD_ARG)test_failed();
+      cfgs++;
+
+      err = opus_multistream_decoder_init(dec,48000, 1, 1, -1, mapping);
+      if(err!=OPUS_BAD_ARG)test_failed();
+      cfgs++;
+
+      opus_multistream_decoder_destroy(dec);
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed();
+      cfgs++;
+      opus_multistream_decoder_destroy(dec);
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 255, 255, 1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, -1, 1, 1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 0, 1, 1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 1, -1, 2, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 1, -1, -1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 256, 255, 1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      dec = opus_multistream_decoder_create(48000, 256, 255, 0, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      mapping[0]=255;
+      mapping[1]=1;
+      mapping[2]=2;
+      dec = opus_multistream_decoder_create(48000, 3, 2, 0, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      mapping[0]=0;
+      mapping[1]=0;
+      mapping[2]=0;
+      dec = opus_multistream_decoder_create(48000, 3, 2, 1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed();
+      cfgs++;
+      opus_multistream_decoder_destroy(dec);
+      cfgs++;
+
+      VG_UNDEF(ret_err,sizeof(*ret_err));
+      mapping[0]=0;
+      mapping[1]=255;
+      mapping[2]=1;
+      mapping[3]=2;
+      mapping[4]=3;
+      dec = opus_multistream_decoder_create(48001, 5, 4, 1, mapping, ret_err);
+      if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));}
+      if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed();
+      cfgs++;
+   }
+
+   VG_UNDEF(&err,sizeof(err));
+   mapping[0]=0;
+   mapping[1]=255;
+   mapping[2]=1;
+   mapping[3]=2;
+   dec = opus_multistream_decoder_create(48000, 4, 2, 1, mapping, &err);
+   VG_CHECK(&err,sizeof(err));
+   if(err!=OPUS_OK || dec==NULL)test_failed();
+   cfgs++;
+
+   fprintf(stdout,"    opus_multistream_decoder_create() ............ OK.\n");
+   fprintf(stdout,"    opus_multistream_decoder_init() .............. OK.\n");
+
+   VG_UNDEF(&dec_final_range,sizeof(dec_final_range));
+   err=opus_multistream_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
+   if(err!=OPUS_OK)test_failed();
+   VG_CHECK(&dec_final_range,sizeof(dec_final_range));
+   fprintf(stdout,"    OPUS_GET_FINAL_RANGE ......................... OK.\n");
+   cfgs++;
+
+   streamdec=0;
+   VG_UNDEF(&streamdec,sizeof(streamdec));
+   err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(-1,&streamdec));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(1,&streamdec));
+   if(err!=OPUS_OK||streamdec==NULL)test_failed();
+   VG_CHECK(streamdec,opus_decoder_get_size(1));
+   cfgs++;
+   err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(2,&streamdec));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(0,&streamdec));
+   if(err!=OPUS_OK||streamdec==NULL)test_failed();
+   VG_CHECK(streamdec,opus_decoder_get_size(1));
+   fprintf(stdout,"    OPUS_MULTISTREAM_GET_DECODER_STATE ........... OK.\n");
+   cfgs++;
+
+   for(j=0;j<2;j++)
+   {
+      OpusDecoder *od;
+      err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od));
+      if(err != OPUS_OK)test_failed();
+      VG_UNDEF(&i,sizeof(i));
+      err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i));
+      VG_CHECK(&i,sizeof(i));
+      if(err != OPUS_OK || i!=0)test_failed();
+      cfgs++;
+   }
+   err=opus_multistream_decoder_ctl(dec,OPUS_SET_GAIN(15));
+   if(err!=OPUS_OK)test_failed();
+   fprintf(stdout,"    OPUS_SET_GAIN ................................ OK.\n");
+   for(j=0;j<2;j++)
+   {
+      OpusDecoder *od;
+      err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od));
+      if(err != OPUS_OK)test_failed();
+      VG_UNDEF(&i,sizeof(i));
+      err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i));
+      VG_CHECK(&i,sizeof(i));
+      if(err != OPUS_OK || i!=15)test_failed();
+      cfgs++;
+   }
+   fprintf(stdout,"    OPUS_GET_GAIN ................................ OK.\n");
+
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_multistream_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&i));
+   if(err != OPUS_OK || i!=0)test_failed();
+   fprintf(stdout,"    OPUS_GET_BANDWIDTH ........................... OK.\n");
+   cfgs++;
+
+   err=opus_multistream_decoder_ctl(dec,OPUS_UNIMPLEMENTED);
+   if(err!=OPUS_UNIMPLEMENTED)test_failed();
+   fprintf(stdout,"    OPUS_UNIMPLEMENTED ........................... OK.\n");
+   cfgs++;
+
+#if 0
+   /*Currently unimplemented for multistream*/
+   /*GET_PITCH has different execution paths depending on the previously decoded frame.*/
+   err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(nullvalue));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i));
+   if(err != OPUS_OK || i>0 || i<-1)test_failed();
+   cfgs++;
+   VG_UNDEF(packet,sizeof(packet));
+   packet[0]=63<<2;packet[1]=packet[2]=0;
+   if(opus_multistream_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed();
+   cfgs++;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i));
+   if(err != OPUS_OK || i>0 || i<-1)test_failed();
+   cfgs++;
+   packet[0]=1;
+   if(opus_multistream_decode(dec, packet, 1, sbuf, 960, 0)!=960)test_failed();
+   cfgs++;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i));
+   if(err != OPUS_OK || i>0 || i<-1)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_GET_PITCH ............................... OK.\n");
+#endif
+
+   /*Reset the decoder*/
+   if(opus_multistream_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+   fprintf(stdout,"    OPUS_RESET_STATE ............................. OK.\n");
+   cfgs++;
+
+   opus_multistream_decoder_destroy(dec);
+   cfgs++;
+   VG_UNDEF(&err,sizeof(err));
+   dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, &err);
+   if(err!=OPUS_OK || dec==NULL)test_failed();
+   cfgs++;
+
+   packet[0]=(63<<2)+3;
+   packet[1]=49;
+   for(j=2;j<51;j++)packet[j]=0;
+   VG_UNDEF(sbuf,sizeof(sbuf));
+   if(opus_multistream_decode(dec, packet, 51, sbuf, 960, 0)!=OPUS_INVALID_PACKET)test_failed();
+   cfgs++;
+   packet[0]=(63<<2);
+   packet[1]=packet[2]=0;
+   if(opus_multistream_decode(dec, packet, -1, sbuf, 960, 0)!=OPUS_BAD_ARG){printf("%d\n",opus_multistream_decode(dec, packet, -1, sbuf, 960, 0));test_failed();}
+   cfgs++;
+   if(opus_multistream_decode(dec, packet, 3, sbuf, 60, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+   cfgs++;
+   if(opus_multistream_decode(dec, packet, 3, sbuf, 480, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+   cfgs++;
+   if(opus_multistream_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed();
+   cfgs++;
+   fprintf(stdout,"    opus_multistream_decode() .................... OK.\n");
+#ifndef DISABLE_FLOAT_API
+   VG_UNDEF(fbuf,sizeof(fbuf));
+   if(opus_multistream_decode_float(dec, packet, 3, fbuf, 960, 0)!=960)test_failed();
+   cfgs++;
+   fprintf(stdout,"    opus_multistream_decode_float() .............. OK.\n");
+#endif
+
+#if 0
+   /*These tests are disabled because the library crashes with null states*/
+   if(opus_multistream_decoder_ctl(0,OPUS_RESET_STATE)         !=OPUS_INVALID_STATE)test_failed();
+   if(opus_multistream_decoder_init(0,48000,1)                 !=OPUS_INVALID_STATE)test_failed();
+   if(opus_multistream_decode(0,packet,1,outbuf,2880,0)        !=OPUS_INVALID_STATE)test_failed();
+   if(opus_multistream_decode_float(0,packet,1,0,2880,0)       !=OPUS_INVALID_STATE)test_failed();
+   if(opus_multistream_decoder_get_nb_samples(0,packet,1)      !=OPUS_INVALID_STATE)test_failed();
+#endif
+   opus_multistream_decoder_destroy(dec);
+   cfgs++;
+   fprintf(stdout,"       All multistream decoder interface tests passed\n");
+   fprintf(stdout,"                             (%6d API invocations)\n",cfgs);
+   return cfgs;
+}
+
+#ifdef VALGRIND
+#define UNDEFINE_FOR_PARSE  toc=-1; \
+   frames[0]=(unsigned char *)0; \
+   frames[1]=(unsigned char *)0; \
+   payload_offset=-1; \
+   VG_UNDEF(&toc,sizeof(toc)); \
+   VG_UNDEF(frames,sizeof(frames));\
+   VG_UNDEF(&payload_offset,sizeof(payload_offset));
+#else
+#define UNDEFINE_FOR_PARSE  toc=-1; \
+   frames[0]=(unsigned char *)0; \
+   frames[1]=(unsigned char *)0; \
+   payload_offset=-1;
+#endif
+
+/* This test exercises the heck out of the libopus parser.
+   It is much larger than the parser itself in part because
+   it tries to hit a lot of corner cases that could never
+   fail with the libopus code, but might be problematic for
+   other implementations. */
+opus_int32 test_parse(void)
+{
+   opus_int32 i,j,jj,sz;
+   unsigned char packet[1276];
+   opus_int32 cfgs,cfgs_total;
+   unsigned char toc;
+   const unsigned char *frames[48];
+   short size[48];
+   int payload_offset, ret;
+   fprintf(stdout,"\n  Packet header parsing tests\n");
+   fprintf(stdout,"  ---------------------------------------------------\n");
+   memset(packet,0,sizeof(char)*1276);
+   packet[0]=63<<2;
+   if(opus_packet_parse(packet,1,&toc,frames,0,&payload_offset)!=OPUS_BAD_ARG)test_failed();
+   cfgs_total=cfgs=1;
+   /*code 0*/
+   for(i=0;i<64;i++)
+   {
+      packet[0]=i<<2;
+      UNDEFINE_FOR_PARSE
+      ret=opus_packet_parse(packet,4,&toc,frames,size,&payload_offset);
+      cfgs++;
+      if(ret!=1)test_failed();
+      if(size[0]!=3)test_failed();
+      if(frames[0]!=packet+1)test_failed();
+   }
+   fprintf(stdout,"    code 0 (%2d cases) ............................ OK.\n",cfgs);
+   cfgs_total+=cfgs;cfgs=0;
+
+   /*code 1, two frames of the same size*/
+   for(i=0;i<64;i++)
+   {
+      packet[0]=(i<<2)+1;
+      for(jj=0;jj<=1275*2+3;jj++)
+      {
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,jj,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if((jj&1)==1 && jj<=2551)
+         {
+            /* Must pass if payload length even (packet length odd) and
+               size<=2551, must fail otherwise. */
+            if(ret!=2)test_failed();
+            if(size[0]!=size[1] || size[0]!=((jj-1)>>1))test_failed();
+            if(frames[0]!=packet+1)test_failed();
+            if(frames[1]!=frames[0]+size[0])test_failed();
+            if((toc>>2)!=i)test_failed();
+         } else if(ret!=OPUS_INVALID_PACKET)test_failed();
+      }
+   }
+   fprintf(stdout,"    code 1 (%6d cases) ........................ OK.\n",cfgs);
+   cfgs_total+=cfgs;cfgs=0;
+
+   for(i=0;i<64;i++)
+   {
+      /*code 2, length code overflow*/
+      packet[0]=(i<<2)+2;
+      UNDEFINE_FOR_PARSE
+      ret=opus_packet_parse(packet,1,&toc,frames,size,&payload_offset);
+      cfgs++;
+      if(ret!=OPUS_INVALID_PACKET)test_failed();
+      packet[1]=252;
+      UNDEFINE_FOR_PARSE
+      ret=opus_packet_parse(packet,2,&toc,frames,size,&payload_offset);
+      cfgs++;
+      if(ret!=OPUS_INVALID_PACKET)test_failed();
+      for(j=0;j<1275;j++)
+      {
+         if(j<252)packet[1]=j;
+         else{packet[1]=252+(j&3);packet[2]=(j-252)>>2;}
+         /*Code 2, one too short*/
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,j+(j<252?2:3)-1,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=OPUS_INVALID_PACKET)test_failed();
+         /*Code 2, one too long*/
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,j+(j<252?2:3)+1276,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=OPUS_INVALID_PACKET)test_failed();
+         /*Code 2, second zero*/
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,j+(j<252?2:3),&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=2)test_failed();
+         if(size[0]!=j||size[1]!=0)test_failed();
+         if(frames[1]!=frames[0]+size[0])test_failed();
+         if((toc>>2)!=i)test_failed();
+         /*Code 2, normal*/
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,(j<<1)+4,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=2)test_failed();
+         if(size[0]!=j||size[1]!=(j<<1)+3-j-(j<252?1:2))test_failed();
+         if(frames[1]!=frames[0]+size[0])test_failed();
+         if((toc>>2)!=i)test_failed();
+      }
+   }
+   fprintf(stdout,"    code 2 (%6d cases) ........................ OK.\n",cfgs);
+   cfgs_total+=cfgs;cfgs=0;
+
+   for(i=0;i<64;i++)
+   {
+      packet[0]=(i<<2)+3;
+      /*code 3, length code overflow*/
+      UNDEFINE_FOR_PARSE
+      ret=opus_packet_parse(packet,1,&toc,frames,size,&payload_offset);
+      cfgs++;
+      if(ret!=OPUS_INVALID_PACKET)test_failed();
+   }
+   fprintf(stdout,"    code 3 m-truncation (%2d cases) ............... OK.\n",cfgs);
+   cfgs_total+=cfgs;cfgs=0;
+
+   for(i=0;i<64;i++)
+   {
+      /*code 3, m is zero or 49-63*/
+      packet[0]=(i<<2)+3;
+      for(jj=49;jj<=64;jj++)
+      {
+        packet[1]=0+(jj&63); /*CBR, no padding*/
+        UNDEFINE_FOR_PARSE
+        ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset);
+        cfgs++;
+        if(ret!=OPUS_INVALID_PACKET)test_failed();
+        packet[1]=128+(jj&63); /*VBR, no padding*/
+        UNDEFINE_FOR_PARSE
+        ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset);
+        cfgs++;
+        if(ret!=OPUS_INVALID_PACKET)test_failed();
+        packet[1]=64+(jj&63); /*CBR, padding*/
+        UNDEFINE_FOR_PARSE
+        ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset);
+        cfgs++;
+        if(ret!=OPUS_INVALID_PACKET)test_failed();
+        packet[1]=128+64+(jj&63); /*VBR, padding*/
+        UNDEFINE_FOR_PARSE
+        ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset);
+        cfgs++;
+        if(ret!=OPUS_INVALID_PACKET)test_failed();
+      }
+   }
+   fprintf(stdout,"    code 3 m=0,49-64 (%2d cases) ................ OK.\n",cfgs);
+   cfgs_total+=cfgs;cfgs=0;
+
+   for(i=0;i<64;i++)
+   {
+      packet[0]=(i<<2)+3;
+      /*code 3, m is one, cbr*/
+      packet[1]=1;
+      for(j=0;j<1276;j++)
+      {
+        UNDEFINE_FOR_PARSE
+        ret=opus_packet_parse(packet,j+2,&toc,frames,size,&payload_offset);
+        cfgs++;
+        if(ret!=1)test_failed();
+        if(size[0]!=j)test_failed();
+        if((toc>>2)!=i)test_failed();
+      }
+      UNDEFINE_FOR_PARSE
+      ret=opus_packet_parse(packet,1276+2,&toc,frames,size,&payload_offset);
+      cfgs++;
+      if(ret!=OPUS_INVALID_PACKET)test_failed();
+   }
+   fprintf(stdout,"    code 3 m=1 CBR (%2d cases) ................. OK.\n",cfgs);
+   cfgs_total+=cfgs;cfgs=0;
+
+   for(i=0;i<64;i++)
+   {
+      int frame_samp;
+      /*code 3, m>1 CBR*/
+      packet[0]=(i<<2)+3;
+      frame_samp=opus_packet_get_samples_per_frame(packet,48000);
+      for(j=2;j<49;j++)
+      {
+         packet[1]=j;
+         for(sz=2;sz<((j+2)*1275);sz++)
+         {
+            UNDEFINE_FOR_PARSE
+            ret=opus_packet_parse(packet,sz,&toc,frames,size,&payload_offset);
+            cfgs++;
+            /*Must be <=120ms, must be evenly divisible, can't have frames>1275 bytes*/
+            if(frame_samp*j<=5760 && (sz-2)%j==0 && (sz-2)/j<1276)
+            {
+               if(ret!=j)test_failed();
+               for(jj=1;jj<ret;jj++)if(frames[jj]!=frames[jj-1]+size[jj-1])test_failed();
+               if((toc>>2)!=i)test_failed();
+            } else if(ret!=OPUS_INVALID_PACKET)test_failed();
+         }
+      }
+      /*Super jumbo packets*/
+      packet[1]=5760/frame_samp;
+      UNDEFINE_FOR_PARSE
+      ret=opus_packet_parse(packet,1275*packet[1]+2,&toc,frames,size,&payload_offset);
+      cfgs++;
+      if(ret!=packet[1])test_failed();
+      for(jj=0;jj<ret;jj++)if(size[jj]!=1275)test_failed();
+   }
+   fprintf(stdout,"    code 3 m=1-48 CBR (%2d cases) .......... OK.\n",cfgs);
+   cfgs_total+=cfgs;cfgs=0;
+
+   for(i=0;i<64;i++)
+   {
+      int frame_samp;
+      /*Code 3 VBR, m one*/
+      packet[0]=(i<<2)+3;
+      packet[1]=128+1;
+      frame_samp=opus_packet_get_samples_per_frame(packet,48000);
+      for(jj=0;jj<1276;jj++)
+      {
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,2+jj,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=1)test_failed();
+         if(size[0]!=jj)test_failed();
+         if((toc>>2)!=i)test_failed();
+      }
+      UNDEFINE_FOR_PARSE
+      ret=opus_packet_parse(packet,2+1276,&toc,frames,size,&payload_offset);
+      cfgs++;
+      if(ret!=OPUS_INVALID_PACKET)test_failed();
+      for(j=2;j<49;j++)
+      {
+         packet[1]=128+j;
+         /*Length code overflow*/
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,2+j-2,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=OPUS_INVALID_PACKET)test_failed();
+         packet[2]=252;
+         packet[3]=0;
+         for(jj=4;jj<2+j;jj++)packet[jj]=0;
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,2+j,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=OPUS_INVALID_PACKET)test_failed();
+         /*One byte too short*/
+         for(jj=2;jj<2+j;jj++)packet[jj]=0;
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,2+j-2,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=OPUS_INVALID_PACKET)test_failed();
+         /*One byte too short thanks to length coding*/
+         packet[2]=252;
+         packet[3]=0;
+         for(jj=4;jj<2+j;jj++)packet[jj]=0;
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,2+j+252-1,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(ret!=OPUS_INVALID_PACKET)test_failed();
+         /*Most expensive way of coding zeros*/
+         for(jj=2;jj<2+j;jj++)packet[jj]=0;
+         UNDEFINE_FOR_PARSE
+         ret=opus_packet_parse(packet,2+j-1,&toc,frames,size,&payload_offset);
+         cfgs++;
+         if(frame_samp*j<=5760){
+            if(ret!=j)test_failed();
+            for(jj=0;jj<j;jj++)if(size[jj]!=0)test_failed();
+            if((toc>>2)!=i)test_failed();
+         } else if(ret!=OPUS_INVALID_PACKET)test_failed();
+         /*Quasi-CBR use of mode 3*/
+         for(sz=0;sz<8;sz++)
+         {
+            const int tsz[8]={50,201,403,700,1472,5110,20400,61298};
+            int pos=0;
+            int as=(tsz[sz]+i-j-2)/j;
+            for(jj=0;jj<j-1;jj++)
+            {
+              if(as<252){packet[2+pos]=as;pos++;}
+              else{packet[2+pos]=252+(as&3);packet[3+pos]=(as-252)>>2;pos+=2;}
+            }
+            UNDEFINE_FOR_PARSE
+            ret=opus_packet_parse(packet,tsz[sz]+i,&toc,frames,size,&payload_offset);
+            cfgs++;
+            if(frame_samp*j<=5760 && as<1276 && (tsz[sz]+i-2-pos-as*(j-1))<1276){
+               if(ret!=j)test_failed();
+               for(jj=0;jj<j-1;jj++)if(size[jj]!=as)test_failed();
+               if(size[j-1]!=(tsz[sz]+i-2-pos-as*(j-1)))test_failed();
+               if((toc>>2)!=i)test_failed();
+            } else if(ret!=OPUS_INVALID_PACKET)test_failed();
+         }
+      }
+   }
+   fprintf(stdout,"    code 3 m=1-48 VBR (%2d cases) ............. OK.\n",cfgs);
+   cfgs_total+=cfgs;cfgs=0;
+
+   for(i=0;i<64;i++)
+   {
+      packet[0]=(i<<2)+3;
+      /*Padding*/
+      packet[1]=128+1+64;
+      /*Overflow the length coding*/
+      for(jj=2;jj<127;jj++)packet[jj]=255;
+      UNDEFINE_FOR_PARSE
+      ret=opus_packet_parse(packet,127,&toc,frames,size,&payload_offset);
+      cfgs++;
+      if(ret!=OPUS_INVALID_PACKET)test_failed();
+
+      for(sz=0;sz<4;sz++)
+      {
+         const int tsz[4]={0,72,512,1275};
+         for(jj=sz;jj<65025;jj+=11)
+         {
+            int pos;
+            for(pos=0;pos<jj/254;pos++)packet[2+pos]=255;
+            packet[2+pos]=jj%254;
+            pos++;
+            if(sz==0&&i==63)
+            {
+               /*Code more padding than there is room in the packet*/
+               UNDEFINE_FOR_PARSE
+               ret=opus_packet_parse(packet,2+jj+pos-1,&toc,frames,size,&payload_offset);
+               cfgs++;
+               if(ret!=OPUS_INVALID_PACKET)test_failed();
+            }
+            UNDEFINE_FOR_PARSE
+            ret=opus_packet_parse(packet,2+jj+tsz[sz]+i+pos,&toc,frames,size,&payload_offset);
+            cfgs++;
+            if(tsz[sz]+i<1276)
+            {
+               if(ret!=1)test_failed();
+               if(size[0]!=tsz[sz]+i)test_failed();
+               if((toc>>2)!=i)test_failed();
+            } else if (ret!=OPUS_INVALID_PACKET)test_failed();
+         }
+      }
+   }
+   fprintf(stdout,"    code 3 padding (%2d cases) ............... OK.\n",cfgs);
+   cfgs_total+=cfgs;
+   fprintf(stdout,"    opus_packet_parse ............................ OK.\n");
+   fprintf(stdout,"                      All packet parsing tests passed\n");
+   fprintf(stdout,"                          (%d API invocations)\n",cfgs_total);
+   return cfgs_total;
+}
+
+/* This is a helper macro for the encoder tests.
+   The encoder api tests all have a pattern of set-must-fail, set-must-fail,
+   set-must-pass, get-and-compare, set-must-pass, get-and-compare. */
+#define CHECK_SETGET(setcall,getcall,badv,badv2,goodv,goodv2,sok,gok) \
+   i=(badv);\
+   if(opus_encoder_ctl(enc,setcall)==OPUS_OK)test_failed();\
+   i=(badv2);\
+   if(opus_encoder_ctl(enc,setcall)==OPUS_OK)test_failed();\
+   j=i=(goodv);\
+   if(opus_encoder_ctl(enc,setcall)!=OPUS_OK)test_failed();\
+   i=-12345;\
+   VG_UNDEF(&i,sizeof(i)); \
+   err=opus_encoder_ctl(enc,getcall);\
+   if(err!=OPUS_OK || i!=j)test_failed();\
+   j=i=(goodv2);\
+   if(opus_encoder_ctl(enc,setcall)!=OPUS_OK)test_failed();\
+   fprintf(stdout,sok);\
+   i=-12345;\
+   VG_UNDEF(&i,sizeof(i)); \
+   err=opus_encoder_ctl(enc,getcall);\
+   if(err!=OPUS_OK || i!=j)test_failed();\
+   fprintf(stdout,gok);\
+   cfgs+=6;
+
+opus_int32 test_enc_api(void)
+{
+   opus_uint32 enc_final_range;
+   OpusEncoder *enc;
+   opus_int32 i,j;
+   unsigned char packet[1276];
+#ifndef DISABLE_FLOAT_API
+   float fbuf[960*2];
+#endif
+   short sbuf[960*2];
+   int c,err,cfgs;
+
+   cfgs=0;
+   /*First test invalid configurations which should fail*/
+   fprintf(stdout,"\n  Encoder basic API tests\n");
+   fprintf(stdout,"  ---------------------------------------------------\n");
+   for(c=0;c<4;c++)
+   {
+      i=opus_encoder_get_size(c);
+      if(((c==1||c==2)&&(i<=2048||i>1<<17))||((c!=1&&c!=2)&&i!=0))test_failed();
+      fprintf(stdout,"    opus_encoder_get_size(%d)=%d ...............%s OK.\n",c,i,i>0?"":"....");
+      cfgs++;
+   }
+
+   /*Test with unsupported sample rates, channel counts*/
+   for(c=0;c<4;c++)
+   {
+      for(i=-7;i<=96000;i++)
+      {
+         int fs;
+         if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue;
+         switch(i)
+         {
+           case(-5):fs=-8000;break;
+           case(-6):fs=INT32_MAX;break;
+           case(-7):fs=INT32_MIN;break;
+           default:fs=i;
+         }
+         err = OPUS_OK;
+         VG_UNDEF(&err,sizeof(err));
+         enc = opus_encoder_create(fs, c, OPUS_APPLICATION_VOIP, &err);
+         if(err!=OPUS_BAD_ARG || enc!=NULL)test_failed();
+         cfgs++;
+         enc = opus_encoder_create(fs, c, OPUS_APPLICATION_VOIP, 0);
+         if(enc!=NULL)test_failed();
+         cfgs++;
+         opus_encoder_destroy(enc);
+         enc=malloc(opus_encoder_get_size(2));
+         if(enc==NULL)test_failed();
+         err = opus_encoder_init(enc, fs, c, OPUS_APPLICATION_VOIP);
+         if(err!=OPUS_BAD_ARG)test_failed();
+         cfgs++;
+         free(enc);
+      }
+   }
+
+   enc = opus_encoder_create(48000, 2, OPUS_AUTO, NULL);
+   if(enc!=NULL)test_failed();
+   cfgs++;
+
+   VG_UNDEF(&err,sizeof(err));
+   enc = opus_encoder_create(48000, 2, OPUS_AUTO, &err);
+   if(err!=OPUS_BAD_ARG || enc!=NULL)test_failed();
+   cfgs++;
+
+   VG_UNDEF(&err,sizeof(err));
+   enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, NULL);
+   if(enc==NULL)test_failed();
+   opus_encoder_destroy(enc);
+   cfgs++;
+
+   VG_UNDEF(&err,sizeof(err));
+   enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err);
+   if(err!=OPUS_OK || enc==NULL)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i));
+   if(err!=OPUS_OK || i<0 || i>32766)test_failed();
+   cfgs++;
+   opus_encoder_destroy(enc);
+
+   VG_UNDEF(&err,sizeof(err));
+   enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &err);
+   if(err!=OPUS_OK || enc==NULL)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i));
+   if(err!=OPUS_OK || i<0 || i>32766)test_failed();
+   opus_encoder_destroy(enc);
+   cfgs++;
+
+   VG_UNDEF(&err,sizeof(err));
+   enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &err);
+   if(err!=OPUS_OK || enc==NULL)test_failed();
+   cfgs++;
+
+   fprintf(stdout,"    opus_encoder_create() ........................ OK.\n");
+   fprintf(stdout,"    opus_encoder_init() .......................... OK.\n");
+
+   i=-12345;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i));
+   if(err!=OPUS_OK || i<0 || i>32766)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_GET_LOOKAHEAD ........................... OK.\n");
+
+   err=opus_encoder_ctl(enc,OPUS_GET_SAMPLE_RATE(&i));
+   if(err!=OPUS_OK || i!=48000)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_GET_SAMPLE_RATE((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_GET_SAMPLE_RATE ......................... OK.\n");
+
+   if(opus_encoder_ctl(enc,OPUS_UNIMPLEMENTED)!=OPUS_UNIMPLEMENTED)test_failed();
+   fprintf(stdout,"    OPUS_UNIMPLEMENTED ........................... OK.\n");
+   cfgs++;
+
+   err=opus_encoder_ctl(enc,OPUS_GET_APPLICATION((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_APPLICATION(i),OPUS_GET_APPLICATION(&i),-1,OPUS_AUTO,
+     OPUS_APPLICATION_AUDIO,OPUS_APPLICATION_RESTRICTED_LOWDELAY,
+     "    OPUS_SET_APPLICATION ......................... OK.\n",
+     "    OPUS_GET_APPLICATION ......................... OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_BITRATE((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   if(opus_encoder_ctl(enc,OPUS_SET_BITRATE(1073741832))!=OPUS_OK)test_failed();
+   cfgs++;
+   VG_UNDEF(&i,sizeof(i));
+   if(opus_encoder_ctl(enc,OPUS_GET_BITRATE(&i))!=OPUS_OK)test_failed();
+   if(i>700000||i<256000)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_BITRATE(i),OPUS_GET_BITRATE(&i),-12345,0,
+     500,256000,
+     "    OPUS_SET_BITRATE ............................. OK.\n",
+     "    OPUS_GET_BITRATE ............................. OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_FORCE_CHANNELS((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_FORCE_CHANNELS(i),OPUS_GET_FORCE_CHANNELS(&i),-1,3,
+     1,OPUS_AUTO,
+     "    OPUS_SET_FORCE_CHANNELS ...................... OK.\n",
+     "    OPUS_GET_FORCE_CHANNELS ...................... OK.\n")
+
+   i=-2;
+   if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))==OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_FULLBAND+1;
+   if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))==OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_NARROWBAND;
+   if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_FULLBAND;
+   if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_WIDEBAND;
+   if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_MEDIUMBAND;
+   if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_SET_BANDWIDTH ........................... OK.\n");
+   /*We don't test if the bandwidth has actually changed.
+     because the change may be delayed until the encoder is advanced.*/
+   i=-12345;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_encoder_ctl(enc,OPUS_GET_BANDWIDTH(&i));
+   if(err!=OPUS_OK || (i!=OPUS_BANDWIDTH_NARROWBAND&&
+      i!=OPUS_BANDWIDTH_MEDIUMBAND&&i!=OPUS_BANDWIDTH_WIDEBAND&&
+      i!=OPUS_BANDWIDTH_FULLBAND&&i!=OPUS_AUTO))test_failed();
+   cfgs++;
+   if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(OPUS_AUTO))!=OPUS_OK)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_GET_BANDWIDTH((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_GET_BANDWIDTH ........................... OK.\n");
+
+   i=-2;
+   if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))==OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_FULLBAND+1;
+   if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))==OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_NARROWBAND;
+   if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_FULLBAND;
+   if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_WIDEBAND;
+   if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed();
+   cfgs++;
+   i=OPUS_BANDWIDTH_MEDIUMBAND;
+   if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_SET_MAX_BANDWIDTH ....................... OK.\n");
+   /*We don't test if the bandwidth has actually changed.
+     because the change may be delayed until the encoder is advanced.*/
+   i=-12345;
+   VG_UNDEF(&i,sizeof(i));
+   err=opus_encoder_ctl(enc,OPUS_GET_MAX_BANDWIDTH(&i));
+   if(err!=OPUS_OK || (i!=OPUS_BANDWIDTH_NARROWBAND&&
+      i!=OPUS_BANDWIDTH_MEDIUMBAND&&i!=OPUS_BANDWIDTH_WIDEBAND&&
+      i!=OPUS_BANDWIDTH_FULLBAND))test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_GET_MAX_BANDWIDTH((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_GET_MAX_BANDWIDTH ....................... OK.\n");
+
+   err=opus_encoder_ctl(enc,OPUS_GET_DTX((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_DTX(i),OPUS_GET_DTX(&i),-1,2,
+     1,0,
+     "    OPUS_SET_DTX ................................. OK.\n",
+     "    OPUS_GET_DTX ................................. OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_COMPLEXITY((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_COMPLEXITY(i),OPUS_GET_COMPLEXITY(&i),-1,11,
+     0,10,
+     "    OPUS_SET_COMPLEXITY .......................... OK.\n",
+     "    OPUS_GET_COMPLEXITY .......................... OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_INBAND_FEC((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_INBAND_FEC(i),OPUS_GET_INBAND_FEC(&i),-1,2,
+     1,0,
+     "    OPUS_SET_INBAND_FEC .......................... OK.\n",
+     "    OPUS_GET_INBAND_FEC .......................... OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_PACKET_LOSS_PERC((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_PACKET_LOSS_PERC(i),OPUS_GET_PACKET_LOSS_PERC(&i),-1,101,
+     100,0,
+     "    OPUS_SET_PACKET_LOSS_PERC .................... OK.\n",
+     "    OPUS_GET_PACKET_LOSS_PERC .................... OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_VBR((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_VBR(i),OPUS_GET_VBR(&i),-1,2,
+     1,0,
+     "    OPUS_SET_VBR ................................. OK.\n",
+     "    OPUS_GET_VBR ................................. OK.\n")
+
+/*   err=opus_encoder_ctl(enc,OPUS_GET_VOICE_RATIO((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_VOICE_RATIO(i),OPUS_GET_VOICE_RATIO(&i),-2,101,
+     0,50,
+     "    OPUS_SET_VOICE_RATIO ......................... OK.\n",
+     "    OPUS_GET_VOICE_RATIO ......................... OK.\n")*/
+
+   err=opus_encoder_ctl(enc,OPUS_GET_VBR_CONSTRAINT((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_VBR_CONSTRAINT(i),OPUS_GET_VBR_CONSTRAINT(&i),-1,2,
+     1,0,
+     "    OPUS_SET_VBR_CONSTRAINT ...................... OK.\n",
+     "    OPUS_GET_VBR_CONSTRAINT ...................... OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_SIGNAL((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_SIGNAL(i),OPUS_GET_SIGNAL(&i),-12345,0x7FFFFFFF,
+     OPUS_SIGNAL_MUSIC,OPUS_AUTO,
+     "    OPUS_SET_SIGNAL .............................. OK.\n",
+     "    OPUS_GET_SIGNAL .............................. OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_LSB_DEPTH((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_LSB_DEPTH(i),OPUS_GET_LSB_DEPTH(&i),7,25,16,24,
+     "    OPUS_SET_LSB_DEPTH ........................... OK.\n",
+     "    OPUS_GET_LSB_DEPTH ........................... OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_PREDICTION_DISABLED(&i));
+   if(i!=0)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_GET_PREDICTION_DISABLED((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_PREDICTION_DISABLED(i),OPUS_GET_PREDICTION_DISABLED(&i),-1,2,1,0,
+     "    OPUS_SET_PREDICTION_DISABLED ................. OK.\n",
+     "    OPUS_GET_PREDICTION_DISABLED ................. OK.\n")
+
+   err=opus_encoder_ctl(enc,OPUS_GET_EXPERT_FRAME_DURATION((opus_int32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_2_5_MS));
+   if(err!=OPUS_OK)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_5_MS));
+   if(err!=OPUS_OK)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_10_MS));
+   if(err!=OPUS_OK)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS));
+   if(err!=OPUS_OK)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_40_MS));
+   if(err!=OPUS_OK)test_failed();
+   cfgs++;
+   err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_60_MS));
+   if(err!=OPUS_OK)test_failed();
+   cfgs++;
+   CHECK_SETGET(OPUS_SET_EXPERT_FRAME_DURATION(i),OPUS_GET_EXPERT_FRAME_DURATION(&i),0,-1,
+         OPUS_FRAMESIZE_60_MS,OPUS_FRAMESIZE_ARG,
+     "    OPUS_SET_EXPERT_FRAME_DURATION ............... OK.\n",
+     "    OPUS_GET_EXPERT_FRAME_DURATION ............... OK.\n")
+
+   /*OPUS_SET_FORCE_MODE is not tested here because it's not a public API, however the encoder tests use it*/
+
+   err=opus_encoder_ctl(enc,OPUS_GET_FINAL_RANGE((opus_uint32 *)NULL));
+   if(err!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   if(opus_encoder_ctl(enc,OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_GET_FINAL_RANGE ......................... OK.\n");
+
+   /*Reset the encoder*/
+   if(opus_encoder_ctl(enc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+   cfgs++;
+   fprintf(stdout,"    OPUS_RESET_STATE ............................. OK.\n");
+
+   memset(sbuf,0,sizeof(short)*2*960);
+   VG_UNDEF(packet,sizeof(packet));
+   i=opus_encode(enc, sbuf, 960, packet, sizeof(packet));
+   if(i<1 || (i>(opus_int32)sizeof(packet)))test_failed();
+   VG_CHECK(packet,i);
+   cfgs++;
+   fprintf(stdout,"    opus_encode() ................................ OK.\n");
+#ifndef DISABLE_FLOAT_API
+   memset(fbuf,0,sizeof(float)*2*960);
+   VG_UNDEF(packet,sizeof(packet));
+   i=opus_encode_float(enc, fbuf, 960, packet, sizeof(packet));
+   if(i<1 || (i>(opus_int32)sizeof(packet)))test_failed();
+   VG_CHECK(packet,i);
+   cfgs++;
+   fprintf(stdout,"    opus_encode_float() .......................... OK.\n");
+#endif
+
+#if 0
+   /*These tests are disabled because the library crashes with null states*/
+   if(opus_encoder_ctl(0,OPUS_RESET_STATE)               !=OPUS_INVALID_STATE)test_failed();
+   if(opus_encoder_init(0,48000,1,OPUS_APPLICATION_VOIP) !=OPUS_INVALID_STATE)test_failed();
+   if(opus_encode(0,sbuf,960,packet,sizeof(packet))      !=OPUS_INVALID_STATE)test_failed();
+   if(opus_encode_float(0,fbuf,960,packet,sizeof(packet))!=OPUS_INVALID_STATE)test_failed();
+#endif
+   opus_encoder_destroy(enc);
+   cfgs++;
+   fprintf(stdout,"                   All encoder interface tests passed\n");
+   fprintf(stdout,"                             (%d API invocations)\n",cfgs);
+   return cfgs;
+}
+
+#define max_out (1276*48+48*2+2)
+int test_repacketizer_api(void)
+{
+   int ret,cfgs,i,j,k;
+   OpusRepacketizer *rp;
+   unsigned char *packet;
+   unsigned char *po;
+   cfgs=0;
+   fprintf(stdout,"\n  Repacketizer tests\n");
+   fprintf(stdout,"  ---------------------------------------------------\n");
+
+   packet=malloc(max_out);
+   if(packet==NULL)test_failed();
+   memset(packet,0,max_out);
+   po=malloc(max_out+256);
+   if(po==NULL)test_failed();
+
+   i=opus_repacketizer_get_size();
+   if(i<=0)test_failed();
+   cfgs++;
+   fprintf(stdout,"    opus_repacketizer_get_size()=%d ............. OK.\n",i);
+
+   rp=malloc(i);
+   rp=opus_repacketizer_init(rp);
+   if(rp==NULL)test_failed();
+   cfgs++;
+   free(rp);
+   fprintf(stdout,"    opus_repacketizer_init ....................... OK.\n");
+
+   rp=opus_repacketizer_create();
+   if(rp==NULL)test_failed();
+   cfgs++;
+   fprintf(stdout,"    opus_repacketizer_create ..................... OK.\n");
+
+   if(opus_repacketizer_get_nb_frames(rp)!=0)test_failed();
+   cfgs++;
+   fprintf(stdout,"    opus_repacketizer_get_nb_frames .............. OK.\n");
+
+   /*Length overflows*/
+   VG_UNDEF(packet,4);
+   if(opus_repacketizer_cat(rp,packet,0)!=OPUS_INVALID_PACKET)test_failed(); /* Zero len */
+   cfgs++;
+   packet[0]=1;
+   if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Odd payload code 1 */
+   cfgs++;
+   packet[0]=2;
+   if(opus_repacketizer_cat(rp,packet,1)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow one */
+   cfgs++;
+   packet[0]=3;
+   if(opus_repacketizer_cat(rp,packet,1)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 no count */
+   cfgs++;
+   packet[0]=2;
+   packet[1]=255;
+   if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow two */
+   cfgs++;
+   packet[0]=2;
+   packet[1]=250;
+   if(opus_repacketizer_cat(rp,packet,251)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow three */
+   cfgs++;
+   packet[0]=3;
+   packet[1]=0;
+   if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 m=0 */
+   cfgs++;
+   packet[1]=49;
+   if(opus_repacketizer_cat(rp,packet,100)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 m=49 */
+   cfgs++;
+   packet[0]=0;
+   if(opus_repacketizer_cat(rp,packet,3)!=OPUS_OK)test_failed();
+   cfgs++;
+   packet[0]=1<<2;
+   if(opus_repacketizer_cat(rp,packet,3)!=OPUS_INVALID_PACKET)test_failed(); /* Change in TOC */
+   cfgs++;
+
+   /* Code 0,1,3 CBR -> Code 0,1,3 CBR */
+   opus_repacketizer_init(rp);
+   for(j=0;j<32;j++)
+   {
+      /* TOC types, test half with stereo */
+      int maxi;
+      packet[0]=((j<<1)+(j&1))<<2;
+      maxi=960/opus_packet_get_samples_per_frame(packet,8000);
+      for(i=1;i<=maxi;i++)
+      {
+         /* Number of CBR frames in the input packets */
+         int maxp;
+         packet[0]=((j<<1)+(j&1))<<2;
+         if(i>1)packet[0]+=i==2?1:3;
+         packet[1]=i>2?i:0;
+         maxp=960/(i*opus_packet_get_samples_per_frame(packet,8000));
+         for(k=0;k<=(1275+75);k+=3)
+         {
+            /*Payload size*/
+            opus_int32 cnt,rcnt;
+            if(k%i!=0)continue; /* Only testing CBR here, payload must be a multiple of the count */
+            for(cnt=0;cnt<maxp+2;cnt++)
+            {
+               if(cnt>0)
+               {
+                  ret=opus_repacketizer_cat(rp,packet,k+(i>2?2:1));
+                  if((cnt<=maxp&&k<=(1275*i))?ret!=OPUS_OK:ret!=OPUS_INVALID_PACKET)test_failed();
+                  cfgs++;
+               }
+               rcnt=k<=(1275*i)?(cnt<maxp?cnt:maxp):0;
+               if(opus_repacketizer_get_nb_frames(rp)!=rcnt*i)test_failed();
+               cfgs++;
+               ret=opus_repacketizer_out_range(rp,0,rcnt*i,po,max_out);
+               if(rcnt>0)
+               {
+                  int len;
+                  len=k*rcnt+((rcnt*i)>2?2:1);
+                  if(ret!=len)test_failed();
+                  if((rcnt*i)<2&&(po[0]&3)!=0)test_failed();                      /* Code 0 */
+                  if((rcnt*i)==2&&(po[0]&3)!=1)test_failed();                     /* Code 1 */
+                  if((rcnt*i)>2&&(((po[0]&3)!=3)||(po[1]!=rcnt*i)))test_failed(); /* Code 3 CBR */
+                  cfgs++;
+                  if(opus_repacketizer_out(rp,po,len)!=len)test_failed();
+                  cfgs++;
+                  if(opus_packet_unpad(po,len)!=len)test_failed();
+                  cfgs++;
+                  if(opus_packet_pad(po,len,len+1)!=OPUS_OK)test_failed();
+                  cfgs++;
+                  if(opus_packet_pad(po,len+1,len+256)!=OPUS_OK)test_failed();
+                  cfgs++;
+                  if(opus_packet_unpad(po,len+256)!=len)test_failed();
+                  cfgs++;
+                  if(opus_multistream_packet_unpad(po,len,1)!=len)test_failed();
+                  cfgs++;
+                  if(opus_multistream_packet_pad(po,len,len+1,1)!=OPUS_OK)test_failed();
+                  cfgs++;
+                  if(opus_multistream_packet_pad(po,len+1,len+256,1)!=OPUS_OK)test_failed();
+                  cfgs++;
+                  if(opus_multistream_packet_unpad(po,len+256,1)!=len)test_failed();
+                  cfgs++;
+                  if(opus_repacketizer_out(rp,po,len-1)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+                  cfgs++;
+                  if(len>1)
+                  {
+                     if(opus_repacketizer_out(rp,po,1)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+                     cfgs++;
+                  }
+                  if(opus_repacketizer_out(rp,po,0)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+                  cfgs++;
+               } else if (ret!=OPUS_BAD_ARG)test_failed();                        /* M must not be 0 */
+            }
+            opus_repacketizer_init(rp);
+         }
+      }
+   }
+
+   /*Change in input count code, CBR out*/
+   opus_repacketizer_init(rp);
+   packet[0]=0;
+   if(opus_repacketizer_cat(rp,packet,5)!=OPUS_OK)test_failed();
+   cfgs++;
+   packet[0]+=1;
+   if(opus_repacketizer_cat(rp,packet,9)!=OPUS_OK)test_failed();
+   cfgs++;
+   i=opus_repacketizer_out(rp,po,max_out);
+   if((i!=(4+8+2))||((po[0]&3)!=3)||((po[1]&63)!=3)||((po[1]>>7)!=0))test_failed();
+   cfgs++;
+   i=opus_repacketizer_out_range(rp,0,1,po,max_out);
+   if(i!=5||(po[0]&3)!=0)test_failed();
+   cfgs++;
+   i=opus_repacketizer_out_range(rp,1,2,po,max_out);
+   if(i!=5||(po[0]&3)!=0)test_failed();
+   cfgs++;
+
+   /*Change in input count code, VBR out*/
+   opus_repacketizer_init(rp);
+   packet[0]=1;
+   if(opus_repacketizer_cat(rp,packet,9)!=OPUS_OK)test_failed();
+   cfgs++;
+   packet[0]=0;
+   if(opus_repacketizer_cat(rp,packet,3)!=OPUS_OK)test_failed();
+   cfgs++;
+   i=opus_repacketizer_out(rp,po,max_out);
+   if((i!=(2+8+2+2))||((po[0]&3)!=3)||((po[1]&63)!=3)||((po[1]>>7)!=1))test_failed();
+   cfgs++;
+
+   /*VBR in, VBR out*/
+   opus_repacketizer_init(rp);
+   packet[0]=2;
+   packet[1]=4;
+   if(opus_repacketizer_cat(rp,packet,8)!=OPUS_OK)test_failed();
+   cfgs++;
+   if(opus_repacketizer_cat(rp,packet,8)!=OPUS_OK)test_failed();
+   cfgs++;
+   i=opus_repacketizer_out(rp,po,max_out);
+   if((i!=(2+1+1+1+4+2+4+2))||((po[0]&3)!=3)||((po[1]&63)!=4)||((po[1]>>7)!=1))test_failed();
+   cfgs++;
+
+   /*VBR in, CBR out*/
+   opus_repacketizer_init(rp);
+   packet[0]=2;
+   packet[1]=4;
+   if(opus_repacketizer_cat(rp,packet,10)!=OPUS_OK)test_failed();
+   cfgs++;
+   if(opus_repacketizer_cat(rp,packet,10)!=OPUS_OK)test_failed();
+   cfgs++;
+   i=opus_repacketizer_out(rp,po,max_out);
+   if((i!=(2+4+4+4+4))||((po[0]&3)!=3)||((po[1]&63)!=4)||((po[1]>>7)!=0))test_failed();
+   cfgs++;
+
+   /*Count 0 in, VBR out*/
+   for(j=0;j<32;j++)
+   {
+      /* TOC types, test half with stereo */
+      int maxi,sum,rcnt;
+      packet[0]=((j<<1)+(j&1))<<2;
+      maxi=960/opus_packet_get_samples_per_frame(packet,8000);
+      sum=0;
+      rcnt=0;
+      opus_repacketizer_init(rp);
+      for(i=1;i<=maxi+2;i++)
+      {
+         int len;
+         ret=opus_repacketizer_cat(rp,packet,i);
+         if(rcnt<maxi)
+         {
+            if(ret!=OPUS_OK)test_failed();
+            rcnt++;
+            sum+=i-1;
+         } else if (ret!=OPUS_INVALID_PACKET)test_failed();
+         cfgs++;
+         len=sum+(rcnt<2?1:rcnt<3?2:2+rcnt-1);
+         if(opus_repacketizer_out(rp,po,max_out)!=len)test_failed();
+         if(rcnt>2&&(po[1]&63)!=rcnt)test_failed();
+         if(rcnt==2&&(po[0]&3)!=2)test_failed();
+         if(rcnt==1&&(po[0]&3)!=0)test_failed();
+         cfgs++;
+         if(opus_repacketizer_out(rp,po,len)!=len)test_failed();
+         cfgs++;
+         if(opus_packet_unpad(po,len)!=len)test_failed();
+         cfgs++;
+         if(opus_packet_pad(po,len,len+1)!=OPUS_OK)test_failed();
+         cfgs++;
+         if(opus_packet_pad(po,len+1,len+256)!=OPUS_OK)test_failed();
+         cfgs++;
+         if(opus_packet_unpad(po,len+256)!=len)test_failed();
+         cfgs++;
+         if(opus_multistream_packet_unpad(po,len,1)!=len)test_failed();
+         cfgs++;
+         if(opus_multistream_packet_pad(po,len,len+1,1)!=OPUS_OK)test_failed();
+         cfgs++;
+         if(opus_multistream_packet_pad(po,len+1,len+256,1)!=OPUS_OK)test_failed();
+         cfgs++;
+         if(opus_multistream_packet_unpad(po,len+256,1)!=len)test_failed();
+         cfgs++;
+         if(opus_repacketizer_out(rp,po,len-1)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+         cfgs++;
+         if(len>1)
+         {
+            if(opus_repacketizer_out(rp,po,1)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+            cfgs++;
+         }
+         if(opus_repacketizer_out(rp,po,0)!=OPUS_BUFFER_TOO_SMALL)test_failed();
+         cfgs++;
+      }
+   }
+
+   po[0]='O';
+   po[1]='p';
+   if(opus_packet_pad(po,4,4)!=OPUS_OK)test_failed();
+   cfgs++;
+   if(opus_multistream_packet_pad(po,4,4,1)!=OPUS_OK)test_failed();
+   cfgs++;
+   if(opus_packet_pad(po,4,5)!=OPUS_INVALID_PACKET)test_failed();
+   cfgs++;
+   if(opus_multistream_packet_pad(po,4,5,1)!=OPUS_INVALID_PACKET)test_failed();
+   cfgs++;
+   if(opus_packet_pad(po,0,5)!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   if(opus_multistream_packet_pad(po,0,5,1)!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   if(opus_packet_unpad(po,0)!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   if(opus_multistream_packet_unpad(po,0,1)!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   if(opus_packet_unpad(po,4)!=OPUS_INVALID_PACKET)test_failed();
+   cfgs++;
+   if(opus_multistream_packet_unpad(po,4,1)!=OPUS_INVALID_PACKET)test_failed();
+   cfgs++;
+   po[0]=0;
+   po[1]=0;
+   po[2]=0;
+   if(opus_packet_pad(po,5,4)!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+   if(opus_multistream_packet_pad(po,5,4,1)!=OPUS_BAD_ARG)test_failed();
+   cfgs++;
+
+   fprintf(stdout,"    opus_repacketizer_cat ........................ OK.\n");
+   fprintf(stdout,"    opus_repacketizer_out ........................ OK.\n");
+   fprintf(stdout,"    opus_repacketizer_out_range .................. OK.\n");
+   fprintf(stdout,"    opus_packet_pad .............................. OK.\n");
+   fprintf(stdout,"    opus_packet_unpad ............................ OK.\n");
+   fprintf(stdout,"    opus_multistream_packet_pad .................. OK.\n");
+   fprintf(stdout,"    opus_multistream_packet_unpad ................ OK.\n");
+
+   opus_repacketizer_destroy(rp);
+   cfgs++;
+   free(packet);
+   free(po);
+   fprintf(stdout,"                        All repacketizer tests passed\n");
+   fprintf(stdout,"                            (%7d API invocations)\n",cfgs);
+
+   return cfgs;
+}
+
+#ifdef MALLOC_FAIL
+/* GLIBC 2.14 declares __malloc_hook as deprecated, generating a warning
+ * under GCC. However, this is the cleanest way to test malloc failure
+ * handling in our codebase, and the lack of thread safety isn't an
+ * issue here. We therefore disable the warning for this function.
+ */
+#if OPUS_GNUC_PREREQ(4,6)
+/* Save the current warning settings */
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+typedef void *(*mhook)(size_t __size, __const void *);
+#endif
+
+int test_malloc_fail(void)
+{
+#ifdef MALLOC_FAIL
+   OpusDecoder *dec;
+   OpusEncoder *enc;
+   OpusRepacketizer *rp;
+   unsigned char mapping[256] = {0,1};
+   OpusMSDecoder *msdec;
+   OpusMSEncoder *msenc;
+   int rate,c,app,cfgs,err,useerr;
+   int *ep;
+   mhook orig_malloc;
+   cfgs=0;
+#endif
+   fprintf(stdout,"\n  malloc() failure tests\n");
+   fprintf(stdout,"  ---------------------------------------------------\n");
+#ifdef MALLOC_FAIL
+   orig_malloc=__malloc_hook;
+   __malloc_hook=malloc_hook;
+   ep=(int *)opus_alloc(sizeof(int));
+   if(ep!=NULL)
+   {
+      if(ep)free(ep);
+      __malloc_hook=orig_malloc;
+#endif
+      fprintf(stdout,"    opus_decoder_create() ................... SKIPPED.\n");
+      fprintf(stdout,"    opus_encoder_create() ................... SKIPPED.\n");
+      fprintf(stdout,"    opus_repacketizer_create() .............. SKIPPED.\n");
+      fprintf(stdout,"    opus_multistream_decoder_create() ....... SKIPPED.\n");
+      fprintf(stdout,"    opus_multistream_encoder_create() ....... SKIPPED.\n");
+      fprintf(stdout,"(Test only supported with GLIBC and without valgrind)\n");
+      return 0;
+#ifdef MALLOC_FAIL
+   }
+   for(useerr=0;useerr<2;useerr++)
+   {
+      ep=useerr?&err:0;
+      for(rate=0;rate<5;rate++)
+      {
+        for(c=1;c<3;c++)
+        {
+           err=1;
+           if(useerr)
+           {
+              VG_UNDEF(&err,sizeof(err));
+           }
+           dec=opus_decoder_create(opus_rates[rate], c, ep);
+           if(dec!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL))
+           {
+              __malloc_hook=orig_malloc;
+              test_failed();
+           }
+           cfgs++;
+           msdec=opus_multistream_decoder_create(opus_rates[rate], c, 1, c-1, mapping, ep);
+           if(msdec!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL))
+           {
+              __malloc_hook=orig_malloc;
+              test_failed();
+           }
+           cfgs++;
+           for(app=0;app<3;app++)
+           {
+              if(useerr)
+              {
+                 VG_UNDEF(&err,sizeof(err));
+              }
+              enc=opus_encoder_create(opus_rates[rate], c, opus_apps[app],ep);
+              if(enc!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL))
+              {
+                 __malloc_hook=orig_malloc;
+                 test_failed();
+              }
+              cfgs++;
+              msenc=opus_multistream_encoder_create(opus_rates[rate], c, 1, c-1, mapping, opus_apps[app],ep);
+              if(msenc!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL))
+              {
+                 __malloc_hook=orig_malloc;
+                 test_failed();
+              }
+              cfgs++;
+           }
+        }
+     }
+   }
+   rp=opus_repacketizer_create();
+   if(rp!=NULL)
+   {
+      __malloc_hook=orig_malloc;
+      test_failed();
+   }
+   cfgs++;
+   __malloc_hook=orig_malloc;
+   fprintf(stdout,"    opus_decoder_create() ........................ OK.\n");
+   fprintf(stdout,"    opus_encoder_create() ........................ OK.\n");
+   fprintf(stdout,"    opus_repacketizer_create() ................... OK.\n");
+   fprintf(stdout,"    opus_multistream_decoder_create() ............ OK.\n");
+   fprintf(stdout,"    opus_multistream_encoder_create() ............ OK.\n");
+   fprintf(stdout,"                      All malloc failure tests passed\n");
+   fprintf(stdout,"                                 (%2d API invocations)\n",cfgs);
+   return cfgs;
+#endif
+}
+
+#ifdef MALLOC_FAIL
+#if __GNUC_PREREQ(4,6)
+#pragma GCC diagnostic pop /* restore -Wdeprecated-declarations */
+#endif
+#endif
+
+int main(int _argc, char **_argv)
+{
+   opus_int32 total;
+   const char * oversion;
+   if(_argc>1)
+   {
+      fprintf(stderr,"Usage: %s\n",_argv[0]);
+      return 1;
+   }
+   iseed=0;
+
+   oversion=opus_get_version_string();
+   if(!oversion)test_failed();
+   fprintf(stderr,"Testing the %s API deterministically\n", oversion);
+   if(opus_strerror(-32768)==NULL)test_failed();
+   if(opus_strerror(32767)==NULL)test_failed();
+   if(strlen(opus_strerror(0))<1)test_failed();
+   total=4;
+
+   total+=test_dec_api();
+   total+=test_msdec_api();
+   total+=test_parse();
+   total+=test_enc_api();
+   total+=test_repacketizer_api();
+   total+=test_malloc_fail();
+
+   fprintf(stderr,"\nAll API tests passed.\nThe libopus API was invoked %d times.\n",total);
+
+   return 0;
+}
diff --git a/third_party/opus/src/tests/test_opus_common.h b/third_party/opus/src/tests/test_opus_common.h
new file mode 100644
index 0000000..66b9690
--- /dev/null
+++ b/third_party/opus/src/tests/test_opus_common.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+   Written by Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+static OPUS_INLINE void deb2_impl(unsigned char *_t,unsigned char **_p,int _k,int _x,int _y)
+{
+  int i;
+  if(_x>2){
+     if(_y<3)for(i=0;i<_y;i++)*(--*_p)=_t[i+1];
+  }else{
+     _t[_x]=_t[_x-_y];
+     deb2_impl(_t,_p,_k,_x+1,_y);
+     for(i=_t[_x-_y]+1;i<_k;i++){
+       _t[_x]=i;
+       deb2_impl(_t,_p,_k,_x+1,_x);
+     }
+  }
+}
+
+/*Generates a De Bruijn sequence (k,2) with length k^2*/
+static OPUS_INLINE void debruijn2(int _k, unsigned char *_res)
+{
+   unsigned char *p;
+   unsigned char *t;
+   t=malloc(sizeof(unsigned char)*_k*2);
+   memset(t,0,sizeof(unsigned char)*_k*2);
+   p=&_res[_k*_k];
+   deb2_impl(t,&p,_k,1,1);
+   free(t);
+}
+
+/*MWC RNG of George Marsaglia*/
+static opus_uint32 Rz, Rw;
+static OPUS_INLINE opus_uint32 fast_rand(void)
+{
+  Rz=36969*(Rz&65535)+(Rz>>16);
+  Rw=18000*(Rw&65535)+(Rw>>16);
+  return (Rz<<16)+Rw;
+}
+static opus_uint32 iseed;
+
+#ifdef __GNUC__
+__attribute__((noreturn))
+#endif
+static OPUS_INLINE void _test_failed(const char *file, int line)
+{
+  fprintf(stderr,"\n ***************************************************\n");
+  fprintf(stderr," ***         A fatal error was detected.         ***\n");
+  fprintf(stderr," ***************************************************\n");
+  fprintf(stderr,"Please report this failure and include\n");
+  fprintf(stderr,"'make check SEED=%u fails %s at line %d for %s'\n",iseed,file,line,opus_get_version_string());
+  fprintf(stderr,"and any relevant details about your system.\n\n");
+  abort();
+}
+#define test_failed() _test_failed(__FILE__, __LINE__);
diff --git a/third_party/opus/src/tests/test_opus_decode.c b/third_party/opus/src/tests/test_opus_decode.c
new file mode 100644
index 0000000..9c0eb9c
--- /dev/null
+++ b/third_party/opus/src/tests/test_opus_decode.c
@@ -0,0 +1,456 @@
+/* Copyright (c) 2011-2013 Xiph.Org Foundation
+   Written by Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+#include <math.h>
+#include <string.h>
+#include <time.h>
+#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <process.h>
+#define getpid _getpid
+#endif
+#include "opus.h"
+#include "test_opus_common.h"
+
+#define MAX_PACKET (1500)
+#define MAX_FRAME_SAMP (5760)
+
+int test_decoder_code0(int no_fuzz)
+{
+   static const opus_int32 fsv[5]={48000,24000,16000,12000,8000};
+   int err,skip,plen;
+   int out_samples,fec;
+   int t;
+   opus_int32 i;
+   OpusDecoder *dec[5*2];
+   opus_int32 decsize;
+   OpusDecoder *decbak;
+   opus_uint32 dec_final_range1,dec_final_range2,dec_final_acc;
+   unsigned char *packet;
+   unsigned char modes[4096];
+   short *outbuf_int;
+   short *outbuf;
+
+   dec_final_range1=dec_final_range2=2;
+
+   packet=malloc(sizeof(unsigned char)*MAX_PACKET);
+   if(packet==NULL)test_failed();
+
+   outbuf_int=malloc(sizeof(short)*(MAX_FRAME_SAMP+16)*2);
+   for(i=0;i<(MAX_FRAME_SAMP+16)*2;i++)outbuf_int[i]=32749;
+   outbuf=&outbuf_int[8*2];
+
+   fprintf(stdout,"  Starting %d decoders...\n",5*2);
+   for(t=0;t<5*2;t++)
+   {
+      int fs=fsv[t>>1];
+      int c=(t&1)+1;
+      err=OPUS_INTERNAL_ERROR;
+      dec[t] = opus_decoder_create(fs, c, &err);
+      if(err!=OPUS_OK || dec[t]==NULL)test_failed();
+      fprintf(stdout,"    opus_decoder_create(%5d,%d) OK. Copy ",fs,c);
+      {
+         OpusDecoder *dec2;
+         /*The opus state structures contain no pointers and can be freely copied*/
+         dec2=(OpusDecoder *)malloc(opus_decoder_get_size(c));
+         if(dec2==NULL)test_failed();
+         memcpy(dec2,dec[t],opus_decoder_get_size(c));
+         memset(dec[t],255,opus_decoder_get_size(c));
+         opus_decoder_destroy(dec[t]);
+         printf("OK.\n");
+         dec[t]=dec2;
+      }
+   }
+
+   decsize=opus_decoder_get_size(1);
+   decbak=(OpusDecoder *)malloc(decsize);
+   if(decbak==NULL)test_failed();
+
+   for(t=0;t<5*2;t++)
+   {
+      int factor=48000/fsv[t>>1];
+      for(fec=0;fec<2;fec++)
+      {
+         int dur;
+         /*Test PLC on a fresh decoder*/
+         out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, fec);
+         if(out_samples!=120/factor)test_failed();
+         if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
+         if(dur!=120/factor)test_failed();
+
+         /*Test on a size which isn't a multiple of 2.5ms*/
+         out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor+2, fec);
+         if(out_samples!=OPUS_BAD_ARG)test_failed();
+
+         /*Test null pointer input*/
+         out_samples = opus_decode(dec[t], 0, -1, outbuf, 120/factor, fec);
+         if(out_samples!=120/factor)test_failed();
+         out_samples = opus_decode(dec[t], 0, 1, outbuf, 120/factor, fec);
+         if(out_samples!=120/factor)test_failed();
+         out_samples = opus_decode(dec[t], 0, 10, outbuf, 120/factor, fec);
+         if(out_samples!=120/factor)test_failed();
+         out_samples = opus_decode(dec[t], 0, fast_rand(), outbuf, 120/factor, fec);
+         if(out_samples!=120/factor)test_failed();
+         if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
+         if(dur!=120/factor)test_failed();
+
+         /*Zero lengths*/
+         out_samples = opus_decode(dec[t], packet, 0, outbuf, 120/factor, fec);
+         if(out_samples!=120/factor)test_failed();
+
+         /*Zero buffer*/
+         outbuf[0]=32749;
+         out_samples = opus_decode(dec[t], packet, 0, outbuf, 0, fec);
+         if(out_samples>0)test_failed();
+         out_samples = opus_decode(dec[t], packet, 0, 0, 0, fec);
+         if(out_samples>0)test_failed();
+         if(outbuf[0]!=32749)test_failed();
+
+         /*Invalid lengths*/
+         out_samples = opus_decode(dec[t], packet, -1, outbuf, MAX_FRAME_SAMP, fec);
+         if(out_samples>=0)test_failed();
+         out_samples = opus_decode(dec[t], packet, INT_MIN, outbuf, MAX_FRAME_SAMP, fec);
+         if(out_samples>=0)test_failed();
+         out_samples = opus_decode(dec[t], packet, -1, outbuf, -1, fec);
+         if(out_samples>=0)test_failed();
+
+         /*Crazy FEC values*/
+         out_samples = opus_decode(dec[t], packet, 1, outbuf, MAX_FRAME_SAMP, fec?-1:2);
+         if(out_samples>=0)test_failed();
+
+         /*Reset the decoder*/
+         if(opus_decoder_ctl(dec[t], OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+      }
+   }
+   fprintf(stdout,"  dec[all] initial frame PLC OK.\n");
+
+   /*Count code 0 tests*/
+   for(i=0;i<64;i++)
+   {
+      int dur;
+      int j,expected[5*2];
+      packet[0]=i<<2;
+      packet[1]=255;
+      packet[2]=255;
+      err=opus_packet_get_nb_channels(packet);
+      if(err!=(i&1)+1)test_failed();
+
+      for(t=0;t<5*2;t++){
+         expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1);
+         if(expected[t]>2880)test_failed();
+      }
+
+      for(j=0;j<256;j++)
+      {
+         packet[1]=j;
+         for(t=0;t<5*2;t++)
+         {
+            out_samples = opus_decode(dec[t], packet, 3, outbuf, MAX_FRAME_SAMP, 0);
+            if(out_samples!=expected[t])test_failed();
+            if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
+            if(dur!=out_samples)test_failed();
+            opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1));
+            if(t==0)dec_final_range2=dec_final_range1;
+            else if(dec_final_range1!=dec_final_range2)test_failed();
+         }
+      }
+
+      for(t=0;t<5*2;t++){
+         int factor=48000/fsv[t>>1];
+         /* The PLC is run for 6 frames in order to get better PLC coverage. */
+         for(j=0;j<6;j++)
+         {
+            out_samples = opus_decode(dec[t], 0, 0, outbuf, expected[t], 0);
+            if(out_samples!=expected[t])test_failed();
+            if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
+            if(dur!=out_samples)test_failed();
+         }
+         /* Run the PLC once at 2.5ms, as a simulation of someone trying to
+            do small drift corrections. */
+         if(expected[t]!=120/factor)
+         {
+            out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, 0);
+            if(out_samples!=120/factor)test_failed();
+            if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
+            if(dur!=out_samples)test_failed();
+         }
+         out_samples = opus_decode(dec[t], packet, 2, outbuf, expected[t]-1, 0);
+         if(out_samples>0)test_failed();
+      }
+   }
+   fprintf(stdout,"  dec[all] all 2-byte prefix for length 3 and PLC, all modes (64) OK.\n");
+
+   if(no_fuzz)
+   {
+      fprintf(stdout,"  Skipping many tests which fuzz the decoder as requested.\n");
+      free(decbak);
+      for(t=0;t<5*2;t++)opus_decoder_destroy(dec[t]);
+      printf("  Decoders stopped.\n");
+
+      err=0;
+      for(i=0;i<8*2;i++)err|=outbuf_int[i]!=32749;
+      for(i=MAX_FRAME_SAMP*2;i<(MAX_FRAME_SAMP+8)*2;i++)err|=outbuf[i]!=32749;
+      if(err)test_failed();
+
+      free(outbuf_int);
+      free(packet);
+      return 0;
+   }
+
+   {
+     /*We only test a subset of the modes here simply because the longer
+       durations end up taking a long time.*/
+      static const int cmodes[4]={16,20,24,28};
+      static const opus_uint32 cres[4]={116290185,2172123586u,2172123586u,2172123586u};
+      static const opus_uint32 lres[3]={3285687739u,1481572662,694350475};
+      static const int lmodes[3]={0,4,8};
+      int mode=fast_rand()%4;
+
+      packet[0]=cmodes[mode]<<3;
+      dec_final_acc=0;
+      t=fast_rand()%10;
+
+      for(i=0;i<65536;i++)
+      {
+         int factor=48000/fsv[t>>1];
+         packet[1]=i>>8;
+         packet[2]=i&255;
+         packet[3]=255;
+         out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0);
+         if(out_samples!=120/factor)test_failed();
+         opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1));
+         dec_final_acc+=dec_final_range1;
+      }
+      if(dec_final_acc!=cres[mode])test_failed();
+      fprintf(stdout,"  dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,cmodes[mode]);
+
+      mode=fast_rand()%3;
+      packet[0]=lmodes[mode]<<3;
+      dec_final_acc=0;
+      t=fast_rand()%10;
+      for(i=0;i<65536;i++)
+      {
+         int factor=48000/fsv[t>>1];
+         packet[1]=i>>8;
+         packet[2]=i&255;
+         packet[3]=255;
+         out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0);
+         if(out_samples!=480/factor)test_failed();
+         opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1));
+         dec_final_acc+=dec_final_range1;
+      }
+      if(dec_final_acc!=lres[mode])test_failed();
+      fprintf(stdout,"  dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,lmodes[mode]);
+   }
+
+   skip=fast_rand()%7;
+   for(i=0;i<64;i++)
+   {
+      int j,expected[5*2];
+      packet[0]=i<<2;
+      for(t=0;t<5*2;t++)expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1);
+      for(j=2+skip;j<1275;j+=4)
+      {
+         int jj;
+         for(jj=0;jj<j;jj++)packet[jj+1]=fast_rand()&255;
+         for(t=0;t<5*2;t++)
+         {
+            out_samples = opus_decode(dec[t], packet, j+1, outbuf, MAX_FRAME_SAMP, 0);
+            if(out_samples!=expected[t])test_failed();
+            opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1));
+            if(t==0)dec_final_range2=dec_final_range1;
+            else if(dec_final_range1!=dec_final_range2)test_failed();
+         }
+      }
+   }
+   fprintf(stdout,"  dec[all] random packets, all modes (64), every 8th size from from %d bytes to maximum OK.\n",2+skip);
+
+   debruijn2(64,modes);
+   plen=(fast_rand()%18+3)*8+skip+3;
+   for(i=0;i<4096;i++)
+   {
+      int j,expected[5*2];
+      packet[0]=modes[i]<<2;
+      for(t=0;t<5*2;t++)expected[t]=opus_decoder_get_nb_samples(dec[t],packet,plen);
+      for(j=0;j<plen;j++)packet[j+1]=(fast_rand()|fast_rand())&255;
+      memcpy(decbak,dec[0],decsize);
+      if(opus_decode(decbak, packet, plen+1, outbuf, expected[0], 1)!=expected[0])test_failed();
+      memcpy(decbak,dec[0],decsize);
+      if(opus_decode(decbak,  0, 0, outbuf, MAX_FRAME_SAMP, 1)<20)test_failed();
+      memcpy(decbak,dec[0],decsize);
+      if(opus_decode(decbak,  0, 0, outbuf, MAX_FRAME_SAMP, 0)<20)test_failed();
+      for(t=0;t<5*2;t++)
+      {
+         int dur;
+         out_samples = opus_decode(dec[t], packet, plen+1, outbuf, MAX_FRAME_SAMP, 0);
+         if(out_samples!=expected[t])test_failed();
+         if(t==0)dec_final_range2=dec_final_range1;
+         else if(dec_final_range1!=dec_final_range2)test_failed();
+         if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
+         if(dur!=out_samples)test_failed();
+      }
+   }
+   fprintf(stdout,"  dec[all] random packets, all mode pairs (4096), %d bytes/frame OK.\n",plen+1);
+
+   plen=(fast_rand()%18+3)*8+skip+3;
+   t=rand()&3;
+   for(i=0;i<4096;i++)
+   {
+      int count,j,expected;
+      packet[0]=modes[i]<<2;
+      expected=opus_decoder_get_nb_samples(dec[t],packet,plen);
+      for(count=0;count<10;count++)
+      {
+         for(j=0;j<plen;j++)packet[j+1]=(fast_rand()|fast_rand())&255;
+         out_samples = opus_decode(dec[t], packet, plen+1, outbuf, MAX_FRAME_SAMP, 0);
+         if(out_samples!=expected)test_failed();
+      }
+   }
+   fprintf(stdout,"  dec[%3d] random packets, all mode pairs (4096)*10, %d bytes/frame OK.\n",t,plen+1);
+
+   {
+      int tmodes[1]={25<<2};
+      opus_uint32 tseeds[1]={140441};
+      int tlen[1]={157};
+      opus_int32 tret[1]={480};
+      t=fast_rand()&1;
+      for(i=0;i<1;i++)
+      {
+         int j;
+         packet[0]=tmodes[i];
+         Rw=Rz=tseeds[i];
+         for(j=1;j<tlen[i];j++)packet[j]=fast_rand()&255;
+         out_samples=opus_decode(dec[t], packet, tlen[i], outbuf, MAX_FRAME_SAMP, 0);
+         if(out_samples!=tret[i])test_failed();
+      }
+      fprintf(stdout,"  dec[%3d] pre-selected random packets OK.\n",t);
+   }
+
+   free(decbak);
+   for(t=0;t<5*2;t++)opus_decoder_destroy(dec[t]);
+   printf("  Decoders stopped.\n");
+
+   err=0;
+   for(i=0;i<8*2;i++)err|=outbuf_int[i]!=32749;
+   for(i=MAX_FRAME_SAMP*2;i<(MAX_FRAME_SAMP+8)*2;i++)err|=outbuf[i]!=32749;
+   if(err)test_failed();
+
+   free(outbuf_int);
+   free(packet);
+   return 0;
+}
+
+#ifndef DISABLE_FLOAT_API
+void test_soft_clip(void)
+{
+   int i,j;
+   float x[1024];
+   float s[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+   fprintf(stdout,"  Testing opus_pcm_soft_clip... ");
+   for(i=0;i<1024;i++)
+   {
+      for (j=0;j<1024;j++)
+      {
+        x[j]=(i&255)*(1/32.f)-4.f;
+      }
+      opus_pcm_soft_clip(&x[i],1024-i,1,s);
+      for (j=i;j<1024;j++)
+      {
+        if(x[i]>1.f)test_failed();
+        if(x[i]<-1.f)test_failed();
+      }
+   }
+   for(i=1;i<9;i++)
+   {
+      for (j=0;j<1024;j++)
+      {
+        x[j]=(i&255)*(1/32.f)-4.f;
+      }
+      opus_pcm_soft_clip(x,1024/i,i,s);
+      for (j=0;j<(1024/i)*i;j++)
+      {
+        if(x[i]>1.f)test_failed();
+        if(x[i]<-1.f)test_failed();
+      }
+   }
+   opus_pcm_soft_clip(x,0,1,s);
+   opus_pcm_soft_clip(x,1,0,s);
+   opus_pcm_soft_clip(x,1,1,0);
+   opus_pcm_soft_clip(x,1,-1,s);
+   opus_pcm_soft_clip(x,-1,1,s);
+   opus_pcm_soft_clip(0,1,1,s);
+   printf("OK.\n");
+}
+#endif
+
+int main(int _argc, char **_argv)
+{
+   const char * oversion;
+   const char * env_seed;
+   int env_used;
+
+   if(_argc>2)
+   {
+      fprintf(stderr,"Usage: %s [<seed>]\n",_argv[0]);
+      return 1;
+   }
+
+   env_used=0;
+   env_seed=getenv("SEED");
+   if(_argc>1)iseed=atoi(_argv[1]);
+   else if(env_seed)
+   {
+      iseed=atoi(env_seed);
+      env_used=1;
+   }
+   else iseed=(opus_uint32)time(NULL)^((getpid()&65535)<<16);
+   Rw=Rz=iseed;
+
+   oversion=opus_get_version_string();
+   if(!oversion)test_failed();
+   fprintf(stderr,"Testing %s decoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535);
+   if(env_used)fprintf(stderr,"  Random seed set from the environment (SEED=%s).\n", env_seed);
+
+   /*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data
+     into the decoders. This is helpful because garbage data
+     may cause the decoders to clip, which angers CLANG IOC.*/
+   test_decoder_code0(getenv("TEST_OPUS_NOFUZZ")!=NULL);
+#ifndef DISABLE_FLOAT_API
+   test_soft_clip();
+#endif
+
+   return 0;
+}
diff --git a/third_party/opus/src/tests/test_opus_encode.c b/third_party/opus/src/tests/test_opus_encode.c
new file mode 100644
index 0000000..132d074
--- /dev/null
+++ b/third_party/opus/src/tests/test_opus_encode.c
@@ -0,0 +1,509 @@
+/* Copyright (c) 2011-2013 Xiph.Org Foundation
+   Written by Gregory Maxwell */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+#include <math.h>
+#include <string.h>
+#include <time.h>
+#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <process.h>
+#define getpid _getpid
+#endif
+#include "opus_multistream.h"
+#include "opus.h"
+#include "../src/opus_private.h"
+#include "test_opus_common.h"
+
+#define MAX_PACKET (1500)
+#define SAMPLES (48000*30)
+#define SSAMPLES (SAMPLES/3)
+#define MAX_FRAME_SAMP (5760)
+
+#define PI (3.141592653589793238462643f)
+
+void generate_music(short *buf, opus_int32 len)
+{
+   opus_int32 a1,b1,a2,b2;
+   opus_int32 c1,c2,d1,d2;
+   opus_int32 i,j;
+   a1=b1=a2=b2=0;
+   c1=c2=d1=d2=0;
+   j=0;
+   /*60ms silence*/
+   for(i=0;i<2880;i++)buf[i*2]=buf[i*2+1]=0;
+   for(i=2880;i<len;i++)
+   {
+     opus_uint32 r;
+     opus_int32 v1,v2;
+     v1=v2=(((j*((j>>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15;
+     r=fast_rand();v1+=r&65535;v1-=r>>16;
+     r=fast_rand();v2+=r&65535;v2-=r>>16;
+     b1=v1-a1+((b1*61+32)>>6);a1=v1;
+     b2=v2-a2+((b2*61+32)>>6);a2=v2;
+     c1=(30*(c1+b1+d1)+32)>>6;d1=b1;
+     c2=(30*(c2+b2+d2)+32)>>6;d2=b2;
+     v1=(c1+128)>>8;
+     v2=(c2+128)>>8;
+     buf[i*2]=v1>32767?32767:(v1<-32768?-32768:v1);
+     buf[i*2+1]=v2>32767?32767:(v2<-32768?-32768:v2);
+     if(i%6==0)j++;
+   }
+}
+
+#if 0
+static int save_ctr = 0;
+static void int_to_char(opus_uint32 i, unsigned char ch[4])
+{
+    ch[0] = i>>24;
+    ch[1] = (i>>16)&0xFF;
+    ch[2] = (i>>8)&0xFF;
+    ch[3] = i&0xFF;
+}
+
+static OPUS_INLINE void save_packet(unsigned char* p, int len, opus_uint32 rng)
+{
+   FILE *fout;
+   unsigned char int_field[4];
+   char name[256];
+   snprintf(name,255,"test_opus_encode.%llu.%d.bit",(unsigned long long)iseed,save_ctr);
+   fprintf(stdout,"writing %d byte packet to %s\n",len,name);
+   fout=fopen(name, "wb+");
+   if(fout==NULL)test_failed();
+   int_to_char(len, int_field);
+   fwrite(int_field, 1, 4, fout);
+   int_to_char(rng, int_field);
+   fwrite(int_field, 1, 4, fout);
+   fwrite(p, 1, len, fout);
+   fclose(fout);
+   save_ctr++;
+}
+#endif
+
+int run_test1(int no_fuzz)
+{
+   static const int fsizes[6]={960*3,960*2,120,240,480,960};
+   static const char *mstrings[3] = {"    LP","Hybrid","  MDCT"};
+   unsigned char mapping[256] = {0,1,255};
+   unsigned char db62[36];
+   opus_int32 i;
+   int rc,j,err;
+   OpusEncoder *enc;
+   OpusMSEncoder *MSenc;
+   OpusDecoder *dec;
+   OpusMSDecoder *MSdec;
+   OpusMSDecoder *MSdec_err;
+   OpusDecoder *dec_err[10];
+   short *inbuf;
+   short *outbuf;
+   short *out2buf;
+   opus_int32 bitrate_bps;
+   unsigned char packet[MAX_PACKET+257];
+   opus_uint32 enc_final_range;
+   opus_uint32 dec_final_range;
+   int fswitch;
+   int fsize;
+   int count;
+
+  /*FIXME: encoder api tests, fs!=48k, mono, VBR*/
+
+   fprintf(stdout,"  Encode+Decode tests.\n");
+
+   enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &err);
+   if(err != OPUS_OK || enc==NULL)test_failed();
+
+   for(i=0;i<2;i++)
+   {
+      int *ret_err;
+      ret_err = i?0:&err;
+      MSenc = opus_multistream_encoder_create(8000, 2, 2, 0, mapping, OPUS_UNIMPLEMENTED, ret_err);
+      if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
+
+      MSenc = opus_multistream_encoder_create(8000, 0, 1, 0, mapping, OPUS_APPLICATION_VOIP, ret_err);
+      if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
+
+      MSenc = opus_multistream_encoder_create(44100, 2, 2, 0, mapping, OPUS_APPLICATION_VOIP, ret_err);
+      if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
+
+      MSenc = opus_multistream_encoder_create(8000, 2, 2, 3, mapping, OPUS_APPLICATION_VOIP, ret_err);
+      if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
+
+      MSenc = opus_multistream_encoder_create(8000, 2, -1, 0, mapping, OPUS_APPLICATION_VOIP, ret_err);
+      if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
+
+      MSenc = opus_multistream_encoder_create(8000, 256, 2, 0, mapping, OPUS_APPLICATION_VOIP, ret_err);
+      if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
+   }
+
+   MSenc = opus_multistream_encoder_create(8000, 2, 2, 0, mapping, OPUS_APPLICATION_AUDIO, &err);
+   if(err != OPUS_OK || MSenc==NULL)test_failed();
+
+   /*Some multistream encoder API tests*/
+   if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_BITRATE(&i))!=OPUS_OK)test_failed();
+   if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_LSB_DEPTH(&i))!=OPUS_OK)test_failed();
+   if(i<16)test_failed();
+
+   {
+      OpusEncoder *tmp_enc;
+      if(opus_multistream_encoder_ctl(MSenc,  OPUS_MULTISTREAM_GET_ENCODER_STATE(1,&tmp_enc))!=OPUS_OK)test_failed();
+      if(opus_encoder_ctl(tmp_enc, OPUS_GET_LSB_DEPTH(&j))!=OPUS_OK)test_failed();
+      if(i!=j)test_failed();
+      if(opus_multistream_encoder_ctl(MSenc,  OPUS_MULTISTREAM_GET_ENCODER_STATE(2,&tmp_enc))!=OPUS_BAD_ARG)test_failed();
+   }
+
+   dec = opus_decoder_create(48000, 2, &err);
+   if(err != OPUS_OK || dec==NULL)test_failed();
+
+   MSdec = opus_multistream_decoder_create(48000, 2, 2, 0, mapping, &err);
+   if(err != OPUS_OK || MSdec==NULL)test_failed();
+
+   MSdec_err = opus_multistream_decoder_create(48000, 3, 2, 0, mapping, &err);
+   if(err != OPUS_OK || MSdec_err==NULL)test_failed();
+
+   dec_err[0]=(OpusDecoder *)malloc(opus_decoder_get_size(2));
+   memcpy(dec_err[0],dec,opus_decoder_get_size(2));
+   dec_err[1] = opus_decoder_create(48000, 1, &err);
+   dec_err[2] = opus_decoder_create(24000, 2, &err);
+   dec_err[3] = opus_decoder_create(24000, 1, &err);
+   dec_err[4] = opus_decoder_create(16000, 2, &err);
+   dec_err[5] = opus_decoder_create(16000, 1, &err);
+   dec_err[6] = opus_decoder_create(12000, 2, &err);
+   dec_err[7] = opus_decoder_create(12000, 1, &err);
+   dec_err[8] = opus_decoder_create(8000, 2, &err);
+   dec_err[9] = opus_decoder_create(8000, 1, &err);
+   for(i=0;i<10;i++)if(dec_err[i]==NULL)test_failed();
+
+   {
+      OpusEncoder *enccpy;
+      /*The opus state structures contain no pointers and can be freely copied*/
+      enccpy=(OpusEncoder *)malloc(opus_encoder_get_size(2));
+      memcpy(enccpy,enc,opus_encoder_get_size(2));
+      memset(enc,255,opus_encoder_get_size(2));
+      opus_encoder_destroy(enc);
+      enc=enccpy;
+   }
+
+   inbuf=(short *)malloc(sizeof(short)*SAMPLES*2);
+   outbuf=(short *)malloc(sizeof(short)*SAMPLES*2);
+   out2buf=(short *)malloc(sizeof(short)*MAX_FRAME_SAMP*3);
+   if(inbuf==NULL || outbuf==NULL || out2buf==NULL)test_failed();
+
+   generate_music(inbuf,SAMPLES);
+
+/*   FILE *foo;
+   foo = fopen("foo.sw", "wb+");
+   fwrite(inbuf, 1, SAMPLES*2*2, foo);
+   fclose(foo);*/
+
+   if(opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO))!=OPUS_OK)test_failed();
+   if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(-2))!=OPUS_BAD_ARG)test_failed();
+
+   for(rc=0;rc<3;rc++)
+   {
+      if(opus_encoder_ctl(enc, OPUS_SET_VBR(rc<2))!=OPUS_OK)test_failed();
+      if(opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed();
+      if(opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed();
+      if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed();
+      for(j=0;j<13;j++)
+      {
+         int rate;
+         int modes[13]={0,0,0,1,1,1,1,2,2,2,2,2,2};
+         int rates[13]={6000,12000,48000,16000,32000,48000,64000,512000,13000,24000,48000,64000,96000};
+         int frame[13]={960*2,960,480,960,960,960,480,960*3,960*3,960,480,240,120};
+         rate=rates[j]+fast_rand()%rates[j];
+         count=i=0;
+         do {
+            int bw,len,out_samples,frame_size;
+            frame_size=frame[j];
+            if((fast_rand()&255)==0)
+            {
+               if(opus_encoder_ctl(enc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+               if(opus_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+               if((fast_rand()&1)!=0)
+               {
+                  if(opus_decoder_ctl(dec_err[fast_rand()&1], OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+               }
+            }
+            if((fast_rand()&127)==0)
+            {
+               if(opus_decoder_ctl(dec_err[fast_rand()&1], OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+            }
+            if(fast_rand()%10==0){
+               int complex=fast_rand()%11;
+               if(opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complex))!=OPUS_OK)test_failed();
+            }
+            if(fast_rand()%50==0)opus_decoder_ctl(dec, OPUS_RESET_STATE);
+            if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed();
+            if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_SILK_ONLY+modes[j]))!=OPUS_OK)test_failed();
+            if(opus_encoder_ctl(enc, OPUS_SET_DTX(fast_rand()&1))!=OPUS_OK)test_failed();
+            if(opus_encoder_ctl(enc, OPUS_SET_BITRATE(rate))!=OPUS_OK)test_failed();
+            if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS((rates[j]>=64000?2:1)))!=OPUS_OK)test_failed();
+            if(opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed();
+            if(opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed();
+            bw=modes[j]==0?OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%3):
+               modes[j]==1?OPUS_BANDWIDTH_SUPERWIDEBAND+(fast_rand()&1):
+                           OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%5);
+            if(modes[j]==2&&bw==OPUS_BANDWIDTH_MEDIUMBAND)bw+=3;
+            if(opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bw))!=OPUS_OK)test_failed();
+            len = opus_encode(enc, &inbuf[i<<1], frame_size, packet, MAX_PACKET);
+            if(len<0 || len>MAX_PACKET)test_failed();
+            if(opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed();
+            if((fast_rand()&3)==0)
+            {
+               if(opus_packet_pad(packet,len,len+1)!=OPUS_OK)test_failed();
+               len++;
+            }
+            if((fast_rand()&7)==0)
+            {
+               if(opus_packet_pad(packet,len,len+256)!=OPUS_OK)test_failed();
+               len+=256;
+            }
+            if((fast_rand()&3)==0)
+            {
+               len=opus_packet_unpad(packet,len);
+               if(len<1)test_failed();
+            }
+            out_samples = opus_decode(dec, packet, len, &outbuf[i<<1], MAX_FRAME_SAMP, 0);
+            if(out_samples!=frame_size)test_failed();
+            if(opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed();
+            if(enc_final_range!=dec_final_range)test_failed();
+            /*LBRR decode*/
+            out_samples = opus_decode(dec_err[0], packet, len, out2buf, frame_size, (fast_rand()&3)!=0);
+            if(out_samples!=frame_size)test_failed();
+            out_samples = opus_decode(dec_err[1], packet, (fast_rand()&3)==0?0:len, out2buf, MAX_FRAME_SAMP, (fast_rand()&7)!=0);
+            if(out_samples<120)test_failed();
+            i+=frame_size;
+            count++;
+         }while(i<(SSAMPLES-MAX_FRAME_SAMP));
+         fprintf(stdout,"    Mode %s FB encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate);
+      }
+   }
+
+   if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(OPUS_AUTO))!=OPUS_OK)test_failed();
+   if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO))!=OPUS_OK)test_failed();
+   if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0))!=OPUS_OK)test_failed();
+   if(opus_encoder_ctl(enc, OPUS_SET_DTX(0))!=OPUS_OK)test_failed();
+
+   for(rc=0;rc<3;rc++)
+   {
+      if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR(rc<2))!=OPUS_OK)test_failed();
+      if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed();
+      if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed();
+      if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed();
+      for(j=0;j<16;j++)
+      {
+         int rate;
+         int modes[16]={0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2};
+         int rates[16]={4000,12000,32000,8000,16000,32000,48000,88000,4000,12000,32000,8000,16000,32000,48000,88000};
+         int frame[16]={160*1,160,80,160,160,80,40,20,160*1,160,80,160,160,80,40,20};
+         if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0&&j==1))!=OPUS_OK)test_failed();
+         if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_FORCE_MODE(MODE_SILK_ONLY+modes[j]))!=OPUS_OK)test_failed();
+         rate=rates[j]+fast_rand()%rates[j];
+         if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_DTX(fast_rand()&1))!=OPUS_OK)test_failed();
+         if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_BITRATE(rate))!=OPUS_OK)test_failed();
+         count=i=0;
+         do {
+            int pred,len,out_samples,frame_size,loss;
+            if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_PREDICTION_DISABLED(&pred))!=OPUS_OK)test_failed();
+            if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PREDICTION_DISABLED((int)(fast_rand()&15)<(pred?11:4)))!=OPUS_OK)test_failed();
+            frame_size=frame[j];
+            if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed();
+            if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed();
+            if((fast_rand()&255)==0)
+            {
+               if(opus_multistream_encoder_ctl(MSenc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+               if(opus_multistream_decoder_ctl(MSdec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+               if((fast_rand()&3)!=0)
+               {
+                  if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+               }
+            }
+            if((fast_rand()&255)==0)
+            {
+               if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+            }
+            len = opus_multistream_encode(MSenc, &inbuf[i<<1], frame_size, packet, MAX_PACKET);
+            if(len<0 || len>MAX_PACKET)test_failed();
+            if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed();
+            if((fast_rand()&3)==0)
+            {
+               if(opus_multistream_packet_pad(packet,len,len+1,2)!=OPUS_OK)test_failed();
+               len++;
+            }
+            if((fast_rand()&7)==0)
+            {
+               if(opus_multistream_packet_pad(packet,len,len+256,2)!=OPUS_OK)test_failed();
+               len+=256;
+            }
+            if((fast_rand()&3)==0)
+            {
+               len=opus_multistream_packet_unpad(packet,len,2);
+               if(len<1)test_failed();
+            }
+            out_samples = opus_multistream_decode(MSdec, packet, len, out2buf, MAX_FRAME_SAMP, 0);
+            if(out_samples!=frame_size*6)test_failed();
+            if(opus_multistream_decoder_ctl(MSdec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed();
+            if(enc_final_range!=dec_final_range)test_failed();
+            /*LBRR decode*/
+            loss=(fast_rand()&63)==0;
+            out_samples = opus_multistream_decode(MSdec_err, packet, loss?0:len, out2buf, frame_size*6, (fast_rand()&3)!=0);
+            if(out_samples!=(frame_size*6))test_failed();
+            i+=frame_size;
+            count++;
+         }while(i<(SSAMPLES/12-MAX_FRAME_SAMP));
+         fprintf(stdout,"    Mode %s NB dual-mono MS encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate);
+      }
+   }
+
+   bitrate_bps=512000;
+   fsize=fast_rand()%31;
+   fswitch=100;
+
+   debruijn2(6,db62);
+   count=i=0;
+   do {
+      unsigned char toc;
+      const unsigned char *frames[48];
+      short size[48];
+      int payload_offset;
+      opus_uint32 dec_final_range2;
+      int jj,dec2;
+      int len,out_samples;
+      int frame_size=fsizes[db62[fsize]];
+      opus_int32 offset=i%(SAMPLES-MAX_FRAME_SAMP);
+
+      opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
+
+      len = opus_encode(enc, &inbuf[offset<<1], frame_size, packet, MAX_PACKET);
+      if(len<0 || len>MAX_PACKET)test_failed();
+      count++;
+
+      opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range));
+
+      out_samples = opus_decode(dec, packet, len, &outbuf[offset<<1], MAX_FRAME_SAMP, 0);
+      if(out_samples!=frame_size)test_failed();
+
+      opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
+
+      /* compare final range encoder rng values of encoder and decoder */
+      if(dec_final_range!=enc_final_range)test_failed();
+
+      /* We fuzz the packet, but take care not to only corrupt the payload
+         Corrupted headers are tested elsewhere and we need to actually run
+         the decoders in order to compare them. */
+      if(opus_packet_parse(packet,len,&toc,frames,size,&payload_offset)<=0)test_failed();
+      if((fast_rand()&1023)==0)len=0;
+      for(j=(frames[0]-packet);j<len;j++)for(jj=0;jj<8;jj++)packet[j]^=((!no_fuzz)&&((fast_rand()&1023)==0))<<jj;
+      out_samples = opus_decode(dec_err[0], len>0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0);
+      if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed();
+      if((len>0&&out_samples!=frame_size))test_failed(); /*FIXME use lastframe*/
+
+      opus_decoder_ctl(dec_err[0], OPUS_GET_FINAL_RANGE(&dec_final_range));
+
+      /*randomly select one of the decoders to compare with*/
+      dec2=fast_rand()%9+1;
+      out_samples = opus_decode(dec_err[dec2], len>0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0);
+      if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); /*FIXME, use factor, lastframe for loss*/
+
+      opus_decoder_ctl(dec_err[dec2], OPUS_GET_FINAL_RANGE(&dec_final_range2));
+      if(len>0&&dec_final_range!=dec_final_range2)test_failed();
+
+      fswitch--;
+      if(fswitch<1)
+      {
+        int new_size;
+        fsize=(fsize+1)%36;
+        new_size=fsizes[db62[fsize]];
+        if(new_size==960||new_size==480)fswitch=2880/new_size*(fast_rand()%19+1);
+        else fswitch=(fast_rand()%(2880/new_size))+1;
+      }
+      bitrate_bps=((fast_rand()%508000+4000)+bitrate_bps)>>1;
+      i+=frame_size;
+   }while(i<SAMPLES*4);
+   fprintf(stdout,"    All framesize pairs switching encode, %d frames OK.\n",count);
+
+   if(opus_encoder_ctl(enc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+   opus_encoder_destroy(enc);
+   if(opus_multistream_encoder_ctl(MSenc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+   opus_multistream_encoder_destroy(MSenc);
+   if(opus_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+   opus_decoder_destroy(dec);
+   if(opus_multistream_decoder_ctl(MSdec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
+   opus_multistream_decoder_destroy(MSdec);
+   opus_multistream_decoder_destroy(MSdec_err);
+   for(i=0;i<10;i++)opus_decoder_destroy(dec_err[i]);
+   free(inbuf);
+   free(outbuf);
+   free(out2buf);
+   return 0;
+}
+
+int main(int _argc, char **_argv)
+{
+   const char * oversion;
+   const char * env_seed;
+   int env_used;
+
+   if(_argc>2)
+   {
+      fprintf(stderr,"Usage: %s [<seed>]\n",_argv[0]);
+      return 1;
+   }
+
+   env_used=0;
+   env_seed=getenv("SEED");
+   if(_argc>1)iseed=atoi(_argv[1]);
+   else if(env_seed)
+   {
+      iseed=atoi(env_seed);
+      env_used=1;
+   }
+   else iseed=(opus_uint32)time(NULL)^((getpid()&65535)<<16);
+   Rw=Rz=iseed;
+
+   oversion=opus_get_version_string();
+   if(!oversion)test_failed();
+   fprintf(stderr,"Testing %s encoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535);
+   if(env_used)fprintf(stderr,"  Random seed set from the environment (SEED=%s).\n", env_seed);
+
+   /*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data
+     into the decoders. This is helpful because garbage data
+     may cause the decoders to clip, which angers CLANG IOC.*/
+   run_test1(getenv("TEST_OPUS_NOFUZZ")!=NULL);
+
+   fprintf(stderr,"Tests completed successfully.\n");
+
+   return 0;
+}
diff --git a/third_party/opus/src/tests/test_opus_padding.c b/third_party/opus/src/tests/test_opus_padding.c
new file mode 100644
index 0000000..c22e8f0
--- /dev/null
+++ b/third_party/opus/src/tests/test_opus_padding.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2012 Xiph.Org Foundation
+   Written by Jüri Aedla and Ralph Giles */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Check for overflow in reading the padding length.
+ * http://lists.xiph.org/pipermail/opus/2012-November/001834.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "opus.h"
+#include "test_opus_common.h"
+
+#define PACKETSIZE 16909318
+#define CHANNELS 2
+#define FRAMESIZE 5760
+
+int test_overflow(void)
+{
+  OpusDecoder *decoder;
+  int result;
+  int error;
+
+  unsigned char *in = malloc(PACKETSIZE);
+  opus_int16 *out = malloc(FRAMESIZE*CHANNELS*sizeof(*out));
+
+  fprintf(stderr, "  Checking for padding overflow... ");
+  if (!in || !out) {
+    fprintf(stderr, "FAIL (out of memory)\n");
+    return -1;
+  }
+  in[0] = 0xff;
+  in[1] = 0x41;
+  memset(in + 2, 0xff, PACKETSIZE - 3);
+  in[PACKETSIZE-1] = 0x0b;
+
+  decoder = opus_decoder_create(48000, CHANNELS, &error);
+  result = opus_decode(decoder, in, PACKETSIZE, out, FRAMESIZE, 0);
+  opus_decoder_destroy(decoder);
+
+  free(in);
+  free(out);
+
+  if (result != OPUS_INVALID_PACKET) {
+    fprintf(stderr, "FAIL!\n");
+    test_failed();
+  }
+
+  fprintf(stderr, "OK.\n");
+
+  return 1;
+}
+
+int main(void)
+{
+  const char *oversion;
+  int tests = 0;;
+
+  iseed = 0;
+  oversion = opus_get_version_string();
+  if (!oversion) test_failed();
+  fprintf(stderr, "Testing %s padding.\n", oversion);
+
+  tests += test_overflow();
+
+  fprintf(stderr, "All padding tests passed.\n");
+
+  return 0;
+}
diff --git a/third_party/opus/src/win32/genversion.bat b/third_party/opus/src/win32/genversion.bat
new file mode 100755
index 0000000..cd1d4dc
--- /dev/null
+++ b/third_party/opus/src/win32/genversion.bat
@@ -0,0 +1,46 @@
+@echo off
+
+setlocal enableextensions enabledelayedexpansion
+
+for /f %%v in ('git --git-dir="%~dp0..\.git" describe --tags --match "v*"') do set version=%%v
+
+if not "%version%"=="" goto :gotversion
+
+if exist "%~dp0..\version.mk" goto :getversion
+
+echo Git cannot be found, nor can version.mk. Generating unknown version.
+
+set version=unknown
+
+goto :gotversion
+
+:getversion
+
+for /f "delims== tokens=2" %%v in (%~dps0..\version.mk) do set version=%%v
+
+set version=!version:^"=!
+set version=!version: =!
+
+:gotversion
+
+set version_out=#define %~2 "%version%"
+set version_mk=%~2 = "%version%"
+
+echo %version_out%> "%~1_temp"
+
+if %version%==unknown goto :skipgenerate
+
+echo # static version string; update manually every release.> "%~dp0..\version.mk"
+echo %version_mk%>> "%~dp0..\version.mk"
+
+:skipgenerate
+
+echo n | comp "%~1_temp" "%~1" > NUL 2> NUL
+
+if not errorlevel 1 goto exit
+
+copy /y "%~1_temp" "%~1"
+
+:exit
+
+del "%~1_temp"
diff --git a/third_party/ots/README b/third_party/ots/README
index 8dc1ebb8..4a0fa1a2 100644
--- a/third_party/ots/README
+++ b/third_party/ots/README
@@ -1,21 +1,35 @@
-Sanitiser for OpenType
-----------------------
+OpenType Sanitiser
+==================
 
-(Idea from Alex Russell)
+The OpenType Sanitiser (OTS) parses and serialises OpenType files (OTF, TTF)
+and WOFF and WOFF2 font files, validating them and sanitising them as it goes.
 
-The CSS font-face property[1] is great for web typography. Having to use images
+The C library is integrated into Chromium and Firefox, and also simple
+command line tools to check files offline in a Terminal.
+
+The CSS [font-face property][1] is great for web typography. Having to use images
 in order to get the correct typeface is a great sadness; one should be able to
 use vectors.
 
-However, the TrueType renderers on many platforms have never been part of the
-attack surface before and putting them on the front line is a scary proposition.
-Esp on platforms like Windows where it's a closed-source blob running with high
-privilege.
+However, on many platforms the system-level TrueType font renderers have never
+been part of the attack surface before, and putting them on the front line is
+a scary proposition... Especially on platforms like Windows, where it's a
+closed-source blob running with high privilege.
 
-Thus, the OpenType Sanitiser (OTS) is designed to parse and serialise OpenType
-files, validating them and sanitising them as it goes.
+Installation
+------------
 
+See [INSTALL][2]
 
-See INSTALL for build instructions.
+Usage
+-----
 
-[1] http://www.w3.org/TR/CSS2/fonts.html#font-descriptions
+See [docs][3]
+
+* * *
+
+Thanks to Alex Russell for the original idea.
+
+[1]: http://www.w3.org/TR/CSS2/fonts.html#font-descriptions
+[2]: https://github.com/khaledhosny/ots/tree/master/INSTALL
+[3]: https://github.com/khaledhosny/ots/tree/master/docs/
diff --git a/third_party/ots/README.chromium b/third_party/ots/README.chromium
index 60dbf4c..35dec35 100644
--- a/third_party/ots/README.chromium
+++ b/third_party/ots/README.chromium
@@ -1,6 +1,6 @@
 Name: OTS (OpenType Sanitizer)
 URL: https://github.com/khaledhosny/ots.git
-Version: 8ade3d16fbb0273e7f828191b4ad37b3819ce302
+Version: 8d70cffebbfa58f67a5c3ed0e9bc84dccdbc5bc0
 Security Critical: yes
 License: BSD
 
diff --git a/third_party/ots/src/cmap.cc b/third_party/ots/src/cmap.cc
index cbb5f3c3..325f8e0 100644
--- a/third_party/ots/src/cmap.cc
+++ b/third_party/ots/src/cmap.cc
@@ -658,20 +658,21 @@
   }
 
   // check if the table is sorted first by platform ID, then by encoding ID.
-  uint32_t last_id = 0;
-  for (unsigned i = 0; i < num_tables; ++i) {
-    uint32_t current_id
-        = (subtable_headers[i].platform << 24)
-        + (subtable_headers[i].encoding << 16)
-        + subtable_headers[i].language;
-    if ((i != 0) && (last_id >= current_id)) {
+  for (unsigned i = 1; i < num_tables; ++i) {
+    if (subtable_headers[i - 1].platform > subtable_headers[i].platform ||
+        (subtable_headers[i - 1].platform == subtable_headers[i].platform &&
+         (subtable_headers[i - 1].encoding > subtable_headers[i].encoding ||
+          (subtable_headers[i - 1].encoding == subtable_headers[i].encoding &&
+           subtable_headers[i - 1].language > subtable_headers[i].language))))
       OTS_WARNING("subtable %d with platform ID %d, encoding ID %d, language ID %d "
                   "following subtable with platform ID %d, encoding ID %d, language ID %d",
                   i,
-                  (uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id),
-                  (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id));
-    }
-    last_id = current_id;
+                  subtable_headers[i].platform,
+                  subtable_headers[i].encoding,
+                  subtable_headers[i].language,
+                  subtable_headers[i - 1].platform,
+                  subtable_headers[i - 1].encoding,
+                  subtable_headers[i - 1].language);
   }
 
   // Now, verify that all the lengths are sane
diff --git a/third_party/ots/src/math.cc b/third_party/ots/src/math.cc
index 0688071..36417dc 100644
--- a/third_party/ots/src/math.cc
+++ b/third_party/ots/src/math.cc
@@ -448,6 +448,11 @@
                                         uint16_t offset_coverage,
                                         uint16_t glyph_count,
                                         const unsigned sequence_end) {
+  // Zero glyph count, nothing to parse.
+  if (!glyph_count) {
+    return true;
+  }
+
   // Check coverage table.
   if (offset_coverage < sequence_end || offset_coverage >= length) {
     return OTS_FAILURE();
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index a7196497..279ed57 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -470,7 +470,6 @@
   ldflags = []
 
   base_cmake_args = ['-GNinja',
-                     '-DCMAKE_BUILD_TYPE=Release',
                      '-DLLVM_ENABLE_ASSERTIONS=ON',
                      '-DLLVM_ENABLE_THREADS=OFF',
                      '-DLLVM_ENABLE_TIMESTAMPS=OFF',
@@ -478,6 +477,13 @@
                      '-DLLVM_USE_CRT_RELEASE=MT',
                      ]
 
+  if use_head_revision:
+    # For ToT builds, which are used to catch compiler bugs early, enable debug
+    # info for better backtraces when crashing.
+    base_cmake_args += ['-DCMAKE_BUILD_TYPE=RelWithDebInfo']
+  else:
+    base_cmake_args += ['-DCMAKE_BUILD_TYPE=Release']
+
   binutils_incdir = ''
   if sys.platform.startswith('linux'):
     binutils_incdir = os.path.join(BINUTILS_DIR, 'Linux_x64/Release/include')
@@ -652,11 +658,13 @@
     # If any Chromium tools were built, install those now.
     RunCommand(['ninja', 'cr-install'], msvc_arch='x64')
 
-  if sys.platform == 'darwin':
-    # See http://crbug.com/256342
-    RunCommand(['strip', '-x', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
-  elif sys.platform.startswith('linux'):
-    RunCommand(['strip', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
+  if not use_head_revision:
+    # Strip the binaries to save size, except for ToT builds.
+    if sys.platform == 'darwin':
+      # See http://crbug.com/256342
+      RunCommand(['strip', '-x', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
+    elif sys.platform.startswith('linux'):
+      RunCommand(['strip', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
 
   # TODO(thakis): Check that `clang --version` matches VERSION.
 
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c3a41fc..cba61b4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -16730,6 +16730,16 @@
   </summary>
 </histogram>
 
+<histogram name="FileBrowser.QuickView.FileType" enum="ViewFileType">
+  <owner>oka@google.com</owner>
+  <summary>File types that were tried to be opened with quick view.</summary>
+</histogram>
+
+<histogram name="FileBrowser.QuickView.VolumeType" enum="FileManagerVolumeType">
+  <owner>oka@google.com</owner>
+  <summary>The volume type where quick view is opened.</summary>
+</histogram>
+
 <histogram name="FileBrowser.SuggestApps.Close"
     enum="SuggestAppsDialogCloseReason">
   <owner>joshwoodward@google.com</owner>
diff --git a/tools/perf/benchmarks/memory_infra.py b/tools/perf/benchmarks/memory_infra.py
index f371f44..11947a6 100644
--- a/tools/perf/benchmarks/memory_infra.py
+++ b/tools/perf/benchmarks/memory_infra.py
@@ -165,6 +165,12 @@
     return (not _IGNORED_STATS_RE.search(value.name) and
             'renderer_processes' in value.name)
 
+  @classmethod
+  def ShouldDisable(cls, possible_browser):
+    # http://crbug.com/634319
+    return (possible_browser.browser_type == 'reference' and
+            possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X')
+
 
 class _MemoryV8Benchmark(_MemoryInfra):
 
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py
index 6a3ce42..e1632e57 100644
--- a/tools/perf/benchmarks/power.py
+++ b/tools/perf/benchmarks/power.py
@@ -44,6 +44,7 @@
 
 
 @benchmark.Enabled('android')
+@benchmark.Disabled('android-webview')  # http://crbug.com/622300
 class PowerToughAdCases(perf_benchmark.PerfBenchmark):
   """Android power test with tough ad pages."""
   test = power.Power
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index 2d80785..815143c7 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -55,6 +55,10 @@
     # is able to cope with the data load generated by TBMv2 metrics.
     return not _IGNORED_STATS_RE.search(value.name)
 
+  @classmethod
+  def ShouldDisable(cls, possible_browser):
+    return cls.IsSvelte(possible_browser)  # http://crbug.com/634112
+
 
 class DesktopMemorySystemHealth(_MemorySystemHealthBenchmark):
   """Desktop Chrome Memory System Health Benchmark."""
diff --git a/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm b/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
index 2fcab68b..9128367 100644
--- a/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
+++ b/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
@@ -39,7 +39,6 @@
   float scale_factor = 1.0f;
   unsigned filter = GL_LINEAR;
   scoped_refptr<gl::GLImageIOSurface> gl_image;
-  ui::CARendererLayerParams::FilterEffects filter_effects;
 };
 
 scoped_refptr<gl::GLImageIOSurface> CreateGLImage(const gfx::Size& size,
@@ -63,14 +62,12 @@
 
 bool ScheduleCALayer(ui::CARendererLayerTree* tree,
                      CALayerProperties* properties) {
-  ui::CARendererLayerParams params = ui::CARendererLayerParams(
+  return tree->ScheduleCALayer(ui::CARendererLayerParams(
       properties->is_clipped, properties->clip_rect,
       properties->sorting_context_id, properties->transform,
       properties->gl_image.get(), properties->contents_rect, properties->rect,
       properties->background_color, properties->edge_aa_mask,
-      properties->opacity, properties->filter);
-  params.filter_effects = properties->filter_effects;
-  return tree->ScheduleCALayer(params);
+      properties->opacity, properties->filter));
 }
 
 void UpdateCALayerTree(std::unique_ptr<ui::CARendererLayerTree>& ca_layer_tree,
@@ -365,34 +362,6 @@
     EXPECT_NSEQ(kCAFilterNearest, [content_layer magnificationFilter]);
   }
 
-  // Add every filter effect.
-  {
-    using FilterEffectType = ui::CARendererLayerParams::FilterEffectType;
-    for (int i = static_cast<int>(FilterEffectType::MIN);
-         i <= static_cast<int>(FilterEffectType::MAX); i++) {
-      ui::CARendererLayerParams::FilterEffect filter_effect;
-      filter_effect.type = static_cast<FilterEffectType>(i);
-      filter_effect.amount = i * 0.05 + 0.1;
-      properties.filter_effects.push_back(filter_effect);
-    }
-    UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
-    // Validate the content layer.
-    EXPECT_EQ(9u, [[content_layer filters] count]);
-    EXPECT_GT([content_layer shadowRadius], 0.0);
-    EXPECT_LT([content_layer shadowRadius], 1.0);
-  }
-
-  // Remove every filter effect.
-  {
-    properties.filter_effects.clear();
-    UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
-    // Validate the content layer.
-    EXPECT_EQ(0u, [[content_layer filters] count]);
-    EXPECT_EQ(0.0, [content_layer shadowRadius]);
-  }
-
   // Add the clipping and IOSurface contents back.
   {
     properties.is_clipped = true;
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
index 87f93122..cb9d092 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
@@ -19,7 +19,6 @@
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/mac/io_surface.h"
 #include "ui/gfx/transform.h"
-#include "ui/gl/ca_renderer_layer_params.h"
 
 @class AVSampleBufferDisplayLayer;
 
@@ -142,8 +141,7 @@
                  unsigned background_color,
                  unsigned edge_aa_mask,
                  float opacity,
-                 unsigned filter,
-                 const CARendererLayerParams::FilterEffects& filter_effects);
+                 unsigned filter);
     ContentLayer(ContentLayer&& layer);
 
     // See the behavior of RootLayer for the effects of these functions on the
@@ -173,9 +171,6 @@
     base::scoped_nsobject<AVSampleBufferDisplayLayer> av_layer;
     bool use_av_layer = false;
 
-    // Filter effects to apply to this layer.
-    CARendererLayerParams::FilterEffects filter_effects;
-
    private:
     DISALLOW_COPY_AND_ASSIGN(ContentLayer);
   };
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
index 654d281..dcc8cca2 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
@@ -16,6 +16,7 @@
 #include "ui/base/cocoa/animation_utils.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/gfx/geometry/dip_util.h"
+#include "ui/gl/ca_renderer_layer_params.h"
 #include "ui/gl/gl_image_io_surface.h"
 
 #if !defined(MAC_OS_X_VERSION_10_8) || \
@@ -45,61 +46,10 @@
 extern const CMTime kCMTimeInvalid;
 #endif  // MAC_OS_X_VERSION_10_8
 
-// CAFilter and CAColorMatrix are QuartzCore SPI.
-@interface CAFilter : NSObject<NSCopying, NSMutableCopying, NSCoding>
-@end
-
-@interface CAFilter (QuartzCoreSPI)
-+ (CAFilter*)filterWithType:(NSString*)type;
-@end
-
-// TODO(erikchen): Test out the named filter kCAFilterColorInvert.
-// https://crbug.com/581526.
-extern NSString* const kCAFilterColorMatrix;
-extern NSString* const kCAFilterColorMonochrome;
-extern NSString* const kCAFilterColorHueRotate;
-extern NSString* const kCAFilterColorSaturate;
-extern NSString* const kCAFilterGaussianBlur;
-
-struct CAColorMatrix {
-  float m11, m12, m13, m14, m15;
-  float m21, m22, m23, m24, m25;
-  float m31, m32, m33, m34, m35;
-  float m41, m42, m43, m44, m45;
-};
-typedef struct CAColorMatrix CAColorMatrix;
-
-@interface NSValue (QuartzCoreSPI)
-+ (NSValue*)valueWithCAColorMatrix:(CAColorMatrix)t;
-@end
-
 namespace ui {
 
 namespace {
 
-float Blend(float from, float to, float progress) {
-  return from + (to - from) * progress;
-}
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-double DegreeToRadians(double degree)  { return degree * M_PI / 180.0; }
-
-// These values were obtained from https://www.w3.org/TR/filter-effects/.
-static const double kSepiaFullConstants[3][3] = {
-  { 0.393, 0.769, 0.189 },
-  { 0.349, 0.686, 0.168 },
-  { 0.272, 0.534, 0.131 }
-};
-
-static const double kSepiaNoneConstants[3][3] = {
-  { 1, 0, 0 },
-  { 0, 1, 0 },
-  { 0, 0, 1 }
-};
-
 // This will enqueue |io_surface| to be drawn by |av_layer|. This will
 // retain |cv_pixel_buffer| until it is no longer being displayed.
 bool AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(
@@ -177,161 +127,6 @@
                                                         cv_pixel_buffer);
 }
 
-// If the filter effect can be represented as a named filter, return it.
-// Otherwise, return nil.
-CAFilter* NamedFilterForType(CARendererLayerParams::FilterEffectType type,
-                             float amount) {
-  CAFilter* filter = nil;
-  switch (type) {
-    case CARendererLayerParams::FilterEffectType::GRAYSCALE:
-      filter = [CAFilter filterWithType:kCAFilterColorMonochrome];
-      [filter setValue:@(amount) forKey:@"inputAmount"];
-      break;
-    case CARendererLayerParams::FilterEffectType::SATURATE:
-      filter = [CAFilter filterWithType:kCAFilterColorSaturate];
-      [filter setValue:@(amount) forKey:@"inputAmount"];
-      break;
-    case CARendererLayerParams::FilterEffectType::HUE_ROTATE:
-      filter = [CAFilter filterWithType:kCAFilterColorHueRotate];
-      [filter setValue:@(DegreeToRadians(amount)) forKey:@"inputAngle"];
-      break;
-    case CARendererLayerParams::FilterEffectType::BLUR:
-      filter = [CAFilter filterWithType:kCAFilterGaussianBlur];
-      [filter setValue:@(amount) forKey:@"inputRadius"];
-      break;
-    default:
-      break;
-  }
-  return filter;
-}
-
-// If the filter effect has a corresponding color matrix, return it. Otherwise,
-// return nil.
-NSValue* ColorMatrixForType(CARendererLayerParams::FilterEffectType type,
-                            float amount) {
-  switch (type) {
-    case CARendererLayerParams::FilterEffectType::SEPIA:
-    {
-      float t = std::min(std::max(0.0f, amount), 1.0f);
-      CAColorMatrix colorMatrix = {
-        Blend(kSepiaNoneConstants[0][0], kSepiaFullConstants[0][0], t),
-        Blend(kSepiaNoneConstants[0][1], kSepiaFullConstants[0][1], t),
-        Blend(kSepiaNoneConstants[0][2], kSepiaFullConstants[0][2], t),
-        0, 0,
-
-        Blend(kSepiaNoneConstants[1][0], kSepiaFullConstants[1][0], t),
-        Blend(kSepiaNoneConstants[1][1], kSepiaFullConstants[1][1], t),
-        Blend(kSepiaNoneConstants[1][2], kSepiaFullConstants[1][2], t),
-        0, 0,
-
-        Blend(kSepiaNoneConstants[2][0], kSepiaFullConstants[2][0], t),
-        Blend(kSepiaNoneConstants[2][1], kSepiaFullConstants[2][1], t),
-        Blend(kSepiaNoneConstants[2][2], kSepiaFullConstants[2][2], t),
-        0, 0, 0, 0, 0, 1, 0
-      };
-      return [NSValue valueWithCAColorMatrix:colorMatrix];
-    }
-    case CARendererLayerParams::FilterEffectType::INVERT:
-    {
-      float multiplier = 1 - amount * 2;
-      CAColorMatrix colorMatrix = {
-        multiplier, 0, 0, 0, amount,
-        0, multiplier, 0, 0, amount,
-        0, 0, multiplier, 0, amount,
-        0, 0, 0, 1, 0
-      };
-      return [NSValue valueWithCAColorMatrix:colorMatrix];
-    }
-    case CARendererLayerParams::FilterEffectType::BRIGHTNESS:
-    {
-      CAColorMatrix colorMatrix = {
-        amount, 0, 0, 0, 0,
-        0, amount, 0, 0, 0,
-        0, 0, amount, 0, 0,
-        0, 0, 0, 1, 0
-      };
-      return [NSValue valueWithCAColorMatrix:colorMatrix];
-    }
-    case CARendererLayerParams::FilterEffectType::CONTRAST:
-    {
-      float intercept = -0.5 * amount + 0.5;
-      CAColorMatrix colorMatrix = {
-        amount, 0, 0, 0, intercept,
-        0, amount, 0, 0, intercept,
-        0, 0, amount, 0, intercept,
-        0, 0, 0, 1, 0
-      };
-      return [NSValue valueWithCAColorMatrix:colorMatrix];
-    }
-    case CARendererLayerParams::FilterEffectType::OPACITY:
-    {
-      CAColorMatrix colorMatrix = {
-        1, 0, 0, 0, 0,
-        0, 1, 0, 0, 0,
-        0, 0, 1, 0, 0,
-        0, 0, 0, amount, 0
-      };
-      return [NSValue valueWithCAColorMatrix:colorMatrix];
-    }
-    default:
-      return nil;
-  }
-}
-
-// Updates the CALayer to accurately represent the given |filter_effects|.
-void UpdateFiltersOnCALayer(
-    const CARendererLayerParams::FilterEffects& filter_effects,
-    CALayer* layer) {
-  if (filter_effects.empty()) {
-    // It's possible that this enables shadow properties, even if there were
-    // none before. That's an implementation detail of Core Animation.
-    [layer setShadowOffset:CGSizeZero];
-    [layer setShadowColor:nil];
-    [layer setShadowRadius:0];
-    [layer setShadowOpacity:0];
-    layer.filters = @[];
-    return;
-  }
-
-  NSMutableArray* filters = [NSMutableArray array];
-  for (const CARendererLayerParams::FilterEffect& filter_effect :
-       filter_effects) {
-    CAFilter* filter =
-        NamedFilterForType(filter_effect.type, filter_effect.amount);
-    if (filter) {
-      [filters addObject:filter];
-      continue;
-    }
-
-    NSValue* color_matrix =
-        ColorMatrixForType(filter_effect.type, filter_effect.amount);
-    if (color_matrix) {
-      CAFilter* filter = [CAFilter filterWithType:kCAFilterColorMatrix];
-      [filter setValue:color_matrix forKey:@"inputColorMatrix"];
-      [filters addObject:filter];
-      continue;
-    }
-
-    DCHECK_EQ(CARendererLayerParams::FilterEffectType::DROP_SHADOW,
-              filter_effect.type);
-    [layer setShadowOffset:CGSizeMake(filter_effect.drop_shadow_offset.x(),
-                                      filter_effect.drop_shadow_offset.y())];
-
-    CGFloat rgba_color_components[4] = {
-        SkColorGetR(filter_effect.drop_shadow_color) / 255.,
-        SkColorGetG(filter_effect.drop_shadow_color) / 255.,
-        SkColorGetB(filter_effect.drop_shadow_color) / 255.,
-        SkColorGetA(filter_effect.drop_shadow_color) / 255.,
-    };
-    base::ScopedCFTypeRef<CGColorRef> srgb_color(CGColorCreate(
-        CGColorSpaceCreateWithName(kCGColorSpaceSRGB), rgba_color_components));
-    [layer setShadowColor:srgb_color.get()];
-    [layer setShadowRadius:filter_effect.amount];
-    [layer setShadowOpacity:1];
-  }
-  layer.filters = filters;
-}
-
 }  // namespace
 
 CARendererLayerTree::CARendererLayerTree() {}
@@ -479,8 +274,7 @@
     unsigned background_color,
     unsigned edge_aa_mask,
     float opacity,
-    unsigned filter,
-    const CARendererLayerParams::FilterEffects& filter_effects)
+    unsigned filter)
     : io_surface(io_surface),
       cv_pixel_buffer(cv_pixel_buffer),
       contents_rect(contents_rect),
@@ -488,8 +282,7 @@
       background_color(background_color),
       ca_edge_aa_mask(0),
       opacity(opacity),
-      ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest),
-      filter_effects(filter_effects) {
+      ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) {
   DCHECK(filter == GL_LINEAR || filter == GL_NEAREST);
 
   // Because the root layer has setGeometryFlipped:YES, there is some ambiguity
@@ -536,8 +329,7 @@
       ca_filter(layer.ca_filter),
       ca_layer(std::move(layer.ca_layer)),
       av_layer(std::move(layer.av_layer)),
-      use_av_layer(layer.use_av_layer),
-      filter_effects(layer.filter_effects) {
+      use_av_layer(layer.use_av_layer) {
   DCHECK(!layer.ca_layer);
   DCHECK(!layer.av_layer);
 }
@@ -615,7 +407,7 @@
   content_layers.push_back(
       ContentLayer(io_surface, cv_pixel_buffer, params.contents_rect,
                    params.rect, params.background_color, params.edge_aa_mask,
-                   params.opacity, params.filter, params.filter_effects));
+                   params.opacity, params.filter));
 }
 
 void CARendererLayerTree::RootLayer::CommitToCA(CALayer* superlayer,
@@ -743,9 +535,6 @@
   bool update_ca_edge_aa_mask = true;
   bool update_opacity = true;
   bool update_ca_filter = true;
-  bool update_filter_effects =
-      (old_layer && !old_layer->filter_effects.empty()) ||
-      !filter_effects.empty();
   if (old_layer && old_layer->use_av_layer == use_av_layer) {
     DCHECK(old_layer->ca_layer);
     std::swap(ca_layer, old_layer->ca_layer);
@@ -758,7 +547,6 @@
     update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask;
     update_opacity = old_layer->opacity != opacity;
     update_ca_filter = old_layer->ca_filter != ca_filter;
-    update_filter_effects = old_layer->filter_effects != filter_effects;
   } else {
     if (use_av_layer) {
       av_layer.reset([[AVSampleBufferDisplayLayer alloc] init]);
@@ -777,7 +565,7 @@
   bool update_anything = update_contents || update_contents_rect ||
                          update_rect || update_background_color ||
                          update_ca_edge_aa_mask || update_opacity ||
-                         update_ca_filter || update_filter_effects;
+                         update_ca_filter;
   if (use_av_layer) {
     if (update_contents) {
       if (cv_pixel_buffer) {
@@ -821,9 +609,6 @@
     [ca_layer setMagnificationFilter:ca_filter];
     [ca_layer setMinificationFilter:ca_filter];
   }
-  if (update_filter_effects) {
-    UpdateFiltersOnCALayer(filter_effects, ca_layer.get());
-  }
 
   static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kShowMacOverlayBorders);
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 92f3af1..4a3b7c0 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -516,9 +516,16 @@
 
   // Compares two nodes in an accessibility tree in pre-order traversal.
   enum AXTreeOrder {
-    undefined,  // Not in the same tree, or other error.
-    before,     // First node is before the second one.
-    equal,      // Nodes are the same.
-    after       // First node is after the second one.
+    // Not in the same tree, or other error.
+    undefined,
+
+    // First node is before the second one.
+    before,
+
+    // Nodes are the same.
+    equal,
+
+    // First node is after the second one.
+    after
   };
 };
diff --git a/ui/android/window_android.cc b/ui/android/window_android.cc
index c437c66..5aa9e400 100644
--- a/ui/android/window_android.cc
+++ b/ui/android/window_android.cc
@@ -17,6 +17,7 @@
 namespace ui {
 
 using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
 using base::android::JavaRef;
 using base::android::ScopedJavaLocalRef;
 
diff --git a/ui/base/l10n/l10n_util_android.cc b/ui/base/l10n/l10n_util_android.cc
index 6261969b..e78ebbd 100644
--- a/ui/base/l10n/l10n_util_android.cc
+++ b/ui/base/l10n/l10n_util_android.cc
@@ -17,6 +17,9 @@
 #include "third_party/icu/source/common/unicode/uloc.h"
 #include "ui/base/l10n/time_format.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace l10n_util {
 
 jint GetFirstStrongCharacterDirection(JNIEnv* env,
diff --git a/ui/chromeos/BUILD.gn b/ui/chromeos/BUILD.gn
index 69fd5c6..f57b983 100644
--- a/ui/chromeos/BUILD.gn
+++ b/ui/chromeos/BUILD.gn
@@ -94,4 +94,8 @@
     "//ui/views",
     "//ui/views:test_support",
   ]
+  data = [
+    "$root_out_dir/locales/en-US.pak",
+    "$root_out_dir/ui_test.pak",
+  ]
 }
diff --git a/ui/events/devices/BUILD.gn b/ui/events/devices/BUILD.gn
index 314a3ee..832f4dd 100644
--- a/ui/events/devices/BUILD.gn
+++ b/ui/events/devices/BUILD.gn
@@ -21,12 +21,15 @@
 
   defines = [ "EVENTS_DEVICES_IMPLEMENTATION" ]
 
+  public_deps = [
+    "//ui/gfx",
+  ]
+
   deps = [
     "//base",
     "//base/third_party/dynamic_annotations",
     "//skia",
     "//ui/display",
-    "//ui/gfx",
     "//ui/gfx/geometry",
   ]
 }
diff --git a/ui/file_manager/OWNERS b/ui/file_manager/OWNERS
index 85ce43d..30844727 100644
--- a/ui/file_manager/OWNERS
+++ b/ui/file_manager/OWNERS
@@ -1,5 +1,6 @@
 fukino@chromium.org
 hirono@chromium.org
 mtomasz@chromium.org
+oka@chromium.org
 yawano@chromium.org
 yoshiki@chromium.org
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
index 0597f03..caec6b2 100644
--- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
+++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -118,6 +118,7 @@
           './progress_center_item_group.js',
           './quick_view_controller.js',
           './quick_view_model.js',
+          './quick_view_uma.js',
           './scan_controller.js',
           './search_controller.js',
           './sort_menu_controller.js',
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 2ac4b44..e711f470 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -266,6 +266,12 @@
   this.columnVisibilityController_ = null;
 
   /**
+   * @type {QuickViewUma}
+   * @private
+   */
+  this.quickViewUma_ = null;
+
+  /**
    * @type {QuickViewController}
    * @private
    */
@@ -557,12 +563,15 @@
       chrome.commandLinePrivate.hasSwitch(
           'disable-files-quick-view', function(disabled) {
             if (!disabled) {
+              this.quickViewUma_ =
+                  new QuickViewUma(assert(this.volumeManager_));
               this.quickViewController_ = new QuickViewController(
                   quickView, assert(this.metadataModel_),
                   assert(this.selectionHandler_),
                   assert(this.ui_.listContainer), assert(this.quickViewModel_),
                   assert(this.taskController_),
-                  fileListSelectionModel);
+                  fileListSelectionModel,
+                  assert(this.quickViewUma_));
               this.metadataBoxController_ = new MetadataBoxController(
                   this.metadataModel_, quickView.getFilesMetadataBox(),
                   quickView, this.quickViewModel_, this.fileMetadataFormatter_);
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index 64381415..6ba5710b 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -235,9 +235,8 @@
  *
  * @const
  * @type {Array<string>}
- * @private
  */
-FileTasks.UMA_INDEX_KNOWN_EXTENSIONS_ = Object.freeze([
+FileTasks.UMA_INDEX_KNOWN_EXTENSIONS = Object.freeze([
   'other', '.3ga', '.3gp', '.aac', '.alac', '.asf', '.avi', '.bmp', '.csv',
   '.doc', '.docx', '.flac', '.gif', '.jpeg', '.jpg', '.log', '.m3u', '.m3u8',
   '.m4a', '.m4v', '.mid', '.mkv', '.mov', '.mp3', '.mp4', '.mpg', '.odf',
@@ -277,11 +276,11 @@
   for (var i = 0; i < entries.length; i++) {
     var entry = entries[i];
     var extension = FileType.getExtension(entry).toLowerCase();
-    if (FileTasks.UMA_INDEX_KNOWN_EXTENSIONS_.indexOf(extension) < 0) {
+    if (FileTasks.UMA_INDEX_KNOWN_EXTENSIONS.indexOf(extension) < 0) {
       extension = 'other';
     }
     metrics.recordEnum(
-        'ViewingFileType', extension, FileTasks.UMA_INDEX_KNOWN_EXTENSIONS_);
+        'ViewingFileType', extension, FileTasks.UMA_INDEX_KNOWN_EXTENSIONS);
   }
 };
 
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index 06b6956..ecfd5cc 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -132,6 +132,7 @@
 //<include src="progress_center_item_group.js">
 //<include src="quick_view_controller.js">
 //<include src="quick_view_model.js">
+//<include src="quick_view_uma.js">
 //<include src="scan_controller.js">
 //<include src="search_controller.js">
 //<include src="share_client.js">
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
index d68398af..d859d5fe 100644
--- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -12,12 +12,13 @@
  * @param {!QuickViewModel} quickViewModel
  * @param {!TaskController} taskController
  * @param {!cr.ui.ListSelectionModel} fileListSelectionModel
+ * @param {!QuickViewUma} quickViewUma
  *
  * @constructor
  */
 function QuickViewController(
     quickView, metadataModel, selectionHandler, listContainer, quickViewModel,
-    taskController, fileListSelectionModel) {
+    taskController, fileListSelectionModel, quickViewUma) {
   /**
    * @type {!FilesQuickView}
    * @private
@@ -31,6 +32,12 @@
   this.quickViewModel_ = quickViewModel;
 
   /**
+   * @type {!QuickViewUma}
+   * @private
+   */
+  this.quickViewUma_ = quickViewUma;
+
+  /**
    * @type {!MetadataModel}
    * @private
    */
@@ -139,6 +146,7 @@
   this.updateQuickView_().then(function() {
     if (!this.quickView_.isOpened()) {
       this.quickView_.open();
+      this.quickViewUma_.onOpened(this.entries_[0]);
     }
   }.bind(this));
 };
@@ -173,6 +181,7 @@
   var entry =
       (/** @type {!FileEntry} */ (this.quickViewModel_.getSelectedEntry()));
   assert(entry);
+  this.quickViewUma_.onEntryChanged(entry);
   return this.metadataModel_.get([entry], ['thumbnailUrl', 'externalFileUrl'])
       .then(this.onMetadataLoaded_.bind(this, entry));
 };
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_uma.js b/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
new file mode 100644
index 0000000..7f43d93
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
@@ -0,0 +1,64 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * UMA exporter for Quick View.
+ *
+ * @param {!VolumeManagerWrapper} volumeManager
+ *
+ * @constructor
+ */
+function QuickViewUma(volumeManager) {
+
+  /**
+   * @type {!VolumeManagerWrapper}
+   * @private
+   */
+  this.volumeManager_ = volumeManager;
+}
+
+/**
+ * Keep the order of this in sync with FileManagerVolumeType in
+ * tools/metrics/histograms/histograms.xml.
+ *
+ * @type {!Array<VolumeManagerCommon.VolumeType>}
+ * @const
+ */
+QuickViewUma.VolumeType = [
+  VolumeManagerCommon.VolumeType.DRIVE,
+  VolumeManagerCommon.VolumeType.DOWNLOADS,
+  VolumeManagerCommon.VolumeType.REMOVABLE,
+  VolumeManagerCommon.VolumeType.ARCHIVE,
+  VolumeManagerCommon.VolumeType.PROVIDED,
+  VolumeManagerCommon.VolumeType.MTP,
+];
+
+/**
+ * Exports UMA based on the entry shown in Quick View.
+ *
+ * @param {!FileEntry} entry
+ */
+QuickViewUma.prototype.onEntryChanged = function(entry) {
+  var extension = FileType.getExtension(entry).toLowerCase();
+  if (FileTasks.UMA_INDEX_KNOWN_EXTENSIONS.indexOf(extension) < 0) {
+    extension = 'other';
+  }
+  metrics.recordEnum(
+      'QuickView.FileType', extension, FileTasks.UMA_INDEX_KNOWN_EXTENSIONS);
+};
+
+/**
+ * Exports UMA based on the entry selected when Quick View is opened.
+ *
+ * @param {!FileEntry} entry
+ */
+QuickViewUma.prototype.onOpened = function(entry) {
+  var volumeType = this.volumeManager_.getVolumeInfo(entry).volumeType;
+  if (QuickViewUma.VolumeType.includes(volumeType)) {
+    metrics.recordEnum(
+        'QuickView.VolumeType', volumeType, QuickViewUma.VolumeType);
+  } else {
+    console.error('Unknown volume type: ' + volumeType);
+  }
+};
diff --git a/ui/gfx/android/java_bitmap.cc b/ui/gfx/android/java_bitmap.cc
index 69bd667d..f3d0037 100644
--- a/ui/gfx/android/java_bitmap.cc
+++ b/ui/gfx/android/java_bitmap.cc
@@ -13,6 +13,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
 
 namespace gfx {
 
diff --git a/ui/gfx/android/shared_device_display_info.cc b/ui/gfx/android/shared_device_display_info.cc
index 228626f..b5c0f856 100644
--- a/ui/gfx/android/shared_device_display_info.cc
+++ b/ui/gfx/android/shared_device_display_info.cc
@@ -10,6 +10,8 @@
 #include "base/logging.h"
 #include "jni/DeviceDisplayInfo_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace gfx {
 
 // static JNI call
diff --git a/ui/gfx/android/view_configuration.cc b/ui/gfx/android/view_configuration.cc
index c82dcbc..2a9ca90 100644
--- a/ui/gfx/android/view_configuration.cc
+++ b/ui/gfx/android/view_configuration.cc
@@ -13,6 +13,7 @@
 
 using base::android::AttachCurrentThread;
 using base::android::GetApplicationContext;
+using base::android::JavaParamRef;
 
 namespace gfx {
 
diff --git a/ui/gl/android/scoped_java_surface.cc b/ui/gl/android/scoped_java_surface.cc
index c3f3734..62746cc 100644
--- a/ui/gl/android/scoped_java_surface.cc
+++ b/ui/gl/android/scoped_java_surface.cc
@@ -8,6 +8,8 @@
 #include "jni/Surface_jni.h"
 #include "ui/gl/android/surface_texture.h"
 
+using base::android::ScopedJavaLocalRef;
+
 namespace gl {
 
 ScopedJavaSurface::ScopedJavaSurface() {
diff --git a/ui/gl/android/surface_texture_listener.cc b/ui/gl/android/surface_texture_listener.cc
index 6cd4d60..5b2c713 100644
--- a/ui/gl/android/surface_texture_listener.cc
+++ b/ui/gl/android/surface_texture_listener.cc
@@ -9,6 +9,8 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "jni/SurfaceTextureListener_jni.h"
 
+using base::android::JavaParamRef;
+
 namespace gl {
 
 SurfaceTextureListener::SurfaceTextureListener(const base::Closure& callback,
diff --git a/ui/gl/ca_renderer_layer_params.cc b/ui/gl/ca_renderer_layer_params.cc
index 952e703..8a4d745 100644
--- a/ui/gl/ca_renderer_layer_params.cc
+++ b/ui/gl/ca_renderer_layer_params.cc
@@ -33,11 +33,4 @@
     const CARendererLayerParams& other) = default;
 CARendererLayerParams::~CARendererLayerParams() = default;
 
-bool CARendererLayerParams::FilterEffect::operator==(
-    const FilterEffect& rhs) const {
-  return type == rhs.type && amount == rhs.amount &&
-         drop_shadow_offset == rhs.drop_shadow_offset &&
-         drop_shadow_color == rhs.drop_shadow_color;
-}
-
 }  // namespace ui
diff --git a/ui/gl/ca_renderer_layer_params.h b/ui/gl/ca_renderer_layer_params.h
index 46a93b1..22ba8aa 100644
--- a/ui/gl/ca_renderer_layer_params.h
+++ b/ui/gl/ca_renderer_layer_params.h
@@ -69,8 +69,6 @@
     float amount = 0;
     gfx::Point drop_shadow_offset;
     SkColor drop_shadow_color = 0;
-
-    bool operator==(const FilterEffect& rhs) const;
   };
   using FilterEffects = std::vector<FilterEffect>;
 
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index c7adc68b..efdc8f87 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -229,6 +229,10 @@
   'names': ['glCompileShader'],
   'arguments': 'GLuint shader', },
 { 'return_type': 'void',
+  'versions': [{ 'name': 'glCompressedCopyTextureCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_copy_compressed_texture'], }],
+  'arguments': 'GLuint sourceId, GLuint destId', },
+{ 'return_type': 'void',
   'names': ['glCompressedTexImage2D'],
   'arguments':
       'GLenum target, GLint level, GLenum internalformat, GLsizei width, '
@@ -257,6 +261,14 @@
       'GLenum readTarget, GLenum writeTarget, GLintptr readOffset, '
       'GLintptr writeOffset, GLsizeiptr size', },
 { 'return_type': 'void',
+  'versions': [{ 'name': 'glCopySubTextureCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_copy_texture'], }],
+  'arguments':
+      'GLuint sourceId, GLuint destId, GLint xoffset, GLint yoffset, '
+      'GLint x, GLint y, GLsizei width, GLsizei height, '
+      'GLboolean unpackFlipY, GLboolean unpackPremultiplyAlpha, '
+      'GLboolean unpackUnmultiplyAlpha', },
+{ 'return_type': 'void',
   'names': ['glCopyTexImage2D'],
   'arguments':
       'GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, '
@@ -272,6 +284,13 @@
       'GLenum target, GLint level, GLint xoffset, GLint yoffset, '
       'GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height', },
 { 'return_type': 'void',
+  'versions': [{ 'name': 'glCopyTextureCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_copy_texture'], }],
+  'arguments':
+      'GLuint sourceId, GLuint destId, GLint internalFormat, '
+      'GLenum destType, GLboolean unpackFlipY, '
+      'GLboolean unpackPremultiplyAlpha, GLboolean unpackUnmultiplyAlpha', },
+{ 'return_type': 'void',
   'names': ['glCoverageModulationNV'],
   'arguments': 'GLenum components'},
 { 'return_type': 'void',
diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h
index 4b13dfd..5fa38c28 100644
--- a/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/ui/gl/gl_bindings_api_autogen_gl.h
@@ -126,6 +126,7 @@
                    GLboolean blue,
                    GLboolean alpha) override;
 void glCompileShaderFn(GLuint shader) override;
+void glCompressedCopyTextureCHROMIUMFn(GLuint sourceId, GLuint destId) override;
 void glCompressedTexImage2DFn(GLenum target,
                               GLint level,
                               GLenum internalformat,
@@ -168,6 +169,17 @@
                            GLintptr readOffset,
                            GLintptr writeOffset,
                            GLsizeiptr size) override;
+void glCopySubTextureCHROMIUMFn(GLuint sourceId,
+                                GLuint destId,
+                                GLint xoffset,
+                                GLint yoffset,
+                                GLint x,
+                                GLint y,
+                                GLsizei width,
+                                GLsizei height,
+                                GLboolean unpackFlipY,
+                                GLboolean unpackPremultiplyAlpha,
+                                GLboolean unpackUnmultiplyAlpha) override;
 void glCopyTexImage2DFn(GLenum target,
                         GLint level,
                         GLenum internalformat,
@@ -193,6 +205,13 @@
                            GLint y,
                            GLsizei width,
                            GLsizei height) override;
+void glCopyTextureCHROMIUMFn(GLuint sourceId,
+                             GLuint destId,
+                             GLint internalFormat,
+                             GLenum destType,
+                             GLboolean unpackFlipY,
+                             GLboolean unpackPremultiplyAlpha,
+                             GLboolean unpackUnmultiplyAlpha) override;
 void glCoverageModulationNVFn(GLenum components) override;
 void glCoverFillPathInstancedNVFn(GLsizei numPaths,
                                   GLenum pathNameType,
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index 04ba21a1..7d1083f 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -84,6 +84,7 @@
       reinterpret_cast<glColorMaskProc>(GetGLProcAddress("glColorMask"));
   fn.glCompileShaderFn = reinterpret_cast<glCompileShaderProc>(
       GetGLProcAddress("glCompileShader"));
+  fn.glCompressedCopyTextureCHROMIUMFn = 0;
   fn.glCompressedTexImage2DFn = reinterpret_cast<glCompressedTexImage2DProc>(
       GetGLProcAddress("glCompressedTexImage2D"));
   fn.glCompressedTexImage3DFn = 0;
@@ -92,11 +93,13 @@
           GetGLProcAddress("glCompressedTexSubImage2D"));
   fn.glCompressedTexSubImage3DFn = 0;
   fn.glCopyBufferSubDataFn = 0;
+  fn.glCopySubTextureCHROMIUMFn = 0;
   fn.glCopyTexImage2DFn = reinterpret_cast<glCopyTexImage2DProc>(
       GetGLProcAddress("glCopyTexImage2D"));
   fn.glCopyTexSubImage2DFn = reinterpret_cast<glCopyTexSubImage2DProc>(
       GetGLProcAddress("glCopyTexSubImage2D"));
   fn.glCopyTexSubImage3DFn = 0;
+  fn.glCopyTextureCHROMIUMFn = 0;
   fn.glCoverageModulationNVFn = 0;
   fn.glCoverFillPathInstancedNVFn = 0;
   fn.glCoverFillPathNVFn = 0;
@@ -521,6 +524,14 @@
   ext.b_GL_CHROMIUM_bind_uniform_location =
       extensions.find("GL_CHROMIUM_bind_uniform_location ") !=
       std::string::npos;
+  ext.b_GL_CHROMIUM_compressed_copy_texture =
+      extensions.find("GL_CHROMIUM_compressed_copy_texture ") !=
+      std::string::npos;
+  ext.b_GL_CHROMIUM_copy_compressed_texture =
+      extensions.find("GL_CHROMIUM_copy_compressed_texture ") !=
+      std::string::npos;
+  ext.b_GL_CHROMIUM_copy_texture =
+      extensions.find("GL_CHROMIUM_copy_texture ") != std::string::npos;
   ext.b_GL_CHROMIUM_gles_depth_binding_hack =
       extensions.find("GL_CHROMIUM_gles_depth_binding_hack ") !=
       std::string::npos;
@@ -803,6 +814,14 @@
         GetGLProcAddress("glClientWaitSync"));
   }
 
+  debug_fn.glCompressedCopyTextureCHROMIUMFn = 0;
+  if (ext.b_GL_CHROMIUM_copy_compressed_texture ||
+      ext.b_GL_CHROMIUM_compressed_copy_texture) {
+    fn.glCompressedCopyTextureCHROMIUMFn =
+        reinterpret_cast<glCompressedCopyTextureCHROMIUMProc>(
+            GetGLProcAddress("glCompressedCopyTextureCHROMIUM"));
+  }
+
   debug_fn.glCompressedTexImage3DFn = 0;
   if (!ver->is_es || ver->IsAtLeastGLES(3u, 0u)) {
     fn.glCompressedTexImage3DFn = reinterpret_cast<glCompressedTexImage3DProc>(
@@ -822,12 +841,25 @@
         GetGLProcAddress("glCopyBufferSubData"));
   }
 
+  debug_fn.glCopySubTextureCHROMIUMFn = 0;
+  if (ext.b_GL_CHROMIUM_copy_texture) {
+    fn.glCopySubTextureCHROMIUMFn =
+        reinterpret_cast<glCopySubTextureCHROMIUMProc>(
+            GetGLProcAddress("glCopySubTextureCHROMIUM"));
+  }
+
   debug_fn.glCopyTexSubImage3DFn = 0;
   if (!ver->is_es || ver->IsAtLeastGLES(3u, 0u)) {
     fn.glCopyTexSubImage3DFn = reinterpret_cast<glCopyTexSubImage3DProc>(
         GetGLProcAddress("glCopyTexSubImage3D"));
   }
 
+  debug_fn.glCopyTextureCHROMIUMFn = 0;
+  if (ext.b_GL_CHROMIUM_copy_texture) {
+    fn.glCopyTextureCHROMIUMFn = reinterpret_cast<glCopyTextureCHROMIUMProc>(
+        GetGLProcAddress("glCopyTextureCHROMIUM"));
+  }
+
   debug_fn.glCoverageModulationNVFn = 0;
   if (ext.b_GL_NV_framebuffer_mixed_samples) {
     fn.glCoverageModulationNVFn = reinterpret_cast<glCoverageModulationNVProc>(
@@ -2534,6 +2566,14 @@
   g_driver_gl.debug_fn.glCompileShaderFn(shader);
 }
 
+static void GL_BINDING_CALL
+Debug_glCompressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId) {
+  GL_SERVICE_LOG("glCompressedCopyTextureCHROMIUM"
+                 << "(" << sourceId << ", " << destId << ")");
+  DCHECK(g_driver_gl.debug_fn.glCompressedCopyTextureCHROMIUMFn != nullptr);
+  g_driver_gl.debug_fn.glCompressedCopyTextureCHROMIUMFn(sourceId, destId);
+}
+
 static void GL_BINDING_CALL Debug_glCompressedTexImage2D(GLenum target,
                                                          GLint level,
                                                          GLenum internalformat,
@@ -2629,6 +2669,31 @@
                                              readOffset, writeOffset, size);
 }
 
+static void GL_BINDING_CALL
+Debug_glCopySubTextureCHROMIUM(GLuint sourceId,
+                               GLuint destId,
+                               GLint xoffset,
+                               GLint yoffset,
+                               GLint x,
+                               GLint y,
+                               GLsizei width,
+                               GLsizei height,
+                               GLboolean unpackFlipY,
+                               GLboolean unpackPremultiplyAlpha,
+                               GLboolean unpackUnmultiplyAlpha) {
+  GL_SERVICE_LOG("glCopySubTextureCHROMIUM"
+                 << "(" << sourceId << ", " << destId << ", " << xoffset << ", "
+                 << yoffset << ", " << x << ", " << y << ", " << width << ", "
+                 << height << ", " << GLEnums::GetStringBool(unpackFlipY)
+                 << ", " << GLEnums::GetStringBool(unpackPremultiplyAlpha)
+                 << ", " << GLEnums::GetStringBool(unpackUnmultiplyAlpha)
+                 << ")");
+  DCHECK(g_driver_gl.debug_fn.glCopySubTextureCHROMIUMFn != nullptr);
+  g_driver_gl.debug_fn.glCopySubTextureCHROMIUMFn(
+      sourceId, destId, xoffset, yoffset, x, y, width, height, unpackFlipY,
+      unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
+}
+
 static void GL_BINDING_CALL Debug_glCopyTexImage2D(GLenum target,
                                                    GLint level,
                                                    GLenum internalformat,
@@ -2683,6 +2748,26 @@
                                              zoffset, x, y, width, height);
 }
 
+static void GL_BINDING_CALL
+Debug_glCopyTextureCHROMIUM(GLuint sourceId,
+                            GLuint destId,
+                            GLint internalFormat,
+                            GLenum destType,
+                            GLboolean unpackFlipY,
+                            GLboolean unpackPremultiplyAlpha,
+                            GLboolean unpackUnmultiplyAlpha) {
+  GL_SERVICE_LOG("glCopyTextureCHROMIUM"
+                 << "(" << sourceId << ", " << destId << ", " << internalFormat
+                 << ", " << GLEnums::GetStringEnum(destType) << ", "
+                 << GLEnums::GetStringBool(unpackFlipY) << ", "
+                 << GLEnums::GetStringBool(unpackPremultiplyAlpha) << ", "
+                 << GLEnums::GetStringBool(unpackUnmultiplyAlpha) << ")");
+  DCHECK(g_driver_gl.debug_fn.glCopyTextureCHROMIUMFn != nullptr);
+  g_driver_gl.debug_fn.glCopyTextureCHROMIUMFn(
+      sourceId, destId, internalFormat, destType, unpackFlipY,
+      unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
+}
+
 static void GL_BINDING_CALL Debug_glCoverageModulationNV(GLenum components) {
   GL_SERVICE_LOG("glCoverageModulationNV"
                  << "(" << GLEnums::GetStringEnum(components) << ")");
@@ -5749,6 +5834,12 @@
     debug_fn.glCompileShaderFn = fn.glCompileShaderFn;
     fn.glCompileShaderFn = Debug_glCompileShader;
   }
+  if (!debug_fn.glCompressedCopyTextureCHROMIUMFn) {
+    debug_fn.glCompressedCopyTextureCHROMIUMFn =
+        fn.glCompressedCopyTextureCHROMIUMFn;
+    fn.glCompressedCopyTextureCHROMIUMFn =
+        Debug_glCompressedCopyTextureCHROMIUM;
+  }
   if (!debug_fn.glCompressedTexImage2DFn) {
     debug_fn.glCompressedTexImage2DFn = fn.glCompressedTexImage2DFn;
     fn.glCompressedTexImage2DFn = Debug_glCompressedTexImage2D;
@@ -5769,6 +5860,10 @@
     debug_fn.glCopyBufferSubDataFn = fn.glCopyBufferSubDataFn;
     fn.glCopyBufferSubDataFn = Debug_glCopyBufferSubData;
   }
+  if (!debug_fn.glCopySubTextureCHROMIUMFn) {
+    debug_fn.glCopySubTextureCHROMIUMFn = fn.glCopySubTextureCHROMIUMFn;
+    fn.glCopySubTextureCHROMIUMFn = Debug_glCopySubTextureCHROMIUM;
+  }
   if (!debug_fn.glCopyTexImage2DFn) {
     debug_fn.glCopyTexImage2DFn = fn.glCopyTexImage2DFn;
     fn.glCopyTexImage2DFn = Debug_glCopyTexImage2D;
@@ -5781,6 +5876,10 @@
     debug_fn.glCopyTexSubImage3DFn = fn.glCopyTexSubImage3DFn;
     fn.glCopyTexSubImage3DFn = Debug_glCopyTexSubImage3D;
   }
+  if (!debug_fn.glCopyTextureCHROMIUMFn) {
+    debug_fn.glCopyTextureCHROMIUMFn = fn.glCopyTextureCHROMIUMFn;
+    fn.glCopyTextureCHROMIUMFn = Debug_glCopyTextureCHROMIUM;
+  }
   if (!debug_fn.glCoverageModulationNVFn) {
     debug_fn.glCoverageModulationNVFn = fn.glCoverageModulationNVFn;
     fn.glCoverageModulationNVFn = Debug_glCoverageModulationNV;
@@ -7133,6 +7232,11 @@
   driver_->fn.glCompileShaderFn(shader);
 }
 
+void GLApiBase::glCompressedCopyTextureCHROMIUMFn(GLuint sourceId,
+                                                  GLuint destId) {
+  driver_->fn.glCompressedCopyTextureCHROMIUMFn(sourceId, destId);
+}
+
 void GLApiBase::glCompressedTexImage2DFn(GLenum target,
                                          GLint level,
                                          GLenum internalformat,
@@ -7196,6 +7300,22 @@
                                     writeOffset, size);
 }
 
+void GLApiBase::glCopySubTextureCHROMIUMFn(GLuint sourceId,
+                                           GLuint destId,
+                                           GLint xoffset,
+                                           GLint yoffset,
+                                           GLint x,
+                                           GLint y,
+                                           GLsizei width,
+                                           GLsizei height,
+                                           GLboolean unpackFlipY,
+                                           GLboolean unpackPremultiplyAlpha,
+                                           GLboolean unpackUnmultiplyAlpha) {
+  driver_->fn.glCopySubTextureCHROMIUMFn(
+      sourceId, destId, xoffset, yoffset, x, y, width, height, unpackFlipY,
+      unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
+}
+
 void GLApiBase::glCopyTexImage2DFn(GLenum target,
                                    GLint level,
                                    GLenum internalformat,
@@ -7233,6 +7353,18 @@
                                     y, width, height);
 }
 
+void GLApiBase::glCopyTextureCHROMIUMFn(GLuint sourceId,
+                                        GLuint destId,
+                                        GLint internalFormat,
+                                        GLenum destType,
+                                        GLboolean unpackFlipY,
+                                        GLboolean unpackPremultiplyAlpha,
+                                        GLboolean unpackUnmultiplyAlpha) {
+  driver_->fn.glCopyTextureCHROMIUMFn(
+      sourceId, destId, internalFormat, destType, unpackFlipY,
+      unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
+}
+
 void GLApiBase::glCoverageModulationNVFn(GLenum components) {
   driver_->fn.glCoverageModulationNVFn(components);
 }
@@ -9075,6 +9207,13 @@
   gl_api_->glCompileShaderFn(shader);
 }
 
+void TraceGLApi::glCompressedCopyTextureCHROMIUMFn(GLuint sourceId,
+                                                   GLuint destId) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "TraceGLAPI::glCompressedCopyTextureCHROMIUM")
+  gl_api_->glCompressedCopyTextureCHROMIUMFn(sourceId, destId);
+}
+
 void TraceGLApi::glCompressedTexImage2DFn(GLenum target,
                                           GLint level,
                                           GLenum internalformat,
@@ -9143,6 +9282,23 @@
                                  writeOffset, size);
 }
 
+void TraceGLApi::glCopySubTextureCHROMIUMFn(GLuint sourceId,
+                                            GLuint destId,
+                                            GLint xoffset,
+                                            GLint yoffset,
+                                            GLint x,
+                                            GLint y,
+                                            GLsizei width,
+                                            GLsizei height,
+                                            GLboolean unpackFlipY,
+                                            GLboolean unpackPremultiplyAlpha,
+                                            GLboolean unpackUnmultiplyAlpha) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopySubTextureCHROMIUM")
+  gl_api_->glCopySubTextureCHROMIUMFn(
+      sourceId, destId, xoffset, yoffset, x, y, width, height, unpackFlipY,
+      unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
+}
+
 void TraceGLApi::glCopyTexImage2DFn(GLenum target,
                                     GLint level,
                                     GLenum internalformat,
@@ -9183,6 +9339,19 @@
                                  width, height);
 }
 
+void TraceGLApi::glCopyTextureCHROMIUMFn(GLuint sourceId,
+                                         GLuint destId,
+                                         GLint internalFormat,
+                                         GLenum destType,
+                                         GLboolean unpackFlipY,
+                                         GLboolean unpackPremultiplyAlpha,
+                                         GLboolean unpackUnmultiplyAlpha) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCopyTextureCHROMIUM")
+  gl_api_->glCopyTextureCHROMIUMFn(sourceId, destId, internalFormat, destType,
+                                   unpackFlipY, unpackPremultiplyAlpha,
+                                   unpackUnmultiplyAlpha);
+}
+
 void TraceGLApi::glCoverageModulationNVFn(GLenum components) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glCoverageModulationNV")
   gl_api_->glCoverageModulationNVFn(components);
@@ -11352,6 +11521,14 @@
   LOG(ERROR) << "Trying to call glCompileShader() without current GL context";
 }
 
+void NoContextGLApi::glCompressedCopyTextureCHROMIUMFn(GLuint sourceId,
+                                                       GLuint destId) {
+  NOTREACHED() << "Trying to call glCompressedCopyTextureCHROMIUM() without "
+                  "current GL context";
+  LOG(ERROR) << "Trying to call glCompressedCopyTextureCHROMIUM() without "
+                "current GL context";
+}
+
 void NoContextGLApi::glCompressedTexImage2DFn(GLenum target,
                                               GLint level,
                                               GLenum internalformat,
@@ -11424,6 +11601,24 @@
       << "Trying to call glCopyBufferSubData() without current GL context";
 }
 
+void NoContextGLApi::glCopySubTextureCHROMIUMFn(
+    GLuint sourceId,
+    GLuint destId,
+    GLint xoffset,
+    GLint yoffset,
+    GLint x,
+    GLint y,
+    GLsizei width,
+    GLsizei height,
+    GLboolean unpackFlipY,
+    GLboolean unpackPremultiplyAlpha,
+    GLboolean unpackUnmultiplyAlpha) {
+  NOTREACHED()
+      << "Trying to call glCopySubTextureCHROMIUM() without current GL context";
+  LOG(ERROR)
+      << "Trying to call glCopySubTextureCHROMIUM() without current GL context";
+}
+
 void NoContextGLApi::glCopyTexImage2DFn(GLenum target,
                                         GLint level,
                                         GLenum internalformat,
@@ -11466,6 +11661,19 @@
       << "Trying to call glCopyTexSubImage3D() without current GL context";
 }
 
+void NoContextGLApi::glCopyTextureCHROMIUMFn(GLuint sourceId,
+                                             GLuint destId,
+                                             GLint internalFormat,
+                                             GLenum destType,
+                                             GLboolean unpackFlipY,
+                                             GLboolean unpackPremultiplyAlpha,
+                                             GLboolean unpackUnmultiplyAlpha) {
+  NOTREACHED()
+      << "Trying to call glCopyTextureCHROMIUM() without current GL context";
+  LOG(ERROR)
+      << "Trying to call glCopyTextureCHROMIUM() without current GL context";
+}
+
 void NoContextGLApi::glCoverageModulationNVFn(GLenum components) {
   NOTREACHED()
       << "Trying to call glCoverageModulationNV() without current GL context";
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h
index beb63df..2acc11c9 100644
--- a/ui/gl/gl_bindings_autogen_gl.h
+++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -143,6 +143,9 @@
                                                GLboolean blue,
                                                GLboolean alpha);
 typedef void(GL_BINDING_CALL* glCompileShaderProc)(GLuint shader);
+typedef void(GL_BINDING_CALL* glCompressedCopyTextureCHROMIUMProc)(
+    GLuint sourceId,
+    GLuint destId);
 typedef void(GL_BINDING_CALL* glCompressedTexImage2DProc)(GLenum target,
                                                           GLint level,
                                                           GLenum internalformat,
@@ -185,6 +188,18 @@
                                                        GLintptr readOffset,
                                                        GLintptr writeOffset,
                                                        GLsizeiptr size);
+typedef void(GL_BINDING_CALL* glCopySubTextureCHROMIUMProc)(
+    GLuint sourceId,
+    GLuint destId,
+    GLint xoffset,
+    GLint yoffset,
+    GLint x,
+    GLint y,
+    GLsizei width,
+    GLsizei height,
+    GLboolean unpackFlipY,
+    GLboolean unpackPremultiplyAlpha,
+    GLboolean unpackUnmultiplyAlpha);
 typedef void(GL_BINDING_CALL* glCopyTexImage2DProc)(GLenum target,
                                                     GLint level,
                                                     GLenum internalformat,
@@ -210,6 +225,14 @@
                                                        GLint y,
                                                        GLsizei width,
                                                        GLsizei height);
+typedef void(GL_BINDING_CALL* glCopyTextureCHROMIUMProc)(
+    GLuint sourceId,
+    GLuint destId,
+    GLint internalFormat,
+    GLenum destType,
+    GLboolean unpackFlipY,
+    GLboolean unpackPremultiplyAlpha,
+    GLboolean unpackUnmultiplyAlpha);
 typedef void(GL_BINDING_CALL* glCoverageModulationNVProc)(GLenum components);
 typedef void(GL_BINDING_CALL* glCoverFillPathInstancedNVProc)(
     GLsizei numPaths,
@@ -1064,6 +1087,9 @@
   bool b_GL_ARB_transform_feedback2;
   bool b_GL_ARB_vertex_array_object;
   bool b_GL_CHROMIUM_bind_uniform_location;
+  bool b_GL_CHROMIUM_compressed_copy_texture;
+  bool b_GL_CHROMIUM_copy_compressed_texture;
+  bool b_GL_CHROMIUM_copy_texture;
   bool b_GL_CHROMIUM_gles_depth_binding_hack;
   bool b_GL_CHROMIUM_glgetstringi_hack;
   bool b_GL_EXT_blend_func_extended;
@@ -1144,14 +1170,17 @@
   glClientWaitSyncProc glClientWaitSyncFn;
   glColorMaskProc glColorMaskFn;
   glCompileShaderProc glCompileShaderFn;
+  glCompressedCopyTextureCHROMIUMProc glCompressedCopyTextureCHROMIUMFn;
   glCompressedTexImage2DProc glCompressedTexImage2DFn;
   glCompressedTexImage3DProc glCompressedTexImage3DFn;
   glCompressedTexSubImage2DProc glCompressedTexSubImage2DFn;
   glCompressedTexSubImage3DProc glCompressedTexSubImage3DFn;
   glCopyBufferSubDataProc glCopyBufferSubDataFn;
+  glCopySubTextureCHROMIUMProc glCopySubTextureCHROMIUMFn;
   glCopyTexImage2DProc glCopyTexImage2DFn;
   glCopyTexSubImage2DProc glCopyTexSubImage2DFn;
   glCopyTexSubImage3DProc glCopyTexSubImage3DFn;
+  glCopyTextureCHROMIUMProc glCopyTextureCHROMIUMFn;
   glCoverageModulationNVProc glCoverageModulationNVFn;
   glCoverFillPathInstancedNVProc glCoverFillPathInstancedNVFn;
   glCoverFillPathNVProc glCoverFillPathNVFn;
@@ -1552,6 +1581,8 @@
                              GLboolean blue,
                              GLboolean alpha) = 0;
   virtual void glCompileShaderFn(GLuint shader) = 0;
+  virtual void glCompressedCopyTextureCHROMIUMFn(GLuint sourceId,
+                                                 GLuint destId) = 0;
   virtual void glCompressedTexImage2DFn(GLenum target,
                                         GLint level,
                                         GLenum internalformat,
@@ -1594,6 +1625,17 @@
                                      GLintptr readOffset,
                                      GLintptr writeOffset,
                                      GLsizeiptr size) = 0;
+  virtual void glCopySubTextureCHROMIUMFn(GLuint sourceId,
+                                          GLuint destId,
+                                          GLint xoffset,
+                                          GLint yoffset,
+                                          GLint x,
+                                          GLint y,
+                                          GLsizei width,
+                                          GLsizei height,
+                                          GLboolean unpackFlipY,
+                                          GLboolean unpackPremultiplyAlpha,
+                                          GLboolean unpackUnmultiplyAlpha) = 0;
   virtual void glCopyTexImage2DFn(GLenum target,
                                   GLint level,
                                   GLenum internalformat,
@@ -1619,6 +1661,13 @@
                                      GLint y,
                                      GLsizei width,
                                      GLsizei height) = 0;
+  virtual void glCopyTextureCHROMIUMFn(GLuint sourceId,
+                                       GLuint destId,
+                                       GLint internalFormat,
+                                       GLenum destType,
+                                       GLboolean unpackFlipY,
+                                       GLboolean unpackPremultiplyAlpha,
+                                       GLboolean unpackUnmultiplyAlpha) = 0;
   virtual void glCoverageModulationNVFn(GLenum components) = 0;
   virtual void glCoverFillPathInstancedNVFn(GLsizei numPaths,
                                             GLenum pathNameType,
@@ -2394,6 +2443,8 @@
 #define glClientWaitSync ::gl::g_current_gl_context->glClientWaitSyncFn
 #define glColorMask ::gl::g_current_gl_context->glColorMaskFn
 #define glCompileShader ::gl::g_current_gl_context->glCompileShaderFn
+#define glCompressedCopyTextureCHROMIUM \
+  ::gl::g_current_gl_context->glCompressedCopyTextureCHROMIUMFn
 #define glCompressedTexImage2D \
   ::gl::g_current_gl_context->glCompressedTexImage2DFn
 #define glCompressedTexImage3D \
@@ -2403,9 +2454,13 @@
 #define glCompressedTexSubImage3D \
   ::gl::g_current_gl_context->glCompressedTexSubImage3DFn
 #define glCopyBufferSubData ::gl::g_current_gl_context->glCopyBufferSubDataFn
+#define glCopySubTextureCHROMIUM \
+  ::gl::g_current_gl_context->glCopySubTextureCHROMIUMFn
 #define glCopyTexImage2D ::gl::g_current_gl_context->glCopyTexImage2DFn
 #define glCopyTexSubImage2D ::gl::g_current_gl_context->glCopyTexSubImage2DFn
 #define glCopyTexSubImage3D ::gl::g_current_gl_context->glCopyTexSubImage3DFn
+#define glCopyTextureCHROMIUM \
+  ::gl::g_current_gl_context->glCopyTextureCHROMIUMFn
 #define glCoverageModulationNV \
   ::gl::g_current_gl_context->glCoverageModulationNVFn
 #define glCoverFillPathInstancedNV \
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index f89adfe3..4052cb2c 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -441,6 +441,13 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glCompressedCopyTextureCHROMIUM(GLuint sourceId,
+                                                      GLuint destId) {
+  MakeFunctionUnique("glCompressedCopyTextureCHROMIUM");
+  interface_->CompressedCopyTextureCHROMIUM(sourceId, destId);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glCompressedTexImage2D(GLenum target,
                                              GLint level,
                                              GLenum internalformat,
@@ -513,6 +520,24 @@
                                 writeOffset, size);
 }
 
+void GL_BINDING_CALL MockGLInterface::Mock_glCopySubTextureCHROMIUM(
+    GLuint sourceId,
+    GLuint destId,
+    GLint xoffset,
+    GLint yoffset,
+    GLint x,
+    GLint y,
+    GLsizei width,
+    GLsizei height,
+    GLboolean unpackFlipY,
+    GLboolean unpackPremultiplyAlpha,
+    GLboolean unpackUnmultiplyAlpha) {
+  MakeFunctionUnique("glCopySubTextureCHROMIUM");
+  interface_->CopySubTextureCHROMIUM(
+      sourceId, destId, xoffset, yoffset, x, y, width, height, unpackFlipY,
+      unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
+}
+
 void GL_BINDING_CALL
 MockGLInterface::Mock_glCopyTexImage2D(GLenum target,
                                        GLint level,
@@ -554,6 +579,20 @@
                                 width, height);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glCopyTextureCHROMIUM(GLuint sourceId,
+                                            GLuint destId,
+                                            GLint internalFormat,
+                                            GLenum destType,
+                                            GLboolean unpackFlipY,
+                                            GLboolean unpackPremultiplyAlpha,
+                                            GLboolean unpackUnmultiplyAlpha) {
+  MakeFunctionUnique("glCopyTextureCHROMIUM");
+  interface_->CopyTextureCHROMIUM(sourceId, destId, internalFormat, destType,
+                                  unpackFlipY, unpackPremultiplyAlpha,
+                                  unpackUnmultiplyAlpha);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glCoverFillPathInstancedNV(
     GLsizei numPaths,
     GLenum pathNameType,
@@ -3083,6 +3122,8 @@
     return reinterpret_cast<void*>(Mock_glColorMask);
   if (strcmp(name, "glCompileShader") == 0)
     return reinterpret_cast<void*>(Mock_glCompileShader);
+  if (strcmp(name, "glCompressedCopyTextureCHROMIUM") == 0)
+    return reinterpret_cast<void*>(Mock_glCompressedCopyTextureCHROMIUM);
   if (strcmp(name, "glCompressedTexImage2D") == 0)
     return reinterpret_cast<void*>(Mock_glCompressedTexImage2D);
   if (strcmp(name, "glCompressedTexImage3D") == 0)
@@ -3093,12 +3134,16 @@
     return reinterpret_cast<void*>(Mock_glCompressedTexSubImage3D);
   if (strcmp(name, "glCopyBufferSubData") == 0)
     return reinterpret_cast<void*>(Mock_glCopyBufferSubData);
+  if (strcmp(name, "glCopySubTextureCHROMIUM") == 0)
+    return reinterpret_cast<void*>(Mock_glCopySubTextureCHROMIUM);
   if (strcmp(name, "glCopyTexImage2D") == 0)
     return reinterpret_cast<void*>(Mock_glCopyTexImage2D);
   if (strcmp(name, "glCopyTexSubImage2D") == 0)
     return reinterpret_cast<void*>(Mock_glCopyTexSubImage2D);
   if (strcmp(name, "glCopyTexSubImage3D") == 0)
     return reinterpret_cast<void*>(Mock_glCopyTexSubImage3D);
+  if (strcmp(name, "glCopyTextureCHROMIUM") == 0)
+    return reinterpret_cast<void*>(Mock_glCopyTextureCHROMIUM);
   if (strcmp(name, "glCoverFillPathInstancedNV") == 0)
     return reinterpret_cast<void*>(Mock_glCoverFillPathInstancedNV);
   if (strcmp(name, "glCoverFillPathNV") == 0)
diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h
index 746eb84..a183620 100644
--- a/ui/gl/gl_bindings_autogen_mock.h
+++ b/ui/gl/gl_bindings_autogen_mock.h
@@ -169,6 +169,8 @@
                                              GLboolean blue,
                                              GLboolean alpha);
 static void GL_BINDING_CALL Mock_glCompileShader(GLuint shader);
+static void GL_BINDING_CALL
+Mock_glCompressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId);
 static void GL_BINDING_CALL Mock_glCompressedTexImage2D(GLenum target,
                                                         GLint level,
                                                         GLenum internalformat,
@@ -211,6 +213,18 @@
                                                      GLintptr readOffset,
                                                      GLintptr writeOffset,
                                                      GLsizeiptr size);
+static void GL_BINDING_CALL
+Mock_glCopySubTextureCHROMIUM(GLuint sourceId,
+                              GLuint destId,
+                              GLint xoffset,
+                              GLint yoffset,
+                              GLint x,
+                              GLint y,
+                              GLsizei width,
+                              GLsizei height,
+                              GLboolean unpackFlipY,
+                              GLboolean unpackPremultiplyAlpha,
+                              GLboolean unpackUnmultiplyAlpha);
 static void GL_BINDING_CALL Mock_glCopyTexImage2D(GLenum target,
                                                   GLint level,
                                                   GLenum internalformat,
@@ -237,6 +251,14 @@
                                                      GLsizei width,
                                                      GLsizei height);
 static void GL_BINDING_CALL
+Mock_glCopyTextureCHROMIUM(GLuint sourceId,
+                           GLuint destId,
+                           GLint internalFormat,
+                           GLenum destType,
+                           GLboolean unpackFlipY,
+                           GLboolean unpackPremultiplyAlpha,
+                           GLboolean unpackUnmultiplyAlpha);
+static void GL_BINDING_CALL
 Mock_glCoverFillPathInstancedNV(GLsizei numPaths,
                                 GLenum pathNameType,
                                 const void* paths,
diff --git a/ui/gl/gl_context_glx.cc b/ui/gl/gl_context_glx.cc
index e5793f4..4be08f6 100644
--- a/ui/gl/gl_context_glx.cc
+++ b/ui/gl/gl_context_glx.cc
@@ -57,6 +57,8 @@
   // When creating a context with glXCreateContextAttribsARB, a variety of X11
   // errors can be generated. To prevent these errors from crashing our process,
   // we simply ignore them and only look if the GLXContext was created.
+  // Sync to ensure any errors generated are processed.
+  XSync(display, False);
   auto old_error_handler = XSetErrorHandler(IgnoreX11Errors);
   GLXContext context =
       glXCreateContextAttribsARB(display, config, share, True, attribs.data());
diff --git a/ui/gl/gl_mock.h b/ui/gl/gl_mock.h
index 6565e6e72..fb41495b 100644
--- a/ui/gl/gl_mock.h
+++ b/ui/gl/gl_mock.h
@@ -43,6 +43,20 @@
     NOTREACHED();
   }
 
+  void CopySubTextureCHROMIUM(GLuint /*sourceId*/,
+                              GLuint /*destId*/,
+                              GLint /*xoffset*/,
+                              GLint /*yoffset*/,
+                              GLint /*x*/,
+                              GLint /*y*/,
+                              GLsizei /*width*/,
+                              GLsizei /*height*/,
+                              GLboolean /*unpackFlipY*/,
+                              GLboolean /*unpackPremultiplyAlpha*/,
+                              GLboolean /*unpackUnmultiplyAlpha*/) {
+    NOTREACHED();
+  }
+
   void TexSubImage3D(
       GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
       GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h
index 70fbbba..727d02d 100644
--- a/ui/gl/gl_mock_autogen_gl.h
+++ b/ui/gl/gl_mock_autogen_gl.h
@@ -114,6 +114,8 @@
     ColorMask,
     void(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha));
 MOCK_METHOD1(CompileShader, void(GLuint shader));
+MOCK_METHOD2(CompressedCopyTextureCHROMIUM,
+             void(GLuint sourceId, GLuint destId));
 MOCK_METHOD8(CompressedTexImage2D,
              void(GLenum target,
                   GLint level,
@@ -151,6 +153,8 @@
                   GLintptr readOffset,
                   GLintptr writeOffset,
                   GLsizeiptr size));
+// TODO(zmo): crbug.com/456340
+// glCopySubTextureCHROMIUM cannot be mocked because it has 11 args.
 MOCK_METHOD8(CopyTexImage2D,
              void(GLenum target,
                   GLint level,
@@ -179,6 +183,14 @@
                   GLint y,
                   GLsizei width,
                   GLsizei height));
+MOCK_METHOD7(CopyTextureCHROMIUM,
+             void(GLuint sourceId,
+                  GLuint destId,
+                  GLint internalFormat,
+                  GLenum destType,
+                  GLboolean unpackFlipY,
+                  GLboolean unpackPremultiplyAlpha,
+                  GLboolean unpackUnmultiplyAlpha));
 MOCK_METHOD1(CoverageModulationNV, void(GLenum components));
 MOCK_METHOD7(CoverFillPathInstancedNV,
              void(GLsizei numPaths,
diff --git a/ui/gl/gl_stub_autogen_gl.h b/ui/gl/gl_stub_autogen_gl.h
index f55fb91..a19ab179 100644
--- a/ui/gl/gl_stub_autogen_gl.h
+++ b/ui/gl/gl_stub_autogen_gl.h
@@ -126,6 +126,8 @@
                    GLboolean blue,
                    GLboolean alpha) override {}
 void glCompileShaderFn(GLuint shader) override {}
+void glCompressedCopyTextureCHROMIUMFn(GLuint sourceId,
+                                       GLuint destId) override {}
 void glCompressedTexImage2DFn(GLenum target,
                               GLint level,
                               GLenum internalformat,
@@ -168,6 +170,17 @@
                            GLintptr readOffset,
                            GLintptr writeOffset,
                            GLsizeiptr size) override {}
+void glCopySubTextureCHROMIUMFn(GLuint sourceId,
+                                GLuint destId,
+                                GLint xoffset,
+                                GLint yoffset,
+                                GLint x,
+                                GLint y,
+                                GLsizei width,
+                                GLsizei height,
+                                GLboolean unpackFlipY,
+                                GLboolean unpackPremultiplyAlpha,
+                                GLboolean unpackUnmultiplyAlpha) override {}
 void glCopyTexImage2DFn(GLenum target,
                         GLint level,
                         GLenum internalformat,
@@ -193,6 +206,13 @@
                            GLint y,
                            GLsizei width,
                            GLsizei height) override {}
+void glCopyTextureCHROMIUMFn(GLuint sourceId,
+                             GLuint destId,
+                             GLint internalFormat,
+                             GLenum destType,
+                             GLboolean unpackFlipY,
+                             GLboolean unpackPremultiplyAlpha,
+                             GLboolean unpackUnmultiplyAlpha) override {}
 void glCoverageModulationNVFn(GLenum components) override {}
 void glCoverFillPathInstancedNVFn(GLsizei numPaths,
                                   GLenum pathNameType,
diff --git a/ui/platform_window/android/platform_ime_controller_android.cc b/ui/platform_window/android/platform_ime_controller_android.cc
index 98aa99c..a2e068a 100644
--- a/ui/platform_window/android/platform_ime_controller_android.cc
+++ b/ui/platform_window/android/platform_ime_controller_android.cc
@@ -8,6 +8,9 @@
 #include "base/android/jni_string.h"
 #include "jni/PlatformImeControllerAndroid_jni.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace ui {
 
 // static
diff --git a/ui/platform_window/android/platform_window_android.cc b/ui/platform_window/android/platform_window_android.cc
index dbda6a9..e755412e 100644
--- a/ui/platform_window/android/platform_window_android.cc
+++ b/ui/platform_window/android/platform_window_android.cc
@@ -15,6 +15,9 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/platform_window/platform_window_delegate.h"
 
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
 namespace ui {
 
 namespace {
diff --git a/ui/shell_dialogs/select_file_dialog_android.cc b/ui/shell_dialogs/select_file_dialog_android.cc
index 11b9d4c..c4af2495 100644
--- a/ui/shell_dialogs/select_file_dialog_android.cc
+++ b/ui/shell_dialogs/select_file_dialog_android.cc
@@ -17,6 +17,8 @@
 #include "ui/shell_dialogs/selected_file_info.h"
 
 using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
 
 namespace ui {
 
diff --git a/ui/views/touchui/touch_selection_menu_runner_views.cc b/ui/views/touchui/touch_selection_menu_runner_views.cc
index b506f787..b208d5ff 100644
--- a/ui/views/touchui/touch_selection_menu_runner_views.cc
+++ b/ui/views/touchui/touch_selection_menu_runner_views.cc
@@ -161,10 +161,7 @@
   LabelButton* button = new LabelButton(this, label);
   button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight));
   button->SetFocusForPlatform();
-  const gfx::FontList& font_list =
-      ui::ResourceBundle::GetSharedInstance().GetFontList(
-          ui::ResourceBundle::SmallFont);
-  button->SetFontList(font_list);
+  button->AdjustFontSize(ui::ResourceBundle::kSmallFontDelta);
   button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
   button->set_tag(tag);
   return button;