diff --git a/Cargo.lock b/Cargo.lock
index 8a9d1497df45f4e9ebf6baa9e8d19c54f81ecbf7..e62167ed8c185a1e0cf588fd99b1eec85b25b9a7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -50,11 +50,11 @@ dependencies = [
 
 [[package]]
 name = "audioipc"
-version = "0.2.2"
+version = "0.2.3"
 dependencies = [
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -71,10 +71,10 @@ dependencies = [
 
 [[package]]
 name = "audioipc-client"
-version = "0.3.0"
+version = "0.4.0"
 dependencies = [
- "audioipc 0.2.2",
- "cubeb-backend 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "audioipc 0.2.3",
+ "cubeb-backend 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -88,9 +88,9 @@ dependencies = [
 name = "audioipc-server"
 version = "0.2.2"
 dependencies = [
- "audioipc 0.2.2",
+ "audioipc 0.2.3",
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -406,34 +406,34 @@ dependencies = [
 
 [[package]]
 name = "cubeb"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cubeb-core 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cubeb-backend"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cubeb-core 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cubeb-core"
-version = "0.4.4"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "cubeb-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cubeb-pulse"
-version = "0.1.1"
+version = "0.2.0"
 dependencies = [
- "cubeb-backend 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb-backend 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulse 0.2.0",
  "pulse-ffi 0.1.0",
  "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -441,7 +441,7 @@ dependencies = [
 
 [[package]]
 name = "cubeb-sys"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -724,11 +724,11 @@ dependencies = [
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
- "audioipc-client 0.3.0",
+ "audioipc-client 0.4.0",
  "audioipc-server 0.2.2",
  "cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "cubeb-pulse 0.1.1",
- "cubeb-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cubeb-pulse 0.2.0",
+ "cubeb-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "geckoservo 0.0.1",
@@ -2222,10 +2222,10 @@ dependencies = [
 "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
 "checksum cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b6557bdb1dc9647eae1cf7f5601b14cd45fc3c7ccf2df618387416fe542da6ea"
 "checksum cstr-macros 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f9f316203d1ea36f4f18316822806f6999aa3dc5ed1adf51e35b77e3b3933d78"
-"checksum cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ed237804b9799d1c29089e6cab3f4b7160186179981a61865feff13d55a902f8"
-"checksum cubeb-backend 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f6d8f189a1cf9cce9aec45eb0aeb1d221514d788b89a1cd6bc2b76110ee4d81"
-"checksum cubeb-core 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7dcedc8ffadc0481f1dfbdeb315e7d7ae9afe6a70815d22efcca8e0bd2ba89e0"
-"checksum cubeb-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fab28c0e152330f74bcbec1572c374397458957d5ad50605879352ec562f41aa"
+"checksum cubeb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7923bed2d5a1a64ba0c3e8b6badc360508ba488d1f2f59f16a688802e755bb85"
+"checksum cubeb-backend 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcac95519416d9ec814db2dc40e6293e7da25b906023d93f48b87f0587ab138"
+"checksum cubeb-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "169d9a36f5daa60f9c4597905132aef056cf62693addd4a3421492853ccad565"
+"checksum cubeb-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e405ad4dff2c1a7cbfa6998e5925e8ceafe900feeacfcad35a3e3790bea0f2aa"
 "checksum darling 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d3effd06d4057f275cb7858889f4952920bab78dd8ff0f6e7dfe0c8d2e67ed89"
 "checksum darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "167dd3e235c2f1da16a635c282630452cdf49191eb05711de1bcd1d3d5068c00"
 "checksum darling_macro 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c53edaba455f6073a10c27c72440860eb3f60444f8c8660a391032eeae744d82"
diff --git a/third_party/rust/cubeb-backend/.cargo-checksum.json b/third_party/rust/cubeb-backend/.cargo-checksum.json
index 6e43cad87faa90cac36b9878b429cae9e3a83080..edae3f1315a8b29d3a96904968e52ca1babefeb8 100644
--- a/third_party/rust/cubeb-backend/.cargo-checksum.json
+++ b/third_party/rust/cubeb-backend/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"d3e2dd5ca6196dcab0d81eaa4971cb43dd0200fbaa7be17b46290a9b9405c3d8","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/capi.rs":"a1f0b172d313459a4d44d3897a76cadc41be6485d8739660c0a421967a9bed80","src/lib.rs":"94b80747ae1037423a2281f2572fc6d15cd7702417974ae3730adccd71c7a300","src/log.rs":"af1d787754706e34d6b8f4ac88aa89078ae9a16970b168ad8dc17cc4180688c2","src/ops.rs":"0af019afdf8c79e27a6f56ecccf597a70f6fdfe3b3c26cdbb16808cd0c453602","src/traits.rs":"93b1499e767d9c279d60887d049d59d2f206938d397298bf0199a55b817a0441","tests/test_capi.rs":"2938826a8c4df04351cba5ac1da5d228329e307300ea40bf1e9f4bba1f2e5b2d"},"package":"4f6d8f189a1cf9cce9aec45eb0aeb1d221514d788b89a1cd6bc2b76110ee4d81"}
\ No newline at end of file
+{"files":{"Cargo.toml":"4bae03732c4f490b3c7dbc07d2eabccf5d0f6b5ab2c1c74d592cc7609c9d8d8e","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/capi.rs":"300e76bd3901de540b21a2cfc8d15dbcd1b2940d5fbb517fc5fe568af2ec2775","src/lib.rs":"94b80747ae1037423a2281f2572fc6d15cd7702417974ae3730adccd71c7a300","src/log.rs":"af1d787754706e34d6b8f4ac88aa89078ae9a16970b168ad8dc17cc4180688c2","src/ops.rs":"55cbf9bdccdd854834eba72e8bde3e59a9a4193e65209769a1a6e0d8a320b8f6","src/traits.rs":"1a6e3401bb25088d355041704bd89099d62b51eda94da177e7e860646c52b955","tests/test_capi.rs":"9d949cbdb1c19e229ce4f652999a058c283cf7d5a882a669dbca08b71ac2fb62"},"package":"fdcac95519416d9ec814db2dc40e6293e7da25b906023d93f48b87f0587ab138"}
\ No newline at end of file
diff --git a/third_party/rust/cubeb-backend/Cargo.toml b/third_party/rust/cubeb-backend/Cargo.toml
index d4eebb605f037c36c7dec1c4198beb8251db2a68..cb9ebe252fd15f464fa5dca4235a11ca99815d24 100644
--- a/third_party/rust/cubeb-backend/Cargo.toml
+++ b/third_party/rust/cubeb-backend/Cargo.toml
@@ -12,7 +12,7 @@
 
 [package]
 name = "cubeb-backend"
-version = "0.4.1"
+version = "0.5.0"
 authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
 description = "Bindings to libcubeb internals to facilitate implementing cubeb backends in rust.\n"
 homepage = "https://github.com/djg/cubeb-rs"
@@ -21,7 +21,7 @@ categories = ["api-bindings"]
 license = "ISC"
 repository = "https://github.com/djg/cubeb-rs"
 [dependencies.cubeb-core]
-version = "0.4.1"
+version = "0.5.0"
 
 [features]
 gecko-in-tree = ["cubeb-core/gecko-in-tree"]
diff --git a/third_party/rust/cubeb-backend/src/capi.rs b/third_party/rust/cubeb-backend/src/capi.rs
index 190913f9681ca60be724406e4a3070d5070d0955..a827763d7500f27eaab760233602c5641daee506 100644
--- a/third_party/rust/cubeb-backend/src/capi.rs
+++ b/third_party/rust/cubeb-backend/src/capi.rs
@@ -38,8 +38,6 @@ macro_rules! capi_new(
             get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
             get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
             get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
-            get_preferred_channel_layout:
-                Some($crate::capi::capi_get_preferred_channel_layout::<$ctx>),
             enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
             device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
             destroy: Some($crate::capi::capi_destroy::<$ctx>),
@@ -109,16 +107,6 @@ pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: ContextOps>(
     ffi::CUBEB_OK
 }
 
-pub unsafe extern "C" fn capi_get_preferred_channel_layout<CTX: ContextOps>(
-    c: *mut ffi::cubeb,
-    layout: *mut ffi::cubeb_channel_layout,
-) -> c_int {
-    let ctx = &mut *(c as *mut CTX);
-
-    *layout = _try!(ctx.preferred_channel_layout()) as _;
-    ffi::CUBEB_OK
-}
-
 pub unsafe extern "C" fn capi_enumerate_devices<CTX: ContextOps>(
     c: *mut ffi::cubeb,
     devtype: ffi::cubeb_device_type,
diff --git a/third_party/rust/cubeb-backend/src/ops.rs b/third_party/rust/cubeb-backend/src/ops.rs
index c68e9b8ceef58dce3c603d31d083907acf7ae414..9d4193e652adfbccc95f1f80b6790bfafff736f1 100644
--- a/third_party/rust/cubeb-backend/src/ops.rs
+++ b/third_party/rust/cubeb-backend/src/ops.rs
@@ -25,10 +25,6 @@ pub struct Ops {
     >,
     pub get_preferred_sample_rate:
         Option<unsafe extern "C" fn(context: *mut ffi::cubeb, rate: *mut u32) -> c_int>,
-    pub get_preferred_channel_layout: Option<
-        unsafe extern "C" fn(context: *mut ffi::cubeb, layout: *mut ffi::cubeb_channel_layout)
-            -> c_int,
-    >,
     pub enumerate_devices: Option<
         unsafe extern "C" fn(
             context: *mut ffi::cubeb,
diff --git a/third_party/rust/cubeb-backend/src/traits.rs b/third_party/rust/cubeb-backend/src/traits.rs
index d33f584506243e230c60d5f4af1110bad8498d82..8f4e0cd8a763b5c868f41108f47fbf447bc9e12e 100644
--- a/third_party/rust/cubeb-backend/src/traits.rs
+++ b/third_party/rust/cubeb-backend/src/traits.rs
@@ -3,8 +3,8 @@
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
-use cubeb_core::{ChannelLayout, Context, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType,
-                 Result, Stream, StreamParams, StreamParamsRef};
+use cubeb_core::{Context, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType, Result, Stream,
+                 StreamParams, StreamParamsRef};
 use ffi;
 use std::ffi::CStr;
 use std::os::raw::c_void;
@@ -15,7 +15,6 @@ pub trait ContextOps {
     fn max_channel_count(&mut self) -> Result<u32>;
     fn min_latency(&mut self, params: StreamParams) -> Result<u32>;
     fn preferred_sample_rate(&mut self) -> Result<u32>;
-    fn preferred_channel_layout(&mut self) -> Result<ChannelLayout>;
     fn enumerate_devices(
         &mut self,
         devtype: DeviceType,
diff --git a/third_party/rust/cubeb-backend/tests/test_capi.rs b/third_party/rust/cubeb-backend/tests/test_capi.rs
index 2b2f43bb5aade5c17aa69699fe17677acbc56871..deda864f618086d1f8cd7b0f3e3cd9090e93579e 100644
--- a/third_party/rust/cubeb-backend/tests/test_capi.rs
+++ b/third_party/rust/cubeb-backend/tests/test_capi.rs
@@ -8,9 +8,8 @@
 #[macro_use]
 extern crate cubeb_backend;
 
-use cubeb_backend::{ffi, ChannelLayout, Context, ContextOps, DeviceCollectionRef, DeviceId,
-                    DeviceRef, DeviceType, Ops, Result, Stream, StreamOps, StreamParams,
-                    StreamParamsRef};
+use cubeb_backend::{ffi, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef,
+                    DeviceType, Ops, Result, Stream, StreamOps, StreamParams, StreamParamsRef};
 use std::ffi::CStr;
 use std::os::raw::c_void;
 use std::ptr;
@@ -41,9 +40,6 @@ impl ContextOps for TestContext {
     fn preferred_sample_rate(&mut self) -> Result<u32> {
         Ok(0u32)
     }
-    fn preferred_channel_layout(&mut self) -> Result<ChannelLayout> {
-        Ok(ChannelLayout::Mono as _)
-    }
     fn enumerate_devices(
         &mut self,
         _devtype: DeviceType,
@@ -171,17 +167,6 @@ fn test_ops_context_preferred_sample_rate() {
     assert_eq!(rate, 0);
 }
 
-#[test]
-fn test_ops_context_preferred_channel_layout() {
-    let c: *mut ffi::cubeb = ptr::null_mut();
-    let mut layout = ChannelLayout::Undefined;
-    assert_eq!(
-        unsafe { OPS.get_preferred_channel_layout.unwrap()(c, &mut layout as *mut _ as *mut _) },
-        ffi::CUBEB_OK
-    );
-    assert_eq!(layout, ChannelLayout::Mono);
-}
-
 #[test]
 fn test_ops_context_enumerate_devices() {
     let c: *mut ffi::cubeb = ptr::null_mut();
diff --git a/third_party/rust/cubeb-core/.cargo-checksum.json b/third_party/rust/cubeb-core/.cargo-checksum.json
index b3cbb16c1de6d917509e681bbf856eca6c0f646b..eb67c4663bde6decaafc9b2d1416bfa26e6bc72e 100644
--- a/third_party/rust/cubeb-core/.cargo-checksum.json
+++ b/third_party/rust/cubeb-core/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"f9beebeb032911cbb1856ad4278a61b2d58105e89e8a15971a2ec4ac69d8d367","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/builders.rs":"f4f4764697c65c08bfbf156005c5f40a43bb8b9ae72a4986dc8b5252537de7ec","src/channel.rs":"bc1e970d9a32ffa9f51f285bce511c20f33c4dd56add27d0bb27273e6483aa90","src/context.rs":"39f643da2716c003c9a190a6138a7d5f8a99aca05df463a2dad00938c9cf4067","src/device.rs":"490d2e94ecae1e149476c2e8d9aa03c4163987c3efccc962b2d3123e4c09dedf","src/device_collection.rs":"f6d0c1628cc34b524f86b84a1e1c79971c3f64ebc4ac64eeb10a1330bbe8c238","src/error.rs":"855ff3d3597753f832ecea00e403c71129afd80db3d39456cf3e23cb9aeb91e7","src/ffi_types.rs":"d815d7a80895b5e86907e708dc0219fca4ac4668cde114afee434e7d702a145d","src/format.rs":"5513c537a72af1c222ee7c30b26d4de9d368a69772688b95d88b1a99f6892d5c","src/lib.rs":"6010a5e20b836b8e5c9fba382fde819e6f3c18c0ec2016e6e7e118eabedbcd51","src/log.rs":"c46bae3472043fd076df3229c3421d948a87fae8495c1524b41ab2d8608f612a","src/stream.rs":"28fce5a49384437f5106b0575aebfb09d7b1875e4adb53d57102d79666bbab43","src/try_call.rs":"231bfa3f3448f7531427bb228beb2bcd4fd711f0b13d2d8f412af013470f40c7","src/util.rs":"308cfbaacd615ff600e74415c52daeef007fff34a4a0648a73c0042f6067f84f"},"package":"7dcedc8ffadc0481f1dfbdeb315e7d7ae9afe6a70815d22efcca8e0bd2ba89e0"}
\ No newline at end of file
+{"files":{"Cargo.toml":"5cc2013bd01c4f844a0056af1b3a484f39c77b8aeac03c3f15e4598caf9625a9","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/builders.rs":"ca97e3a3d1f3fc451c17851c8538964ec67f3964dfe29e902d904ee7445becca","src/channel.rs":"c8d5a76ef3ecdd96cd4de516e3d4d139bbb83c4690d1c3f5fd07fffc47be51f1","src/context.rs":"09625b75070ec88d566a907ab2e574e2d85df4c6df295f798b3372df2cdc8f7a","src/device.rs":"490d2e94ecae1e149476c2e8d9aa03c4163987c3efccc962b2d3123e4c09dedf","src/device_collection.rs":"f6d0c1628cc34b524f86b84a1e1c79971c3f64ebc4ac64eeb10a1330bbe8c238","src/error.rs":"855ff3d3597753f832ecea00e403c71129afd80db3d39456cf3e23cb9aeb91e7","src/ffi_types.rs":"d815d7a80895b5e86907e708dc0219fca4ac4668cde114afee434e7d702a145d","src/format.rs":"5513c537a72af1c222ee7c30b26d4de9d368a69772688b95d88b1a99f6892d5c","src/lib.rs":"6010a5e20b836b8e5c9fba382fde819e6f3c18c0ec2016e6e7e118eabedbcd51","src/log.rs":"c46bae3472043fd076df3229c3421d948a87fae8495c1524b41ab2d8608f612a","src/stream.rs":"cd8dccefe88c584264af908169f566b1f65fdab79792a9abf7e38342ca9b8e62","src/try_call.rs":"231bfa3f3448f7531427bb228beb2bcd4fd711f0b13d2d8f412af013470f40c7","src/util.rs":"308cfbaacd615ff600e74415c52daeef007fff34a4a0648a73c0042f6067f84f"},"package":"169d9a36f5daa60f9c4597905132aef056cf62693addd4a3421492853ccad565"}
\ No newline at end of file
diff --git a/third_party/rust/cubeb-core/Cargo.toml b/third_party/rust/cubeb-core/Cargo.toml
index 340ef0505ea68bb85b34f4f988ba2df1adebce5c..ac35932895ab48668881fe54896d1288ea152a6d 100644
--- a/third_party/rust/cubeb-core/Cargo.toml
+++ b/third_party/rust/cubeb-core/Cargo.toml
@@ -12,7 +12,7 @@
 
 [package]
 name = "cubeb-core"
-version = "0.4.4"
+version = "0.5.0"
 authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
 description = "Common types and definitions for cubeb rust and C bindings. Not intended for direct use.\n"
 homepage = "https://github.com/djg/cubeb-rs"
@@ -24,7 +24,7 @@ repository = "https://github.com/djg/cubeb-rs"
 version = "1.0"
 
 [dependencies.cubeb-sys]
-version = "0.4.1"
+version = "0.5.0"
 
 [features]
 gecko-in-tree = ["cubeb-sys/gecko-in-tree"]
diff --git a/third_party/rust/cubeb-core/src/builders.rs b/third_party/rust/cubeb-core/src/builders.rs
index e75babb5c7f2374fdb8258ba1d13207c12404a33..b3a1ab2e17d195b7461b55bde127541bf9a8ce13 100644
--- a/third_party/rust/cubeb-core/src/builders.rs
+++ b/third_party/rust/cubeb-core/src/builders.rs
@@ -117,24 +117,27 @@ mod tests {
             ) );
 
         check!(
-            Undefined,
-            DualMono,
-            DualMonoLfe,
-            Mono,
-            MonoLfe,
-            Stereo,
-            StereoLfe,
-            Layout3F,
-            Layout3FLfe,
-            Layout2F1,
-            Layout2F1Lfe,
-            Layout3F1,
-            Layout3F1Lfe,
-            Layout2F2,
-            Layout2F2Lfe,
-            Layout3F2,
-            Layout3F3RLfe,
-            Layout3F4Lfe
+            UNDEFINED,
+            MONO,
+            MONO_LFE,
+            STEREO,
+            STEREO_LFE,
+            _3F,
+            _3F_LFE,
+            _2F1,
+            _2F1_LFE,
+            _3F1,
+            _3F1_LFE,
+            _2F2,
+            _2F2_LFE,
+            QUAD,
+            QUAD_LFE,
+            _3F2,
+            _3F2_LFE,
+            _3F2_BACK,
+            _3F2_LFE_BACK,
+            _3F3R_LFE,
+            _3F4_LFE
         );
     }
 
@@ -210,25 +213,27 @@ mod tests {
                 )*
             ) );
 
-        check!(Undefined => CUBEB_LAYOUT_UNDEFINED,
-               DualMono => CUBEB_LAYOUT_DUAL_MONO,
-               DualMonoLfe => CUBEB_LAYOUT_DUAL_MONO_LFE,
-               Mono => CUBEB_LAYOUT_MONO,
-               MonoLfe => CUBEB_LAYOUT_MONO_LFE,
-               Stereo => CUBEB_LAYOUT_STEREO,
-               StereoLfe => CUBEB_LAYOUT_STEREO_LFE,
-               Layout3F => CUBEB_LAYOUT_3F,
-               Layout3FLfe => CUBEB_LAYOUT_3F_LFE,
-               Layout2F1 => CUBEB_LAYOUT_2F1,
-               Layout2F1Lfe => CUBEB_LAYOUT_2F1_LFE,
-               Layout3F1 => CUBEB_LAYOUT_3F1,
-               Layout3F1Lfe => CUBEB_LAYOUT_3F1_LFE,
-               Layout2F2 => CUBEB_LAYOUT_2F2,
-               Layout2F2Lfe => CUBEB_LAYOUT_2F2_LFE,
-               Layout3F2 => CUBEB_LAYOUT_3F2,
-               Layout3F2Lfe => CUBEB_LAYOUT_3F2_LFE,
-               Layout3F3RLfe => CUBEB_LAYOUT_3F3R_LFE,
-               Layout3F4Lfe => CUBEB_LAYOUT_3F4_LFE);
+        check!(UNDEFINED => CUBEB_LAYOUT_UNDEFINED,
+               MONO => CUBEB_LAYOUT_MONO,
+               MONO_LFE => CUBEB_LAYOUT_MONO_LFE,
+               STEREO => CUBEB_LAYOUT_STEREO,
+               STEREO_LFE => CUBEB_LAYOUT_STEREO_LFE,
+               _3F => CUBEB_LAYOUT_3F,
+               _3F_LFE => CUBEB_LAYOUT_3F_LFE,
+               _2F1 => CUBEB_LAYOUT_2F1,
+               _2F1_LFE=> CUBEB_LAYOUT_2F1_LFE,
+               _3F1 => CUBEB_LAYOUT_3F1,
+               _3F1_LFE =>  CUBEB_LAYOUT_3F1_LFE,
+               _2F2 => CUBEB_LAYOUT_2F2,
+               _2F2_LFE => CUBEB_LAYOUT_2F2_LFE,
+               QUAD => CUBEB_LAYOUT_QUAD,
+               QUAD_LFE => CUBEB_LAYOUT_QUAD_LFE,
+               _3F2 => CUBEB_LAYOUT_3F2,
+               _3F2_LFE => CUBEB_LAYOUT_3F2_LFE,
+               _3F2_BACK => CUBEB_LAYOUT_3F2_BACK,
+               _3F2_LFE_BACK => CUBEB_LAYOUT_3F2_LFE_BACK,
+               _3F3R_LFE => CUBEB_LAYOUT_3F3R_LFE,
+               _3F4_LFE => CUBEB_LAYOUT_3F4_LFE);
     }
 
     #[test]
diff --git a/third_party/rust/cubeb-core/src/channel.rs b/third_party/rust/cubeb-core/src/channel.rs
index fc670387ba339b3db1ccaa8c06c262a8675e3c12..8602f4ce6fccf055f125da31865b539c40355d85 100644
--- a/third_party/rust/cubeb-core/src/channel.rs
+++ b/third_party/rust/cubeb-core/src/channel.rs
@@ -5,101 +5,147 @@
 
 use ffi;
 
-/// SMPTE channel layout (also known as wave order)
-///
-/// ---------------------------------------------------
-/// Name          | Channels
-/// ---------------------------------------------------
-/// DUAL-MONO     | L   R
-/// DUAL-MONO-LFE | L   R   LFE
-/// MONO          | M
-/// MONO-LFE      | M   LFE
-/// STEREO        | L   R
-/// STEREO-LFE    | L   R   LFE
-/// 3F            | L   R   C
-/// 3F-LFE        | L   R   C    LFE
-/// 2F1           | L   R   S
-/// 2F1-LFE       | L   R   LFE  S
-/// 3F1           | L   R   C    S
-/// 3F1-LFE       | L   R   C    LFE S
-/// 2F2           | L   R   LS   RS
-/// 2F2-LFE       | L   R   LFE  LS   RS
-/// 3F2           | L   R   C    LS   RS
-/// 3F2-LFE       | L   R   C    LFE  LS   RS
-/// 3F3R-LFE      | L   R   C    LFE  RC   LS   RS
-/// 3F4-LFE       | L   R   C    LFE  RLS  RRS  LS   RS
-/// ---------------------------------------------------
-///
-/// The abbreviation of channel name is defined in following table:
-/// ---------------------------
-/// Abbr | Channel name
-/// ---------------------------
-/// M    | Mono
-/// L    | Left
-/// R    | Right
-/// C    | Center
-/// LS   | Left Surround
-/// RS   | Right Surround
-/// RLS  | Rear Left Surround
-/// RC   | Rear Center
-/// RRS  | Rear Right Surround
-/// LFE  | Low Frequency Effects
-/// ---------------------------
-#[cfg_attr(target_env = "msvc", repr(i32))]
-#[cfg_attr(not(target_env = "msvc"), repr(u32))]
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum ChannelLayout {
-    Undefined = ffi::CUBEB_LAYOUT_UNDEFINED,
-    DualMono = ffi::CUBEB_LAYOUT_DUAL_MONO,
-    DualMonoLfe = ffi::CUBEB_LAYOUT_DUAL_MONO_LFE,
-    Mono = ffi::CUBEB_LAYOUT_MONO,
-    MonoLfe = ffi::CUBEB_LAYOUT_MONO_LFE,
-    Stereo = ffi::CUBEB_LAYOUT_STEREO,
-    StereoLfe = ffi::CUBEB_LAYOUT_STEREO_LFE,
-    Layout3F = ffi::CUBEB_LAYOUT_3F,
-    Layout3FLfe = ffi::CUBEB_LAYOUT_3F_LFE,
-    Layout2F1 = ffi::CUBEB_LAYOUT_2F1,
-    Layout2F1Lfe = ffi::CUBEB_LAYOUT_2F1_LFE,
-    Layout3F1 = ffi::CUBEB_LAYOUT_3F1,
-    Layout3F1Lfe = ffi::CUBEB_LAYOUT_3F1_LFE,
-    Layout2F2 = ffi::CUBEB_LAYOUT_2F2,
-    Layout2F2Lfe = ffi::CUBEB_LAYOUT_2F2_LFE,
-    Layout3F2 = ffi::CUBEB_LAYOUT_3F2,
-    Layout3F2Lfe = ffi::CUBEB_LAYOUT_3F2_LFE,
-    Layout3F3RLfe = ffi::CUBEB_LAYOUT_3F3R_LFE,
-    Layout3F4Lfe = ffi::CUBEB_LAYOUT_3F4_LFE,
+bitflags! {
+    /// Some common layout definitions
+    pub struct ChannelLayout: ffi::cubeb_channel_layout {
+        ///
+        const FRONT_LEFT = ffi::CHANNEL_FRONT_LEFT;
+        const FRONT_RIGHT = ffi::CHANNEL_FRONT_RIGHT;
+        const FRONT_CENTER = ffi::CHANNEL_FRONT_CENTER;
+        const LOW_FREQUENCY = ffi::CHANNEL_LOW_FREQUENCY;
+        const BACK_LEFT = ffi::CHANNEL_BACK_LEFT;
+        const BACK_RIGHT = ffi::CHANNEL_BACK_RIGHT;
+        const FRONT_LEFT_OF_CENTER = ffi::CHANNEL_FRONT_LEFT_OF_CENTER;
+        const FRONT_RIGHT_OF_CENTER = ffi::CHANNEL_FRONT_RIGHT_OF_CENTER;
+        const BACK_CENTER = ffi::CHANNEL_BACK_CENTER;
+        const SIDE_LEFT = ffi::CHANNEL_SIDE_LEFT;
+        const SIDE_RIGHT = ffi::CHANNEL_SIDE_RIGHT;
+        const TOP_CENTER = ffi::CHANNEL_TOP_CENTER;
+        const TOP_FRONT_LEFT = ffi::CHANNEL_TOP_FRONT_LEFT;
+        const TOP_FRONT_CENTER = ffi::CHANNEL_TOP_FRONT_CENTER;
+        const TOP_FRONT_RIGHT = ffi::CHANNEL_TOP_FRONT_RIGHT;
+        const TOP_BACK_LEFT = ffi::CHANNEL_TOP_BACK_LEFT;
+        const TOP_BACK_CENTER = ffi::CHANNEL_TOP_BACK_CENTER;
+        const TOP_BACK_RIGHT = ffi::CHANNEL_TOP_BACK_RIGHT;
+    }
+}
+
+macro_rules! bits {
+    ($($x:ident => $y:ident),*) => {
+        $(pub const $x: ChannelLayout = ChannelLayout { bits: ffi::$y };)*
+    }
+}
+
+impl ChannelLayout {
+    bits!(UNDEFINED => CUBEB_LAYOUT_UNDEFINED,
+          MONO => CUBEB_LAYOUT_MONO,
+          MONO_LFE => CUBEB_LAYOUT_MONO_LFE,
+          STEREO => CUBEB_LAYOUT_STEREO,
+          STEREO_LFE => CUBEB_LAYOUT_STEREO_LFE,
+          _3F => CUBEB_LAYOUT_3F,
+          _3F_LFE => CUBEB_LAYOUT_3F_LFE,
+          _2F1 => CUBEB_LAYOUT_2F1,
+          _2F1_LFE => CUBEB_LAYOUT_2F1_LFE,
+          _3F1 => CUBEB_LAYOUT_3F1,
+          _3F1_LFE => CUBEB_LAYOUT_3F1_LFE,
+          _2F2 => CUBEB_LAYOUT_2F2,
+          _2F2_LFE => CUBEB_LAYOUT_2F2_LFE,
+          QUAD => CUBEB_LAYOUT_QUAD,
+          QUAD_LFE => CUBEB_LAYOUT_QUAD_LFE,
+          _3F2 => CUBEB_LAYOUT_3F2,
+          _3F2_LFE => CUBEB_LAYOUT_3F2_LFE,
+          _3F2_BACK => CUBEB_LAYOUT_3F2_BACK,
+          _3F2_LFE_BACK => CUBEB_LAYOUT_3F2_LFE_BACK,
+          _3F3R_LFE => CUBEB_LAYOUT_3F3R_LFE,
+          _3F4_LFE => CUBEB_LAYOUT_3F4_LFE
+    );
+}
+
+impl From<ffi::cubeb_channel> for ChannelLayout {
+    fn from(x: ffi::cubeb_channel) -> Self {
+        ChannelLayout::from_bits_truncate(x)
+    }
 }
 
-impl From<ffi::cubeb_channel_layout> for ChannelLayout {
-    fn from(x: ffi::cubeb_channel_layout) -> ChannelLayout {
-        match x {
-            ffi::CUBEB_LAYOUT_DUAL_MONO => ChannelLayout::DualMono,
-            ffi::CUBEB_LAYOUT_DUAL_MONO_LFE => ChannelLayout::DualMonoLfe,
-            ffi::CUBEB_LAYOUT_MONO => ChannelLayout::Mono,
-            ffi::CUBEB_LAYOUT_MONO_LFE => ChannelLayout::MonoLfe,
-            ffi::CUBEB_LAYOUT_STEREO => ChannelLayout::Stereo,
-            ffi::CUBEB_LAYOUT_STEREO_LFE => ChannelLayout::StereoLfe,
-            ffi::CUBEB_LAYOUT_3F => ChannelLayout::Layout3F,
-            ffi::CUBEB_LAYOUT_3F_LFE => ChannelLayout::Layout3FLfe,
-            ffi::CUBEB_LAYOUT_2F1 => ChannelLayout::Layout2F1,
-            ffi::CUBEB_LAYOUT_2F1_LFE => ChannelLayout::Layout2F1Lfe,
-            ffi::CUBEB_LAYOUT_3F1 => ChannelLayout::Layout3F1,
-            ffi::CUBEB_LAYOUT_3F1_LFE => ChannelLayout::Layout3F1Lfe,
-            ffi::CUBEB_LAYOUT_2F2 => ChannelLayout::Layout2F2,
-            ffi::CUBEB_LAYOUT_2F2_LFE => ChannelLayout::Layout2F2Lfe,
-            ffi::CUBEB_LAYOUT_3F2 => ChannelLayout::Layout3F2,
-            ffi::CUBEB_LAYOUT_3F2_LFE => ChannelLayout::Layout3F2Lfe,
-            ffi::CUBEB_LAYOUT_3F3R_LFE => ChannelLayout::Layout3F3RLfe,
-            ffi::CUBEB_LAYOUT_3F4_LFE => ChannelLayout::Layout3F4Lfe,
-            // TODO: Implement TryFrom
-            // Everything else is just undefined.
-            _ => ChannelLayout::Undefined,
-        }
+impl Into<ffi::cubeb_channel> for ChannelLayout {
+    fn into(self) -> ffi::cubeb_channel {
+        self.bits()
     }
 }
 
-impl Into<ffi::cubeb_channel_layout> for ChannelLayout {
-    fn into(self) -> ffi::cubeb_channel_layout {
-        self as ffi::cubeb_channel_layout
+impl ChannelLayout {
+    pub fn num_channels(&self) -> u32 {
+        let layout = *self;
+        unsafe { ffi::cubeb_channel_layout_nb_channels(layout.into()) }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use ffi;
+
+    #[test]
+    fn channel_layout_from_raw() {
+        macro_rules! check(
+            ($($raw:ident => $real:ident),*) => (
+                $(let x = super::ChannelLayout::from(ffi::$raw);;
+                  assert_eq!(x, super::ChannelLayout::$real);
+                )*
+            ) );
+
+        check!(CUBEB_LAYOUT_UNDEFINED => UNDEFINED,
+               CUBEB_LAYOUT_MONO => MONO,
+               CUBEB_LAYOUT_MONO_LFE => MONO_LFE,
+               CUBEB_LAYOUT_STEREO => STEREO,
+               CUBEB_LAYOUT_STEREO_LFE => STEREO_LFE,
+               CUBEB_LAYOUT_3F => _3F,
+               CUBEB_LAYOUT_3F_LFE => _3F_LFE,
+               CUBEB_LAYOUT_2F1 => _2F1,
+               CUBEB_LAYOUT_2F1_LFE => _2F1_LFE,
+               CUBEB_LAYOUT_3F1 => _3F1,
+               CUBEB_LAYOUT_3F1_LFE => _3F1_LFE,
+               CUBEB_LAYOUT_2F2 => _2F2,
+               CUBEB_LAYOUT_2F2_LFE => _2F2_LFE,
+               CUBEB_LAYOUT_QUAD => QUAD,
+               CUBEB_LAYOUT_QUAD_LFE => QUAD_LFE,
+               CUBEB_LAYOUT_3F2 => _3F2,
+               CUBEB_LAYOUT_3F2_LFE => _3F2_LFE,
+               CUBEB_LAYOUT_3F2_BACK => _3F2_BACK,
+               CUBEB_LAYOUT_3F2_LFE_BACK => _3F2_LFE_BACK,
+               CUBEB_LAYOUT_3F3R_LFE => _3F3R_LFE,
+               CUBEB_LAYOUT_3F4_LFE => _3F4_LFE);
+    }
+
+    #[test]
+    fn channel_layout_into_raw() {
+        macro_rules! check(
+            ($($real:ident => $raw:ident),*) => (
+                $(let x = super::ChannelLayout::$real;
+                  let x: ffi::cubeb_channel_layout = x.into();
+                  assert_eq!(x, ffi::$raw);
+                )*
+            ) );
+
+        check!(UNDEFINED => CUBEB_LAYOUT_UNDEFINED,
+               MONO => CUBEB_LAYOUT_MONO,
+               MONO_LFE => CUBEB_LAYOUT_MONO_LFE,
+               STEREO => CUBEB_LAYOUT_STEREO,
+               STEREO_LFE => CUBEB_LAYOUT_STEREO_LFE,
+               _3F => CUBEB_LAYOUT_3F,
+               _3F_LFE => CUBEB_LAYOUT_3F_LFE,
+               _2F1 => CUBEB_LAYOUT_2F1,
+               _2F1_LFE=> CUBEB_LAYOUT_2F1_LFE,
+               _3F1 => CUBEB_LAYOUT_3F1,
+               _3F1_LFE =>  CUBEB_LAYOUT_3F1_LFE,
+               _2F2 => CUBEB_LAYOUT_2F2,
+               _2F2_LFE => CUBEB_LAYOUT_2F2_LFE,
+               QUAD => CUBEB_LAYOUT_QUAD,
+               QUAD_LFE => CUBEB_LAYOUT_QUAD_LFE,
+               _3F2 => CUBEB_LAYOUT_3F2,
+               _3F2_LFE => CUBEB_LAYOUT_3F2_LFE,
+               _3F2_BACK => CUBEB_LAYOUT_3F2_BACK,
+               _3F2_LFE_BACK => CUBEB_LAYOUT_3F2_LFE_BACK,
+               _3F3R_LFE => CUBEB_LAYOUT_3F3R_LFE,
+               _3F4_LFE => CUBEB_LAYOUT_3F4_LFE);
     }
 }
diff --git a/third_party/rust/cubeb-core/src/context.rs b/third_party/rust/cubeb-core/src/context.rs
index eede5f2f1a7bf67e9d2c5fb224ed9d893dc202a0..a9fdcd1395698afda096cd1ed4d9ef426286ae17 100644
--- a/third_party/rust/cubeb-core/src/context.rs
+++ b/third_party/rust/cubeb-core/src/context.rs
@@ -3,7 +3,7 @@
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
-use {ChannelLayout, DeviceCollection, DeviceId, DeviceType, Result, Stream, StreamParamsRef};
+use {DeviceCollection, DeviceId, DeviceType, Result, Stream, StreamParamsRef};
 use ffi;
 use std::{ptr, str};
 use std::ffi::CStr;
@@ -76,17 +76,6 @@ impl ContextRef {
         Ok(rate)
     }
 
-    pub fn preferred_channel_layout(&self) -> Result<ChannelLayout> {
-        let mut layout: ffi::cubeb_channel_layout = ffi::CUBEB_LAYOUT_UNDEFINED;
-        unsafe {
-            let _ = try_call!(ffi::cubeb_get_preferred_channel_layout(
-                self.as_ptr(),
-                &mut layout
-            ));
-        }
-        Ok(ChannelLayout::from(layout))
-    }
-
     #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
     pub unsafe fn stream_init(
         &self,
diff --git a/third_party/rust/cubeb-core/src/stream.rs b/third_party/rust/cubeb-core/src/stream.rs
index c2ff6f0ef95089d3beb45bef77d22aba6300788b..c26d59d80fbc90e71e464ceb2c77dcead38c9b7d 100644
--- a/third_party/rust/cubeb-core/src/stream.rs
+++ b/third_party/rust/cubeb-core/src/stream.rs
@@ -85,35 +85,7 @@ impl StreamParamsRef {
     }
 
     pub fn layout(&self) -> ChannelLayout {
-        macro_rules! check( ($($raw:ident => $real:ident),*) => {{
-            let layout = self.get_ref().layout;
-            $(if layout == ffi::$raw {
-                ChannelLayout::$real
-            }) else *
-            else {
-                panic!("unknown channel layout: {}", layout)
-            }
-        }} );
-
-        check!(CUBEB_LAYOUT_UNDEFINED => Undefined,
-               CUBEB_LAYOUT_DUAL_MONO => DualMono,
-               CUBEB_LAYOUT_DUAL_MONO_LFE => DualMonoLfe,
-               CUBEB_LAYOUT_MONO => Mono,
-               CUBEB_LAYOUT_MONO_LFE => MonoLfe,
-               CUBEB_LAYOUT_STEREO => Stereo,
-               CUBEB_LAYOUT_STEREO_LFE => StereoLfe,
-               CUBEB_LAYOUT_3F => Layout3F,
-               CUBEB_LAYOUT_3F_LFE => Layout3FLfe,
-               CUBEB_LAYOUT_2F1 => Layout2F1,
-               CUBEB_LAYOUT_2F1_LFE => Layout2F1Lfe,
-               CUBEB_LAYOUT_3F1 => Layout3F1,
-               CUBEB_LAYOUT_3F1_LFE => Layout3F1Lfe,
-               CUBEB_LAYOUT_2F2 => Layout2F2,
-               CUBEB_LAYOUT_2F2_LFE => Layout2F2Lfe,
-               CUBEB_LAYOUT_3F2 => Layout3F2,
-               CUBEB_LAYOUT_3F2_LFE => Layout3F2Lfe,
-               CUBEB_LAYOUT_3F3R_LFE => Layout3F3RLfe,
-               CUBEB_LAYOUT_3F4_LFE => Layout3F4Lfe)
+        ChannelLayout::from(self.get_ref().layout)
     }
 
     pub fn prefs(&self) -> StreamPrefs {
@@ -297,25 +269,27 @@ mod tests {
                 )*
             ) );
 
-        check!(CUBEB_LAYOUT_UNDEFINED => Undefined,
-               CUBEB_LAYOUT_DUAL_MONO => DualMono,
-               CUBEB_LAYOUT_DUAL_MONO_LFE => DualMonoLfe,
-               CUBEB_LAYOUT_MONO => Mono,
-               CUBEB_LAYOUT_MONO_LFE => MonoLfe,
-               CUBEB_LAYOUT_STEREO => Stereo,
-               CUBEB_LAYOUT_STEREO_LFE => StereoLfe,
-               CUBEB_LAYOUT_3F => Layout3F,
-               CUBEB_LAYOUT_3F_LFE => Layout3FLfe,
-               CUBEB_LAYOUT_2F1 => Layout2F1,
-               CUBEB_LAYOUT_2F1_LFE => Layout2F1Lfe,
-               CUBEB_LAYOUT_3F1 => Layout3F1,
-               CUBEB_LAYOUT_3F1_LFE => Layout3F1Lfe,
-               CUBEB_LAYOUT_2F2 => Layout2F2,
-               CUBEB_LAYOUT_2F2_LFE => Layout2F2Lfe,
-               CUBEB_LAYOUT_3F2 => Layout3F2,
-               CUBEB_LAYOUT_3F2_LFE => Layout3F2Lfe,
-               CUBEB_LAYOUT_3F3R_LFE => Layout3F3RLfe,
-               CUBEB_LAYOUT_3F4_LFE => Layout3F4Lfe);
+        check!(CUBEB_LAYOUT_UNDEFINED => UNDEFINED,
+               CUBEB_LAYOUT_MONO => MONO,
+               CUBEB_LAYOUT_MONO_LFE => MONO_LFE,
+               CUBEB_LAYOUT_STEREO => STEREO,
+               CUBEB_LAYOUT_STEREO_LFE => STEREO_LFE,
+               CUBEB_LAYOUT_3F => _3F,
+               CUBEB_LAYOUT_3F_LFE => _3F_LFE,
+               CUBEB_LAYOUT_2F1 => _2F1,
+               CUBEB_LAYOUT_2F1_LFE => _2F1_LFE,
+               CUBEB_LAYOUT_3F1 => _3F1,
+               CUBEB_LAYOUT_3F1_LFE => _3F1_LFE,
+               CUBEB_LAYOUT_2F2 => _2F2,
+               CUBEB_LAYOUT_2F2_LFE => _2F2_LFE,
+               CUBEB_LAYOUT_QUAD => QUAD,
+               CUBEB_LAYOUT_QUAD_LFE => QUAD_LFE,
+               CUBEB_LAYOUT_3F2 => _3F2,
+               CUBEB_LAYOUT_3F2_LFE => _3F2_LFE,
+               CUBEB_LAYOUT_3F2_BACK => _3F2_BACK,
+               CUBEB_LAYOUT_3F2_LFE_BACK => _3F2_LFE_BACK,
+               CUBEB_LAYOUT_3F3R_LFE => _3F3R_LFE,
+               CUBEB_LAYOUT_3F4_LFE => _3F4_LFE);
     }
 
     #[test]
diff --git a/third_party/rust/cubeb-sys/.cargo-checksum.json b/third_party/rust/cubeb-sys/.cargo-checksum.json
index bd8441d2ed1c12a514418c767d9f69b652cc5635..eab1e98e6b765d8353aea887578b17d975a53079 100644
--- a/third_party/rust/cubeb-sys/.cargo-checksum.json
+++ b/third_party/rust/cubeb-sys/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"9c7435ec35196feeee3229e1f2ead5101d14e18a72956820464378e335bd9cf6","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","build.rs":"49985a30631de0015517fc260321aa03a003eaf26d80650bebd928d55edc9444","libcubeb/.gitmodules":"6fe6fc18ff76ba8dd3dc749247d61a2f4a18c1e42b1890581e234ab8151d4c95","libcubeb/.travis.yml":"edb891b3c9edc375d8296d93a79bcbb8e5f884f695b3115a7c0d57cf45471823","libcubeb/AUTHORS":"829e45d138c7c8827799f302806fa4be8cd8bd4bad70a2fe26c3a27a5cf36948","libcubeb/CMakeLists.txt":"017e5e2a43ccaff30f4dc52070a31a0c4938b46714e9c4ae7558e5d3d53115ed","libcubeb/Config.cmake.in":"88019286c96ef3d5d3a673b183c8655dfc97ceede07d3eb6c18f0c51bb896388","libcubeb/INSTALL.md":"7a84cdfbe86e7d3180e2203603b88571df61b369421fa97ee86740ffd4d4db8e","libcubeb/LICENSE":"44c6b5ae5ec3fe2fbc608b00e6f4896f4d2d5c7e525fcbaa3eaa3cf2f3d5a983","libcubeb/README.md":"aa417156dc65069264901b75fc3c792c73021ec61c909de04e109bd4184c07ab","libcubeb/TODO":"6f8065136e005d2becee810e3d8697a94f2c755f8c79687adfac7136ad165e80","libcubeb/appveyor.yml":"9a87fdc18b76fca1167289ecb2ec3a210b76984c1d7e92268b2cd36f1e00f541","libcubeb/cmake/sanitizers-cmake/CMakeLists.txt":"89b282c19b3897ff666f7847d5e679ae928ca7e76ffd0d23f7c58c9464048b61","libcubeb/cmake/sanitizers-cmake/LICENSE":"4b67e7ae8c91e68e1a929eb1cbaa4c773c6d19aa91aaa12c390cf9560d1c9799","libcubeb/cmake/sanitizers-cmake/README.md":"30ab1524618ac828b75f9b83c665a0bd50b839b42ce61519a8048d73f401da6e","libcubeb/cmake/sanitizers-cmake/cmake/FindASan.cmake":"cba07ffe438c57bef0840ed6a2d2890676530b66509da3c616438c53018baa4f","libcubeb/cmake/sanitizers-cmake/cmake/FindMSan.cmake":"1303aac5028fe9f64d42be0afd47f1291e679d74f8280b3dc5271f20ebf4d7a4","libcubeb/cmake/sanitizers-cmake/cmake/FindSanitizers.cmake":"ce1971b943bbef08fb9aba958cf28e3cbdff075406c85a3cfed22e00c9f8d9a8","libcubeb/cmake/sanitizers-cmake/cmake/FindTSan.cmake":"edca39b287312e9a8fc718f6ec791d2520515900b37426091310fe1bd52dc6a1","libcubeb/cmake/sanitizers-cmake/cmake/FindUBSan.cmake":"5b9d3621f629c807a1345a7cb053677a8bf25782a079e345dda53d04aecdc4b7","libcubeb/cmake/sanitizers-cmake/cmake/asan-wrapper":"4e543936e6374e24b80a0f92135c07c2e2101c0d110e51bddaf0e70ae8ec391e","libcubeb/cmake/sanitizers-cmake/cmake/sanitize-helpers.cmake":"282620734c2a8062f1280d0dde3121b8b01af26e5ecaa7d4308e145f80ecd115","libcubeb/cmake/sanitizers-cmake/tests/CMakeLists.txt":"fb983bab7040be002847db59c2493abfd249f67ad06e3a9270fbceb9fabda11c","libcubeb/cmake/sanitizers-cmake/tests/asan_test.cpp":"8b351c7c8668b4a2438286df426f0ad322cade6d1c6199a74668ccbd1c5204a4","libcubeb/cmake/toolchain-cross-android.cmake":"59d2355845a71647b353fb8b18fca630db8ffee7bb8500143e2d6fbc409cec97","libcubeb/cmake/toolchain-cross-mingw.cmake":"b09dc261981c0d4a0f8430f05aae9c8fc545651cd9cbfacd09754277b776b532","libcubeb/cubeb.supp":"19f33e59f8dc91a327c923e44c2c3f9af0a043ce1d6a8cac275ba094b4bfe0da","libcubeb/docs/Doxyfile.in":"0815f19789cedd310652a133bab260c27b57e95f7a65458df2dfca38ea4f1041","libcubeb/googletest/CHANGES":"72c8a289bfe4dd9160074a3a2238c8067a5bc7ca49fd87f70a134c3f373932a4","libcubeb/googletest/CMakeLists.txt":"cdf938ce79ea066866dc614de3925bfaa48d9e19e04049db2ec8c5443abaaa9b","libcubeb/googletest/CONTRIBUTORS":"4d911cd5e6d71f3f4bbcb2788b2f916df4b0ce1e088752a159457a1d936ae0ce","libcubeb/googletest/COPYING":"9702de7e4117a8e2b20dafab11ffda58c198aede066406496bef670d40a22138","libcubeb/googletest/Makefile.am":"a795e5a18e82ba06fd97509d92d773b7fafd0dd7086db8a1211fbd151b503bac","libcubeb/googletest/README":"484b19654362942fac9734c8fab0ed3d99249b81c69027bdb7de46054abada6b","libcubeb/googletest/build-aux/.keep":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","libcubeb/googletest/cmake/internal_utils.cmake":"6f4670a5825cf8ae0415be9dd43d82a7f30316d75cab20a4c60afb6d9db2a01d","libcubeb/googletest/codegear/gtest.cbproj":"9fa07a66b8c01773256e508187775407c465ed9055651e93d390426d1888721a","libcubeb/googletest/codegear/gtest.groupproj":"76c001cb2ee0070e26d1570fb6db5250f2585179c707496c5ef6d12e582cf205","libcubeb/googletest/codegear/gtest_all.cc":"c8750dc2b7b3612edb60e8d23fc2f60ae264451916c4b15f81cbf60ea30eb75d","libcubeb/googletest/codegear/gtest_link.cc":"e5e47c086f932471e0ca748a62b3b1597e5e731f4d34fb8cb8b2ca2db7ba3ed0","libcubeb/googletest/codegear/gtest_main.cbproj":"056448ba7f41fae3f704b1001922d9f6e419cf8cbcf3a55bf0ecc59ece1fa9a1","libcubeb/googletest/codegear/gtest_unittest.cbproj":"2c48be90b0dbc3224a8bd6c4dc21f78dd1b08c81685e6bd4952bb6df6ee38701","libcubeb/googletest/configure.ac":"fadebffdaeaccebb60fbe4a501c1138c296e01348a5da45fabf5e4233248baa8","libcubeb/googletest/include/gtest/gtest-death-test.h":"fdd087f700cd04a3ce4bdd36f35769de52a44bfc0c5bae2dc9681d4cbcd3c44a","libcubeb/googletest/include/gtest/gtest-message.h":"eaf44df1284d94333507c47091c84eaaf43814e6a02a1b1c0061ca7b363e74d6","libcubeb/googletest/include/gtest/gtest-param-test.h":"f226f0a24c04cddbceaaa45d8a5e575ce18c3392349f9b8ba73317e37e62368d","libcubeb/googletest/include/gtest/gtest-param-test.h.pump":"17c65fd5cc5218279044a61f3873c9c952b0924a7ba5147d4999d400b122207f","libcubeb/googletest/include/gtest/gtest-printers.h":"7046f611398d63ee0f1c37bdb4fd08d9931979b2fedf13b781e6d85d4b3b5d60","libcubeb/googletest/include/gtest/gtest-spi.h":"560407dd45e8e57fa6927504c9e4a4cfdecf30f8cada975c1ffddce765e6a88a","libcubeb/googletest/include/gtest/gtest-test-part.h":"c4d6d840284728740c284646075e8ffc85b63b9f74f3ed488b18ef3c2c2b9005","libcubeb/googletest/include/gtest/gtest-typed-test.h":"1ec858bbb9ed8a8bb553232df016437c080b2670f00453b4de297c286eb78c21","libcubeb/googletest/include/gtest/gtest.h":"47433ca72a43bda7a380c34fe6d4ff451797c687e9bbd74d1f366bcdfa0cb013","libcubeb/googletest/include/gtest/gtest_pred_impl.h":"f03a3f77e3c231889c0ace6f63b2c4e410e4a9330287ea09443b23b9a3cf9092","libcubeb/googletest/include/gtest/gtest_prod.h":"4a99a3d986a45b4d6d9b3af54809f015c54aa98274793a4ae173f5010d0ad33c","libcubeb/googletest/include/gtest/internal/gtest-death-test-internal.h":"0b3abead866363f3e6b4201acc8d2763072e033826b22ae5ebffd790e1415235","libcubeb/googletest/include/gtest/internal/gtest-filepath.h":"638d2bb6c06a894513b03311a8e931ac835fc00afc4bd21fab3afc05732c23a0","libcubeb/googletest/include/gtest/internal/gtest-internal.h":"12c2c83df0a9dc5b46697ccd8271dfa34ee5f3d1972dcb56585bc1459d9583c9","libcubeb/googletest/include/gtest/internal/gtest-linked_ptr.h":"9bd319548dd073630dfd349c06a440c6a582feec47d4ff14f348ec32f8b4c1f3","libcubeb/googletest/include/gtest/internal/gtest-param-util-generated.h":"10db93fa7e98820192bae6f560664469dd33b265036fca64253c89b6801f96cb","libcubeb/googletest/include/gtest/internal/gtest-param-util-generated.h.pump":"abb72365d94d2811b34c195dc520fbf41c7dcb42aae5a1cfa0502cf619b21e70","libcubeb/googletest/include/gtest/internal/gtest-param-util.h":"7f9311f033ef6916217d87cef53b1db6c4e8733be930e4b48fe7e11d21b33da0","libcubeb/googletest/include/gtest/internal/gtest-port.h":"612932c2930a7cf2c3514d89a8d6b51a2c0030d251309b71765ed1c9954e20c5","libcubeb/googletest/include/gtest/internal/gtest-string.h":"a46aa36165c400d1e926f942be03fe04cd7ccb1e59f7a2a03b919c4eea05b997","libcubeb/googletest/include/gtest/internal/gtest-tuple.h":"43e7e3c92f8e4258cf3927a9204b214d4d03e6c796f88f3ad4e66b1ac20aa938","libcubeb/googletest/include/gtest/internal/gtest-tuple.h.pump":"16fa027ed3c5940699e0ac906815e66620993bcf75b0acaf826d4f09348d4b83","libcubeb/googletest/include/gtest/internal/gtest-type-util.h":"6d177af46a9b1e14b969972a8b886667f95e69037aba411433a44fb9b92e7037","libcubeb/googletest/include/gtest/internal/gtest-type-util.h.pump":"22092f44127af91651f57ce222e20914d5d32ae02f1c0964f6d5d7bc019af339","libcubeb/googletest/m4/acx_pthread.m4":"3326e3746b6b351d1671fe31f798269cda8de92c365b8a8305404ec0fa6c6b32","libcubeb/googletest/m4/gtest.m4":"d3c37ebd1aa792c967d4357755cc670bc6deb30091d9e6db498871d90a30ea4c","libcubeb/googletest/make/Makefile":"9b86e2a112dd55c6bf6a2b39e6f4078faf60cfecb8282ebf9b025167ed233420","libcubeb/googletest/msvc/gtest-md.sln":"0beab679b42cf0c431eaf4fe143bbf3b01fc064e20c74d9e33e7e437a70487d4","libcubeb/googletest/msvc/gtest-md.vcproj":"52e873e964daf9d5409b4e9bb471ddf2827be04985cd96c40620f9275d17a256","libcubeb/googletest/msvc/gtest.sln":"be21c2340650ec2259a2fbaeb8608ae6d3e982a0626a0f91128a771dc88e6bea","libcubeb/googletest/msvc/gtest.vcproj":"0064616c7d88a284c1b7c05baab038f239134ea9c6c563628f286f9600b3f921","libcubeb/googletest/msvc/gtest_main-md.vcproj":"f83a294a92b616bf34ccae6743ff916297bdba61d6125a9637a813d467a30372","libcubeb/googletest/msvc/gtest_main.vcproj":"9f03270a00896eab0c7015c6fb1a73818d024e462d3944ba1d3ceb313a051649","libcubeb/googletest/msvc/gtest_prod_test-md.vcproj":"7caa108733e2d5f140da004d2133e04a9a105811909c0e2d4ec06e2971983592","libcubeb/googletest/msvc/gtest_prod_test.vcproj":"cf5bfb7f3de9a59a0eba5535067845d12c33c3fd8fecc3d03aa702665db29578","libcubeb/googletest/msvc/gtest_unittest-md.vcproj":"e7949b21cf0418f2a7afe8aa94616e2c40e3ba0801c2f0826f3a3a3d2e6f48b0","libcubeb/googletest/msvc/gtest_unittest.vcproj":"5b097d596fbbc1c4090fd518008a0961b29661194e1c02d8a2d3daaa557e626f","libcubeb/googletest/samples/prime_tables.h":"2903df1d1e6643a5f624fe3ea3f931c3410eb1858ac347c5df278273c6c91ca4","libcubeb/googletest/samples/sample1.cc":"dc106c5940d87bb4bbef3d77815eab642ee173a3340b2b9c532b5c711c4c2d0e","libcubeb/googletest/samples/sample1.h":"7a7bf9a0fbd2401e8b2cb554bfcb9bd0ed228212f3b970675c1b1d38d4e188bb","libcubeb/googletest/samples/sample10_unittest.cc":"ccebb6393a5a8468399f7e511219b667a2233f82312ce59834a4bb0997d8700e","libcubeb/googletest/samples/sample1_unittest.cc":"904be0d4a095e74393515195392bd10e1e916bb2ca61f3f94b1bd6aebea29cb6","libcubeb/googletest/samples/sample2.cc":"f14b8a1e69d52eef1a70053fb256818c7eca64e8eda08de43cf46e896e57fcc2","libcubeb/googletest/samples/sample2.h":"df956ba520dafca068dbc1e28f36567db3cba36293e06762318af8cda6a12bd4","libcubeb/googletest/samples/sample2_unittest.cc":"abe7e0b253d328cb82ae67623fbe3c89eb94699102510c64a0b568eaca101e05","libcubeb/googletest/samples/sample3-inl.h":"3fe482bbd4f725f5820f5d6beab4d0d4a524be8addf4b344a9a470ec5aabc451","libcubeb/googletest/samples/sample3_unittest.cc":"252c06b4531dc35213ebdd7311700b9b4057bc1bdeeba0cd767b2bc86c456639","libcubeb/googletest/samples/sample4.cc":"b4260f5fa35d78ac114a9abb59fce12403faf0273df41f57e83c341ae7979222","libcubeb/googletest/samples/sample4.h":"604905cae7e5587805c3b884a36eda7a2bebdfedb53b24b0fd9a220eec0ef1a9","libcubeb/googletest/samples/sample4_unittest.cc":"6cfb4821d8cb1c77fbb5af4f8aec569948762d8ea314827e3ead967b5b6a223e","libcubeb/googletest/samples/sample5_unittest.cc":"73646d9038873a68bb2e56b12495d7f7b65b5c23901109701da446af454ba2ec","libcubeb/googletest/samples/sample6_unittest.cc":"833fee399954f908cf0f3b789832e505329787f4cf73607a7b31ca0f62f368d7","libcubeb/googletest/samples/sample7_unittest.cc":"8013ee68d61c181e4e936cdae3a9a635646274f8512033ef11bff7214e03e4a6","libcubeb/googletest/samples/sample8_unittest.cc":"7b7510fadf4955d2f934d23d652dbd35add832e50bdfcc98421fb9be4588d808","libcubeb/googletest/samples/sample9_unittest.cc":"8b827040dea37b460cbcaea0b255b98974a9840f6ef7bd82aaa7d4ad2c724335","libcubeb/googletest/scripts/fuse_gtest_files.py":"adecf64c6bab65b31740c321e568cf174f753d5617745aa5762d842339d68b53","libcubeb/googletest/scripts/gen_gtest_pred_impl.py":"78fb7e20a014c251d723186eb58040e4eb32405b73c9288d787ea0a0e4ff5183","libcubeb/googletest/scripts/gtest-config.in":"9a43978eeee88e188845d737c17f4d024d4e74feae09da7997e8fbe4ea6cc176","libcubeb/googletest/scripts/pump.py":"3856a3d7be37f78e0f214ee7d4f29d05f1ca14218b67539d67c9a16e992f670c","libcubeb/googletest/scripts/test/Makefile":"3576b257594a2d8e843b9e4de8c83353d837833bb86431fb1b4198022b1bcddc","libcubeb/googletest/scripts/upload.py":"f75d0712e3b13bebd8daa0a15e4eb32c9e3034a933f4fcccf65b1e999a7ae066","libcubeb/googletest/scripts/upload_gtest.py":"6e76fc0a7a3831c01cfffd18c220d44438073a66338d91ca61fc84b924021e61","libcubeb/googletest/src/gtest-all.cc":"568ac119f5e6418f1fbcfbdf185d724657d7f3539b47822da229ac5d015626b2","libcubeb/googletest/src/gtest-death-test.cc":"eec1b3c8252670c76acbbaf63483946897ce625139b53a566406b6313f023896","libcubeb/googletest/src/gtest-filepath.cc":"31b7fcda5d11346f8a487597c6a70ff057f1192e0cb11f27eb7841a9f3aa8b86","libcubeb/googletest/src/gtest-internal-inl.h":"c9d428a6b5990ace091e40c4ce8b7bf6c50c186a8314b1c4a4cdc988ca0ac1a4","libcubeb/googletest/src/gtest-port.cc":"95bcf473622d1b901c734e5c2aeb8efb058555ec924212a61bb04f049bb5a069","libcubeb/googletest/src/gtest-printers.cc":"6f191a7fc7f5a0a967fd11964057f2e2d2eaf2f37ccece16bd816531f52b3154","libcubeb/googletest/src/gtest-test-part.cc":"e489868b4cdc66f4fc33bc2326ac86bc1acc5808ab58bbb288c9dcfc330faddc","libcubeb/googletest/src/gtest-typed-test.cc":"ca9e819df728c25a6a1fc072806c22f3494e1dffe4bd0d48284f38dbdd3a0dd5","libcubeb/googletest/src/gtest.cc":"5cf9a3e897892c9f0e5c887f91d3c8c8c5665bd7348560441fc0b946c254873c","libcubeb/googletest/src/gtest_main.cc":"22fa1f77542b882d1798d7f696045c5895942a626e26200a175fa4382e1fa5b5","libcubeb/googletest/test/gtest-death-test_ex_test.cc":"613ccf50a3ff8f84c975a13e86ea01ea4e36933072388a3738b4acf9ed3ed7cf","libcubeb/googletest/test/gtest-death-test_test.cc":"df8384a847bdf889233c3d45d171f784991def7a9b6a08442138569fbae32b9d","libcubeb/googletest/test/gtest-filepath_test.cc":"49760f91723845b113bb60bb9b1a1426ed1da1f4ebfef2462128980ea5692cc9","libcubeb/googletest/test/gtest-linked_ptr_test.cc":"1b9cb4ff67475900db9de34ae9749b94193048a1f7a741091ba5a2dd7fc7a79b","libcubeb/googletest/test/gtest-listener_test.cc":"acf78f2c9a730525ea5adc93e9196a42de8fbfe488db1dfd02656bdbd477b2c0","libcubeb/googletest/test/gtest-message_test.cc":"b1fc68f8b75ce25fbd79b3f7d3c9c793381ef07b3203e1a2d9b610cb597542be","libcubeb/googletest/test/gtest-options_test.cc":"74e3ae0c310edb3139b0032266219d3ce7f386ded6feafa57fef03f4493ed7fa","libcubeb/googletest/test/gtest-param-test2_test.cc":"a0f1efbcab3f7e49df639383157626931f64756f7e738be081760f93f7308332","libcubeb/googletest/test/gtest-param-test_test.cc":"ef8bd344e959053f562b0c9e0d15e2fb6c1e534772a67aaf3f90bd6bad0bf99f","libcubeb/googletest/test/gtest-param-test_test.h":"9d7f47b79d54df7cc050aa6038b0464aa684dfca669a847bf70ea16e4a000628","libcubeb/googletest/test/gtest-port_test.cc":"1600f78ef0860a0f5b5525e5e5041ff32a216cc6ae948b1ea61fe04ec603f67d","libcubeb/googletest/test/gtest-printers_test.cc":"7898e4b4163ee0821fed248e1c75d9f4a0a511a2b4bbfad1ef2f4a11a099f6e7","libcubeb/googletest/test/gtest-test-part_test.cc":"62c8906bb0d12ea84d60217b3773cd8e1768db4aab934880db2316df7026cab8","libcubeb/googletest/test/gtest-tuple_test.cc":"2850dc1f73a3f8020d8a4d80688a28d9b736eae6d677222c3f871d8d33b25501","libcubeb/googletest/test/gtest-typed-test2_test.cc":"c52b65e7181610d6e577631cd50177399884913ff28d08aedfedc92f05185044","libcubeb/googletest/test/gtest-typed-test_test.cc":"c7daff5211028da79b3ca0473dca18ada9197f38e710f72d0493ad3332ce3ec9","libcubeb/googletest/test/gtest-typed-test_test.h":"3145698534d8869beb624c9c8ed114f75bead046b2eeb92ada5a724993ee7786","libcubeb/googletest/test/gtest-unittest-api_test.cc":"e3f54c28ef2849e8b12af666ed46aace50c3e047845072ee6f974ce4528bd297","libcubeb/googletest/test/gtest_all_test.cc":"db0c3c42b385570b1d517e3ee927671b8fad4e206247fca738ec477222ac3d97","libcubeb/googletest/test/gtest_break_on_failure_unittest.py":"11c91bc1c68cfdb913e2affb01261b55fb3b0c18773a45875e9c25cb330a4dcd","libcubeb/googletest/test/gtest_break_on_failure_unittest_.cc":"1da12e4bdda2a0bc7b59d4638fe34b2d3798134224fd9237eeebdd09c3326011","libcubeb/googletest/test/gtest_catch_exceptions_test.py":"305cef45c6dc034bdf72fd91aba1e89e1c6b5d222c3d6baffff5acdfd9b3873e","libcubeb/googletest/test/gtest_catch_exceptions_test_.cc":"b297a4f4d5bc0285ea9eb8869741631658305e49d4513bca904842aacb82128b","libcubeb/googletest/test/gtest_color_test.py":"c4cb006682a40f2d88759a4bcabf0d4be623720b135c71447f1788d17ea23d0f","libcubeb/googletest/test/gtest_color_test_.cc":"f263ba349afe58a558bf0fee98a98bb9207a648e7cd4f908a87799bd13d001ea","libcubeb/googletest/test/gtest_env_var_test.py":"79819598cd1e366eaa8f2a4fee2d638b6ef0686e490402fae792ccce58d876c0","libcubeb/googletest/test/gtest_env_var_test_.cc":"0eee5dfbb2a2598f4e76626346b921928ec1e052e38f254cc97c60d05611ab46","libcubeb/googletest/test/gtest_environment_test.cc":"a52a21ea29c2203b03fa93922733546d171f98d3b2fcd42972269e98fd124715","libcubeb/googletest/test/gtest_filter_unittest.py":"edc7d278803bba41626eacd050d91d7247f1c5999f9dceb99a8877e238bc73d6","libcubeb/googletest/test/gtest_filter_unittest_.cc":"996ac528ad75c293d8201ce28cf6acccee266286bd369b4cf43f05b8d67a4559","libcubeb/googletest/test/gtest_help_test.py":"b43ab690c08e4bffd84a47b361167496298697f9511bdf4a745bf305b5cfbdfc","libcubeb/googletest/test/gtest_help_test_.cc":"ff4b121098f0fe7cb4abf11fdd31f2fe7a477286ec9175482138bc038d61c807","libcubeb/googletest/test/gtest_list_tests_unittest.py":"7caebc175b44b3c727fc50420ada1a6a9500f3e4ce9e2839f69205437aa85e7a","libcubeb/googletest/test/gtest_list_tests_unittest_.cc":"d82d8b72914897232c2ff9fd091a7b0add68b7cf75f3f210d3a487ebeea84cfe","libcubeb/googletest/test/gtest_main_unittest.cc":"0f66f318809c88f0fbe034a340a75331720c4e33be5378022baffaf588ef1202","libcubeb/googletest/test/gtest_no_test_unittest.cc":"7cf487e07c3d27376c2cb8af33d02239b7966623875d37b7aa0259e927a9c2f6","libcubeb/googletest/test/gtest_output_test.py":"cf0dc1979572d94450a5e611b44f3fdb88d9cd980d669a723f0ed63057b5e2c4","libcubeb/googletest/test/gtest_output_test_.cc":"f69569374c2b3d06aa04a38ebc4f92ddc303e6af503f8b533cd8e6bf9f104899","libcubeb/googletest/test/gtest_output_test_golden_lin.txt":"4f3e49c10a524a99437cdcb5294e3335a7f3c07ea8462e65730f703a5fe4fec3","libcubeb/googletest/test/gtest_pred_impl_unittest.cc":"e406eccf75b6b58746a95d1c7ea7bc8e80ff974e438ef7c83074a46d4e62db9a","libcubeb/googletest/test/gtest_prod_test.cc":"b42ca1a6d0a1e43bc576b4ff7776c6d2c37234f6dc2a76f2735f261b4a47a526","libcubeb/googletest/test/gtest_repeat_test.cc":"e10abbb71595920aa3bb415029eed74106335fc9ea3d58c417ccfc7cba6a4cdb","libcubeb/googletest/test/gtest_shuffle_test.py":"12dd94eb5f30260ba37059fa74658bda57dffa821f3ba6a2a8b52ff14b1ad029","libcubeb/googletest/test/gtest_shuffle_test_.cc":"af1b2b01ae275f1a9fee7e7940c0f88f39ded063008994d585aad87e3ffadb39","libcubeb/googletest/test/gtest_sole_header_test.cc":"538414c27a593ab8dc34c37b5c877eb3a022d75d1b481ef14ceca00914929754","libcubeb/googletest/test/gtest_stress_test.cc":"0b02fc12f87944226915a999bdcc8a3eaafb34a1ea5bb0df128774abf8667f09","libcubeb/googletest/test/gtest_test_utils.py":"d4a76930aee6658ad8734981ca0c4ea14f34dbe8fdd31d5afe41f6d98f9779ee","libcubeb/googletest/test/gtest_throw_on_failure_ex_test.cc":"11ae790028da20bc7b7af1572eff3cfe8499be43ab64c110e18e1892612a183f","libcubeb/googletest/test/gtest_throw_on_failure_test.py":"ebe18ca0b07f90c53b9b3f9a54ed02df94facf8995cfa90dd41c6f5474537c13","libcubeb/googletest/test/gtest_throw_on_failure_test_.cc":"f8cbf75d8bf9e9ae068a17ff968434c3aec7b7f1137c994d8f14af1a84361aa9","libcubeb/googletest/test/gtest_uninitialized_test.py":"da8e6ce34930753e36fc1dfa2c3e20e48d02bda2a27d3d03a07364312c5f3bd9","libcubeb/googletest/test/gtest_uninitialized_test_.cc":"0b6a9d4983480f87352ca4da946089264b401f7a4a3b1282253fd6cc861bf483","libcubeb/googletest/test/gtest_unittest.cc":"c0c7d1f691ce1e10c3d1647ed5f7a66510725808ad58bb6da4bc03a7a08fb2fc","libcubeb/googletest/test/gtest_xml_outfile1_test_.cc":"29341d777a9c9d25f360d13ed966b30f0cbef1fc88aefe2f01bb88b82cf1ed93","libcubeb/googletest/test/gtest_xml_outfile2_test_.cc":"da7ab3cf0e9b2a293eceed7c5691233d6b61afb557e3c1176dfb75390f85be46","libcubeb/googletest/test/gtest_xml_outfiles_test.py":"b07927b43f44afbfd61761c2cc69f1b68c4fbdeddb992db03ff0c73052518cd4","libcubeb/googletest/test/gtest_xml_output_unittest.py":"b5ff0c0207238d01cada961b8f4656f2ec30a3e1e5bf9d22efdf1745af423031","libcubeb/googletest/test/gtest_xml_output_unittest_.cc":"ad0b9ebe63a146e386df3c5c51916869f6d4647b9832ceacc912fb1272d15f82","libcubeb/googletest/test/gtest_xml_test_utils.py":"ad89a39a6cd5b08e87082341f3e7800dbf1150ea0f1386e0b8cd374aa6832f00","libcubeb/googletest/test/production.cc":"56fef77c3a8e62073ec11653d740a8e534008a0d57925ab0877b843f4fdd6be8","libcubeb/googletest/test/production.h":"a36d10545d12ead5e93a3b0fdca6ff73405f29091cfe38164415e9038888ba8d","libcubeb/googletest/xcode/Config/DebugProject.xcconfig":"fb42302df29bd8e8b5237194c0c04941f0e578527037930d88469baeb7a7f62b","libcubeb/googletest/xcode/Config/FrameworkTarget.xcconfig":"9935ddabe221f074d2f3b969a137d12b0dc0f845a460f58b63232987cb0f37ff","libcubeb/googletest/xcode/Config/General.xcconfig":"0fb768924daba1048f8db28b3a1fbf915b6f788d49d9d37e85979aa4ee92e02d","libcubeb/googletest/xcode/Config/ReleaseProject.xcconfig":"a4878ddd1ed78fb411906623cb51bc0ab4aea1cc3feb5379d2ae2862d8bf3bf5","libcubeb/googletest/xcode/Config/StaticLibraryTarget.xcconfig":"5886291788b3e9d5aadcb979ff055fd26a2413be81016e7afffb813b627d177c","libcubeb/googletest/xcode/Config/TestTarget.xcconfig":"f074e6c2516a6063b253ec6b842d74f5c2abefc7bcf8d8da54097a7bfe016480","libcubeb/googletest/xcode/Resources/Info.plist":"5b7f78a6d5810ce5490649793175c8982d41e6b49af06bc0705bc061567cc9aa","libcubeb/googletest/xcode/Samples/FrameworkSample/Info.plist":"1c13d83e5eed45689d7fe4bf4681030366474bc40608e39e1623c1350513a0cd","libcubeb/googletest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj":"1cf0e1b1abf84414372faf9c8bf634e01fe5750bb3ca769b1eb25fc530b21358","libcubeb/googletest/xcode/Samples/FrameworkSample/runtests.sh":"a587e5b00a8353dee0aca5a4c59b28301ccf7648dee8c79b62a9223f9fc3c8cf","libcubeb/googletest/xcode/Samples/FrameworkSample/widget.cc":"562a2bb615e93186012823c9b41761769638a11e38b54498ad5f699038c8fd32","libcubeb/googletest/xcode/Samples/FrameworkSample/widget.h":"0c7915e45cf7cb8d67db24e49cd0b277f23f967578f917f8e859a6adc4b156f9","libcubeb/googletest/xcode/Samples/FrameworkSample/widget_test.cc":"6a1a49d64912d9829ef3d991faf5a3f0e1e081126a1d8d387cdfa84fab70dc77","libcubeb/googletest/xcode/Scripts/runtests.sh":"1a0672a4151b16f3c797478ba26c534e82b2faa603f90b9aa14e785805f7683a","libcubeb/googletest/xcode/Scripts/versiongenerate.py":"4b9d5c0f4e1b556084109311d156bee6d781968dc5b1dfdc8702364508f1dd43","libcubeb/googletest/xcode/gtest.xcodeproj/project.pbxproj":"a1224decff058bfed01b8eefaee13cab0129492615548c6d0d878003a154f7ff","libcubeb/include/cubeb/cubeb.h":"b0eaa7d2af05c4f473762282d87ac1f0fa4dd1bef5d30bb839e9783268b3346e","libcubeb/scan-build-install.sh":"1ecf22aca367a4d02f810c4cb78db8636e08a12787e94e30c441ce439cf4a265","libcubeb/src/android/audiotrack_definitions.h":"0d5ec772f9ebf61333bc16e61a081a7e3b4cc02342ec4f8f417e220d032fbbc6","libcubeb/src/android/sles_definitions.h":"24e400ca2330ec16d3a37b69b74144697b51dce17f9ead763b1a6ffedc5633ac","libcubeb/src/cubeb-internal.h":"bcac7660194c5f3db59c71abfb8a7a312771234e8601d78eae3bff6f778adf96","libcubeb/src/cubeb-sles.h":"dc84a01ba4de9db1ff108609930b36ba442020ccc3e3d6f16528f429426c430c","libcubeb/src/cubeb-speex-resampler.h":"dbf543eee4cc6e40ba3531a39d327e2cec884c19e26c570aa7eae0647e5f7420","libcubeb/src/cubeb.c":"17d0e6d44f96703e04d326a0a3b7df2632332b1df0e47c136fab30d5f29e4917","libcubeb/src/cubeb_alsa.c":"5eec74a2d6136bc77f26cca98f5c7b2547bc9e78e438589f55f048860f776328","libcubeb/src/cubeb_array_queue.h":"5264ae02799c540ff73e8eb8efa55986772b22562a025ae227c2603b6b8d1036","libcubeb/src/cubeb_assert.h":"ab8ed4fe7070a3aed9419c5f9695fce2318c4dafd91213ae61cac476e64adaa7","libcubeb/src/cubeb_audiotrack.c":"10e55c09b445c078cf40d7e187f606ab2fcd0b86ffe60ceb8319b6e9aabf5a71","libcubeb/src/cubeb_audiounit.cpp":"00267798952785f70ec455a1a405b18991257f105700cd3eb38297ba7fc38f12","libcubeb/src/cubeb_jack.cpp":"54ad5f1238730894754dd2d4c1b74021db44172357f411f75aacaf6ca68b6935","libcubeb/src/cubeb_kai.c":"a71e1de94211ff0e5667a218d71588f1e74102ccf0140b80925c277949871095","libcubeb/src/cubeb_log.cpp":"74bdc0d92a31d6b4ce3c376c6d310db583b869d673e40e6bd0ea795a1e2f937a","libcubeb/src/cubeb_log.h":"ee05fd22ed9820bed79247b8603cdc64f67bcb145be47e78bf0a0e99fb6c0806","libcubeb/src/cubeb_mixer.cpp":"574b33c0026cf02aff39d61a3a2768163422484e1e81cb46b2eb718469244fa3","libcubeb/src/cubeb_mixer.h":"ada2bb1d3356bd2d4e4fb991e63cd2c1132b46e4a832b0fba9842cb836c6c9da","libcubeb/src/cubeb_opensl.c":"86ed3bb3a33b83082bd24ed5cd5f9d3707d18a7942983456709383ea08aace33","libcubeb/src/cubeb_osx_run_loop.cpp":"13c029f7ea04808597b8841b13f248c4476fb7425762f01a59bc6c944cab3a78","libcubeb/src/cubeb_osx_run_loop.h":"ffe80df60b8ea3d0341715b72cc60aae2e0df45141887c01117df543260a0ef8","libcubeb/src/cubeb_panner.cpp":"405a115ff0eb5f00dbab6bc8f2999b02ee4ea4792a87bad7ebd7218ee7980438","libcubeb/src/cubeb_panner.h":"5679df1b9d138c91f6ea642d51e6230cdf3163bdd65db156ad45906916cb74b0","libcubeb/src/cubeb_pulse.c":"5947b03784c22cb7cd5c457150722091566e630221e4250f8daf6b7657050a44","libcubeb/src/cubeb_resampler.cpp":"2d5f5f4ff242d61897b62b4aeaeee85633be54c1eb155c9e35a2c67d8d5b7043","libcubeb/src/cubeb_resampler.h":"ad9800a40c0272fb2a451c02367cc5a516a3067d4acf963d35eb31be367f9224","libcubeb/src/cubeb_resampler_internal.h":"4b4eb6aee343b9c1f73cf17b201329d3714ba44b06ecb1cebf950fdf93a9dfe6","libcubeb/src/cubeb_ring_array.h":"db8dec7a6d778a424045e5ac61c2bc3a3cec8c4fe8e4780f383db4b6f1b2438c","libcubeb/src/cubeb_ringbuffer.h":"2296255ca7835a3ace2fe1852054f43428b677f432b4174bd832ad0224a409eb","libcubeb/src/cubeb_sndio.c":"9bab520c5254f4861aceeaf31de7a1fb6e682191d5d7364f581c390a3f070977","libcubeb/src/cubeb_strings.c":"60f2b8c03a5a01925f9777eec0ab84b0e704b40c03e0d6b9c0e7a16246c81fde","libcubeb/src/cubeb_strings.h":"00e5dc97cf16e28cfb53aaae50ac0e3c0ae8a82aad0720ab6842ce5d9785c39f","libcubeb/src/cubeb_utils.h":"c8229a25741577dde1917375688c463cf671a1ce81b4b058ecea7309ecc260f8","libcubeb/src/cubeb_utils_unix.h":"2a48bd2aefa1b4e4e4968121512bcaaa6be3bca6597ea390b8203c338f5c49b5","libcubeb/src/cubeb_utils_win.h":"74658b6266a8a223c681b0fd06fcc9c891c7b0b95377635c6f1763b240c2ab27","libcubeb/src/cubeb_wasapi.cpp":"bde4016dcb93c5cd36f68c6d44c72b3f58c3794325e48907c0b466dbae66e5f6","libcubeb/src/cubeb_winmm.c":"d61a4f9c4c52ad79275af2e120de5fd35f54a8e7b50072b71dcaf64279d05665","libcubeb/src/speex/arch.h":"2300bce68c588270cdc684dc7f01377e5e251529f4545d93771e111c56d51b0f","libcubeb/src/speex/fixed_generic.h":"306ee7453677fa6067f16c79d358c6c90a9d3d008850b493cdaa59c07e6375c1","libcubeb/src/speex/resample.c":"9c3a1c64ecf3750af82c980d01ea73d3682f73c332a580465d1e787e5c54cd00","libcubeb/src/speex/resample_neon.h":"7d3fd7af9a1ddde22518b9c7b4419073b72b2dfa5be4c3bc8796992bc87b3da0","libcubeb/src/speex/resample_sse.h":"5a196d8e2d8ab5c956f5252f09f5ddc55aee1f99b1341af3fa54a1f4c2157924","libcubeb/src/speex/speex_config_types.h":"24e3ffbf29e5519611a48e5acb959645b01d166dcb4369380d5f776c3f53d4cd","libcubeb/src/speex/speex_resampler.h":"7e439ec0dd30c32216b3ced17135f8992e5aaf53389d3f5996a7d900c453e65f","libcubeb/src/speex/stack_alloc.h":"e8a2fc0874942d2c7177475fcc141fdd0c0156200b8a4e7656d4a20313e2e569","libcubeb/test/README.md":"1c11b038f87daf10ea78abc17bdbdd157940c241df548c24d5872d142a98c1af","libcubeb/test/common.h":"f29b051ef7f5ff8ef08f6b7cd51229381ad4f1cd7454563c3f96188db3e6ebaf","libcubeb/test/test_audio.cpp":"3be1f9d1f5c4f37f7743ffa4065241c746859b8a57a86e687890ceee5c69f957","libcubeb/test/test_deadlock.cpp":"c311519f30c05300715e91b529685a0c61b8e6b67161fa1f4aeb7030587d86f9","libcubeb/test/test_devices.cpp":"eec312a08667d053216a4266ef9e2b04dcdfa487cc4d34a811bb64cb33ed2937","libcubeb/test/test_duplex.cpp":"add22390fe2dbba09def4cece9a0a6a8e69b24a97f874312b931ece43b1ec4c3","libcubeb/test/test_latency.cpp":"0ace31644f499d69adcfa0aa3bad8c859ad51e97b622e2fa6d26374b8af12894","libcubeb/test/test_loopback.cpp":"05aa359587d0e8739889a15f3296cfe338f36352f55abfa0aee1674a23b762b9","libcubeb/test/test_mixer.cpp":"42dbda1b84c91185fccefd21e936b24e0beb0a8dcf0daa7e1418ef0ee031bcda","libcubeb/test/test_overload_callback.cpp":"8a05771e5bedfabf9f8a2e5a9266df90f5e964ead3b07782e2e435d7b69b0beb","libcubeb/test/test_record.cpp":"76d5b4f738ca7c30836ef6cc5851f3e04e396b21cf26511e0eeb7a616049fa04","libcubeb/test/test_resampler.cpp":"ca4bc0493ce0c3a5f02f389ac6e37bc2cdb9a752faad2b6fbc5af0a2223ef645","libcubeb/test/test_ring_array.cpp":"27836d716616abf8b020a710659c10ac5e1d4b64149d22cb89bd7a7a5a5669d1","libcubeb/test/test_ring_buffer.cpp":"f6e5a9f552f15808eb8ac3405559bf0ea61e7da4219cd14ac49fff3bfbf49ca7","libcubeb/test/test_sanity.cpp":"e54ab30e6d897c15fb997d7593bc118b87e9cc0ddbc58b951f509872e47ce524","libcubeb/test/test_tone.cpp":"3938250700c708c9c742ec8d0c9c2984f3e11860ff8dcacdf0ce785d4668f789","libcubeb/test/test_utils.cpp":"e8d7a02a9096dbc0fd15d71f9849415d52958d2ed82cbc7b8507d3228e08d382","src/callbacks.rs":"b4b4eb3f370475488d7c77b338b0bceee94ef59ede8ff41fa797a3d35ea98b5d","src/channel.rs":"a724887b18c796f070d94894e76cfa61d1c5572497bcda011e46504d887537f4","src/context.rs":"dfc04eaff022f377c1e3523a674f088f25b45845a4af4c48faca8ba29c7cc1b4","src/device.rs":"5b65e1c1fdd53fa5208f20bfb809475cbb3c434e02db7d0e4771d13c86f8e369","src/error.rs":"406e3b843ed2d263fe677c4b34fb96a6d780a68bcb56a6f85f041d20d70227bd","src/format.rs":"d4d27790c20eab0b16592f60d5e487425a45a268cf4c74cf843c10ac91bbff4c","src/internal.rs":"c3af5f53dc7957860bf3bc0cd9737d094fb8ac000e7b40c569304cfa76a43145","src/lib.rs":"cb49a3dd8782369172a2f8a61d5c74b4615bfb5fba3677af7d5c149e47d71815","src/log.rs":"6694178177775f2ce5449435d00609e9361c836e23119c07d04892000587dc55","src/macros.rs":"caef13f5d23f7a3ec1a54ec3ca2390ac4ad89d521893f1d0864daf70d57a20aa","src/mixer.rs":"485022afdf333c86d267ac45e54c9c7bacb1268459c6c2ab1ba5d5c0c3608081","src/panner.rs":"341af4b5a5331a3c1a4ab5396125a3600945e588ea33350431dfe6f1a9a0bd80","src/resampler.rs":"762070f8afde2256715b8764380cdfa1204a1a39d98a9da0b2efe88699792f2c","src/stream.rs":"ea3080b6225949938098e3ac38c42939c49a91b322b327ea66e959fe41f51763"},"package":"fab28c0e152330f74bcbec1572c374397458957d5ad50605879352ec562f41aa"}
\ No newline at end of file
+{"files":{"Cargo.toml":"3a9a9f86b409fd16755421048f3ba976501d321acd698601fe5930d7da8b1ada","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","build.rs":"49985a30631de0015517fc260321aa03a003eaf26d80650bebd928d55edc9444","libcubeb/.gitmodules":"6fe6fc18ff76ba8dd3dc749247d61a2f4a18c1e42b1890581e234ab8151d4c95","libcubeb/.travis.yml":"edb891b3c9edc375d8296d93a79bcbb8e5f884f695b3115a7c0d57cf45471823","libcubeb/AUTHORS":"829e45d138c7c8827799f302806fa4be8cd8bd4bad70a2fe26c3a27a5cf36948","libcubeb/CMakeLists.txt":"381886472be5fc0f925aa42268fd2df9f17f5613ee7db489849af474189f0358","libcubeb/Config.cmake.in":"88019286c96ef3d5d3a673b183c8655dfc97ceede07d3eb6c18f0c51bb896388","libcubeb/INSTALL.md":"7a84cdfbe86e7d3180e2203603b88571df61b369421fa97ee86740ffd4d4db8e","libcubeb/LICENSE":"44c6b5ae5ec3fe2fbc608b00e6f4896f4d2d5c7e525fcbaa3eaa3cf2f3d5a983","libcubeb/README.md":"aa417156dc65069264901b75fc3c792c73021ec61c909de04e109bd4184c07ab","libcubeb/TODO":"6f8065136e005d2becee810e3d8697a94f2c755f8c79687adfac7136ad165e80","libcubeb/appveyor.yml":"9a87fdc18b76fca1167289ecb2ec3a210b76984c1d7e92268b2cd36f1e00f541","libcubeb/cmake/sanitizers-cmake/CMakeLists.txt":"89b282c19b3897ff666f7847d5e679ae928ca7e76ffd0d23f7c58c9464048b61","libcubeb/cmake/sanitizers-cmake/LICENSE":"4b67e7ae8c91e68e1a929eb1cbaa4c773c6d19aa91aaa12c390cf9560d1c9799","libcubeb/cmake/sanitizers-cmake/README.md":"30ab1524618ac828b75f9b83c665a0bd50b839b42ce61519a8048d73f401da6e","libcubeb/cmake/sanitizers-cmake/cmake/FindASan.cmake":"cba07ffe438c57bef0840ed6a2d2890676530b66509da3c616438c53018baa4f","libcubeb/cmake/sanitizers-cmake/cmake/FindMSan.cmake":"1303aac5028fe9f64d42be0afd47f1291e679d74f8280b3dc5271f20ebf4d7a4","libcubeb/cmake/sanitizers-cmake/cmake/FindSanitizers.cmake":"ce1971b943bbef08fb9aba958cf28e3cbdff075406c85a3cfed22e00c9f8d9a8","libcubeb/cmake/sanitizers-cmake/cmake/FindTSan.cmake":"edca39b287312e9a8fc718f6ec791d2520515900b37426091310fe1bd52dc6a1","libcubeb/cmake/sanitizers-cmake/cmake/FindUBSan.cmake":"5b9d3621f629c807a1345a7cb053677a8bf25782a079e345dda53d04aecdc4b7","libcubeb/cmake/sanitizers-cmake/cmake/asan-wrapper":"4e543936e6374e24b80a0f92135c07c2e2101c0d110e51bddaf0e70ae8ec391e","libcubeb/cmake/sanitizers-cmake/cmake/sanitize-helpers.cmake":"282620734c2a8062f1280d0dde3121b8b01af26e5ecaa7d4308e145f80ecd115","libcubeb/cmake/sanitizers-cmake/tests/CMakeLists.txt":"fb983bab7040be002847db59c2493abfd249f67ad06e3a9270fbceb9fabda11c","libcubeb/cmake/sanitizers-cmake/tests/asan_test.cpp":"8b351c7c8668b4a2438286df426f0ad322cade6d1c6199a74668ccbd1c5204a4","libcubeb/cmake/toolchain-cross-android.cmake":"59d2355845a71647b353fb8b18fca630db8ffee7bb8500143e2d6fbc409cec97","libcubeb/cmake/toolchain-cross-mingw.cmake":"b09dc261981c0d4a0f8430f05aae9c8fc545651cd9cbfacd09754277b776b532","libcubeb/cubeb.supp":"19f33e59f8dc91a327c923e44c2c3f9af0a043ce1d6a8cac275ba094b4bfe0da","libcubeb/docs/Doxyfile.in":"0815f19789cedd310652a133bab260c27b57e95f7a65458df2dfca38ea4f1041","libcubeb/googletest/CHANGES":"72c8a289bfe4dd9160074a3a2238c8067a5bc7ca49fd87f70a134c3f373932a4","libcubeb/googletest/CMakeLists.txt":"cdf938ce79ea066866dc614de3925bfaa48d9e19e04049db2ec8c5443abaaa9b","libcubeb/googletest/CONTRIBUTORS":"4d911cd5e6d71f3f4bbcb2788b2f916df4b0ce1e088752a159457a1d936ae0ce","libcubeb/googletest/COPYING":"9702de7e4117a8e2b20dafab11ffda58c198aede066406496bef670d40a22138","libcubeb/googletest/Makefile.am":"a795e5a18e82ba06fd97509d92d773b7fafd0dd7086db8a1211fbd151b503bac","libcubeb/googletest/README":"484b19654362942fac9734c8fab0ed3d99249b81c69027bdb7de46054abada6b","libcubeb/googletest/build-aux/.keep":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","libcubeb/googletest/cmake/internal_utils.cmake":"6f4670a5825cf8ae0415be9dd43d82a7f30316d75cab20a4c60afb6d9db2a01d","libcubeb/googletest/codegear/gtest.cbproj":"9fa07a66b8c01773256e508187775407c465ed9055651e93d390426d1888721a","libcubeb/googletest/codegear/gtest.groupproj":"76c001cb2ee0070e26d1570fb6db5250f2585179c707496c5ef6d12e582cf205","libcubeb/googletest/codegear/gtest_all.cc":"c8750dc2b7b3612edb60e8d23fc2f60ae264451916c4b15f81cbf60ea30eb75d","libcubeb/googletest/codegear/gtest_link.cc":"e5e47c086f932471e0ca748a62b3b1597e5e731f4d34fb8cb8b2ca2db7ba3ed0","libcubeb/googletest/codegear/gtest_main.cbproj":"056448ba7f41fae3f704b1001922d9f6e419cf8cbcf3a55bf0ecc59ece1fa9a1","libcubeb/googletest/codegear/gtest_unittest.cbproj":"2c48be90b0dbc3224a8bd6c4dc21f78dd1b08c81685e6bd4952bb6df6ee38701","libcubeb/googletest/configure.ac":"fadebffdaeaccebb60fbe4a501c1138c296e01348a5da45fabf5e4233248baa8","libcubeb/googletest/include/gtest/gtest-death-test.h":"fdd087f700cd04a3ce4bdd36f35769de52a44bfc0c5bae2dc9681d4cbcd3c44a","libcubeb/googletest/include/gtest/gtest-message.h":"eaf44df1284d94333507c47091c84eaaf43814e6a02a1b1c0061ca7b363e74d6","libcubeb/googletest/include/gtest/gtest-param-test.h":"f226f0a24c04cddbceaaa45d8a5e575ce18c3392349f9b8ba73317e37e62368d","libcubeb/googletest/include/gtest/gtest-param-test.h.pump":"17c65fd5cc5218279044a61f3873c9c952b0924a7ba5147d4999d400b122207f","libcubeb/googletest/include/gtest/gtest-printers.h":"7046f611398d63ee0f1c37bdb4fd08d9931979b2fedf13b781e6d85d4b3b5d60","libcubeb/googletest/include/gtest/gtest-spi.h":"560407dd45e8e57fa6927504c9e4a4cfdecf30f8cada975c1ffddce765e6a88a","libcubeb/googletest/include/gtest/gtest-test-part.h":"c4d6d840284728740c284646075e8ffc85b63b9f74f3ed488b18ef3c2c2b9005","libcubeb/googletest/include/gtest/gtest-typed-test.h":"1ec858bbb9ed8a8bb553232df016437c080b2670f00453b4de297c286eb78c21","libcubeb/googletest/include/gtest/gtest.h":"47433ca72a43bda7a380c34fe6d4ff451797c687e9bbd74d1f366bcdfa0cb013","libcubeb/googletest/include/gtest/gtest_pred_impl.h":"f03a3f77e3c231889c0ace6f63b2c4e410e4a9330287ea09443b23b9a3cf9092","libcubeb/googletest/include/gtest/gtest_prod.h":"4a99a3d986a45b4d6d9b3af54809f015c54aa98274793a4ae173f5010d0ad33c","libcubeb/googletest/include/gtest/internal/gtest-death-test-internal.h":"0b3abead866363f3e6b4201acc8d2763072e033826b22ae5ebffd790e1415235","libcubeb/googletest/include/gtest/internal/gtest-filepath.h":"638d2bb6c06a894513b03311a8e931ac835fc00afc4bd21fab3afc05732c23a0","libcubeb/googletest/include/gtest/internal/gtest-internal.h":"12c2c83df0a9dc5b46697ccd8271dfa34ee5f3d1972dcb56585bc1459d9583c9","libcubeb/googletest/include/gtest/internal/gtest-linked_ptr.h":"9bd319548dd073630dfd349c06a440c6a582feec47d4ff14f348ec32f8b4c1f3","libcubeb/googletest/include/gtest/internal/gtest-param-util-generated.h":"10db93fa7e98820192bae6f560664469dd33b265036fca64253c89b6801f96cb","libcubeb/googletest/include/gtest/internal/gtest-param-util-generated.h.pump":"abb72365d94d2811b34c195dc520fbf41c7dcb42aae5a1cfa0502cf619b21e70","libcubeb/googletest/include/gtest/internal/gtest-param-util.h":"7f9311f033ef6916217d87cef53b1db6c4e8733be930e4b48fe7e11d21b33da0","libcubeb/googletest/include/gtest/internal/gtest-port.h":"612932c2930a7cf2c3514d89a8d6b51a2c0030d251309b71765ed1c9954e20c5","libcubeb/googletest/include/gtest/internal/gtest-string.h":"a46aa36165c400d1e926f942be03fe04cd7ccb1e59f7a2a03b919c4eea05b997","libcubeb/googletest/include/gtest/internal/gtest-tuple.h":"43e7e3c92f8e4258cf3927a9204b214d4d03e6c796f88f3ad4e66b1ac20aa938","libcubeb/googletest/include/gtest/internal/gtest-tuple.h.pump":"16fa027ed3c5940699e0ac906815e66620993bcf75b0acaf826d4f09348d4b83","libcubeb/googletest/include/gtest/internal/gtest-type-util.h":"6d177af46a9b1e14b969972a8b886667f95e69037aba411433a44fb9b92e7037","libcubeb/googletest/include/gtest/internal/gtest-type-util.h.pump":"22092f44127af91651f57ce222e20914d5d32ae02f1c0964f6d5d7bc019af339","libcubeb/googletest/m4/acx_pthread.m4":"3326e3746b6b351d1671fe31f798269cda8de92c365b8a8305404ec0fa6c6b32","libcubeb/googletest/m4/gtest.m4":"d3c37ebd1aa792c967d4357755cc670bc6deb30091d9e6db498871d90a30ea4c","libcubeb/googletest/make/Makefile":"9b86e2a112dd55c6bf6a2b39e6f4078faf60cfecb8282ebf9b025167ed233420","libcubeb/googletest/msvc/gtest-md.sln":"0beab679b42cf0c431eaf4fe143bbf3b01fc064e20c74d9e33e7e437a70487d4","libcubeb/googletest/msvc/gtest-md.vcproj":"52e873e964daf9d5409b4e9bb471ddf2827be04985cd96c40620f9275d17a256","libcubeb/googletest/msvc/gtest.sln":"be21c2340650ec2259a2fbaeb8608ae6d3e982a0626a0f91128a771dc88e6bea","libcubeb/googletest/msvc/gtest.vcproj":"0064616c7d88a284c1b7c05baab038f239134ea9c6c563628f286f9600b3f921","libcubeb/googletest/msvc/gtest_main-md.vcproj":"f83a294a92b616bf34ccae6743ff916297bdba61d6125a9637a813d467a30372","libcubeb/googletest/msvc/gtest_main.vcproj":"9f03270a00896eab0c7015c6fb1a73818d024e462d3944ba1d3ceb313a051649","libcubeb/googletest/msvc/gtest_prod_test-md.vcproj":"7caa108733e2d5f140da004d2133e04a9a105811909c0e2d4ec06e2971983592","libcubeb/googletest/msvc/gtest_prod_test.vcproj":"cf5bfb7f3de9a59a0eba5535067845d12c33c3fd8fecc3d03aa702665db29578","libcubeb/googletest/msvc/gtest_unittest-md.vcproj":"e7949b21cf0418f2a7afe8aa94616e2c40e3ba0801c2f0826f3a3a3d2e6f48b0","libcubeb/googletest/msvc/gtest_unittest.vcproj":"5b097d596fbbc1c4090fd518008a0961b29661194e1c02d8a2d3daaa557e626f","libcubeb/googletest/samples/prime_tables.h":"2903df1d1e6643a5f624fe3ea3f931c3410eb1858ac347c5df278273c6c91ca4","libcubeb/googletest/samples/sample1.cc":"dc106c5940d87bb4bbef3d77815eab642ee173a3340b2b9c532b5c711c4c2d0e","libcubeb/googletest/samples/sample1.h":"7a7bf9a0fbd2401e8b2cb554bfcb9bd0ed228212f3b970675c1b1d38d4e188bb","libcubeb/googletest/samples/sample10_unittest.cc":"ccebb6393a5a8468399f7e511219b667a2233f82312ce59834a4bb0997d8700e","libcubeb/googletest/samples/sample1_unittest.cc":"904be0d4a095e74393515195392bd10e1e916bb2ca61f3f94b1bd6aebea29cb6","libcubeb/googletest/samples/sample2.cc":"f14b8a1e69d52eef1a70053fb256818c7eca64e8eda08de43cf46e896e57fcc2","libcubeb/googletest/samples/sample2.h":"df956ba520dafca068dbc1e28f36567db3cba36293e06762318af8cda6a12bd4","libcubeb/googletest/samples/sample2_unittest.cc":"abe7e0b253d328cb82ae67623fbe3c89eb94699102510c64a0b568eaca101e05","libcubeb/googletest/samples/sample3-inl.h":"3fe482bbd4f725f5820f5d6beab4d0d4a524be8addf4b344a9a470ec5aabc451","libcubeb/googletest/samples/sample3_unittest.cc":"252c06b4531dc35213ebdd7311700b9b4057bc1bdeeba0cd767b2bc86c456639","libcubeb/googletest/samples/sample4.cc":"b4260f5fa35d78ac114a9abb59fce12403faf0273df41f57e83c341ae7979222","libcubeb/googletest/samples/sample4.h":"604905cae7e5587805c3b884a36eda7a2bebdfedb53b24b0fd9a220eec0ef1a9","libcubeb/googletest/samples/sample4_unittest.cc":"6cfb4821d8cb1c77fbb5af4f8aec569948762d8ea314827e3ead967b5b6a223e","libcubeb/googletest/samples/sample5_unittest.cc":"73646d9038873a68bb2e56b12495d7f7b65b5c23901109701da446af454ba2ec","libcubeb/googletest/samples/sample6_unittest.cc":"833fee399954f908cf0f3b789832e505329787f4cf73607a7b31ca0f62f368d7","libcubeb/googletest/samples/sample7_unittest.cc":"8013ee68d61c181e4e936cdae3a9a635646274f8512033ef11bff7214e03e4a6","libcubeb/googletest/samples/sample8_unittest.cc":"7b7510fadf4955d2f934d23d652dbd35add832e50bdfcc98421fb9be4588d808","libcubeb/googletest/samples/sample9_unittest.cc":"8b827040dea37b460cbcaea0b255b98974a9840f6ef7bd82aaa7d4ad2c724335","libcubeb/googletest/scripts/fuse_gtest_files.py":"adecf64c6bab65b31740c321e568cf174f753d5617745aa5762d842339d68b53","libcubeb/googletest/scripts/gen_gtest_pred_impl.py":"78fb7e20a014c251d723186eb58040e4eb32405b73c9288d787ea0a0e4ff5183","libcubeb/googletest/scripts/gtest-config.in":"9a43978eeee88e188845d737c17f4d024d4e74feae09da7997e8fbe4ea6cc176","libcubeb/googletest/scripts/pump.py":"3856a3d7be37f78e0f214ee7d4f29d05f1ca14218b67539d67c9a16e992f670c","libcubeb/googletest/scripts/test/Makefile":"3576b257594a2d8e843b9e4de8c83353d837833bb86431fb1b4198022b1bcddc","libcubeb/googletest/scripts/upload.py":"f75d0712e3b13bebd8daa0a15e4eb32c9e3034a933f4fcccf65b1e999a7ae066","libcubeb/googletest/scripts/upload_gtest.py":"6e76fc0a7a3831c01cfffd18c220d44438073a66338d91ca61fc84b924021e61","libcubeb/googletest/src/gtest-all.cc":"568ac119f5e6418f1fbcfbdf185d724657d7f3539b47822da229ac5d015626b2","libcubeb/googletest/src/gtest-death-test.cc":"eec1b3c8252670c76acbbaf63483946897ce625139b53a566406b6313f023896","libcubeb/googletest/src/gtest-filepath.cc":"31b7fcda5d11346f8a487597c6a70ff057f1192e0cb11f27eb7841a9f3aa8b86","libcubeb/googletest/src/gtest-internal-inl.h":"c9d428a6b5990ace091e40c4ce8b7bf6c50c186a8314b1c4a4cdc988ca0ac1a4","libcubeb/googletest/src/gtest-port.cc":"95bcf473622d1b901c734e5c2aeb8efb058555ec924212a61bb04f049bb5a069","libcubeb/googletest/src/gtest-printers.cc":"6f191a7fc7f5a0a967fd11964057f2e2d2eaf2f37ccece16bd816531f52b3154","libcubeb/googletest/src/gtest-test-part.cc":"e489868b4cdc66f4fc33bc2326ac86bc1acc5808ab58bbb288c9dcfc330faddc","libcubeb/googletest/src/gtest-typed-test.cc":"ca9e819df728c25a6a1fc072806c22f3494e1dffe4bd0d48284f38dbdd3a0dd5","libcubeb/googletest/src/gtest.cc":"5cf9a3e897892c9f0e5c887f91d3c8c8c5665bd7348560441fc0b946c254873c","libcubeb/googletest/src/gtest_main.cc":"22fa1f77542b882d1798d7f696045c5895942a626e26200a175fa4382e1fa5b5","libcubeb/googletest/test/gtest-death-test_ex_test.cc":"613ccf50a3ff8f84c975a13e86ea01ea4e36933072388a3738b4acf9ed3ed7cf","libcubeb/googletest/test/gtest-death-test_test.cc":"df8384a847bdf889233c3d45d171f784991def7a9b6a08442138569fbae32b9d","libcubeb/googletest/test/gtest-filepath_test.cc":"49760f91723845b113bb60bb9b1a1426ed1da1f4ebfef2462128980ea5692cc9","libcubeb/googletest/test/gtest-linked_ptr_test.cc":"1b9cb4ff67475900db9de34ae9749b94193048a1f7a741091ba5a2dd7fc7a79b","libcubeb/googletest/test/gtest-listener_test.cc":"acf78f2c9a730525ea5adc93e9196a42de8fbfe488db1dfd02656bdbd477b2c0","libcubeb/googletest/test/gtest-message_test.cc":"b1fc68f8b75ce25fbd79b3f7d3c9c793381ef07b3203e1a2d9b610cb597542be","libcubeb/googletest/test/gtest-options_test.cc":"74e3ae0c310edb3139b0032266219d3ce7f386ded6feafa57fef03f4493ed7fa","libcubeb/googletest/test/gtest-param-test2_test.cc":"a0f1efbcab3f7e49df639383157626931f64756f7e738be081760f93f7308332","libcubeb/googletest/test/gtest-param-test_test.cc":"ef8bd344e959053f562b0c9e0d15e2fb6c1e534772a67aaf3f90bd6bad0bf99f","libcubeb/googletest/test/gtest-param-test_test.h":"9d7f47b79d54df7cc050aa6038b0464aa684dfca669a847bf70ea16e4a000628","libcubeb/googletest/test/gtest-port_test.cc":"1600f78ef0860a0f5b5525e5e5041ff32a216cc6ae948b1ea61fe04ec603f67d","libcubeb/googletest/test/gtest-printers_test.cc":"7898e4b4163ee0821fed248e1c75d9f4a0a511a2b4bbfad1ef2f4a11a099f6e7","libcubeb/googletest/test/gtest-test-part_test.cc":"62c8906bb0d12ea84d60217b3773cd8e1768db4aab934880db2316df7026cab8","libcubeb/googletest/test/gtest-tuple_test.cc":"2850dc1f73a3f8020d8a4d80688a28d9b736eae6d677222c3f871d8d33b25501","libcubeb/googletest/test/gtest-typed-test2_test.cc":"c52b65e7181610d6e577631cd50177399884913ff28d08aedfedc92f05185044","libcubeb/googletest/test/gtest-typed-test_test.cc":"c7daff5211028da79b3ca0473dca18ada9197f38e710f72d0493ad3332ce3ec9","libcubeb/googletest/test/gtest-typed-test_test.h":"3145698534d8869beb624c9c8ed114f75bead046b2eeb92ada5a724993ee7786","libcubeb/googletest/test/gtest-unittest-api_test.cc":"e3f54c28ef2849e8b12af666ed46aace50c3e047845072ee6f974ce4528bd297","libcubeb/googletest/test/gtest_all_test.cc":"db0c3c42b385570b1d517e3ee927671b8fad4e206247fca738ec477222ac3d97","libcubeb/googletest/test/gtest_break_on_failure_unittest.py":"11c91bc1c68cfdb913e2affb01261b55fb3b0c18773a45875e9c25cb330a4dcd","libcubeb/googletest/test/gtest_break_on_failure_unittest_.cc":"1da12e4bdda2a0bc7b59d4638fe34b2d3798134224fd9237eeebdd09c3326011","libcubeb/googletest/test/gtest_catch_exceptions_test.py":"305cef45c6dc034bdf72fd91aba1e89e1c6b5d222c3d6baffff5acdfd9b3873e","libcubeb/googletest/test/gtest_catch_exceptions_test_.cc":"b297a4f4d5bc0285ea9eb8869741631658305e49d4513bca904842aacb82128b","libcubeb/googletest/test/gtest_color_test.py":"c4cb006682a40f2d88759a4bcabf0d4be623720b135c71447f1788d17ea23d0f","libcubeb/googletest/test/gtest_color_test_.cc":"f263ba349afe58a558bf0fee98a98bb9207a648e7cd4f908a87799bd13d001ea","libcubeb/googletest/test/gtest_env_var_test.py":"79819598cd1e366eaa8f2a4fee2d638b6ef0686e490402fae792ccce58d876c0","libcubeb/googletest/test/gtest_env_var_test_.cc":"0eee5dfbb2a2598f4e76626346b921928ec1e052e38f254cc97c60d05611ab46","libcubeb/googletest/test/gtest_environment_test.cc":"a52a21ea29c2203b03fa93922733546d171f98d3b2fcd42972269e98fd124715","libcubeb/googletest/test/gtest_filter_unittest.py":"edc7d278803bba41626eacd050d91d7247f1c5999f9dceb99a8877e238bc73d6","libcubeb/googletest/test/gtest_filter_unittest_.cc":"996ac528ad75c293d8201ce28cf6acccee266286bd369b4cf43f05b8d67a4559","libcubeb/googletest/test/gtest_help_test.py":"b43ab690c08e4bffd84a47b361167496298697f9511bdf4a745bf305b5cfbdfc","libcubeb/googletest/test/gtest_help_test_.cc":"ff4b121098f0fe7cb4abf11fdd31f2fe7a477286ec9175482138bc038d61c807","libcubeb/googletest/test/gtest_list_tests_unittest.py":"7caebc175b44b3c727fc50420ada1a6a9500f3e4ce9e2839f69205437aa85e7a","libcubeb/googletest/test/gtest_list_tests_unittest_.cc":"d82d8b72914897232c2ff9fd091a7b0add68b7cf75f3f210d3a487ebeea84cfe","libcubeb/googletest/test/gtest_main_unittest.cc":"0f66f318809c88f0fbe034a340a75331720c4e33be5378022baffaf588ef1202","libcubeb/googletest/test/gtest_no_test_unittest.cc":"7cf487e07c3d27376c2cb8af33d02239b7966623875d37b7aa0259e927a9c2f6","libcubeb/googletest/test/gtest_output_test.py":"cf0dc1979572d94450a5e611b44f3fdb88d9cd980d669a723f0ed63057b5e2c4","libcubeb/googletest/test/gtest_output_test_.cc":"f69569374c2b3d06aa04a38ebc4f92ddc303e6af503f8b533cd8e6bf9f104899","libcubeb/googletest/test/gtest_output_test_golden_lin.txt":"4f3e49c10a524a99437cdcb5294e3335a7f3c07ea8462e65730f703a5fe4fec3","libcubeb/googletest/test/gtest_pred_impl_unittest.cc":"e406eccf75b6b58746a95d1c7ea7bc8e80ff974e438ef7c83074a46d4e62db9a","libcubeb/googletest/test/gtest_prod_test.cc":"b42ca1a6d0a1e43bc576b4ff7776c6d2c37234f6dc2a76f2735f261b4a47a526","libcubeb/googletest/test/gtest_repeat_test.cc":"e10abbb71595920aa3bb415029eed74106335fc9ea3d58c417ccfc7cba6a4cdb","libcubeb/googletest/test/gtest_shuffle_test.py":"12dd94eb5f30260ba37059fa74658bda57dffa821f3ba6a2a8b52ff14b1ad029","libcubeb/googletest/test/gtest_shuffle_test_.cc":"af1b2b01ae275f1a9fee7e7940c0f88f39ded063008994d585aad87e3ffadb39","libcubeb/googletest/test/gtest_sole_header_test.cc":"538414c27a593ab8dc34c37b5c877eb3a022d75d1b481ef14ceca00914929754","libcubeb/googletest/test/gtest_stress_test.cc":"0b02fc12f87944226915a999bdcc8a3eaafb34a1ea5bb0df128774abf8667f09","libcubeb/googletest/test/gtest_test_utils.py":"d4a76930aee6658ad8734981ca0c4ea14f34dbe8fdd31d5afe41f6d98f9779ee","libcubeb/googletest/test/gtest_throw_on_failure_ex_test.cc":"11ae790028da20bc7b7af1572eff3cfe8499be43ab64c110e18e1892612a183f","libcubeb/googletest/test/gtest_throw_on_failure_test.py":"ebe18ca0b07f90c53b9b3f9a54ed02df94facf8995cfa90dd41c6f5474537c13","libcubeb/googletest/test/gtest_throw_on_failure_test_.cc":"f8cbf75d8bf9e9ae068a17ff968434c3aec7b7f1137c994d8f14af1a84361aa9","libcubeb/googletest/test/gtest_uninitialized_test.py":"da8e6ce34930753e36fc1dfa2c3e20e48d02bda2a27d3d03a07364312c5f3bd9","libcubeb/googletest/test/gtest_uninitialized_test_.cc":"0b6a9d4983480f87352ca4da946089264b401f7a4a3b1282253fd6cc861bf483","libcubeb/googletest/test/gtest_unittest.cc":"c0c7d1f691ce1e10c3d1647ed5f7a66510725808ad58bb6da4bc03a7a08fb2fc","libcubeb/googletest/test/gtest_xml_outfile1_test_.cc":"29341d777a9c9d25f360d13ed966b30f0cbef1fc88aefe2f01bb88b82cf1ed93","libcubeb/googletest/test/gtest_xml_outfile2_test_.cc":"da7ab3cf0e9b2a293eceed7c5691233d6b61afb557e3c1176dfb75390f85be46","libcubeb/googletest/test/gtest_xml_outfiles_test.py":"b07927b43f44afbfd61761c2cc69f1b68c4fbdeddb992db03ff0c73052518cd4","libcubeb/googletest/test/gtest_xml_output_unittest.py":"b5ff0c0207238d01cada961b8f4656f2ec30a3e1e5bf9d22efdf1745af423031","libcubeb/googletest/test/gtest_xml_output_unittest_.cc":"ad0b9ebe63a146e386df3c5c51916869f6d4647b9832ceacc912fb1272d15f82","libcubeb/googletest/test/gtest_xml_test_utils.py":"ad89a39a6cd5b08e87082341f3e7800dbf1150ea0f1386e0b8cd374aa6832f00","libcubeb/googletest/test/production.cc":"56fef77c3a8e62073ec11653d740a8e534008a0d57925ab0877b843f4fdd6be8","libcubeb/googletest/test/production.h":"a36d10545d12ead5e93a3b0fdca6ff73405f29091cfe38164415e9038888ba8d","libcubeb/googletest/xcode/Config/DebugProject.xcconfig":"fb42302df29bd8e8b5237194c0c04941f0e578527037930d88469baeb7a7f62b","libcubeb/googletest/xcode/Config/FrameworkTarget.xcconfig":"9935ddabe221f074d2f3b969a137d12b0dc0f845a460f58b63232987cb0f37ff","libcubeb/googletest/xcode/Config/General.xcconfig":"0fb768924daba1048f8db28b3a1fbf915b6f788d49d9d37e85979aa4ee92e02d","libcubeb/googletest/xcode/Config/ReleaseProject.xcconfig":"a4878ddd1ed78fb411906623cb51bc0ab4aea1cc3feb5379d2ae2862d8bf3bf5","libcubeb/googletest/xcode/Config/StaticLibraryTarget.xcconfig":"5886291788b3e9d5aadcb979ff055fd26a2413be81016e7afffb813b627d177c","libcubeb/googletest/xcode/Config/TestTarget.xcconfig":"f074e6c2516a6063b253ec6b842d74f5c2abefc7bcf8d8da54097a7bfe016480","libcubeb/googletest/xcode/Resources/Info.plist":"5b7f78a6d5810ce5490649793175c8982d41e6b49af06bc0705bc061567cc9aa","libcubeb/googletest/xcode/Samples/FrameworkSample/Info.plist":"1c13d83e5eed45689d7fe4bf4681030366474bc40608e39e1623c1350513a0cd","libcubeb/googletest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj":"1cf0e1b1abf84414372faf9c8bf634e01fe5750bb3ca769b1eb25fc530b21358","libcubeb/googletest/xcode/Samples/FrameworkSample/runtests.sh":"a587e5b00a8353dee0aca5a4c59b28301ccf7648dee8c79b62a9223f9fc3c8cf","libcubeb/googletest/xcode/Samples/FrameworkSample/widget.cc":"562a2bb615e93186012823c9b41761769638a11e38b54498ad5f699038c8fd32","libcubeb/googletest/xcode/Samples/FrameworkSample/widget.h":"0c7915e45cf7cb8d67db24e49cd0b277f23f967578f917f8e859a6adc4b156f9","libcubeb/googletest/xcode/Samples/FrameworkSample/widget_test.cc":"6a1a49d64912d9829ef3d991faf5a3f0e1e081126a1d8d387cdfa84fab70dc77","libcubeb/googletest/xcode/Scripts/runtests.sh":"1a0672a4151b16f3c797478ba26c534e82b2faa603f90b9aa14e785805f7683a","libcubeb/googletest/xcode/Scripts/versiongenerate.py":"4b9d5c0f4e1b556084109311d156bee6d781968dc5b1dfdc8702364508f1dd43","libcubeb/googletest/xcode/gtest.xcodeproj/project.pbxproj":"a1224decff058bfed01b8eefaee13cab0129492615548c6d0d878003a154f7ff","libcubeb/include/cubeb/cubeb.h":"a73748e7fafc73122a81f0639e9148179ca29b6582f225000a60283bf68417ab","libcubeb/scan-build-install.sh":"1ecf22aca367a4d02f810c4cb78db8636e08a12787e94e30c441ce439cf4a265","libcubeb/src/android/audiotrack_definitions.h":"0d5ec772f9ebf61333bc16e61a081a7e3b4cc02342ec4f8f417e220d032fbbc6","libcubeb/src/android/cubeb-output-latency.h":"000fb7bec38105f54b9d40fc436440c637d63390b219775d335216d29d767226","libcubeb/src/android/cubeb_media_library.h":"f67965fb2ea38f0023eb4c76024341ba9563ac1a135507b6f12a9aabd85e30a9","libcubeb/src/android/sles_definitions.h":"24e400ca2330ec16d3a37b69b74144697b51dce17f9ead763b1a6ffedc5633ac","libcubeb/src/cubeb-internal.h":"ef7e7e19c40f743c814a39b8a47b9f03df054894018ad88b49129ffad2564bfa","libcubeb/src/cubeb-jni-instances.h":"8195554372bf60dea569873c9e5fb1106a2cf5dedc66a13d2bc967da0ff48a12","libcubeb/src/cubeb-jni.cpp":"81f001720c41c69b5927e32bd19b9e8e7176d7c33d63c2a58bd0d695dace4fd2","libcubeb/src/cubeb-jni.h":"73f810a32087a6062fd49ba89542655a7e19cecac6f40f8411e1d77ce42a45d1","libcubeb/src/cubeb-sles.h":"dc84a01ba4de9db1ff108609930b36ba442020ccc3e3d6f16528f429426c430c","libcubeb/src/cubeb-speex-resampler.h":"dbf543eee4cc6e40ba3531a39d327e2cec884c19e26c570aa7eae0647e5f7420","libcubeb/src/cubeb.c":"2de6d02fefd308dcc755dc9009cdb42d2d60f900237b4eda305ddcaa180f13db","libcubeb/src/cubeb_alsa.c":"6c833e379eea5d64a65a209f8e60c2aa2d6e038ea855554cd3f2664c463abbcd","libcubeb/src/cubeb_array_queue.h":"5264ae02799c540ff73e8eb8efa55986772b22562a025ae227c2603b6b8d1036","libcubeb/src/cubeb_assert.h":"ab8ed4fe7070a3aed9419c5f9695fce2318c4dafd91213ae61cac476e64adaa7","libcubeb/src/cubeb_audiotrack.c":"fe66d36dfecbfaad164ee8c871b39fd6e708a2f8f1f8524a5c0148ab86bab467","libcubeb/src/cubeb_audiounit.cpp":"8c127f884bb773e3856cc7c1f74b85210d1c589b199b61a6d6322a9c0bc1fbd0","libcubeb/src/cubeb_jack.cpp":"129c011feb01e8c6d573862218c31a8bf90522539a28a5ece8bcf87867be9daf","libcubeb/src/cubeb_kai.c":"a71e1de94211ff0e5667a218d71588f1e74102ccf0140b80925c277949871095","libcubeb/src/cubeb_log.cpp":"74bdc0d92a31d6b4ce3c376c6d310db583b869d673e40e6bd0ea795a1e2f937a","libcubeb/src/cubeb_log.h":"ee05fd22ed9820bed79247b8603cdc64f67bcb145be47e78bf0a0e99fb6c0806","libcubeb/src/cubeb_mixer.cpp":"5ed48f4ff41100ed46292d45253a0fa52573c64022317c3311f9d586b98d4c6a","libcubeb/src/cubeb_mixer.h":"541846b5f3fb5ff5ed1cb97d25b5a9e733500faa9f8e1e76bb5e7ba25991ae7e","libcubeb/src/cubeb_opensl.c":"d10d2d35667a48c8fc31f0ecdd47a8c62d7988bc83fb53d4186d0f37c0fc2ad3","libcubeb/src/cubeb_osx_run_loop.cpp":"13c029f7ea04808597b8841b13f248c4476fb7425762f01a59bc6c944cab3a78","libcubeb/src/cubeb_osx_run_loop.h":"ffe80df60b8ea3d0341715b72cc60aae2e0df45141887c01117df543260a0ef8","libcubeb/src/cubeb_panner.cpp":"405a115ff0eb5f00dbab6bc8f2999b02ee4ea4792a87bad7ebd7218ee7980438","libcubeb/src/cubeb_panner.h":"5679df1b9d138c91f6ea642d51e6230cdf3163bdd65db156ad45906916cb74b0","libcubeb/src/cubeb_pulse.c":"f64e466cc704a569df9a7480062f5dee1c1ba1094762b6689d9941aa50bda208","libcubeb/src/cubeb_resampler.cpp":"2d5f5f4ff242d61897b62b4aeaeee85633be54c1eb155c9e35a2c67d8d5b7043","libcubeb/src/cubeb_resampler.h":"ad9800a40c0272fb2a451c02367cc5a516a3067d4acf963d35eb31be367f9224","libcubeb/src/cubeb_resampler_internal.h":"4b4eb6aee343b9c1f73cf17b201329d3714ba44b06ecb1cebf950fdf93a9dfe6","libcubeb/src/cubeb_ring_array.h":"db8dec7a6d778a424045e5ac61c2bc3a3cec8c4fe8e4780f383db4b6f1b2438c","libcubeb/src/cubeb_ringbuffer.h":"2296255ca7835a3ace2fe1852054f43428b677f432b4174bd832ad0224a409eb","libcubeb/src/cubeb_sndio.c":"d64d6ed34987d89a3041988274834a8346c3af6f08e3dd641a0cef2c71eab6c3","libcubeb/src/cubeb_strings.c":"60f2b8c03a5a01925f9777eec0ab84b0e704b40c03e0d6b9c0e7a16246c81fde","libcubeb/src/cubeb_strings.h":"00e5dc97cf16e28cfb53aaae50ac0e3c0ae8a82aad0720ab6842ce5d9785c39f","libcubeb/src/cubeb_utils.cpp":"5bd7de8bbf7bbdc3a275525edd92bad590fb90fb4d35e77017fdd5d25a5769e6","libcubeb/src/cubeb_utils.h":"27baa42747771bf9232741382b83722f5c731e5dcd4dc2e9b595aca91c5647a5","libcubeb/src/cubeb_utils_unix.h":"2a48bd2aefa1b4e4e4968121512bcaaa6be3bca6597ea390b8203c338f5c49b5","libcubeb/src/cubeb_utils_win.h":"74658b6266a8a223c681b0fd06fcc9c891c7b0b95377635c6f1763b240c2ab27","libcubeb/src/cubeb_wasapi.cpp":"1d476782be50c0944ed0ef4b24f8c64b17e315e1051941aed21b79d7bd06aeb0","libcubeb/src/cubeb_winmm.c":"3f59675847c8ff899d34898616d813b12bd3b6c925cb32fb43f6f9357d0cced5","libcubeb/src/speex/arch.h":"2300bce68c588270cdc684dc7f01377e5e251529f4545d93771e111c56d51b0f","libcubeb/src/speex/fixed_generic.h":"306ee7453677fa6067f16c79d358c6c90a9d3d008850b493cdaa59c07e6375c1","libcubeb/src/speex/resample.c":"9c3a1c64ecf3750af82c980d01ea73d3682f73c332a580465d1e787e5c54cd00","libcubeb/src/speex/resample_neon.h":"7d3fd7af9a1ddde22518b9c7b4419073b72b2dfa5be4c3bc8796992bc87b3da0","libcubeb/src/speex/resample_sse.h":"5a196d8e2d8ab5c956f5252f09f5ddc55aee1f99b1341af3fa54a1f4c2157924","libcubeb/src/speex/speex_config_types.h":"24e3ffbf29e5519611a48e5acb959645b01d166dcb4369380d5f776c3f53d4cd","libcubeb/src/speex/speex_resampler.h":"7e439ec0dd30c32216b3ced17135f8992e5aaf53389d3f5996a7d900c453e65f","libcubeb/src/speex/stack_alloc.h":"e8a2fc0874942d2c7177475fcc141fdd0c0156200b8a4e7656d4a20313e2e569","libcubeb/test/README.md":"1c11b038f87daf10ea78abc17bdbdd157940c241df548c24d5872d142a98c1af","libcubeb/test/common.h":"45eccf0f0c506f2f424149bc434180e296f85ed682b3ffca78cd53f91487d210","libcubeb/test/test_audio.cpp":"c10a9f438d8667153cde2ca13e4b2eebda22d0db93a045299fdbd8c924c44c6c","libcubeb/test/test_callback_ret.cpp":"fdcd25f6da30f2e1dba147d2a790994737d61afbaa30e0e0e9bf41dd5fa41953","libcubeb/test/test_deadlock.cpp":"c311519f30c05300715e91b529685a0c61b8e6b67161fa1f4aeb7030587d86f9","libcubeb/test/test_devices.cpp":"eec312a08667d053216a4266ef9e2b04dcdfa487cc4d34a811bb64cb33ed2937","libcubeb/test/test_duplex.cpp":"add22390fe2dbba09def4cece9a0a6a8e69b24a97f874312b931ece43b1ec4c3","libcubeb/test/test_latency.cpp":"0ace31644f499d69adcfa0aa3bad8c859ad51e97b622e2fa6d26374b8af12894","libcubeb/test/test_loopback.cpp":"e5dfcd868b25468a43dd4d8482702b9494e807db05c041b6fdcb295c59f1f01c","libcubeb/test/test_overload_callback.cpp":"8a05771e5bedfabf9f8a2e5a9266df90f5e964ead3b07782e2e435d7b69b0beb","libcubeb/test/test_record.cpp":"76d5b4f738ca7c30836ef6cc5851f3e04e396b21cf26511e0eeb7a616049fa04","libcubeb/test/test_resampler.cpp":"ca4bc0493ce0c3a5f02f389ac6e37bc2cdb9a752faad2b6fbc5af0a2223ef645","libcubeb/test/test_ring_array.cpp":"27836d716616abf8b020a710659c10ac5e1d4b64149d22cb89bd7a7a5a5669d1","libcubeb/test/test_ring_buffer.cpp":"f6e5a9f552f15808eb8ac3405559bf0ea61e7da4219cd14ac49fff3bfbf49ca7","libcubeb/test/test_sanity.cpp":"f978de12e7046518fbf848fcb5dbb2b5033c7624d5f4b59c0f3e02e7155c3884","libcubeb/test/test_tone.cpp":"3938250700c708c9c742ec8d0c9c2984f3e11860ff8dcacdf0ce785d4668f789","libcubeb/test/test_utils.cpp":"e8d7a02a9096dbc0fd15d71f9849415d52958d2ed82cbc7b8507d3228e08d382","src/callbacks.rs":"b4b4eb3f370475488d7c77b338b0bceee94ef59ede8ff41fa797a3d35ea98b5d","src/channel.rs":"1ae3c22ccc848d6d7b5d312e5a6e64b41871d5bb611d34192651356b57c253c2","src/context.rs":"96bf3442b1dd40262d3088dbb6c473f5451fd91320cef93c522b40f284599803","src/device.rs":"5b65e1c1fdd53fa5208f20bfb809475cbb3c434e02db7d0e4771d13c86f8e369","src/error.rs":"406e3b843ed2d263fe677c4b34fb96a6d780a68bcb56a6f85f041d20d70227bd","src/format.rs":"d4d27790c20eab0b16592f60d5e487425a45a268cf4c74cf843c10ac91bbff4c","src/internal.rs":"c3af5f53dc7957860bf3bc0cd9737d094fb8ac000e7b40c569304cfa76a43145","src/lib.rs":"cb49a3dd8782369172a2f8a61d5c74b4615bfb5fba3677af7d5c149e47d71815","src/log.rs":"6694178177775f2ce5449435d00609e9361c836e23119c07d04892000587dc55","src/macros.rs":"caef13f5d23f7a3ec1a54ec3ca2390ac4ad89d521893f1d0864daf70d57a20aa","src/mixer.rs":"1eb1c8eca9f3f94d7b9a179acca31faee6193d7177d502d5300fcb956430772f","src/panner.rs":"341af4b5a5331a3c1a4ab5396125a3600945e588ea33350431dfe6f1a9a0bd80","src/resampler.rs":"762070f8afde2256715b8764380cdfa1204a1a39d98a9da0b2efe88699792f2c","src/stream.rs":"ea3080b6225949938098e3ac38c42939c49a91b322b327ea66e959fe41f51763"},"package":"e405ad4dff2c1a7cbfa6998e5925e8ceafe900feeacfcad35a3e3790bea0f2aa"}
\ No newline at end of file
diff --git a/third_party/rust/cubeb-sys/Cargo.toml b/third_party/rust/cubeb-sys/Cargo.toml
index 6e50a06ca36bbcbbc18e8da11f0c4fbe1df554ff..cd9f02ff45b6dae4976168767c4f9cc43438b917 100644
--- a/third_party/rust/cubeb-sys/Cargo.toml
+++ b/third_party/rust/cubeb-sys/Cargo.toml
@@ -12,7 +12,7 @@
 
 [package]
 name = "cubeb-sys"
-version = "0.4.1"
+version = "0.5.0"
 authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
 build = "build.rs"
 links = "cubeb"
diff --git a/third_party/rust/cubeb-sys/libcubeb/CMakeLists.txt b/third_party/rust/cubeb-sys/libcubeb/CMakeLists.txt
index 4fac1b8f0754d844f98d5843954ef2a96860dc24..cdb00f9106f9b931a4324bbba4daba8c9f1d8d1a 100644
--- a/third_party/rust/cubeb-sys/libcubeb/CMakeLists.txt
+++ b/third_party/rust/cubeb-sys/libcubeb/CMakeLists.txt
@@ -59,6 +59,7 @@ add_library(cubeb
   src/cubeb_panner.cpp
   src/cubeb_log.cpp
   src/cubeb_strings.c
+  src/cubeb_utils.cpp
    $<TARGET_OBJECTS:speex>)
 target_include_directories(cubeb
   PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>
@@ -181,7 +182,8 @@ endif()
 check_include_files(SLES/OpenSLES.h USE_OPENSL)
 if(USE_OPENSL)
   target_sources(cubeb PRIVATE
-    src/cubeb_opensl.c)
+    src/cubeb_opensl.c
+    src/cubeb-jni.cpp)
   target_compile_definitions(cubeb PRIVATE USE_OPENSL)
   target_link_libraries(cubeb PRIVATE OpenSLES)
 endif()
@@ -237,6 +239,7 @@ if(BUILD_TESTS)
   cubeb_add_test(audio)
   cubeb_add_test(record)
   cubeb_add_test(devices)
+  cubeb_add_test(callback_ret)
 
   add_executable(test_resampler test/test_resampler.cpp src/cubeb_resampler.cpp $<TARGET_OBJECTS:speex>)
   target_include_directories(test_resampler PRIVATE ${gtest_SOURCE_DIR}/include)
@@ -260,27 +263,6 @@ if(BUILD_TESTS)
   cubeb_add_test(latency test_latency)
   cubeb_add_test(ring_array)
 
-  add_executable(test_mixer test/test_mixer.cpp src/cubeb_mixer.cpp)
-  if(USE_AUDIOUNIT)
-    target_compile_definitions(test_mixer PRIVATE USE_AUDIOUNIT)
-  endif()
-  target_include_directories(test_mixer PRIVATE ${gtest_SOURCE_DIR}/include)
-  target_include_directories(test_mixer PRIVATE src)
-  target_link_libraries(test_mixer PRIVATE cubeb gtest_main)
-  add_test(mixer test_mixer)
-  add_sanitizers(test_mixer)
-  install(TARGETS test_mixer DESTINATION ${CMAKE_INSTALL_PREFIX})
-
   cubeb_add_test(utils)
   cubeb_add_test(ring_buffer)
-
-  if(USE_AUDIOUNIT)
-    add_executable(test_deadlock test/test_deadlock.cpp)
-    target_include_directories(test_deadlock PRIVATE ${gtest_SOURCE_DIR}/include)
-    target_include_directories(test_deadlock PRIVATE src)
-    target_link_libraries(test_deadlock PRIVATE cubeb gtest_main)
-    add_test(deadlock test_deadlock)
-    add_sanitizers(test_deadlock)
-    install(TARGETS test_deadlock DESTINATION ${CMAKE_INSTALL_PREFIX})
-  endif()
 endif()
diff --git a/third_party/rust/cubeb-sys/libcubeb/include/cubeb/cubeb.h b/third_party/rust/cubeb-sys/libcubeb/include/cubeb/cubeb.h
index b7dc86260c9a33620eae6d6cd0e4dbb0086ccfad..afca25597f0afc9536bd81b1fcfb43d07aa29176 100644
--- a/third_party/rust/cubeb-sys/libcubeb/include/cubeb/cubeb.h
+++ b/third_party/rust/cubeb-sys/libcubeb/include/cubeb/cubeb.h
@@ -157,63 +157,66 @@ typedef enum {
   CUBEB_LOG_VERBOSE = 2, /**< Verbose logging of callbacks, can have performance implications. */
 } cubeb_log_level;
 
-/** SMPTE channel layout (also known as wave order)
- * DUAL-MONO      L   R
- * DUAL-MONO-LFE  L   R   LFE
- * MONO           M
- * MONO-LFE       M   LFE
- * STEREO         L   R
- * STEREO-LFE     L   R   LFE
- * 3F             L   R   C
- * 3F-LFE         L   R   C    LFE
- * 2F1            L   R   RC
- * 2F1-LFE        L   R   LFE  RC
- * 3F1            L   R   C    RC
- * 3F1-LFE        L   R   C    LFE  RC
- * 2F2            L   R   LS   RS
- * 2F2-LFE        L   R   LFE  LS   RS
- * 3F2            L   R   C    LS   RS
- * 3F2-LFE        L   R   C    LFE  LS   RS
- * 3F3R-LFE       L   R   C    LFE  RC   LS   RS
- * 3F4-LFE        L   R   C    LFE  RLS  RRS  LS   RS
- *
- * The abbreviation of channel name is defined in following table:
- * Abbr  Channel name
- * ---------------------------
- * M     Mono
- * L     Left
- * R     Right
- * C     Center
- * LS    Left Surround
- * RS    Right Surround
- * RLS   Rear Left Surround
- * RC    Rear Center
- * RRS   Rear Right Surround
- * LFE   Low Frequency Effects
- */
-
 typedef enum {
-  CUBEB_LAYOUT_UNDEFINED, // Indicate the speaker's layout is undefined.
-  CUBEB_LAYOUT_DUAL_MONO,
-  CUBEB_LAYOUT_DUAL_MONO_LFE,
-  CUBEB_LAYOUT_MONO,
-  CUBEB_LAYOUT_MONO_LFE,
-  CUBEB_LAYOUT_STEREO,
-  CUBEB_LAYOUT_STEREO_LFE,
-  CUBEB_LAYOUT_3F,
-  CUBEB_LAYOUT_3F_LFE,
-  CUBEB_LAYOUT_2F1,
-  CUBEB_LAYOUT_2F1_LFE,
-  CUBEB_LAYOUT_3F1,
-  CUBEB_LAYOUT_3F1_LFE,
-  CUBEB_LAYOUT_2F2,
-  CUBEB_LAYOUT_2F2_LFE,
-  CUBEB_LAYOUT_3F2,
-  CUBEB_LAYOUT_3F2_LFE,
-  CUBEB_LAYOUT_3F3R_LFE,
-  CUBEB_LAYOUT_3F4_LFE,
-  CUBEB_LAYOUT_MAX
-} cubeb_channel_layout;
+  CHANNEL_UNKNOWN = 0,
+  CHANNEL_FRONT_LEFT = 1 << 0,
+  CHANNEL_FRONT_RIGHT = 1 << 1,
+  CHANNEL_FRONT_CENTER = 1 << 2,
+  CHANNEL_LOW_FREQUENCY = 1 << 3,
+  CHANNEL_BACK_LEFT = 1 << 4,
+  CHANNEL_BACK_RIGHT = 1 << 5,
+  CHANNEL_FRONT_LEFT_OF_CENTER = 1 << 6,
+  CHANNEL_FRONT_RIGHT_OF_CENTER = 1 << 7,
+  CHANNEL_BACK_CENTER = 1 << 8,
+  CHANNEL_SIDE_LEFT = 1 << 9,
+  CHANNEL_SIDE_RIGHT = 1 << 10,
+  CHANNEL_TOP_CENTER = 1 << 11,
+  CHANNEL_TOP_FRONT_LEFT = 1 << 12,
+  CHANNEL_TOP_FRONT_CENTER = 1 << 13,
+  CHANNEL_TOP_FRONT_RIGHT = 1 << 14,
+  CHANNEL_TOP_BACK_LEFT = 1 << 15,
+  CHANNEL_TOP_BACK_CENTER = 1 << 16,
+  CHANNEL_TOP_BACK_RIGHT = 1 << 17
+} cubeb_channel;
+
+typedef uint32_t cubeb_channel_layout;
+// Some common layout definitions.
+enum {
+  CUBEB_LAYOUT_UNDEFINED = 0, // Indicate the speaker's layout is undefined.
+  CUBEB_LAYOUT_MONO = CHANNEL_FRONT_CENTER,
+  CUBEB_LAYOUT_MONO_LFE = CUBEB_LAYOUT_MONO | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_STEREO = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT,
+  CUBEB_LAYOUT_STEREO_LFE = CUBEB_LAYOUT_STEREO | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_3F =
+    CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER,
+  CUBEB_LAYOUT_3F_LFE = CUBEB_LAYOUT_3F | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_2F1 =
+    CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_BACK_CENTER,
+  CUBEB_LAYOUT_2F1_LFE = CUBEB_LAYOUT_2F1 | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_3F1 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                     CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER,
+  CUBEB_LAYOUT_3F1_LFE = CUBEB_LAYOUT_3F1 | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_2F2 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                     CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT,
+  CUBEB_LAYOUT_2F2_LFE = CUBEB_LAYOUT_2F2 | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_QUAD = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                      CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT,
+  CUBEB_LAYOUT_QUAD_LFE = CUBEB_LAYOUT_QUAD | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_3F2 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                     CHANNEL_FRONT_CENTER | CHANNEL_SIDE_LEFT |
+                     CHANNEL_SIDE_RIGHT,
+  CUBEB_LAYOUT_3F2_LFE = CUBEB_LAYOUT_3F2 | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_3F2_BACK = CUBEB_LAYOUT_QUAD | CHANNEL_FRONT_CENTER,
+  CUBEB_LAYOUT_3F2_LFE_BACK = CUBEB_LAYOUT_3F2_BACK | CHANNEL_LOW_FREQUENCY,
+  CUBEB_LAYOUT_3F3R_LFE = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                          CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
+                          CHANNEL_BACK_CENTER | CHANNEL_SIDE_LEFT |
+                          CHANNEL_SIDE_RIGHT,
+  CUBEB_LAYOUT_3F4_LFE = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                         CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
+                         CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT |
+                         CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT,
+};
 
 /** Miscellaneous stream preferences. */
 typedef enum {
@@ -230,7 +233,7 @@ typedef struct {
                                      #cubeb_sample_format. */
   uint32_t rate;                /**< Requested sample rate.  Valid range is [1000, 192000]. */
   uint32_t channels;            /**< Requested channel count.  Valid range is [1, 8]. */
-  cubeb_channel_layout layout;  /**< Requested channel layout. This must be consistent with the provided channels. */
+  cubeb_channel_layout layout;  /**< Requested channel layout. This must be consistent with the provided channels. CUBEB_LAYOUT_UNDEFINED if unknown */
   cubeb_stream_prefs prefs;     /**< Requested preferences. */
 } cubeb_stream_params;
 
@@ -366,8 +369,12 @@ typedef struct {
     @param output_buffer A pointer to a buffer to be filled with audio samples,
                          or nullptr if this is an input-only stream.
     @param nframes The number of frames of the two buffer.
-    @retval Number of frames written to the output buffer. If this number is
-            less than nframes, then the stream will start to drain.
+    @retval If the stream has output, this is the number of frames written to
+            the output buffer. In this case, if this number is less than
+            nframes then the stream will start to drain. If the stream is
+            input only, then returning nframes indicates data has been read.
+            In this case, a value less than nframes will result in the stream
+            being stopped.
     @retval CUBEB_ERROR on error, in which case the data callback will stop
             and the stream will enter a shutdown state. */
 typedef long (* cubeb_data_callback)(cubeb_stream * stream,
@@ -401,6 +408,10 @@ typedef void (* cubeb_log_callback)(char const * fmt, ...);
 
 /** Initialize an application context.  This will perform any library or
     application scoped initialization.
+
+    Note: On Windows platforms, COM must be initialized in MTA mode on
+    any thread that will call the cubeb API.
+
     @param context A out param where an opaque pointer to the application
                    context will be returned.
     @param context_name A name for the context. Depending on the platform this
@@ -454,15 +465,6 @@ CUBEB_EXPORT int cubeb_get_min_latency(cubeb * context,
     @retval CUBEB_ERROR_NOT_SUPPORTED */
 CUBEB_EXPORT int cubeb_get_preferred_sample_rate(cubeb * context, uint32_t * rate);
 
-/** Get the preferred layout for this backend: this is hardware and
-    platform dependent.
-    @param context A pointer to the cubeb context.
-    @param layout The layout of the current speaker configuration.
-    @retval CUBEB_OK
-    @retval CUBEB_ERROR_INVALID_PARAMETER
-    @retval CUBEB_ERROR_NOT_SUPPORTED */
-CUBEB_EXPORT int cubeb_get_preferred_channel_layout(cubeb * context, cubeb_channel_layout * layout);
-
 /** Destroy an application context. This must be called after all stream have
  *  been destroyed.
     @param context A pointer to the cubeb context.*/
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/android/cubeb-output-latency.h b/third_party/rust/cubeb-sys/libcubeb/src/android/cubeb-output-latency.h
new file mode 100644
index 0000000000000000000000000000000000000000..a824fc1c2453d4b05c7d849087c171a6061182de
--- /dev/null
+++ b/third_party/rust/cubeb-sys/libcubeb/src/android/cubeb-output-latency.h
@@ -0,0 +1,76 @@
+#ifndef _CUBEB_OUTPUT_LATENCY_H_
+#define _CUBEB_OUTPUT_LATENCY_H_
+
+#include <stdbool.h>
+#include "cubeb_media_library.h"
+#include "../cubeb-jni.h"
+
+struct output_latency_function {
+  media_lib * from_lib;
+  cubeb_jni * from_jni;
+  int version;
+};
+
+typedef struct output_latency_function output_latency_function;
+
+const int ANDROID_JELLY_BEAN_MR1_4_2 = 17;
+
+output_latency_function *
+cubeb_output_latency_load_method(int version)
+{
+  output_latency_function * ol = NULL;
+  ol = calloc(1, sizeof(output_latency_function));
+
+  ol->version = version;
+
+  if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2){
+    ol->from_jni = cubeb_jni_init();
+    return ol;
+  }
+
+  ol->from_lib = cubeb_load_media_library();
+  return ol;
+}
+
+bool
+cubeb_output_latency_method_is_loaded(output_latency_function * ol)
+{
+  assert(ol && (ol->from_jni || ol->from_lib));
+  if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2){
+    return !!ol->from_jni;
+  }
+
+  return !!ol->from_lib;
+}
+
+void
+cubeb_output_latency_unload_method(output_latency_function * ol)
+{
+  if (!ol) {
+    return;
+  }
+
+  if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2 && ol->from_jni) {
+    cubeb_jni_destroy(ol->from_jni);
+  }
+
+  if (ol->version <= ANDROID_JELLY_BEAN_MR1_4_2 && ol->from_lib) {
+    cubeb_close_media_library(ol->from_lib);
+  }
+
+  free(ol);
+}
+
+uint32_t
+cubeb_get_output_latency(output_latency_function * ol)
+{
+  assert(cubeb_output_latency_method_is_loaded(ol));
+
+  if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2){
+    return cubeb_get_output_latency_from_jni(ol->from_jni);
+  }
+
+  return cubeb_get_output_latency_from_media_library(ol->from_lib);
+}
+
+#endif // _CUBEB_OUTPUT_LATENCY_H_
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/android/cubeb_media_library.h b/third_party/rust/cubeb-sys/libcubeb/src/android/cubeb_media_library.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab21b779dfad4f6a7534d2c6db221289a11c8255
--- /dev/null
+++ b/third_party/rust/cubeb-sys/libcubeb/src/android/cubeb_media_library.h
@@ -0,0 +1,62 @@
+#ifndef _CUBEB_MEDIA_LIBRARY_H_
+#define _CUBEB_MEDIA_LIBRARY_H_
+
+struct media_lib {
+  void * libmedia;
+  int32_t (* get_output_latency)(uint32_t * latency, int stream_type);
+};
+
+typedef struct media_lib media_lib;
+
+media_lib *
+cubeb_load_media_library()
+{
+  media_lib ml = {0};
+  ml.libmedia = dlopen("libmedia.so", RTLD_LAZY);
+  if (!ml.libmedia) {
+    return NULL;
+  }
+
+  // Get the latency, in ms, from AudioFlinger. First, try the most recent signature.
+  // status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t streamType)
+  ml.get_output_latency =
+    dlsym(ml.libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t");
+  if (!ml.get_output_latency) {
+    // In case of failure, try the signature from legacy version.
+    // status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType)
+    ml.get_output_latency =
+      dlsym(ml.libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPji");
+    if (!ml.get_output_latency) {
+      return NULL;
+    }
+  }
+
+  media_lib * rv = NULL;
+  rv = calloc(1, sizeof(media_lib));
+  assert(rv);
+  *rv = ml;
+  return rv;
+}
+
+void
+cubeb_close_media_library(media_lib * ml)
+{
+  dlclose(ml->libmedia);
+  ml->libmedia = NULL;
+  ml->get_output_latency = NULL;
+  free(ml);
+}
+
+uint32_t
+cubeb_get_output_latency_from_media_library(media_lib * ml)
+{
+  uint32_t latency = 0;
+  const int audio_stream_type_music = 3;
+  int32_t r = ml->get_output_latency(&latency, audio_stream_type_music);
+  if (r) {
+    return 0;
+  }
+  return latency;
+}
+
+#endif // _CUBEB_MEDIA_LIBRARY_H_
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb-internal.h b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-internal.h
index 25bad3a1d0f9948afbc4a7e1cbe39b706ab537fc..9b6199c2efb2eb8ac5aa09513cf4cd4992765832 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb-internal.h
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-internal.h
@@ -33,14 +33,6 @@ extern "C" {
 }
 #endif
 
-typedef struct {
-  char const * name;
-  unsigned int const channels;
-  cubeb_channel_layout const layout;
-} cubeb_layout_map;
-
-extern cubeb_layout_map const CUBEB_CHANNEL_LAYOUT_MAPS[CUBEB_LAYOUT_MAX];
-
 struct cubeb_ops {
   int (* init)(cubeb ** context, char const * context_name);
   char const * (* get_backend_id)(cubeb * context);
@@ -49,7 +41,6 @@ struct cubeb_ops {
                           cubeb_stream_params params,
                           uint32_t * latency_ms);
   int (* get_preferred_sample_rate)(cubeb * context, uint32_t * rate);
-  int (* get_preferred_channel_layout)(cubeb * context, cubeb_channel_layout * layout);
   int (* enumerate_devices)(cubeb * context, cubeb_device_type type,
                             cubeb_device_collection * collection);
   int (* device_collection_destroy)(cubeb * context,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni-instances.h b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni-instances.h
new file mode 100644
index 0000000000000000000000000000000000000000..4fed046592132b49c1036f2157db87d309398af2
--- /dev/null
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni-instances.h
@@ -0,0 +1,30 @@
+#ifndef _CUBEB_JNI_INSTANCES_H_
+#define _CUBEB_JNI_INSTANCES_H_
+
+/*
+ * The methods in this file offer a way to pass in the required
+ * JNI instances in the cubeb library. By default they return NULL.
+ * In this case part of the cubeb API that depends on JNI
+ * will return CUBEB_ERROR_NOT_SUPPORTED. Currently only one
+ * method depends on that:
+ *
+ * cubeb_stream_get_position()
+ *
+ * Users that want to use that cubeb API method must "override"
+ * the methods bellow to return a valid instance of JavaVM
+ * and application's Context object.
+ * */
+
+JNIEnv *
+cubeb_get_jni_env_for_thread()
+{
+  return nullptr;
+}
+
+jobject
+cubeb_jni_get_context_instance()
+{
+  return nullptr;
+}
+
+#endif //_CUBEB_JNI_INSTANCES_H_
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni.cpp b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a5066967af22ef763983019fafee796029671abc
--- /dev/null
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni.cpp
@@ -0,0 +1,68 @@
+#include "jni.h"
+#include <assert.h>
+#include "cubeb-jni-instances.h"
+
+#define AUDIO_STREAM_TYPE_MUSIC 3
+
+struct cubeb_jni {
+  jobject s_audio_manager_obj = nullptr;
+  jclass s_audio_manager_class = nullptr;
+  jmethodID s_get_output_latency_id = nullptr;
+};
+
+extern "C"
+cubeb_jni *
+cubeb_jni_init()
+{
+  jobject ctx_obj = cubeb_jni_get_context_instance();
+  JNIEnv * jni_env = cubeb_get_jni_env_for_thread();
+  if (!jni_env || !ctx_obj) {
+    return nullptr;
+  }
+
+  cubeb_jni * cubeb_jni_ptr = new cubeb_jni;
+  assert(cubeb_jni_ptr);
+
+  // Find the audio manager object and make it global to call it from another method
+  jclass context_class = jni_env->FindClass("android/content/Context");
+  jfieldID audio_service_field = jni_env->GetStaticFieldID(context_class, "AUDIO_SERVICE", "Ljava/lang/String;");
+  jstring jstr = (jstring)jni_env->GetStaticObjectField(context_class, audio_service_field);
+  jmethodID get_system_service_id = jni_env->GetMethodID(context_class, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
+  jobject audio_manager_obj = jni_env->CallObjectMethod(ctx_obj, get_system_service_id, jstr);
+  cubeb_jni_ptr->s_audio_manager_obj = reinterpret_cast<jobject>(jni_env->NewGlobalRef(audio_manager_obj));
+
+  // Make the audio manager class a global reference in order to preserve method id
+  jclass audio_manager_class = jni_env->FindClass("android/media/AudioManager");
+  cubeb_jni_ptr->s_audio_manager_class = reinterpret_cast<jclass>(jni_env->NewGlobalRef(audio_manager_class));
+  cubeb_jni_ptr->s_get_output_latency_id = jni_env->GetMethodID (audio_manager_class, "getOutputLatency", "(I)I");
+
+  jni_env->DeleteLocalRef(ctx_obj);
+  jni_env->DeleteLocalRef(context_class);
+  jni_env->DeleteLocalRef(jstr);
+  jni_env->DeleteLocalRef(audio_manager_obj);
+  jni_env->DeleteLocalRef(audio_manager_class);
+
+  return cubeb_jni_ptr;
+}
+
+extern "C"
+int cubeb_get_output_latency_from_jni(cubeb_jni * cubeb_jni_ptr)
+{
+  assert(cubeb_jni_ptr);
+  JNIEnv * jni_env = cubeb_get_jni_env_for_thread();
+  return jni_env->CallIntMethod(cubeb_jni_ptr->s_audio_manager_obj, cubeb_jni_ptr->s_get_output_latency_id, AUDIO_STREAM_TYPE_MUSIC); //param: AudioManager.STREAM_MUSIC
+}
+
+extern "C"
+void cubeb_jni_destroy(cubeb_jni * cubeb_jni_ptr)
+{
+  assert(cubeb_jni_ptr);
+
+  JNIEnv * jni_env = cubeb_get_jni_env_for_thread();
+  assert(jni_env);
+
+  jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_audio_manager_obj);
+  jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_audio_manager_class);
+
+  delete cubeb_jni_ptr;
+}
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni.h b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni.h
new file mode 100644
index 0000000000000000000000000000000000000000..8c7ddb6acf4d5bb9acbdb214b367bcecaaa98489
--- /dev/null
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni.h
@@ -0,0 +1,10 @@
+#ifndef _CUBEB_JNI_H_
+#define _CUBEB_JNI_H_
+
+typedef struct cubeb_jni cubeb_jni;
+
+cubeb_jni * cubeb_jni_init();
+int cubeb_get_output_latency_from_jni(cubeb_jni * cubeb_jni_ptr);
+void cubeb_jni_destroy(cubeb_jni * cubeb_jni_ptr);
+
+#endif // _CUBEB_JNI_H_
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb.c b/third_party/rust/cubeb-sys/libcubeb/src/cubeb.c
index f9bfdd35628db369bcf0be70a7db21bdd662ae51..ebb2170ceef5cd9e0f83a30030eacb03e36ffe9c 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb.c
@@ -277,20 +277,6 @@ cubeb_get_preferred_sample_rate(cubeb * context, uint32_t * rate)
   return context->ops->get_preferred_sample_rate(context, rate);
 }
 
-int
-cubeb_get_preferred_channel_layout(cubeb * context, cubeb_channel_layout * layout)
-{
-  if (!context || !layout) {
-    return CUBEB_ERROR_INVALID_PARAMETER;
-  }
-
-  if (!context->ops->get_preferred_channel_layout) {
-    return CUBEB_ERROR_NOT_SUPPORTED;
-  }
-
-  return context->ops->get_preferred_channel_layout(context, layout);
-}
-
 void
 cubeb_destroy(cubeb * context)
 {
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_alsa.c b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_alsa.c
index b38ab66cb08a486d290092222fd06740aa699730..bfd4d8f199d415cda8981c9fd9ed1e7468aa1bf2 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_alsa.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_alsa.c
@@ -1358,7 +1358,6 @@ static struct cubeb_ops const alsa_ops = {
   .get_max_channel_count = alsa_get_max_channel_count,
   .get_min_latency = alsa_get_min_latency,
   .get_preferred_sample_rate = alsa_get_preferred_sample_rate,
-  .get_preferred_channel_layout = NULL,
   .enumerate_devices = alsa_enumerate_devices,
   .device_collection_destroy = alsa_device_collection_destroy,
   .destroy = alsa_destroy,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiotrack.c b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiotrack.c
index 98d0bd96ce6c58a46a4bc59210113bc88115721c..0f4dfbbc8faa520bf1265e61da187327c144abcc 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiotrack.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiotrack.c
@@ -423,7 +423,6 @@ static struct cubeb_ops const audiotrack_ops = {
   .get_max_channel_count = audiotrack_get_max_channel_count,
   .get_min_latency = audiotrack_get_min_latency,
   .get_preferred_sample_rate = audiotrack_get_preferred_sample_rate,
-  .get_preferred_channel_layout = NULL,
   .enumerate_devices = NULL,
   .device_collection_destroy = NULL,
   .destroy = audiotrack_destroy,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiounit.cpp b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiounit.cpp
index ac71022169dffd2847c26371ca1a75387941db62..e11bb493c8997167eb526b4a295eea84ba2dea64 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiounit.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiounit.cpp
@@ -87,6 +87,7 @@ struct cubeb {
   dispatch_queue_t serial_queue = dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL);
   // Current used channel layout
   atomic<cubeb_channel_layout> layout{ CUBEB_LAYOUT_UNDEFINED };
+  uint32_t channels = 0;
 };
 
 static unique_ptr<AudioChannelLayout, decltype(&free)>
@@ -188,6 +189,10 @@ struct cubeb_stream {
   AudioObjectID plugin_id = 0;              // used to create aggregate device
   /* Mixer interface */
   unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)> mixer;
+  /* Buffer where remixing/resampling will occur when upmixing is required */
+  /* Only accessed from callback thread */
+  unique_ptr<uint8_t[]> temp_buffer;
+  size_t temp_buffer_size = 0; // size in bytes.
 };
 
 bool has_input(cubeb_stream * stm)
@@ -204,18 +209,44 @@ cubeb_channel
 channel_label_to_cubeb_channel(UInt32 label)
 {
   switch (label) {
-    case kAudioChannelLabel_Mono: return CHANNEL_MONO;
-    case kAudioChannelLabel_Left: return CHANNEL_LEFT;
-    case kAudioChannelLabel_Right: return CHANNEL_RIGHT;
-    case kAudioChannelLabel_Center: return CHANNEL_CENTER;
-    case kAudioChannelLabel_LFEScreen: return CHANNEL_LFE;
-    case kAudioChannelLabel_LeftSurround: return CHANNEL_LS;
-    case kAudioChannelLabel_RightSurround: return CHANNEL_RS;
-    case kAudioChannelLabel_RearSurroundLeft: return CHANNEL_RLS;
-    case kAudioChannelLabel_RearSurroundRight: return CHANNEL_RRS;
-    case kAudioChannelLabel_CenterSurround: return CHANNEL_RCENTER;
-    case kAudioChannelLabel_Unknown: return CHANNEL_UNMAPPED;
-    default: return CHANNEL_INVALID;
+    case kAudioChannelLabel_Left:
+      return CHANNEL_FRONT_LEFT;
+    case kAudioChannelLabel_Right:
+      return CHANNEL_FRONT_RIGHT;
+    case kAudioChannelLabel_Center:
+      return CHANNEL_FRONT_CENTER;
+    case kAudioChannelLabel_LFEScreen:
+      return CHANNEL_LOW_FREQUENCY;
+    case kAudioChannelLabel_LeftSurround:
+      return CHANNEL_BACK_LEFT;
+    case kAudioChannelLabel_RightSurround:
+      return CHANNEL_BACK_RIGHT;
+    case kAudioChannelLabel_LeftCenter:
+      return CHANNEL_FRONT_LEFT_OF_CENTER;
+    case kAudioChannelLabel_RightCenter:
+      return CHANNEL_FRONT_RIGHT_OF_CENTER;
+    case kAudioChannelLabel_CenterSurround:
+      return CHANNEL_BACK_CENTER;
+    case kAudioChannelLabel_LeftSurroundDirect:
+      return CHANNEL_SIDE_LEFT;
+    case kAudioChannelLabel_RightSurroundDirect:
+      return CHANNEL_SIDE_RIGHT;
+    case kAudioChannelLabel_TopCenterSurround:
+      return CHANNEL_TOP_CENTER;
+    case kAudioChannelLabel_VerticalHeightLeft:
+      return CHANNEL_TOP_FRONT_LEFT;
+    case kAudioChannelLabel_VerticalHeightCenter:
+      return CHANNEL_TOP_FRONT_CENTER;
+    case kAudioChannelLabel_VerticalHeightRight:
+      return CHANNEL_TOP_FRONT_RIGHT;
+    case kAudioChannelLabel_TopBackLeft:
+      return CHANNEL_TOP_BACK_LEFT;
+    case kAudioChannelLabel_TopBackCenter:
+      return CHANNEL_TOP_BACK_CENTER;
+    case kAudioChannelLabel_TopBackRight:
+      return CHANNEL_TOP_BACK_RIGHT;
+    default:
+      return CHANNEL_UNKNOWN;
   }
 }
 
@@ -223,18 +254,44 @@ AudioChannelLabel
 cubeb_channel_to_channel_label(cubeb_channel channel)
 {
   switch (channel) {
-    case CHANNEL_MONO: return kAudioChannelLabel_Mono;
-    case CHANNEL_LEFT: return kAudioChannelLabel_Left;
-    case CHANNEL_RIGHT: return kAudioChannelLabel_Right;
-    case CHANNEL_CENTER: return kAudioChannelLabel_Center;
-    case CHANNEL_LFE: return kAudioChannelLabel_LFEScreen;
-    case CHANNEL_LS: return kAudioChannelLabel_LeftSurround;
-    case CHANNEL_RS: return kAudioChannelLabel_RightSurround;
-    case CHANNEL_RLS: return kAudioChannelLabel_RearSurroundLeft;
-    case CHANNEL_RRS: return kAudioChannelLabel_RearSurroundRight;
-    case CHANNEL_RCENTER: return kAudioChannelLabel_CenterSurround;
-    case CHANNEL_UNMAPPED: return kAudioChannelLabel_Unknown;
-    default: return kAudioChannelLabel_Unknown;
+    case CHANNEL_FRONT_LEFT:
+      return kAudioChannelLabel_Left;
+    case CHANNEL_FRONT_RIGHT:
+      return kAudioChannelLabel_Right;
+    case CHANNEL_FRONT_CENTER:
+      return kAudioChannelLabel_Center;
+    case CHANNEL_LOW_FREQUENCY:
+      return kAudioChannelLabel_LFEScreen;
+    case CHANNEL_BACK_LEFT:
+      return kAudioChannelLabel_LeftSurround;
+    case CHANNEL_BACK_RIGHT:
+      return kAudioChannelLabel_RightSurround;
+    case CHANNEL_FRONT_LEFT_OF_CENTER:
+      return kAudioChannelLabel_LeftCenter;
+    case CHANNEL_FRONT_RIGHT_OF_CENTER:
+      return kAudioChannelLabel_RightCenter;
+    case CHANNEL_BACK_CENTER:
+      return kAudioChannelLabel_CenterSurround;
+    case CHANNEL_SIDE_LEFT:
+      return kAudioChannelLabel_LeftSurroundDirect;
+    case CHANNEL_SIDE_RIGHT:
+      return kAudioChannelLabel_RightSurroundDirect;
+    case CHANNEL_TOP_CENTER:
+      return kAudioChannelLabel_TopCenterSurround;
+    case CHANNEL_TOP_FRONT_LEFT:
+      return kAudioChannelLabel_VerticalHeightLeft;
+    case CHANNEL_TOP_FRONT_CENTER:
+      return kAudioChannelLabel_VerticalHeightCenter;
+    case CHANNEL_TOP_FRONT_RIGHT:
+      return kAudioChannelLabel_VerticalHeightRight;
+    case CHANNEL_TOP_BACK_LEFT:
+      return kAudioChannelLabel_TopBackLeft;
+    case CHANNEL_TOP_BACK_CENTER:
+      return kAudioChannelLabel_TopBackCenter;
+    case CHANNEL_TOP_BACK_RIGHT:
+      return kAudioChannelLabel_TopBackRight;
+    default:
+      return CHANNEL_UNKNOWN;
   }
 }
 
@@ -382,6 +439,12 @@ audiounit_input_callback(void * user_ptr,
                                           &total_input_frames,
                                           NULL,
                                           0);
+    if (outframes < total_input_frames) {
+      OSStatus r = AudioOutputUnitStop(stm->input_unit);
+      assert(r == 0);
+      stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
+      return noErr;
+    }
     assert(outframes >= 0);
 
     // Reset input buffer
@@ -411,24 +474,26 @@ is_extra_input_needed(cubeb_stream * stm)
 
 static void
 audiounit_mix_output_buffer(cubeb_stream * stm,
-                            long output_frames,
+                            size_t output_frames,
+                            void * input_buffer,
+                            size_t input_buffer_size,
                             void * output_buffer,
-                            unsigned long output_buffer_length)
-{
-  cubeb_stream_params output_mixer_params = {
-    stm->output_stream_params.format,
-    stm->output_stream_params.rate,
-    CUBEB_CHANNEL_LAYOUT_MAPS[stm->context->layout].channels,
-    stm->context->layout,
-    CUBEB_STREAM_PREF_NONE
-  };
+                            size_t output_buffer_size)
+{
+  assert(input_buffer_size >=
+         cubeb_sample_size(stm->output_stream_params.format) *
+           stm->output_stream_params.channels * output_frames);
+  assert(output_buffer_size >= stm->output_desc.mBytesPerFrame * output_frames);
 
-  // The downmixing(from 5.1) supports in-place conversion, so we can use
-  // the same buffer for both input and output of the mixer.
-  cubeb_mixer_mix(stm->mixer.get(), output_frames,
-                  output_buffer, output_buffer_length,
-                  output_buffer, output_buffer_length,
-                  &stm->output_stream_params, &output_mixer_params);
+  int r = cubeb_mixer_mix(stm->mixer.get(),
+                          output_frames,
+                          input_buffer,
+                          input_buffer_size,
+                          output_buffer,
+                          output_buffer_size);
+  if (r != 0) {
+    LOG("Remix error = %d", r);
+  }
 }
 
 static OSStatus
@@ -473,8 +538,22 @@ audiounit_output_callback(void * user_ptr,
     audiounit_make_silent(&outBufferList->mBuffers[0]);
     return noErr;
   }
+
   /* Get output buffer. */
-  output_buffer = outBufferList->mBuffers[0].mData;
+  if (stm->mixer) {
+    // If remixing needs to occur, we can't directly work in our final
+    // destination buffer as data may be overwritten or too small to start with.
+    size_t size_needed = output_frames * stm->output_stream_params.channels *
+                         cubeb_sample_size(stm->output_stream_params.format);
+    if (stm->temp_buffer_size < size_needed) {
+      stm->temp_buffer.reset(new uint8_t[size_needed]);
+      stm->temp_buffer_size = size_needed;
+    }
+    output_buffer = stm->temp_buffer.get();
+  } else {
+    output_buffer = outBufferList->mBuffers[0].mData;
+  }
+
   /* If Full duplex get also input buffer */
   if (stm->input_unit != NULL) {
     if (is_extra_input_needed(stm)) {
@@ -525,7 +604,6 @@ audiounit_output_callback(void * user_ptr,
     return noErr;
   }
 
-  size_t outbpf = stm->output_desc.mBytesPerFrame;
   stm->draining = (UInt32) outframes < output_frames;
   stm->frames_played = stm->frames_queued;
   stm->frames_queued += outframes;
@@ -536,22 +614,29 @@ audiounit_output_callback(void * user_ptr,
 
   /* Post process output samples. */
   if (stm->draining) {
+    size_t outbpf = cubeb_sample_size(stm->output_stream_params.format);
     /* Clear missing frames (silence) */
     memset((uint8_t*)output_buffer + outframes * outbpf, 0, (output_frames - outframes) * outbpf);
   }
-  /* Pan stereo. */
-  if (panning != 0.0f) {
-    if (outaff & kAudioFormatFlagIsFloat) {
-      cubeb_pan_stereo_buffer_float((float*)output_buffer, outframes, panning);
-    } else if (outaff & kAudioFormatFlagIsSignedInteger) {
-      cubeb_pan_stereo_buffer_int((short*)output_buffer, outframes, panning);
-    }
-  }
 
   /* Mixing */
-  if (stm->output_stream_params.layout != CUBEB_LAYOUT_UNDEFINED) {
-    unsigned long output_buffer_length = outBufferList->mBuffers[0].mDataByteSize;
-    audiounit_mix_output_buffer(stm, output_frames, output_buffer, output_buffer_length);
+  if (stm->mixer) {
+    audiounit_mix_output_buffer(stm,
+                                output_frames,
+                                output_buffer,
+                                stm->temp_buffer_size,
+                                outBufferList->mBuffers[0].mData,
+                                outBufferList->mBuffers[0].mDataByteSize);
+  } else {
+    /* Pan stereo. */
+    if (panning != 0.0f) {
+      if (outaff & kAudioFormatFlagIsFloat) {
+        cubeb_pan_stereo_buffer_float(
+          (float*)output_buffer, outframes, panning);
+      } else if (outaff & kAudioFormatFlagIsSignedInteger) {
+        cubeb_pan_stereo_buffer_int((short*)output_buffer, outframes, panning);
+      }
+    }
   }
 
   return noErr;
@@ -1120,6 +1205,15 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
 static cubeb_channel_layout
 audiounit_convert_channel_layout(AudioChannelLayout * layout)
 {
+  // When having on or two channel, force mono or stereo. Some devices (namely,
+  //  Bose QC35, mark 1 and 2), expose a single channel mapped to the right for
+  //  some reason.
+  if (layout->mNumberChannelDescriptions == 1) {
+    return CUBEB_LAYOUT_MONO;
+  } else if (layout->mNumberChannelDescriptions == 2) {
+    return CUBEB_LAYOUT_STEREO;
+  }
+
   if (layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
     // kAudioChannelLayoutTag_UseChannelBitmap
     // kAudioChannelLayoutTag_Mono
@@ -1129,19 +1223,13 @@ audiounit_convert_channel_layout(AudioChannelLayout * layout)
     return CUBEB_LAYOUT_UNDEFINED;
   }
 
-  // This devices has more channels that we can support, bail out.
-  if (layout->mNumberChannelDescriptions >= CHANNEL_MAX) {
-    LOG("Audio device has more than %d channels, bailing out.", CHANNEL_MAX);
-    return CUBEB_LAYOUT_UNDEFINED;
-  }
-
-  cubeb_channel_map cm;
-  cm.channels = layout->mNumberChannelDescriptions;
+  cubeb_channel_layout cl = 0;
   for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) {
-    cm.map[i] = channel_label_to_cubeb_channel(layout->mChannelDescriptions[i].mChannelLabel);
+    cl |= channel_label_to_cubeb_channel(
+      layout->mChannelDescriptions[i].mChannelLabel);
   }
 
-  return cubeb_channel_map_to_layout(&cm);
+  return cl;
 }
 
 static cubeb_channel_layout
@@ -1176,76 +1264,8 @@ audiounit_get_current_channel_layout(AudioUnit output_unit)
   return audiounit_convert_channel_layout(layout.get());
 }
 
-static cubeb_channel_layout
-audiounit_get_preferred_channel_layout()
-{
-  OSStatus rv = noErr;
-  UInt32 size = 0;
-  AudioDeviceID id;
-
-  id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT);
-  if (id == kAudioObjectUnknown) {
-    return CUBEB_LAYOUT_UNDEFINED;
-  }
-
-  AudioObjectPropertyAddress adr = { kAudioDevicePropertyPreferredChannelLayout,
-                                     kAudioDevicePropertyScopeOutput,
-                                     kAudioObjectPropertyElementMaster };
-  rv = AudioObjectGetPropertyDataSize(id, &adr, 0, NULL, &size);
-  if (rv != noErr) {
-    return CUBEB_LAYOUT_UNDEFINED;
-  }
-  assert(size > 0);
-
-  auto layout = make_sized_audio_channel_layout(size);
-  rv = AudioObjectGetPropertyData(id, &adr, 0, NULL, &size, layout.get());
-  if (rv != noErr) {
-    return CUBEB_LAYOUT_UNDEFINED;
-  }
-
-  return audiounit_convert_channel_layout(layout.get());
-}
-
 static int audiounit_create_unit(AudioUnit * unit, device_info * device);
 
-static int
-audiounit_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layout)
-{
-  // The preferred layout is only returned when the connected sound device
-  // (e.g. ASUS Xonar U7), has preferred layout setting.
-  // For default output on Mac, there is no preferred channel layout,
-  // so it might return UNDEFINED.
-  *layout = audiounit_get_preferred_channel_layout();
-
-  // If the preferred channel layout is UNDEFINED, then we try to access the
-  // current applied channel layout.
-  if (*layout == CUBEB_LAYOUT_UNDEFINED) {
-    // If we already have at least one cubeb stream, then the current channel
-    // layout must be updated. We can return it directly.
-    if (ctx->active_streams) {
-      *layout = ctx->layout;
-      return CUBEB_OK;
-    }
-
-    // If there is no existed stream, then we create a default ouput unit and
-    // use it to get the current used channel layout.
-    AudioUnit output_unit = nullptr;
-    device_info default_out_device;
-    default_out_device.id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT);
-    default_out_device.flags = (DEV_OUTPUT | DEV_SYSTEM_DEFAULT);
-    if (default_out_device.id != kAudioObjectUnknown) {
-      audiounit_create_unit(&output_unit, &default_out_device);
-      *layout = audiounit_get_current_channel_layout(output_unit);
-    }
-  }
-
-  if (*layout == CUBEB_LAYOUT_UNDEFINED) {
-    return CUBEB_ERROR;
-  }
-
-  return CUBEB_OK;
-}
-
 static OSStatus audiounit_remove_device_listener(cubeb * context);
 
 static void
@@ -1314,80 +1334,60 @@ audio_stream_desc_init(AudioStreamBasicDescription * ss,
 void
 audiounit_init_mixer(cubeb_stream * stm)
 {
-  // We only handle downmixing for now.
-  // The audio rendering mechanism on OS X will drop the extra channels beyond
-  // the channels that audio device can provide, so we need to downmix the
+  // We can't rely on macOS' AudioUnit to properly downmix (or upmix) the audio
+  // data, it silently drop the channels so we need to remix the
   // audio data by ourselves to keep all the information.
   stm->mixer.reset(cubeb_mixer_create(stm->output_stream_params.format,
-                                      CUBEB_MIXER_DIRECTION_DOWNMIX));
+                                      stm->output_stream_params.channels,
+                                      stm->output_stream_params.layout,
+                                      stm->context->channels,
+                                      stm->context->layout));
+  assert(stm->mixer);
 }
 
 static int
 audiounit_set_channel_layout(AudioUnit unit,
                              io_side side,
-                             const cubeb_stream_params * stream_params)
+                             cubeb_channel_layout layout)
 {
   if (side != OUTPUT) {
     return CUBEB_ERROR;
   }
 
-  assert(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
-  assert(stream_params->channels == CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels);
-
-  OSStatus r;
-  size_t size = sizeof(AudioChannelLayout);
-  auto layout = make_sized_audio_channel_layout(size);
-
-  switch (stream_params->layout) {
-    case CUBEB_LAYOUT_DUAL_MONO:
-    case CUBEB_LAYOUT_STEREO:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
-      break;
-    case CUBEB_LAYOUT_MONO:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
-      break;
-    case CUBEB_LAYOUT_3F:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_0;
-      break;
-    case CUBEB_LAYOUT_2F1:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_2_1;
-      break;
-    case CUBEB_LAYOUT_3F1:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_1;
-      break;
-    case CUBEB_LAYOUT_2F2:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_2_2;
-      break;
-    case CUBEB_LAYOUT_3F2:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_2;
-      break;
-    case CUBEB_LAYOUT_3F2_LFE:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
-      break;
-    default:
-      layout->mChannelLayoutTag = kAudioChannelLayoutTag_Unknown;
-      break;
+  if (layout == CUBEB_LAYOUT_UNDEFINED) {
+    // We leave everything as-is...
+    return CUBEB_OK;
   }
 
-  // For those layouts that can't be matched to coreaudio's predefined layout,
-  // we use customized layout.
-  if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_Unknown) {
-    size = offsetof(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
-    layout = make_sized_audio_channel_layout(size);
-    layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
-    layout->mNumberChannelDescriptions = stream_params->channels;
-    for (UInt32 i = 0 ; i < stream_params->channels ; ++i) {
-      layout->mChannelDescriptions[i].mChannelLabel =
-        cubeb_channel_to_channel_label(CHANNEL_INDEX_TO_ORDER[stream_params->layout][i]);
-      layout->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
-    }
+
+  OSStatus r;
+  int channels = cubeb_channel_layout_nb_channels(layout);
+
+  // We do not use CoreAudio standard layout for lack of documentation on what
+  // the actual channel orders are. So we set a custom layout.
+  size_t size = offsetof(AudioChannelLayout, mChannelDescriptions[channels]);
+  auto au_layout = make_sized_audio_channel_layout(size);
+  au_layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
+  au_layout->mNumberChannelDescriptions = channels;
+  cubeb_channel_layout channelMap = layout;
+  int i = 0;
+  while (channelMap != 0) {
+    XASSERT(i < channels);
+    uint32_t channel = (channelMap & 1) << i;
+    if (channel != 0) {
+      au_layout->mChannelDescriptions[i].mChannelLabel =
+        cubeb_channel_to_channel_label(static_cast<cubeb_channel>(channel));
+      au_layout->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
+      i += 1;
+    }
+    channelMap = channelMap >> 1;
   }
 
   r = AudioUnitSetProperty(unit,
                            kAudioUnitProperty_AudioChannelLayout,
                            kAudioUnitScope_Input,
                            AU_OUT_BUS,
-                           layout.get(),
+                           au_layout.get(),
                            size);
   if (r != noErr) {
     LOG("AudioUnitSetProperty/%s/kAudioUnitProperty_AudioChannelLayout rv=%d", to_string(side), r);
@@ -1405,14 +1405,9 @@ audiounit_layout_init(cubeb_stream * stm, io_side side)
     return;
   }
 
-  audiounit_set_channel_layout(stm->output_unit, OUTPUT, &stm->output_stream_params);
-
-  // Update the current used channel layout for the cubeb context.
-  // Notice that this channel layout may be different from the layout we set above,
-  // because OSX doesn't return error when the output device can NOT provide
-  // our desired layout. Thus, we update the layout evertime when the cubeb_stream
-  // is created and use it when we need to mix audio data.
   stm->context->layout = audiounit_get_current_channel_layout(stm->output_unit);
+
+  audiounit_set_channel_layout(stm->output_unit, OUTPUT, stm->context->layout);
 }
 
 static vector<AudioObjectID>
@@ -2310,6 +2305,25 @@ audiounit_configure_output(cubeb_stream * stm)
   }
   stm->output_hw_rate = output_hw_desc.mSampleRate;
   LOG("(%p) Output device sampling rate: %.2f", stm, output_hw_desc.mSampleRate);
+  stm->context->channels = output_hw_desc.mChannelsPerFrame;
+
+  // Set the input layout to match the output device layout.
+  audiounit_layout_init(stm, OUTPUT);
+  if (stm->context->channels != stm->output_stream_params.channels ||
+      stm->context->layout != stm->output_stream_params.layout) {
+    LOG("Incompatible channel layouts detected, setting up remixer");
+    audiounit_init_mixer(stm);
+    // We will be remixing the data before it reaches the output device.
+    // We need to adjust the number of channels and other
+    // AudioStreamDescription details.
+    stm->output_desc.mChannelsPerFrame = stm->context->channels;
+    stm->output_desc.mBytesPerFrame = (stm->output_desc.mBitsPerChannel / 8) *
+                                      stm->output_desc.mChannelsPerFrame;
+    stm->output_desc.mBytesPerPacket =
+      stm->output_desc.mBytesPerFrame * stm->output_desc.mFramesPerPacket;
+  } else {
+    stm->mixer = nullptr;
+  }
 
   r = AudioUnitSetProperty(stm->output_unit,
                            kAudioUnitProperty_StreamFormat,
@@ -2353,10 +2367,6 @@ audiounit_configure_output(cubeb_stream * stm)
     return CUBEB_ERROR;
   }
 
-  if (stm->output_stream_params.layout != CUBEB_LAYOUT_UNDEFINED) {
-    audiounit_layout_init(stm, OUTPUT);
-    audiounit_init_mixer(stm);
-  }
   LOG("(%p) Output audiounit init successfully.", stm);
   return CUBEB_OK;
 }
@@ -3468,7 +3478,6 @@ cubeb_ops const audiounit_ops = {
   /*.get_max_channel_count =*/ audiounit_get_max_channel_count,
   /*.get_min_latency =*/ audiounit_get_min_latency,
   /*.get_preferred_sample_rate =*/ audiounit_get_preferred_sample_rate,
-  /*.get_preferred_channel_layout =*/ audiounit_get_preferred_channel_layout,
   /*.enumerate_devices =*/ audiounit_enumerate_devices,
   /*.device_collection_destroy =*/ audiounit_device_collection_destroy,
   /*.destroy =*/ audiounit_destroy,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_jack.cpp b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_jack.cpp
index 5f4128d39970170540e47a0eb6ec5cb6cdefc070..3632da5221f318381ecfc4be00bc22afed30cdc9 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_jack.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_jack.cpp
@@ -119,7 +119,6 @@ static struct cubeb_ops const cbjack_ops = {
   .get_max_channel_count = cbjack_get_max_channel_count,
   .get_min_latency = cbjack_get_min_latency,
   .get_preferred_sample_rate = cbjack_get_preferred_sample_rate,
-  .get_preferred_channel_layout = NULL,
   .enumerate_devices = cbjack_enumerate_devices,
   .device_collection_destroy = cbjack_device_collection_destroy,
   .destroy = cbjack_destroy,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.cpp b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.cpp
index 62ce867961db97a32c8ddb9b52b10296638e8616..1a8cf99d30d2df736518550268f9fbef957f1961 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.cpp
@@ -3,555 +3,645 @@
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
+ *
+ * Adapted from code based on libswresample's rematrix.c
  */
 
+#define NOMINMAX
+
+#include <algorithm>
 #include <cassert>
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+#include <memory>
+#include <type_traits>
 #include "cubeb-internal.h"
 #include "cubeb_mixer.h"
+#include "cubeb_utils.h"
+
+#ifndef FF_ARRAY_ELEMS
+#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+#define CHANNELS_MAX 32
+#define FRONT_LEFT             0
+#define FRONT_RIGHT            1
+#define FRONT_CENTER           2
+#define LOW_FREQUENCY          3
+#define BACK_LEFT              4
+#define BACK_RIGHT             5
+#define FRONT_LEFT_OF_CENTER   6
+#define FRONT_RIGHT_OF_CENTER  7
+#define BACK_CENTER            8
+#define SIDE_LEFT              9
+#define SIDE_RIGHT             10
+#define TOP_CENTER             11
+#define TOP_FRONT_LEFT         12
+#define TOP_FRONT_CENTER       13
+#define TOP_FRONT_RIGHT        14
+#define TOP_BACK_LEFT          15
+#define TOP_BACK_CENTER        16
+#define TOP_BACK_RIGHT         17
+#define NUM_NAMED_CHANNELS     18
+
+#ifndef M_SQRT1_2
+#define M_SQRT1_2      0.70710678118654752440  /* 1/sqrt(2) */
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2        1.41421356237309504880  /* sqrt(2) */
+#endif
+#define SQRT3_2      1.22474487139158904909  /* sqrt(3/2) */
 
-// DUAL_MONO(_LFE) is same as STEREO(_LFE).
-#define MASK_MONO         (1 << CHANNEL_MONO)
-#define MASK_MONO_LFE     (MASK_MONO | (1 << CHANNEL_LFE))
-#define MASK_STEREO       ((1 << CHANNEL_LEFT) | (1 << CHANNEL_RIGHT))
-#define MASK_STEREO_LFE   (MASK_STEREO | (1 << CHANNEL_LFE))
-#define MASK_3F           (MASK_STEREO | (1 << CHANNEL_CENTER))
-#define MASK_3F_LFE       (MASK_3F | (1 << CHANNEL_LFE))
-#define MASK_2F1          (MASK_STEREO | (1 << CHANNEL_RCENTER))
-#define MASK_2F1_LFE      (MASK_2F1 | (1 << CHANNEL_LFE))
-#define MASK_3F1          (MASK_3F | (1 << CHANNEL_RCENTER))
-#define MASK_3F1_LFE      (MASK_3F1 | (1 << CHANNEL_LFE))
-#define MASK_2F2          (MASK_STEREO | (1 << CHANNEL_LS) | (1 << CHANNEL_RS))
-#define MASK_2F2_LFE      (MASK_2F2 | (1 << CHANNEL_LFE))
-#define MASK_3F2          (MASK_2F2 | (1 << CHANNEL_CENTER))
-#define MASK_3F2_LFE      (MASK_3F2 | (1 << CHANNEL_LFE))
-#define MASK_3F3R_LFE     (MASK_3F2_LFE | (1 << CHANNEL_RCENTER))
-#define MASK_3F4_LFE      (MASK_3F2_LFE | (1 << CHANNEL_RLS) | (1 << CHANNEL_RRS))
-
-cubeb_channel_layout cubeb_channel_map_to_layout(cubeb_channel_map const * channel_map)
+#define  C30DB  M_SQRT2
+#define  C15DB  1.189207115
+#define C__0DB  1.0
+#define C_15DB  0.840896415
+#define C_30DB  M_SQRT1_2
+#define C_45DB  0.594603558
+#define C_60DB  0.5
+
+unsigned int cubeb_channel_layout_nb_channels(cubeb_channel_layout x)
 {
-  uint32_t channel_mask = 0;
-  for (uint8_t i = 0 ; i < channel_map->channels ; ++i) {
-    if (channel_map->map[i] == CHANNEL_INVALID ||
-        channel_map->map[i] == CHANNEL_UNMAPPED) {
-      return CUBEB_LAYOUT_UNDEFINED;
+#if __GNUC__ || __clang__
+  return __builtin_popcount (x);
+#elif _MSC_VER
+  return __popcnt(x);
+#else
+  x -= (x >> 1) & 0x55555555;
+  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+  x = (x + (x >> 4)) & 0x0F0F0F0F;
+  x += x >> 8;
+  return (x + (x >> 16)) & 0x3F;
+#endif
+}
+struct MixerContext {
+  MixerContext(cubeb_sample_format f,
+               uint32_t in_channels,
+               cubeb_channel_layout in,
+               uint32_t out_channels,
+               cubeb_channel_layout out)
+    : _format(f)
+    , _in_ch_layout(in == CUBEB_LAYOUT_UNDEFINED
+                      ? (in_channels == 1
+                           ? CUBEB_LAYOUT_MONO
+                           : (in_channels == 2 ? CUBEB_LAYOUT_STEREO
+                                               : CUBEB_LAYOUT_UNDEFINED))
+                      : in)
+    , _out_ch_layout(
+        (out == CUBEB_LAYOUT_UNDEFINED
+           ? (out_channels == 1 ? CUBEB_LAYOUT_MONO
+                                : (out_channels == 2 ? CUBEB_LAYOUT_STEREO
+                                                     : CUBEB_LAYOUT_UNDEFINED))
+           : out))
+    , _in_ch_count(in_channels)
+    , _out_ch_count(out_channels)
+  {
+    if (in_channels != cubeb_channel_layout_nb_channels(in) ||
+        out_channels != cubeb_channel_layout_nb_channels(out)) {
+      // Mismatch between channels and layout, aborting.
+      return;
     }
-    channel_mask |= 1 << channel_map->map[i];
+    _valid = init() >= 0;
   }
 
-  switch(channel_mask) {
-    case MASK_MONO: return CUBEB_LAYOUT_MONO;
-    case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
-    case MASK_STEREO: return CUBEB_LAYOUT_STEREO;
-    case MASK_STEREO_LFE: return CUBEB_LAYOUT_STEREO_LFE;
-    case MASK_3F: return CUBEB_LAYOUT_3F;
-    case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
-    case MASK_2F1: return CUBEB_LAYOUT_2F1;
-    case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
-    case MASK_3F1: return CUBEB_LAYOUT_3F1;
-    case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
-    case MASK_2F2: return CUBEB_LAYOUT_2F2;
-    case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
-    case MASK_3F2: return CUBEB_LAYOUT_3F2;
-    case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
-    case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
-    case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
-    default: return CUBEB_LAYOUT_UNDEFINED;
+  static bool even(cubeb_channel_layout layout)
+  {
+    if (!layout) {
+      return true;
+    }
+    if (layout & (layout - 1)) {
+      return true;
+    }
+    return false;
   }
-}
 
-cubeb_layout_map const CUBEB_CHANNEL_LAYOUT_MAPS[CUBEB_LAYOUT_MAX] = {
-  { "undefined",      0,  CUBEB_LAYOUT_UNDEFINED },
-  { "dual mono",      2,  CUBEB_LAYOUT_DUAL_MONO },
-  { "dual mono lfe",  3,  CUBEB_LAYOUT_DUAL_MONO_LFE },
-  { "mono",           1,  CUBEB_LAYOUT_MONO },
-  { "mono lfe",       2,  CUBEB_LAYOUT_MONO_LFE },
-  { "stereo",         2,  CUBEB_LAYOUT_STEREO },
-  { "stereo lfe",     3,  CUBEB_LAYOUT_STEREO_LFE },
-  { "3f",             3,  CUBEB_LAYOUT_3F },
-  { "3f lfe",         4,  CUBEB_LAYOUT_3F_LFE },
-  { "2f1",            3,  CUBEB_LAYOUT_2F1 },
-  { "2f1 lfe",        4,  CUBEB_LAYOUT_2F1_LFE },
-  { "3f1",            4,  CUBEB_LAYOUT_3F1 },
-  { "3f1 lfe",        5,  CUBEB_LAYOUT_3F1_LFE },
-  { "2f2",            4,  CUBEB_LAYOUT_2F2 },
-  { "2f2 lfe",        5,  CUBEB_LAYOUT_2F2_LFE },
-  { "3f2",            5,  CUBEB_LAYOUT_3F2 },
-  { "3f2 lfe",        6,  CUBEB_LAYOUT_3F2_LFE },
-  { "3f3r lfe",       7,  CUBEB_LAYOUT_3F3R_LFE },
-  { "3f4 lfe",        8,  CUBEB_LAYOUT_3F4_LFE }
-};
+  // Ensure that the layout is sane (that is have symmetrical left/right
+  // channels), if not, layout will be treated as mono.
+  static cubeb_channel_layout clean_layout(cubeb_channel_layout layout)
+  {
+    if (layout && layout != CHANNEL_FRONT_LEFT && !(layout & (layout - 1))) {
+      LOG("Treating layout as mono");
+      return CHANNEL_FRONT_CENTER;
+    }
 
-static int const CHANNEL_ORDER_TO_INDEX[CUBEB_LAYOUT_MAX][CHANNEL_MAX] = {
-//  M | L | R | C | LS | RS | RLS | RC | RRS | LFE
-  { -1, -1, -1, -1,  -1,  -1,   -1,  -1,   -1,  -1 }, // UNDEFINED
-  { -1,  0,  1, -1,  -1,  -1,   -1,  -1,   -1,  -1 }, // DUAL_MONO
-  { -1,  0,  1, -1,  -1,  -1,   -1,  -1,   -1,   2 }, // DUAL_MONO_LFE
-  {  0, -1, -1, -1,  -1,  -1,   -1,  -1,   -1,  -1 }, // MONO
-  {  0, -1, -1, -1,  -1,  -1,   -1,  -1,   -1,   1 }, // MONO_LFE
-  { -1,  0,  1, -1,  -1,  -1,   -1,  -1,   -1,  -1 }, // STEREO
-  { -1,  0,  1, -1,  -1,  -1,   -1,  -1,   -1,   2 }, // STEREO_LFE
-  { -1,  0,  1,  2,  -1,  -1,   -1,  -1,   -1,  -1 }, // 3F
-  { -1,  0,  1,  2,  -1,  -1,   -1,  -1,   -1,   3 }, // 3F_LFE
-  { -1,  0,  1, -1,  -1,  -1,   -1,   2,   -1,  -1 }, // 2F1
-  { -1,  0,  1, -1,  -1,  -1,   -1,   3,   -1,   2 }, // 2F1_LFE
-  { -1,  0,  1,  2,  -1,  -1,   -1,   3,   -1,  -1 }, // 3F1
-  { -1,  0,  1,  2,  -1,  -1,   -1,   4,   -1,   3 }, // 3F1_LFE
-  { -1,  0,  1, -1,   2,   3,   -1,  -1,   -1,  -1 }, // 2F2
-  { -1,  0,  1, -1,   3,   4,   -1,  -1,   -1,   2 }, // 2F2_LFE
-  { -1,  0,  1,  2,   3,   4,   -1,  -1,   -1,  -1 }, // 3F2
-  { -1,  0,  1,  2,   4,   5,   -1,  -1,   -1,   3 }, // 3F2_LFE
-  { -1,  0,  1,  2,   5,   6,   -1,   4,   -1,   3 }, // 3F3R_LFE
-  { -1,  0,  1,  2,   6,   7,    4,  -1,    5,   3 }, // 3F4_LFE
-};
+    return layout;
+  }
 
-// The downmix matrix from TABLE 2 in the ITU-R BS.775-3[1] defines a way to
-// convert 3F2 input data to 1F, 2F, 3F, 2F1, 3F1, 2F2 output data. We extend it
-// to convert 3F2-LFE input data to 1F, 2F, 3F, 2F1, 3F1, 2F2 and their LFEs
-// output data.
-// [1] https://www.itu.int/dms_pubrec/itu-r/rec/bs/R-REC-BS.775-3-201208-I!!PDF-E.pdf
-
-// Number of converted layouts: 1F, 2F, 3F, 2F1, 3F1, 2F2 and their LFEs.
-unsigned int const SUPPORTED_LAYOUT_NUM = 12;
-// Number of input channel for downmix conversion.
-unsigned int const INPUT_CHANNEL_NUM = 6; // 3F2-LFE
-// Max number of possible output channels.
-unsigned int const MAX_OUTPUT_CHANNEL_NUM = 5; // 2F2-LFE or 3F1-LFE
-float const INV_SQRT_2 = 0.707106f; // 1/sqrt(2)
-// Each array contains coefficients that will be multiplied with
-// { L, R, C, LFE, LS, RS } channels respectively.
-static float const DOWNMIX_MATRIX_3F2_LFE[SUPPORTED_LAYOUT_NUM][MAX_OUTPUT_CHANNEL_NUM][INPUT_CHANNEL_NUM] =
-{
-// 1F Mono
-  {
-    { INV_SQRT_2, INV_SQRT_2, 1, 0, 0.5, 0.5 }, // M
-  },
-// 1F Mono-LFE
-  {
-    { INV_SQRT_2, INV_SQRT_2, 1, 0, 0.5, 0.5 }, // M
-    { 0, 0, 0, 1, 0, 0 }                        // LFE
-  },
-// 2F Stereo
-  {
-    { 1, 0, INV_SQRT_2, 0, INV_SQRT_2, 0 },     // L
-    { 0, 1, INV_SQRT_2, 0, 0, INV_SQRT_2 }      // R
-  },
-// 2F Stereo-LFE
-  {
-    { 1, 0, INV_SQRT_2, 0, INV_SQRT_2, 0 },     // L
-    { 0, 1, INV_SQRT_2, 0, 0, INV_SQRT_2 },     // R
-    { 0, 0, 0, 1, 0, 0 }                        // LFE
-  },
-// 3F
-  {
-    { 1, 0, 0, 0, INV_SQRT_2, 0 },              // L
-    { 0, 1, 0, 0, 0, INV_SQRT_2 },              // R
-    { 0, 0, 1, 0, 0, 0 }                        // C
-  },
-// 3F-LFE
-  {
-    { 1, 0, 0, 0, INV_SQRT_2, 0 },              // L
-    { 0, 1, 0, 0, 0, INV_SQRT_2 },              // R
-    { 0, 0, 1, 0, 0, 0 },                       // C
-    { 0, 0, 0, 1, 0, 0 }                        // LFE
-  },
-// 2F1
-  {
-    { 1, 0, INV_SQRT_2, 0, 0, 0 },              // L
-    { 0, 1, INV_SQRT_2, 0, 0, 0 },              // R
-    { 0, 0, 0, 0, INV_SQRT_2, INV_SQRT_2 }      // S
-  },
-// 2F1-LFE
+  static bool sane_layout(cubeb_channel_layout layout)
   {
-    { 1, 0, INV_SQRT_2, 0, 0, 0 },              // L
-    { 0, 1, INV_SQRT_2, 0, 0, 0 },              // R
-    { 0, 0, 0, 1, 0, 0 },                       // LFE
-    { 0, 0, 0, 0, INV_SQRT_2, INV_SQRT_2 }      // S
-  },
-// 3F1
-  {
-    { 1, 0, 0, 0, 0, 0 },                       // L
-    { 0, 1, 0, 0, 0, 0 },                       // R
-    { 0, 0, 1, 0, 0, 0 },                       // C
-    { 0, 0, 0, 0, INV_SQRT_2, INV_SQRT_2 }      // S
-  },
-// 3F1-LFE
-  {
-    { 1, 0, 0, 0, 0, 0 },                       // L
-    { 0, 1, 0, 0, 0, 0 },                       // R
-    { 0, 0, 1, 0, 0, 0 },                       // C
-    { 0, 0, 0, 1, 0, 0 },                       // LFE
-    { 0, 0, 0, 0, INV_SQRT_2, INV_SQRT_2 }      // S
-  },
-// 2F2
-  {
-    { 1, 0, INV_SQRT_2, 0, 0, 0 },              // L
-    { 0, 1, INV_SQRT_2, 0, 0, 0 },              // R
-    { 0, 0, 0, 0, 1, 0 },                       // LS
-    { 0, 0, 0, 0, 0, 1 }                        // RS
-  },
-// 2F2-LFE
-  {
-    { 1, 0, INV_SQRT_2, 0, 0, 0 },              // L
-    { 0, 1, INV_SQRT_2, 0, 0, 0 },              // R
-    { 0, 0, 0, 1, 0, 0 },                       // LFE
-    { 0, 0, 0, 0, 1, 0 },                       // LS
-    { 0, 0, 0, 0, 0, 1 }                        // RS
+    if (!(layout & CUBEB_LAYOUT_3F)) { // at least 1 front speaker
+      return false;
+    }
+    if (!even(layout & (CHANNEL_FRONT_LEFT |
+                        CHANNEL_FRONT_RIGHT))) { // no asymetric front
+      return false;
+    }
+    if (!even(layout &
+              (CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT))) { // no asymetric side
+      return false;
+    }
+    if (!even(layout & (CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT))) {
+      return false;
+    }
+    if (!even(layout &
+              (CHANNEL_FRONT_LEFT_OF_CENTER | CHANNEL_FRONT_RIGHT_OF_CENTER))) {
+      return false;
+    }
+    if (cubeb_channel_layout_nb_channels(layout) >= CHANNELS_MAX) {
+      return false;
+    }
+    return true;
   }
+
+  int auto_matrix();
+  int init();
+
+  const cubeb_sample_format _format;
+  const cubeb_channel_layout _in_ch_layout;              ///< input channel layout
+  const cubeb_channel_layout _out_ch_layout;             ///< output channel layout
+  const uint32_t _in_ch_count;                           ///< input channel count
+  const uint32_t _out_ch_count;                          ///< output channel count
+  const float _surround_mix_level = C_30DB;              ///< surround mixing level
+  const float _center_mix_level = C_30DB;                ///< center mixing level
+  const float _lfe_mix_level = 1;                        ///< LFE mixing level
+  double _matrix[CHANNELS_MAX][CHANNELS_MAX] = {{ 0 }};        ///< floating point rematrixing coefficients
+  float _matrix_flt[CHANNELS_MAX][CHANNELS_MAX] = {{ 0 }};     ///< single precision floating point rematrixing coefficients
+  int32_t _matrix32[CHANNELS_MAX][CHANNELS_MAX] = {{ 0 }};     ///< 17.15 fixed point rematrixing coefficients
+  uint8_t _matrix_ch[CHANNELS_MAX][CHANNELS_MAX+1] = {{ 0 }};  ///< Lists of input channels per output channel that have non zero rematrixing coefficients
+  bool _clipping = false;                          ///< Set to true if clipping detection is required
+  bool _valid = false;                             ///< Set to true if context is valid.
 };
 
-// Convert audio data from 3F2(-LFE) to 1F, 2F, 3F, 2F1, 3F1, 2F2 and their LFEs.
-//
-// ITU-R BS.775-3[1] provides spec for downmixing 3F2 data to 1F, 2F, 3F, 2F1,
-// 3F1, 2F2 data. We simply add LFE to its defined matrix. If both the input
-// and output have LFE channel, then we pass it's data. If only input or output
-// has LFE, then we either drop it or append 0 to the LFE channel.
-//
-// Fig. 1:
-// |<-------------- 1 -------------->|<-------------- 2 -------------->|
-// +----+----+----+------+-----+-----+----+----+----+------+-----+-----+
-// | L0 | R0 | C0 | LFE0 | LS0 | RS0 | L1 | R1 | C1 | LFE1 | LS1 | RS1 | ...
-// +----+----+----+------+-----+-----+----+----+----+------+-----+-----+
-//
-// Fig. 2:
-// |<-- 1 -->|<-- 2 -->|
-// +----+----+----+----+
-// | L0 | R0 | L1 | R1 | ...
-// +----+----+----+----+
-//
-// The figures above shows an example for downmixing from 3F2-LFE(Fig. 1) to
-// to stereo(Fig. 2), where L0 = L0 + 0.707 * (C0 + LS0),
-// R0 = R0 + 0.707 * (C0 + RS0), L1 = L1 + 0.707 * (C1 + LS1),
-// R1 = R1 + 0.707 * (C1 + RS1), ...
-//
-// Nevertheless, the downmixing method is a little bit different on OSX.
-// The audio rendering mechanism on OS X will drop the extra channels beyond
-// the channels that audio device can provide. The trick here is that OSX allows
-// us to set the layout containing other channels that the output device can
-// NOT provide. For example, setting 3F2-LFE layout to a stereo device is fine.
-// Therefore, OSX expects we fill the buffer for playing sound by the defined
-// layout, so there are some will-be-dropped data in the buffer:
-//
-// +---+---+---+-----+----+----+
-// | L | R | C | LFE | LS | RS | ...
-// +---+---+---+-----+----+----+
-//           ^    ^    ^    ^
-//           The data for these four channels will be dropped!
-//
-// To keep all the information, we need to downmix the data before it's dropped.
-// The figure below shows an example for downmixing from 3F2-LFE(Fig. 1)
-// to stereo(Fig. 3) on OSX, where the LO, R0, L1, R0 are same as above.
-//
-// Fig. 3:
-// |<---------- 1 ---------->|<---------- 2 ---------->|
-// +----+----+---+---+---+---+----+----+---+---+---+---+
-// | L0 | R0 | x | x | x | x | L1 | R1 | x | x | x | x | ...
-// +----+----+---+---+---+---+----+----+---+---+---+---+
-//           |<--  dummy  -->|         |<--  dummy  -->|
-template<typename T>
-bool
-downmix_3f2(unsigned long inframes,
-            T const * const in, unsigned long in_len,
-            T * out, unsigned long out_len,
-            cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
+int MixerContext::auto_matrix()
 {
-  if ((in_layout != CUBEB_LAYOUT_3F2 && in_layout != CUBEB_LAYOUT_3F2_LFE) ||
-      out_layout < CUBEB_LAYOUT_MONO || out_layout > CUBEB_LAYOUT_2F2_LFE) {
-    return false;
+  double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS] = { { 0 } };
+  double maxcoef = 0;
+  float maxval;
+
+  cubeb_channel_layout in_ch_layout = clean_layout(_in_ch_layout);
+  cubeb_channel_layout out_ch_layout = clean_layout(_out_ch_layout);
+
+  if (!sane_layout(in_ch_layout)) {
+    // Channel Not Supported
+    LOG("Input Layout %x is not supported", _in_ch_layout);
+    return -1;
   }
 
-  unsigned int in_channels = CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels;
-  unsigned int out_channels = CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels;
-
-  // Conversion from 3F2 to 2F2-LFE or 3F1-LFE is allowed, so we use '<=' instead of '<'.
-  assert(out_channels <= in_channels);
-
-  auto & downmix_matrix = DOWNMIX_MATRIX_3F2_LFE[out_layout - CUBEB_LAYOUT_MONO]; // The matrix is started from mono.
-  unsigned long out_index = 0;
-  for (unsigned long i = 0 ; i < inframes * in_channels; i += in_channels) {
-    for (unsigned int j = 0; j < out_channels; ++j) {
-      T sample = 0;
-      for (unsigned int k = 0 ; k < INPUT_CHANNEL_NUM ; ++k) {
-        // 3F2-LFE has 6 channels: L, R, C, LFE, LS, RS, while 3F2 has only 5
-        // channels: L, R, C, LS, RS. Thus, we need to append 0 to LFE(index 3)
-        // to simulate a 3F2-LFE data when input layout is 3F2.
-        assert((in_layout == CUBEB_LAYOUT_3F2_LFE || k < 3) ? (i + k < in_len) : (k == 3) ? true : (i + k - 1 < in_len));
-        T data = (in_layout == CUBEB_LAYOUT_3F2_LFE) ? in[i + k] : (k == 3) ? 0 : in[i + ((k < 3) ? k : k - 1)];
-        sample += downmix_matrix[j][k] * data;
-      }
-      assert(out_index + j < out_len);
-      out[out_index + j] = sample;
+  if (!sane_layout(out_ch_layout)) {
+    LOG("Output Layout %x is not supported", _out_ch_layout);
+    return -1;
+  }
+
+  for (uint32_t i = 0; i < FF_ARRAY_ELEMS(matrix); i++) {
+    if (in_ch_layout & out_ch_layout & (1U << i)) {
+      matrix[i][i] = 1.0;
     }
-#if defined(USE_AUDIOUNIT)
-    out_index += in_channels;
-#else
-    out_index += out_channels;
-#endif
   }
 
-  return true;
-}
+  cubeb_channel_layout unaccounted = in_ch_layout & ~out_ch_layout;
 
-/* Map the audio data by channel name. */
-template<class T>
-bool
-mix_remap(long inframes,
-          T const * const in, unsigned long in_len,
-          T * out, unsigned long out_len,
-          cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
-{
-  assert(in_layout != out_layout && inframes >= 0);
+  // Rematrixing is done via a matrix of coefficient that should be applied to
+  // all channels. Channels are treated as pair and must be symmetrical (if a
+  // left channel exists, the corresponding right should exist too) unless the
+  // output layout has similar layout. Channels are then mixed toward the front
+  // center or back center if they exist with a slight bias toward the front.
 
-  // We might overwrite the data before we copied them to the mapped index
-  // (e.g. upmixing from stereo to 2F1 or mapping [L, R] to [R, L])
-  if (in == out) {
-    return false;
+  if (unaccounted & CHANNEL_FRONT_CENTER) {
+    if ((out_ch_layout & CUBEB_LAYOUT_STEREO) == CUBEB_LAYOUT_STEREO) {
+      if (in_ch_layout & CUBEB_LAYOUT_STEREO) {
+        matrix[FRONT_LEFT][FRONT_CENTER] += _center_mix_level;
+        matrix[FRONT_RIGHT][FRONT_CENTER] += _center_mix_level;
+      } else {
+        matrix[FRONT_LEFT][FRONT_CENTER] += M_SQRT1_2;
+        matrix[FRONT_RIGHT][FRONT_CENTER] += M_SQRT1_2;
+      }
+    }
   }
-
-  unsigned int in_channels = CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels;
-  unsigned int out_channels = CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels;
-
-  uint32_t in_layout_mask = 0;
-  for (unsigned int i = 0 ; i < in_channels ; ++i) {
-    in_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[in_layout][i];
+  if (unaccounted & CUBEB_LAYOUT_STEREO) {
+    if (out_ch_layout & CHANNEL_FRONT_CENTER) {
+      matrix[FRONT_CENTER][FRONT_LEFT] += M_SQRT1_2;
+      matrix[FRONT_CENTER][FRONT_RIGHT] += M_SQRT1_2;
+      if (in_ch_layout & CHANNEL_FRONT_CENTER)
+        matrix[FRONT_CENTER][FRONT_CENTER] = _center_mix_level * M_SQRT2;
+    }
   }
 
-  uint32_t out_layout_mask = 0;
-  for (unsigned int i = 0 ; i < out_channels ; ++i) {
-    out_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[out_layout][i];
+  if (unaccounted & CHANNEL_BACK_CENTER) {
+    if (out_ch_layout & CHANNEL_BACK_LEFT) {
+      matrix[BACK_LEFT][BACK_CENTER] += M_SQRT1_2;
+      matrix[BACK_RIGHT][BACK_CENTER] += M_SQRT1_2;
+    } else if (out_ch_layout & CHANNEL_SIDE_LEFT) {
+      matrix[SIDE_LEFT][BACK_CENTER] += M_SQRT1_2;
+      matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2;
+    } else if (out_ch_layout & CHANNEL_FRONT_LEFT) {
+      if (unaccounted & (CHANNEL_BACK_LEFT | CHANNEL_SIDE_LEFT)) {
+        matrix[FRONT_LEFT][BACK_CENTER] -= _surround_mix_level * M_SQRT1_2;
+        matrix[FRONT_RIGHT][BACK_CENTER] += _surround_mix_level * M_SQRT1_2;
+      } else {
+        matrix[FRONT_LEFT][BACK_CENTER] -= _surround_mix_level;
+        matrix[FRONT_RIGHT][BACK_CENTER] += _surround_mix_level;
+      }
+    } else if (out_ch_layout & CHANNEL_FRONT_CENTER) {
+      matrix[FRONT_CENTER][BACK_CENTER] +=
+        _surround_mix_level * M_SQRT1_2;
+    }
   }
-
-  // If there is no matched channel, then do nothing.
-  if (!(out_layout_mask & in_layout_mask)) {
-    return false;
+  if (unaccounted & CHANNEL_BACK_LEFT) {
+    if (out_ch_layout & CHANNEL_BACK_CENTER) {
+      matrix[BACK_CENTER][BACK_LEFT] += M_SQRT1_2;
+      matrix[BACK_CENTER][BACK_RIGHT] += M_SQRT1_2;
+    } else if (out_ch_layout & CHANNEL_SIDE_LEFT) {
+      if (in_ch_layout & CHANNEL_SIDE_LEFT) {
+        matrix[SIDE_LEFT][BACK_LEFT] += M_SQRT1_2;
+        matrix[SIDE_RIGHT][BACK_RIGHT] += M_SQRT1_2;
+      } else {
+        matrix[SIDE_LEFT][BACK_LEFT] += 1.0;
+        matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0;
+      }
+    } else if (out_ch_layout & CHANNEL_FRONT_LEFT) {
+      matrix[FRONT_LEFT][BACK_LEFT] -= _surround_mix_level * M_SQRT1_2;
+      matrix[FRONT_LEFT][BACK_RIGHT] -= _surround_mix_level * M_SQRT1_2;
+      matrix[FRONT_RIGHT][BACK_LEFT] += _surround_mix_level * M_SQRT1_2;
+      matrix[FRONT_RIGHT][BACK_RIGHT] += _surround_mix_level * M_SQRT1_2;
+    } else if (out_ch_layout & CHANNEL_FRONT_CENTER) {
+      matrix[FRONT_CENTER][BACK_LEFT] += _surround_mix_level * M_SQRT1_2;
+      matrix[FRONT_CENTER][BACK_RIGHT] += _surround_mix_level * M_SQRT1_2;
+    }
   }
 
-  for (unsigned long i = 0, out_index = 0; i < (unsigned long)inframes * in_channels; i += in_channels, out_index += out_channels) {
-    for (unsigned int j = 0; j < out_channels; ++j) {
-      cubeb_channel channel = CHANNEL_INDEX_TO_ORDER[out_layout][j];
-      uint32_t channel_mask = 1 << channel;
-      int channel_index = CHANNEL_ORDER_TO_INDEX[in_layout][channel];
-      assert(channel_index >= -1);
-      assert(out_index + j < out_len);
-      if (in_layout_mask & channel_mask) {
-        assert(channel_index != -1);
-        assert(i + channel_index < in_len);
-        out[out_index + j] = in[i + channel_index];
+  if (unaccounted & CHANNEL_SIDE_LEFT) {
+    if (out_ch_layout & CHANNEL_BACK_LEFT) {
+      /* if back channels do not exist in the input, just copy side
+         channels to back channels, otherwise mix side into back */
+      if (in_ch_layout & CHANNEL_BACK_LEFT) {
+        matrix[BACK_LEFT][SIDE_LEFT] += M_SQRT1_2;
+        matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2;
       } else {
-        assert(channel_index == -1);
-        out[out_index + j] = 0;
+        matrix[BACK_LEFT][SIDE_LEFT] += 1.0;
+        matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0;
       }
+    } else if (out_ch_layout & CHANNEL_BACK_CENTER) {
+      matrix[BACK_CENTER][SIDE_LEFT] += M_SQRT1_2;
+      matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2;
+    } else if (out_ch_layout & CHANNEL_FRONT_LEFT) {
+      matrix[FRONT_LEFT][SIDE_LEFT] -= _surround_mix_level * M_SQRT1_2;
+      matrix[FRONT_LEFT][SIDE_RIGHT] -= _surround_mix_level * M_SQRT1_2;
+      matrix[FRONT_RIGHT][SIDE_LEFT] += _surround_mix_level * M_SQRT1_2;
+      matrix[FRONT_RIGHT][SIDE_RIGHT] += _surround_mix_level * M_SQRT1_2;
+    } else if (out_ch_layout & CHANNEL_FRONT_CENTER) {
+      matrix[FRONT_CENTER][SIDE_LEFT] += _surround_mix_level * M_SQRT1_2;
+      matrix[FRONT_CENTER][SIDE_RIGHT] += _surround_mix_level * M_SQRT1_2;
     }
   }
 
-  return true;
-}
-
-/* Drop the extra channels beyond the provided output channels. */
-template<typename T>
-void
-downmix_fallback(long inframes,
-                 T const * const in, unsigned long in_len,
-                 T * out, unsigned long out_len,
-                 unsigned int in_channels, unsigned int out_channels)
-{
-  assert(in_channels >= out_channels && inframes >= 0);
-
-  if (in_channels == out_channels && in == out) {
-    return;
+  if (unaccounted & CHANNEL_FRONT_LEFT_OF_CENTER) {
+    if (out_ch_layout & CHANNEL_FRONT_LEFT) {
+      matrix[FRONT_LEFT][FRONT_LEFT_OF_CENTER] += 1.0;
+      matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER] += 1.0;
+    } else if (out_ch_layout & CHANNEL_FRONT_CENTER) {
+      matrix[FRONT_CENTER][FRONT_LEFT_OF_CENTER] += M_SQRT1_2;
+      matrix[FRONT_CENTER][FRONT_RIGHT_OF_CENTER] += M_SQRT1_2;
+    }
   }
-
-  for (unsigned long i = 0, out_index = 0; i < (unsigned long)inframes * in_channels; i += in_channels, out_index += out_channels) {
-    for (unsigned int j = 0; j < out_channels; ++j) {
-      assert(i + j < in_len && out_index + j < out_len);
-      out[out_index + j] = in[i + j];
+  /* mix LFE into front left/right or center */
+  if (unaccounted & CHANNEL_LOW_FREQUENCY) {
+    if (out_ch_layout & CHANNEL_FRONT_CENTER) {
+      matrix[FRONT_CENTER][LOW_FREQUENCY] += _lfe_mix_level;
+    } else if (out_ch_layout & CHANNEL_FRONT_LEFT) {
+      matrix[FRONT_LEFT][LOW_FREQUENCY] += _lfe_mix_level * M_SQRT1_2;
+      matrix[FRONT_RIGHT][LOW_FREQUENCY] += _lfe_mix_level * M_SQRT1_2;
     }
   }
-}
 
-
-template<typename T>
-void
-cubeb_downmix(long inframes,
-              T const * const in, unsigned long in_len,
-              T * out, unsigned long out_len,
-              cubeb_stream_params const * stream_params,
-              cubeb_stream_params const * mixer_params)
-{
-  assert(in && out);
-  assert(inframes);
-  assert(stream_params->channels >= mixer_params->channels &&
-         mixer_params->channels > 0);
-  assert(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
-
-  unsigned int in_channels = stream_params->channels;
-  cubeb_channel_layout in_layout = stream_params->layout;
-
-  unsigned int out_channels = mixer_params->channels;
-  cubeb_channel_layout out_layout = mixer_params->layout;
-
-  // If the channel number is different from the layout's setting,
-  // then we use fallback downmix mechanism.
-  if (out_channels == CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels &&
-      in_channels == CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels) {
-    if (downmix_3f2(inframes, in, in_len, out, out_len, in_layout, out_layout)) {
-      return;
+  // Normalize the conversion matrix.
+  for (uint32_t out_i = 0, i = 0; i < CHANNELS_MAX; i++) {
+    double sum = 0;
+    int in_i = 0;
+    if ((out_ch_layout & (1U << i)) == 0) {
+      continue;
     }
+    for (uint32_t j = 0; j < CHANNELS_MAX; j++) {
+      if ((in_ch_layout & (1U << j)) == 0) {
+        continue;
+      }
+      if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0])) {
+        _matrix[out_i][in_i] = matrix[i][j];
+      } else {
+        _matrix[out_i][in_i] =
+          i == j && (in_ch_layout & out_ch_layout & (1U << i));
+      }
+      sum += fabs(_matrix[out_i][in_i]);
+      in_i++;
+    }
+    maxcoef = std::max(maxcoef, sum);
+    out_i++;
+  }
 
-#if defined(USE_AUDIOUNIT)
-  // We only support downmix for audio 5.1 on OS X currently.
-  return;
-#endif
+  if (_format == CUBEB_SAMPLE_S16NE) {
+    maxval = 1.0;
+  } else {
+    maxval = INT_MAX;
+  }
 
-    if (mix_remap(inframes, in, in_len, out, out_len, in_layout, out_layout)) {
-      return;
+  // Normalize matrix if needed.
+  if (maxcoef > maxval) {
+    maxcoef /= maxval;
+    for (uint32_t i = 0; i < CHANNELS_MAX; i++)
+      for (uint32_t j = 0; j < CHANNELS_MAX; j++) {
+        _matrix[i][j] /= maxcoef;
+      }
+  }
+
+  if (_format == CUBEB_SAMPLE_FLOAT32NE) {
+    for (uint32_t i = 0; i < FF_ARRAY_ELEMS(_matrix); i++) {
+      for (uint32_t j = 0; j < FF_ARRAY_ELEMS(_matrix[0]); j++) {
+        _matrix_flt[i][j] = _matrix[i][j];
+      }
     }
   }
 
-  downmix_fallback(inframes, in, in_len, out, out_len, in_channels, out_channels);
+  return 0;
 }
 
-/* Upmix function, copies a mono channel into L and R. */
-template<typename T>
-void
-mono_to_stereo(long insamples, T const * in, unsigned long in_len,
-               T * out, unsigned long out_len, unsigned int out_channels)
+int MixerContext::init()
 {
-  for (long i = 0, j = 0; i < insamples; ++i, j += out_channels) {
-    assert((unsigned long)i < in_len && (unsigned long)j + 1 < out_len);
-    out[j] = out[j + 1] = in[i];
+  int r = auto_matrix();
+  if (r) {
+    return r;
   }
-}
 
-template<typename T>
-void
-cubeb_upmix(long inframes,
-            T const * const in, unsigned long in_len,
-            T * out, unsigned long out_len,
-            cubeb_stream_params const * stream_params,
-            cubeb_stream_params const * mixer_params)
-{
-  assert(in && out);
-  assert(inframes);
-  assert(mixer_params->channels >= stream_params->channels &&
-         stream_params->channels > 0);
-
-  unsigned int in_channels = stream_params->channels;
-  unsigned int out_channels = mixer_params->channels;
-
-  /* Either way, if we have 2 or more channels, the first two are L and R. */
-  /* If we are playing a mono stream over stereo speakers, copy the data over. */
-  if (in_channels == 1 && out_channels >= 2) {
-    mono_to_stereo(inframes, in, in_len, out, out_len, out_channels);
-  } else {
-    /* Copy through. */
-    for (unsigned int i = 0, o = 0; i < inframes * in_channels;
-        i += in_channels, o += out_channels) {
-      for (unsigned int j = 0; j < in_channels; ++j) {
-        assert(i + j < in_len && o + j < out_len);
-        out[o + j] = in[i + j];
+  // Determine if matrix operation would overflow
+  if (_format == CUBEB_SAMPLE_S16NE) {
+    int maxsum = 0;
+    for (uint32_t i = 0; i < _out_ch_count; i++) {
+      double rem = 0;
+      int sum = 0;
+
+      for (uint32_t j = 0; j < _in_ch_count; j++) {
+        double target = _matrix[i][j] * 32768 + rem;
+        int value = lrintf(target);
+        rem += target - value;
+        sum += std::abs(value);
       }
+      maxsum = std::max(maxsum, sum);
+    }
+    if (maxsum > 32768) {
+      _clipping = true;
     }
   }
 
-  /* Check if more channels. */
-  if (out_channels <= 2) {
-    return;
-  }
-
-  /* Put silence in remaining channels. */
-  for (long i = 0, o = 0; i < inframes; ++i, o += out_channels) {
-    for (unsigned int j = in_channels; j < out_channels; ++j) {
-      assert((unsigned long)o + j < out_len);
-      out[o + j] = 0.0;
+  // FIXME quantize for integers
+  for (uint32_t i = 0; i < CHANNELS_MAX; i++) {
+    int ch_in = 0;
+    for (uint32_t j = 0; j < CHANNELS_MAX; j++) {
+      _matrix32[i][j] = lrintf(_matrix[i][j] * 32768);
+      if (_matrix[i][j]) {
+        _matrix_ch[i][++ch_in] = j;
+      }
     }
+    _matrix_ch[i][0] = ch_in;
   }
+
+  return 0;
 }
 
-bool
-cubeb_should_upmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
+template<typename TYPE_SAMPLE, typename TYPE_COEFF, typename F>
+void
+sum2(TYPE_SAMPLE * out,
+     uint32_t stride_out,
+     const TYPE_SAMPLE * in1,
+     const TYPE_SAMPLE * in2,
+     uint32_t stride_in,
+     TYPE_COEFF coeff1,
+     TYPE_COEFF coeff2,
+     F&& operand,
+     uint32_t frames)
 {
-  return mixer->channels > stream->channels;
+  static_assert(
+    std::is_same<TYPE_COEFF,
+                 typename std::result_of<F(TYPE_COEFF)>::type>::value,
+    "function must return the same type as used by matrix_coeff");
+  for (uint32_t i = 0; i < frames; i++) {
+    *out = operand(coeff1 * *in1 + coeff2 * *in2);
+    out += stride_out;
+    in1 += stride_in;
+    in2 += stride_in;
+  }
 }
 
-bool
-cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
+template<typename TYPE_SAMPLE, typename TYPE_COEFF, typename F>
+void
+copy(TYPE_SAMPLE * out,
+     uint32_t stride_out,
+     const TYPE_SAMPLE * in,
+     uint32_t stride_in,
+     TYPE_COEFF coeff,
+     F&& operand,
+     uint32_t frames)
 {
-  if (mixer->channels > stream->channels || mixer->layout == stream->layout) {
-    return false;
+  static_assert(
+    std::is_same<TYPE_COEFF,
+                 typename std::result_of<F(TYPE_COEFF)>::type>::value,
+    "function must return the same type as used by matrix_coeff");
+  for (uint32_t i = 0; i < frames; i++) {
+    *out = operand(coeff * *in);
+    out += stride_out;
+    in += stride_in;
   }
-
-  return mixer->channels < stream->channels ||
-         // When mixer.channels == stream.channels
-         mixer->layout == CUBEB_LAYOUT_UNDEFINED ||  // fallback downmix
-         (stream->layout == CUBEB_LAYOUT_3F2 &&      // 3f2 downmix
-          (mixer->layout == CUBEB_LAYOUT_2F2_LFE ||
-           mixer->layout == CUBEB_LAYOUT_3F1_LFE));
 }
 
-bool
-cubeb_should_mix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
+template <typename TYPE, typename TYPE_COEFF, size_t COLS, typename F>
+static int rematrix(const MixerContext * s, TYPE * aOut, const TYPE * aIn,
+                    const TYPE_COEFF (&matrix_coeff)[COLS][COLS],
+                    F&& aF, uint32_t frames)
 {
-  return stream->layout != CUBEB_LAYOUT_UNDEFINED &&
-         (cubeb_should_upmix(stream, mixer) || cubeb_should_downmix(stream, mixer));
+  static_assert(
+    std::is_same<TYPE_COEFF,
+                 typename std::result_of<F(TYPE_COEFF)>::type>::value,
+    "function must return the same type as used by matrix_coeff");
+
+  for (uint32_t out_i = 0; out_i < s->_out_ch_count; out_i++) {
+    TYPE* out = aOut + out_i;
+    switch (s->_matrix_ch[out_i][0]) {
+      case 0:
+        for (uint32_t i = 0; i < frames; i++) {
+          out[i * s->_out_ch_count] = 0;
+        }
+        break;
+      case 1: {
+        int in_i = s->_matrix_ch[out_i][1];
+        copy(out,
+             s->_out_ch_count,
+             aIn + in_i,
+             s->_in_ch_count,
+             matrix_coeff[out_i][in_i],
+             aF,
+             frames);
+      } break;
+      case 2:
+        sum2(out,
+             s->_out_ch_count,
+             aIn + s->_matrix_ch[out_i][1],
+             aIn + s->_matrix_ch[out_i][2],
+             s->_in_ch_count,
+             matrix_coeff[out_i][s->_matrix_ch[out_i][1]],
+             matrix_coeff[out_i][s->_matrix_ch[out_i][2]],
+             aF,
+             frames);
+        break;
+      default:
+        for (uint32_t i = 0; i < frames; i++) {
+          TYPE_COEFF v = 0;
+          for (uint32_t j = 0; j < s->_matrix_ch[out_i][0]; j++) {
+            uint32_t in_i = s->_matrix_ch[out_i][1 + j];
+            v +=
+              *(aIn + in_i + i * s->_in_ch_count) * matrix_coeff[out_i][in_i];
+          }
+          out[i * s->_out_ch_count] = aF(v);
+        }
+        break;
+    }
+  }
+  return 0;
 }
 
-struct cubeb_mixer {
-  virtual void mix(long frames,
-                   void * input_buffer, unsigned long input_buffer_length,
-                   void * output_buffer, unsigned long output_buffer_length,
-                   cubeb_stream_params const * stream_params,
-                   cubeb_stream_params const * mixer_params) = 0;
-  virtual ~cubeb_mixer() {};
-};
+struct cubeb_mixer
+{
+  cubeb_mixer(cubeb_sample_format format,
+              uint32_t in_channels,
+              cubeb_channel_layout in_layout,
+              uint32_t out_channels,
+              cubeb_channel_layout out_layout)
+    : _context(format, in_channels, in_layout, out_channels, out_layout)
+  {
+  }
 
-template<typename T>
-struct cubeb_mixer_impl : public cubeb_mixer {
-  explicit cubeb_mixer_impl(unsigned int d)
-    : direction(d)
+  template<typename T>
+  void copy_and_trunc(size_t frames,
+                      const T * input_buffer,
+                      T * output_buffer) const
   {
+    if (_context._in_ch_count <= _context._out_ch_count) {
+      // Not enough channels to copy, fill the gaps with silence.
+      for (uint32_t i = 0; i < frames; i++) {
+        PodCopy(output_buffer, input_buffer, _context._in_ch_count);
+        output_buffer += _context._in_ch_count;
+        input_buffer += _context._in_ch_count;
+        PodZero(output_buffer, _context._out_ch_count - _context._in_ch_count);
+        output_buffer += _context._out_ch_count - _context._in_ch_count;
+      }
+    } else {
+      for (uint32_t i = 0; i < frames; i++) {
+        PodCopy(output_buffer, input_buffer, _context._out_ch_count);
+        output_buffer += _context._out_ch_count;
+        input_buffer += _context._in_ch_count;
+      }
+    }
   }
 
-  void mix(long frames,
-           void * input_buffer, unsigned long input_buffer_length,
-           void * output_buffer, unsigned long output_buffer_length,
-           cubeb_stream_params const * stream_params,
-           cubeb_stream_params const * mixer_params)
+  int mix(size_t frames,
+          void * input_buffer,
+          size_t input_buffer_size,
+          void * output_buffer,
+          size_t output_buffer_size) const
   {
-    if (frames <= 0) {
-      return;
+    if (frames <= 0 || _context._out_ch_count == 0) {
+      return 0;
+    }
+
+    // Check if output buffer is of sufficient size.
+    size_t size_read_needed =
+      frames * _context._in_ch_count * cubeb_sample_size(_context._format);
+    if (input_buffer_size < size_read_needed) {
+      // We don't have enough data to read!
+      return -1;
+    }
+    if (output_buffer_size * _context._in_ch_count <
+        size_read_needed * _context._out_ch_count) {
+      return -1;
     }
 
-    T * in = static_cast<T*>(input_buffer);
-    T * out = static_cast<T*>(output_buffer);
+    if (!valid()) {
+      // The channel layouts were invalid or unsupported, instead we will simply
+      // either drop the extra channels, or fill with silence the missing ones
+      if (_context._format == CUBEB_SAMPLE_FLOAT32NE) {
+        copy_and_trunc(frames,
+                       static_cast<const float*>(input_buffer),
+                       static_cast<float*>(output_buffer));
+      } else {
+        assert(_context._format == CUBEB_SAMPLE_S16NE);
+        copy_and_trunc(frames,
+                       static_cast<int16_t*>(input_buffer),
+                       reinterpret_cast<int16_t*>(output_buffer));
+      }
+      return 0;
+    }
 
-    if ((direction & CUBEB_MIXER_DIRECTION_DOWNMIX) &&
-        cubeb_should_downmix(stream_params, mixer_params)) {
-      cubeb_downmix(frames, in, input_buffer_length, out, output_buffer_length, stream_params, mixer_params);
-    } else if ((direction & CUBEB_MIXER_DIRECTION_UPMIX) &&
-               cubeb_should_upmix(stream_params, mixer_params)) {
-      cubeb_upmix(frames, in, input_buffer_length, out, output_buffer_length, stream_params, mixer_params);
+    switch (_context._format)
+    {
+      case CUBEB_SAMPLE_FLOAT32NE: {
+        auto f = [](float x) { return x; };
+        return rematrix(&_context,
+                        static_cast<float*>(output_buffer),
+                        static_cast<const float*>(input_buffer),
+                        _context._matrix_flt,
+                        f,
+                        frames);
+      }
+      case CUBEB_SAMPLE_S16NE:
+        if (_context._clipping) {
+          auto f = [](int x) {
+            int y = (x + 16384) >> 15;
+            // clip the signed integer value into the -32768,32767 range.
+            if ((y + 0x8000U) & ~0xFFFF) {
+              return (y >> 31) ^ 0x7FFF;
+            }
+            return y;
+          };
+          return rematrix(&_context,
+                          static_cast<int16_t*>(output_buffer),
+                          static_cast<const int16_t*>(input_buffer),
+                          _context._matrix32,
+                          f,
+                          frames);
+        } else {
+          auto f = [](int x) { return (x + 16384) >> 15; };
+          return rematrix(&_context,
+                          static_cast<int16_t*>(output_buffer),
+                          static_cast<const int16_t*>(input_buffer),
+                          _context._matrix32,
+                          f,
+                          frames);
+        }
+        break;
+      default:
+        assert(false);
+        break;
     }
+
+    return -1;
   }
 
-  ~cubeb_mixer_impl() {};
+  // Return false if any of the input or ouput layout were invalid.
+  bool valid() const { return _context._valid; }
 
-  unsigned char const direction;
+  virtual ~cubeb_mixer(){};
+
+  MixerContext _context;
 };
 
-cubeb_mixer * cubeb_mixer_create(cubeb_sample_format format,
-                                 unsigned char direction)
+cubeb_mixer* cubeb_mixer_create(cubeb_sample_format format,
+                                uint32_t in_channels,
+                                cubeb_channel_layout in_layout,
+                                uint32_t out_channels,
+                                cubeb_channel_layout out_layout)
 {
-  assert(direction & CUBEB_MIXER_DIRECTION_DOWNMIX ||
-         direction & CUBEB_MIXER_DIRECTION_UPMIX);
-  switch(format) {
-    case CUBEB_SAMPLE_S16NE:
-      return new cubeb_mixer_impl<short>(direction);
-    case CUBEB_SAMPLE_FLOAT32NE:
-      return new cubeb_mixer_impl<float>(direction);
-    default:
-      assert(false);
-      return nullptr;
-  }
+  return new cubeb_mixer(
+    format, in_channels, in_layout, out_channels, out_layout);
 }
 
 void cubeb_mixer_destroy(cubeb_mixer * mixer)
@@ -559,13 +649,13 @@ void cubeb_mixer_destroy(cubeb_mixer * mixer)
   delete mixer;
 }
 
-void cubeb_mixer_mix(cubeb_mixer * mixer, long frames,
-                     void * input_buffer, unsigned long input_buffer_length,
-                     void * output_buffer, unsigned long output_buffer_length,
-                     cubeb_stream_params const * stream_params,
-                     cubeb_stream_params const * mixer_params)
+int cubeb_mixer_mix(cubeb_mixer * mixer,
+                    size_t frames,
+                    void* input_buffer,
+                    size_t input_buffer_size,
+                    void* output_buffer,
+                    size_t output_buffer_size)
 {
-  assert(mixer);
-  mixer->mix(frames, input_buffer, input_buffer_length, output_buffer, output_buffer_length,
-             stream_params, mixer_params);
+  return mixer->mix(
+    frames, input_buffer, input_buffer_size, output_buffer, output_buffer_size);
 }
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.h b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.h
index 51fb9088a83261d470485b5d488846afa40609e8..dd84b87b5c63c42de2d65dc5d873aafa0d589dc8 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.h
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.h
@@ -8,80 +8,27 @@
 #ifndef CUBEB_MIXER
 #define CUBEB_MIXER
 
-#include "cubeb/cubeb.h" // for cubeb_channel_layout ,CUBEB_CHANNEL_LAYOUT_MAPS and cubeb_stream_params.
-#include <stdbool.h>
+#include "cubeb/cubeb.h" // for cubeb_channel_layout and cubeb_stream_params.
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
-typedef enum {
-  CHANNEL_INVALID = -1,
-  CHANNEL_MONO = 0,
-  CHANNEL_LEFT,
-  CHANNEL_RIGHT,
-  CHANNEL_CENTER,
-  CHANNEL_LS,
-  CHANNEL_RS,
-  CHANNEL_RLS,
-  CHANNEL_RCENTER,
-  CHANNEL_RRS,
-  CHANNEL_LFE,
-  CHANNEL_UNMAPPED,
-  CHANNEL_MAX = 256 // Max number of supported channels.
-} cubeb_channel;
-
-static cubeb_channel const CHANNEL_INDEX_TO_ORDER[CUBEB_LAYOUT_MAX][CHANNEL_MAX] = {
-  { CHANNEL_INVALID },                                                                                            // UNDEFINED
-  { CHANNEL_LEFT, CHANNEL_RIGHT },                                                                                // DUAL_MONO
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE },                                                                   // DUAL_MONO_LFE
-  { CHANNEL_MONO },                                                                                               // MONO
-  { CHANNEL_MONO, CHANNEL_LFE },                                                                                  // MONO_LFE
-  { CHANNEL_LEFT, CHANNEL_RIGHT },                                                                                // STEREO
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE },                                                                   // STEREO_LFE
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER },                                                                // 3F
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE },                                                   // 3F_LFE
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_RCENTER },                                                               // 2F1
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE, CHANNEL_RCENTER },                                                  // 2F1_LFE
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_RCENTER },                                               // 3F1
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RCENTER },                                  // 3F1_LFE
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LS, CHANNEL_RS },                                                        // 2F2
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE, CHANNEL_LS, CHANNEL_RS },                                           // 2F2_LFE
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LS, CHANNEL_RS },                                        // 3F2
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_LS, CHANNEL_RS },                           // 3F2_LFE
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RCENTER, CHANNEL_LS, CHANNEL_RS },          // 3F3R_LFE
-  { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RLS, CHANNEL_RRS, CHANNEL_LS, CHANNEL_RS }  // 3F4_LFE
-  // When more channels are present, the stream is considered unmapped to a
-  // particular speaker set.
-};
-
-typedef struct {
-  unsigned int channels;
-  cubeb_channel map[CHANNEL_MAX];
-} cubeb_channel_map;
-
-cubeb_channel_layout cubeb_channel_map_to_layout(cubeb_channel_map const * channel_map);
-
-bool cubeb_should_upmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
-
-bool cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
-
-bool cubeb_should_mix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
-
-typedef enum {
-  CUBEB_MIXER_DIRECTION_DOWNMIX = 0x01,
-  CUBEB_MIXER_DIRECTION_UPMIX   = 0x02,
-} cubeb_mixer_direction;
-
 typedef struct cubeb_mixer cubeb_mixer;
 cubeb_mixer * cubeb_mixer_create(cubeb_sample_format format,
-                                 unsigned char direction);
+                                 uint32_t in_channels,
+                                 cubeb_channel_layout in_layout,
+                                 uint32_t out_channels,
+                                 cubeb_channel_layout out_layout);
 void cubeb_mixer_destroy(cubeb_mixer * mixer);
-void cubeb_mixer_mix(cubeb_mixer * mixer, long frames,
-                     void * input_buffer, unsigned long input_buffer_length,
-                     void * output_buffer, unsigned long output_buffer_length,
-                     cubeb_stream_params const * stream_params,
-                     cubeb_stream_params const * mixer_params);
+int cubeb_mixer_mix(cubeb_mixer * mixer,
+                    size_t frames,
+                    void * input_buffer,
+                    size_t input_buffer_size,
+                    void * output_buffer,
+                    size_t output_buffer_size);
+
+unsigned int cubeb_channel_layout_nb_channels(cubeb_channel_layout channel_layout);
 
 #if defined(__cplusplus)
 }
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_opensl.c b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_opensl.c
index 8e9d4c73f2d68a5dac0ef74b6ede9958cc94c5cd..01784304567224e97e4268e2f9aee32769f40d0e 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_opensl.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_opensl.c
@@ -26,6 +26,7 @@
 #include "cubeb_resampler.h"
 #include "cubeb-sles.h"
 #include "cubeb_array_queue.h"
+#include "android/cubeb-output-latency.h"
 
 #if defined(__ANDROID__)
 #ifdef LOG
@@ -61,14 +62,13 @@
 #endif
 
 #define DEFAULT_SAMPLE_RATE 48000
+#define DEFAULT_NUM_OF_FRAMES 480
 
 static struct cubeb_ops const opensl_ops;
 
 struct cubeb {
   struct cubeb_ops const * ops;
   void * lib;
-  void * libmedia;
-  int32_t (* get_output_latency)(uint32_t * latency, int stream_type);
   SLInterfaceID SL_IID_BUFFERQUEUE;
   SLInterfaceID SL_IID_PLAY;
 #if defined(__ANDROID__)
@@ -80,11 +80,11 @@ struct cubeb {
   SLObjectItf engObj;
   SLEngineItf eng;
   SLObjectItf outmixObj;
+  output_latency_function * p_output_latency_function;
 };
 
 #define NELEMS(A) (sizeof(A) / sizeof A[0])
 #define NBUFS 4
-#define AUDIO_STREAM_TYPE_MUSIC 3
 
 struct cubeb_stream {
   /* Note: Must match cubeb_stream layout in cubeb.c. */
@@ -153,7 +153,7 @@ struct cubeb_stream {
   cubeb_state_callback state_callback;
 
   cubeb_resampler * resampler;
-  unsigned int inputrate;
+  unsigned int user_output_rate;
   unsigned int output_configured_rate;
   unsigned int latency_frames;
   int64_t lastPosition;
@@ -236,7 +236,6 @@ static void
 play_callback(SLPlayItf caller, void * user_ptr, SLuint32 event)
 {
   cubeb_stream * stm = user_ptr;
-  int draining;
   assert(stm);
   switch (event) {
     case SL_PLAYEVENT_HEADATMARKER:
@@ -668,30 +667,11 @@ opensl_init(cubeb ** context, char const * context_name)
   ctx->ops = &opensl_ops;
 
   ctx->lib = dlopen("libOpenSLES.so", RTLD_LAZY);
-  ctx->libmedia = dlopen("libmedia.so", RTLD_LAZY);
-  if (!ctx->lib || !ctx->libmedia) {
+  if (!ctx->lib) {
     free(ctx);
     return CUBEB_ERROR;
   }
 
-  /* Get the latency, in ms, from AudioFlinger */
-  /* status_t AudioSystem::getOutputLatency(uint32_t* latency,
-   *                                        audio_stream_type_t streamType) */
-  /* First, try the most recent signature. */
-  ctx->get_output_latency =
-    dlsym(ctx->libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t");
-  if (!ctx->get_output_latency) {
-    /* in case of failure, try the legacy version. */
-    /* status_t AudioSystem::getOutputLatency(uint32_t* latency,
-     *                                        int streamType) */
-    ctx->get_output_latency =
-      dlsym(ctx->libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPji");
-    if (!ctx->get_output_latency) {
-      opensl_destroy(ctx);
-      return CUBEB_ERROR;
-    }
-  }
-
   typedef SLresult (*slCreateEngine_t)(SLObjectItf *,
                                        SLuint32,
                                        const SLEngineOption *,
@@ -761,6 +741,11 @@ opensl_init(cubeb ** context, char const * context_name)
     return CUBEB_ERROR;
   }
 
+  ctx->p_output_latency_function = cubeb_output_latency_load_method(android_version);
+  if (!ctx->p_output_latency_function) {
+    LOG("Warning: output latency is not available, cubeb_stream_get_position() is not supported");
+  }
+
   *context = ctx;
 
   LOG("Cubeb init (%p) success", ctx);
@@ -784,124 +769,6 @@ opensl_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
   return CUBEB_OK;
 }
 
-static int
-opensl_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
-{
-  /* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
-   * We don't want to deal with JNI here (and we don't have Java on b2g anyways),
-   * so we just dlopen the library and get the two symbols we need. */
-  int r;
-  void * libmedia;
-  uint32_t (*get_primary_output_samplingrate)();
-  uint32_t (*get_output_samplingrate)(int * samplingRate, int streamType);
-
-  libmedia = dlopen("libmedia.so", RTLD_LAZY);
-  if (!libmedia) {
-    return CUBEB_ERROR;
-  }
-
-  /* uint32_t AudioSystem::getPrimaryOutputSamplingRate(void) */
-  get_primary_output_samplingrate =
-    dlsym(libmedia, "_ZN7android11AudioSystem28getPrimaryOutputSamplingRateEv");
-  if (!get_primary_output_samplingrate) {
-    /* fallback to
-     * status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
-     * if we cannot find getPrimaryOutputSamplingRate. */
-    get_output_samplingrate =
-      dlsym(libmedia, "_ZN7android11AudioSystem21getOutputSamplingRateEPj19audio_stream_type_t");
-    if (!get_output_samplingrate) {
-      /* Another signature exists, with a int instead of an audio_stream_type_t */
-      get_output_samplingrate =
-        dlsym(libmedia, "_ZN7android11AudioSystem21getOutputSamplingRateEPii");
-      if (!get_output_samplingrate) {
-        dlclose(libmedia);
-        return CUBEB_ERROR;
-      }
-    }
-  }
-
-  if (get_primary_output_samplingrate) {
-    *rate = get_primary_output_samplingrate();
-  } else {
-    /* We don't really know about the type, here, so we just pass music. */
-    r = get_output_samplingrate((int *) rate, AUDIO_STREAM_TYPE_MUSIC);
-    if (r) {
-      dlclose(libmedia);
-      return CUBEB_ERROR;
-    }
-  }
-
-  dlclose(libmedia);
-
-  /* Depending on which method we called above, we can get a zero back, yet have
-   * a non-error return value, especially if the audio system is not
-   * ready/shutting down (i.e. when we can't get our hand on the AudioFlinger
-   * thread). */
-  if (*rate == 0) {
-    return CUBEB_ERROR;
-  }
-
-  return CUBEB_OK;
-}
-
-static int
-opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
-{
-  /* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
-   * We don't want to deal with JNI here (and we don't have Java on b2g anyways),
-   * so we just dlopen the library and get the two symbols we need. */
-
-  int r;
-  void * libmedia;
-  size_t (*get_primary_output_frame_count)(void);
-  int (*get_output_frame_count)(size_t * frameCount, int streamType);
-  uint32_t primary_sampling_rate;
-  size_t primary_buffer_size;
-
-  r = opensl_get_preferred_sample_rate(ctx, &primary_sampling_rate);
-
-  if (r) {
-    return CUBEB_ERROR;
-  }
-
-  libmedia = dlopen("libmedia.so", RTLD_LAZY);
-  if (!libmedia) {
-    return CUBEB_ERROR;
-  }
-
-  /* JB variant */
-  /* size_t AudioSystem::getPrimaryOutputFrameCount(void) */
-  get_primary_output_frame_count =
-    dlsym(libmedia, "_ZN7android11AudioSystem26getPrimaryOutputFrameCountEv");
-  if (!get_primary_output_frame_count) {
-    /* ICS variant */
-    /* status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) */
-    get_output_frame_count =
-      dlsym(libmedia, "_ZN7android11AudioSystem19getOutputFrameCountEPii");
-    if (!get_output_frame_count) {
-      dlclose(libmedia);
-      return CUBEB_ERROR;
-    }
-  }
-
-  if (get_primary_output_frame_count) {
-    primary_buffer_size = get_primary_output_frame_count();
-  } else {
-    if (get_output_frame_count(&primary_buffer_size, AUDIO_STREAM_TYPE_MUSIC) != 0) {
-      return CUBEB_ERROR;
-    }
-  }
-
-  /* To get a fast track in Android's mixer, we need to be at the native
-   * samplerate, which is device dependant. Some devices might be able to
-   * resample when playing a fast track, but it's pretty rare. */
-  *latency_frames = primary_buffer_size;
-
-  dlclose(libmedia);
-
-  return CUBEB_OK;
-}
-
 static void
 opensl_destroy(cubeb * ctx)
 {
@@ -910,7 +777,8 @@ opensl_destroy(cubeb * ctx)
   if (ctx->engObj)
     cubeb_destroy_sles_engine(&ctx->engObj);
   dlclose(ctx->lib);
-  dlclose(ctx->libmedia);
+  if (ctx->p_output_latency_function)
+    cubeb_output_latency_unload_method(ctx->p_output_latency_function);
   free(ctx);
 }
 
@@ -997,13 +865,9 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
       // api for input device this is a safe choice.
       stm->input_device_rate = stm->output_configured_rate;
     } else  {
-      // The output preferred rate is used for input only scenario. This is
-      // the correct rate to use to get a fast track for input only.
-      r = opensl_get_preferred_sample_rate(stm->context, &stm->input_device_rate);
-      if (r != CUBEB_OK) {
-        // If everything else fail use a safe choice for Android.
-        stm->input_device_rate = DEFAULT_SAMPLE_RATE;
-      }
+      // The output preferred rate is used for an input only scenario.
+      // The default rate expected to be supported from all android devices.
+      stm->input_device_rate = DEFAULT_SAMPLE_RATE;
     }
     lDataFormat.samplesPerSec = stm->input_device_rate * 1000;
     res = (*stm->context->eng)->CreateAudioRecorder(stm->context->eng,
@@ -1114,7 +978,7 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
   assert(stm);
   assert(params);
 
-  stm->inputrate = params->rate;
+  stm->user_output_rate = params->rate;
   stm->framesize = params->channels * sizeof(int16_t);
   stm->lastPosition = -1;
   stm->lastPositionTimeStamp = 0;
@@ -1151,20 +1015,7 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
 #endif
   assert(NELEMS(ids) == NELEMS(req));
 
-  unsigned int latency_frames = stm->latency_frames;
-  uint32_t preferred_sampling_rate = stm->inputrate;
-#if defined(__ANDROID__)
-  if (get_android_version() >= ANDROID_VERSION_MARSHMALLOW) {
-    // Reset preferred samping rate to trigger fallback to native sampling rate.
-    preferred_sampling_rate = 0;
-    if (opensl_get_min_latency(stm->context, *params, &latency_frames) != CUBEB_OK) {
-      // Default to AudioFlinger's advertised fast track latency of 10ms.
-      latency_frames = 440;
-    }
-    stm->latency_frames = latency_frames;
-  }
-#endif
-
+  uint32_t preferred_sampling_rate = stm->user_output_rate;
   SLresult res = SL_RESULT_CONTENT_UNSUPPORTED;
   if (preferred_sampling_rate) {
     res = (*stm->context->eng)->CreateAudioPlayer(stm->context->eng,
@@ -1177,12 +1028,9 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
   }
 
   // Sample rate not supported? Try again with primary sample rate!
-  if (res == SL_RESULT_CONTENT_UNSUPPORTED) {
-    if (opensl_get_preferred_sample_rate(stm->context, &preferred_sampling_rate)) {
-      // If fail default is used
-      preferred_sampling_rate = DEFAULT_SAMPLE_RATE;
-    }
-
+  if (res == SL_RESULT_CONTENT_UNSUPPORTED &&
+      preferred_sampling_rate != DEFAULT_SAMPLE_RATE) {
+    preferred_sampling_rate = DEFAULT_SAMPLE_RATE;
     format.samplesPerSec = preferred_sampling_rate * 1000;
     res = (*stm->context->eng)->CreateAudioPlayer(stm->context->eng,
                                                   &stm->playerObj,
@@ -1200,7 +1048,7 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
 
   stm->output_configured_rate = preferred_sampling_rate;
   stm->bytespersec = stm->output_configured_rate * stm->framesize;
-  stm->queuebuf_len = stm->framesize * latency_frames;
+  stm->queuebuf_len = stm->framesize * stm->latency_frames;
 
   // Calculate the capacity of input array
   stm->queuebuf_capacity = NBUFS;
@@ -1337,7 +1185,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
   stm->data_callback = data_callback;
   stm->state_callback = state_callback;
   stm->user_ptr = user_ptr;
-  stm->latency_frames = latency_frames;
+  stm->latency_frames = latency_frames ? latency_frames : DEFAULT_NUM_OF_FRAMES;
   stm->input_enabled = (input_stream_params) ? 1 : 0;
   stm->output_enabled = (output_stream_params) ? 1 : 0;
   stm->shutdown = 1;
@@ -1601,11 +1449,12 @@ static int
 opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
 {
   SLmillisecond msec;
-  uint64_t samplerate;
-  SLresult res;
-  int r;
-  uint32_t mixer_latency;
   uint32_t compensation_msec = 0;
+  SLresult res;
+
+  if (!cubeb_output_latency_method_is_loaded(stm->context->p_output_latency_function)) {
+    return CUBEB_ERROR_NOT_SUPPORTED;
+  }
 
   res = (*stm->play)->GetPosition(stm->play, &msec);
   if (res != SL_RESULT_SUCCESS)
@@ -1621,15 +1470,11 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
     stm->lastPosition = msec;
   }
 
-  samplerate = stm->inputrate;
-
-  r = stm->context->get_output_latency(&mixer_latency, AUDIO_STREAM_TYPE_MUSIC);
-  if (r) {
-    return CUBEB_ERROR;
-  }
+  uint64_t samplerate = stm->user_output_rate;
+  uint32_t mixer_latency = cubeb_get_output_latency(stm->context->p_output_latency_function);
 
   pthread_mutex_lock(&stm->mutex);
-  int64_t maximum_position = stm->written * (int64_t)stm->inputrate / stm->output_configured_rate;
+  int64_t maximum_position = stm->written * (int64_t)stm->user_output_rate / stm->output_configured_rate;
   pthread_mutex_unlock(&stm->mutex);
   assert(maximum_position >= 0);
 
@@ -1652,24 +1497,6 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
   return CUBEB_OK;
 }
 
-int
-opensl_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
-{
-  int r;
-  uint32_t mixer_latency; // The latency returned by AudioFlinger is in ms.
-
-  /* audio_stream_type_t is an int, so this is okay. */
-  r = stm->context->get_output_latency(&mixer_latency, AUDIO_STREAM_TYPE_MUSIC);
-  if (r) {
-    return CUBEB_ERROR;
-  }
-
-  *latency = stm->latency_frames + // OpenSL latency
-    mixer_latency * stm->inputrate / 1000; // AudioFlinger latency
-
-  return CUBEB_OK;
-}
-
 int
 opensl_stream_set_volume(cubeb_stream * stm, float volume)
 {
@@ -1705,9 +1532,8 @@ static struct cubeb_ops const opensl_ops = {
   .init = opensl_init,
   .get_backend_id = opensl_get_backend_id,
   .get_max_channel_count = opensl_get_max_channel_count,
-  .get_min_latency = opensl_get_min_latency,
-  .get_preferred_sample_rate = opensl_get_preferred_sample_rate,
-  .get_preferred_channel_layout = NULL,
+  .get_min_latency = NULL,
+  .get_preferred_sample_rate = NULL,
   .enumerate_devices = NULL,
   .device_collection_destroy = NULL,
   .destroy = opensl_destroy,
@@ -1717,7 +1543,7 @@ static struct cubeb_ops const opensl_ops = {
   .stream_stop = opensl_stream_stop,
   .stream_reset_default_device = NULL,
   .stream_get_position = opensl_stream_get_position,
-  .stream_get_latency = opensl_stream_get_latency,
+  .stream_get_latency = NULL,
   .stream_set_volume = opensl_stream_set_volume,
   .stream_set_panning = NULL,
   .stream_get_current_device = NULL,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_pulse.c b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_pulse.c
index 1cac5eadd45b9ff6183bee866bc9c3d44f75da00..079fd69c4a7d5271b2e37f90d58d85dc53bf549b 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_pulse.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_pulse.c
@@ -7,14 +7,14 @@
 #undef NDEBUG
 #include <assert.h>
 #include <dlfcn.h>
-#include <stdlib.h>
 #include <pulse/pulseaudio.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
+#include "cubeb/cubeb.h"
 #include "cubeb_mixer.h"
 #include "cubeb_strings.h"
-#include <stdio.h>
 
 #ifdef DISABLE_LIBPULSE_DLOPEN
 #define WRAP(x) x
@@ -511,44 +511,45 @@ stream_update_timing_info(cubeb_stream * stm)
 static pa_channel_position_t
 cubeb_channel_to_pa_channel(cubeb_channel channel)
 {
-  assert(channel != CHANNEL_INVALID);
-
-  // This variable may be used for multiple times, so we should avoid to
-  // allocate it in stack, or it will be created and removed repeatedly.
-  // Use static to allocate this local variable in data space instead of stack.
-  static pa_channel_position_t map[CHANNEL_MAX] = {
-    // PA_CHANNEL_POSITION_INVALID,      // CHANNEL_INVALID
-    PA_CHANNEL_POSITION_MONO,         // CHANNEL_MONO
-    PA_CHANNEL_POSITION_FRONT_LEFT,   // CHANNEL_LEFT
-    PA_CHANNEL_POSITION_FRONT_RIGHT,  // CHANNEL_RIGHT
-    PA_CHANNEL_POSITION_FRONT_CENTER, // CHANNEL_CENTER
-    PA_CHANNEL_POSITION_SIDE_LEFT,    // CHANNEL_LS
-    PA_CHANNEL_POSITION_SIDE_RIGHT,   // CHANNEL_RS
-    PA_CHANNEL_POSITION_REAR_LEFT,    // CHANNEL_RLS
-    PA_CHANNEL_POSITION_REAR_CENTER,  // CHANNEL_RCENTER
-    PA_CHANNEL_POSITION_REAR_RIGHT,   // CHANNEL_RRS
-    PA_CHANNEL_POSITION_LFE           // CHANNEL_LFE
-  };
-
-  return map[channel];
-}
-
-static cubeb_channel
-pa_channel_to_cubeb_channel(pa_channel_position_t channel)
-{
-  assert(channel != PA_CHANNEL_POSITION_INVALID);
-  switch(channel) {
-    case PA_CHANNEL_POSITION_MONO: return CHANNEL_MONO;
-    case PA_CHANNEL_POSITION_FRONT_LEFT: return CHANNEL_LEFT;
-    case PA_CHANNEL_POSITION_FRONT_RIGHT: return CHANNEL_RIGHT;
-    case PA_CHANNEL_POSITION_FRONT_CENTER: return CHANNEL_CENTER;
-    case PA_CHANNEL_POSITION_SIDE_LEFT: return CHANNEL_LS;
-    case PA_CHANNEL_POSITION_SIDE_RIGHT: return CHANNEL_RS;
-    case PA_CHANNEL_POSITION_REAR_LEFT: return CHANNEL_RLS;
-    case PA_CHANNEL_POSITION_REAR_CENTER: return CHANNEL_RCENTER;
-    case PA_CHANNEL_POSITION_REAR_RIGHT: return CHANNEL_RRS;
-    case PA_CHANNEL_POSITION_LFE: return CHANNEL_LFE;
-    default: return CHANNEL_INVALID;
+  switch (channel) {
+    case CHANNEL_FRONT_LEFT:
+      return PA_CHANNEL_POSITION_FRONT_LEFT;
+    case CHANNEL_FRONT_RIGHT:
+      return PA_CHANNEL_POSITION_FRONT_RIGHT;
+    case CHANNEL_FRONT_CENTER:
+      return PA_CHANNEL_POSITION_FRONT_CENTER;
+    case CHANNEL_LOW_FREQUENCY:
+      return PA_CHANNEL_POSITION_LFE;
+    case CHANNEL_BACK_LEFT:
+      return PA_CHANNEL_POSITION_REAR_LEFT;
+    case CHANNEL_BACK_RIGHT:
+      return PA_CHANNEL_POSITION_REAR_RIGHT;
+    case CHANNEL_FRONT_LEFT_OF_CENTER:
+      return PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
+    case CHANNEL_FRONT_RIGHT_OF_CENTER:
+      return PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
+    case CHANNEL_BACK_CENTER:
+      return PA_CHANNEL_POSITION_REAR_CENTER;
+    case CHANNEL_SIDE_LEFT:
+      return PA_CHANNEL_POSITION_SIDE_LEFT;
+    case CHANNEL_SIDE_RIGHT:
+      return PA_CHANNEL_POSITION_SIDE_RIGHT;
+    case CHANNEL_TOP_CENTER:
+      return PA_CHANNEL_POSITION_TOP_CENTER;
+    case CHANNEL_TOP_FRONT_LEFT:
+      return PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
+    case CHANNEL_TOP_FRONT_CENTER:
+      return PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
+    case CHANNEL_TOP_FRONT_RIGHT:
+      return PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
+    case CHANNEL_TOP_BACK_LEFT:
+      return PA_CHANNEL_POSITION_TOP_REAR_LEFT;
+    case CHANNEL_TOP_BACK_CENTER:
+      return PA_CHANNEL_POSITION_TOP_REAR_CENTER;
+    case CHANNEL_TOP_BACK_RIGHT:
+      return PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
+    default:
+      return PA_CHANNEL_POSITION_INVALID;
   }
 }
 
@@ -558,21 +559,18 @@ layout_to_channel_map(cubeb_channel_layout layout, pa_channel_map * cm)
   assert(cm && layout != CUBEB_LAYOUT_UNDEFINED);
 
   WRAP(pa_channel_map_init)(cm);
-  cm->channels = CUBEB_CHANNEL_LAYOUT_MAPS[layout].channels;
-  for (uint8_t i = 0 ; i < cm->channels ; ++i) {
-    cm->map[i] = cubeb_channel_to_pa_channel(CHANNEL_INDEX_TO_ORDER[layout][i]);
-  }
-}
 
-static cubeb_channel_layout
-channel_map_to_layout(pa_channel_map * cm)
-{
-  cubeb_channel_map cubeb_map;
-  cubeb_map.channels = cm->channels;
-  for (uint32_t i = 0 ; i < cm->channels ; ++i) {
-    cubeb_map.map[i] = pa_channel_to_cubeb_channel(cm->map[i]);
+  uint32_t channels = 0;
+  cubeb_channel_layout channelMap = layout;
+  for (uint32_t i = 0 ; channelMap != 0; ++i) {
+    uint32_t channel = (channelMap & 1) << i;
+    if (channel != 0) {
+      cm->map[channels] = cubeb_channel_to_pa_channel(channel);
+      channels++;
+    }
+    channelMap = channelMap >> 1;
   }
-  return cubeb_channel_map_to_layout(&cubeb_map);
+  cm->channels = cubeb_channel_layout_nb_channels(layout);
 }
 
 static void pulse_context_destroy(cubeb * ctx);
@@ -714,20 +712,6 @@ pulse_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
   return CUBEB_OK;
 }
 
-static int
-pulse_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layout)
-{
-  assert(ctx && layout);
-  (void)ctx;
-
-  if (!ctx->default_sink_info)
-    return CUBEB_ERROR;
-
-  *layout = channel_map_to_layout(&ctx->default_sink_info->channel_map);
-
-  return CUBEB_OK;
-}
-
 static int
 pulse_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
 {
@@ -808,7 +792,7 @@ create_pa_stream(cubeb_stream * stm,
   assert(&stm->input_stream == pa_stm || (&stm->output_stream == pa_stm &&
          (stream_params->layout == CUBEB_LAYOUT_UNDEFINED ||
          (stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
-         CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels == stream_params->channels))));
+         cubeb_channel_layout_nb_channels(stream_params->layout) == stream_params->channels))));
   if (stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) {
     return CUBEB_ERROR_NOT_SUPPORTED;
   }
@@ -1279,7 +1263,7 @@ pulse_sink_info_cb(pa_context * context, const pa_sink_info * info,
 
   device_id = info->name;
   if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
-    assert(false);
+    assert(NULL);
     return;
   }
 
@@ -1348,7 +1332,7 @@ pulse_source_info_cb(pa_context * context, const pa_source_info * info,
 
   device_id = info->name;
   if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
-    assert(false);
+    assert(NULL);
     return;
   }
 
@@ -1588,7 +1572,6 @@ static struct cubeb_ops const pulse_ops = {
   .get_max_channel_count = pulse_get_max_channel_count,
   .get_min_latency = pulse_get_min_latency,
   .get_preferred_sample_rate = pulse_get_preferred_sample_rate,
-  .get_preferred_channel_layout = pulse_get_preferred_channel_layout,
   .enumerate_devices = pulse_enumerate_devices,
   .device_collection_destroy = pulse_device_collection_destroy,
   .destroy = pulse_destroy,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_sndio.c b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_sndio.c
index e5b7ab5d471961e50d1935c2c5809ed08359885c..5a4334316f8325ad579e1ab2bc48ddf45cc1cd0a 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_sndio.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_sndio.c
@@ -536,7 +536,6 @@ static struct cubeb_ops const sndio_ops = {
   .get_max_channel_count = sndio_get_max_channel_count,
   .get_min_latency = sndio_get_min_latency,
   .get_preferred_sample_rate = sndio_get_preferred_sample_rate,
-  .get_preferred_channel_layout = NULL,
   .enumerate_devices = sndio_enumerate_devices,
   .device_collection_destroy = sndio_device_collection_destroy,
   .destroy = sndio_destroy,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.cpp b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..85572a9feaff3399a3d297b9432f5c1161c0290c
--- /dev/null
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright © 2018 Mozilla Foundation
+ *
+ * This program is made available under an ISC-style license.  See the
+ * accompanying file LICENSE for details.
+ */
+
+#include "cubeb_utils.h"
+
+size_t cubeb_sample_size(cubeb_sample_format format)
+{
+  switch (format) {
+    case CUBEB_SAMPLE_S16LE:
+    case CUBEB_SAMPLE_S16BE:
+      return sizeof(int16_t);
+    case CUBEB_SAMPLE_FLOAT32LE:
+    case CUBEB_SAMPLE_FLOAT32BE:
+      return sizeof(float);
+    default:
+      // should never happen as all cases are handled above.
+      assert(false);
+  }
+}
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.h b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.h
index dc08fec9928d0d40d5536a36df8b56ec2f1fe010..df675115596f8573504c138a519e21e735f4ac08 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.h
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.h
@@ -333,6 +333,10 @@ private:
   auto_array<T> ar;
 };
 
+extern "C" {
+  size_t cubeb_sample_size(cubeb_sample_format format);
+}
+
 using auto_lock = std::lock_guard<owned_critical_section>;
 #endif // __cplusplus
 
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_wasapi.cpp b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_wasapi.cpp
index a7d89234386655e7066e87ee707265ecf2639dc7..ac6c6b416c2ad13a091941f403d74b1b543ba170 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_wasapi.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_wasapi.cpp
@@ -135,32 +135,6 @@ private:
   T * ptr = nullptr;
 };
 
-struct auto_com {
-  auto_com() {
-    result = CoInitializeEx(NULL, COINIT_MULTITHREADED);
-  }
-  ~auto_com() {
-    if (result == RPC_E_CHANGED_MODE) {
-      // This is not an error, COM was not initialized by this function, so it is
-      // not necessary to uninit it.
-      LOG("COM was already initialized in STA.");
-    } else if (result == S_FALSE) {
-      // This is not an error. We are allowed to call CoInitializeEx more than
-      // once, as long as it is matches by an CoUninitialize call.
-      // We do that in the dtor which is guaranteed to be called.
-      LOG("COM was already initialized in MTA");
-    }
-    if (SUCCEEDED(result)) {
-      CoUninitialize();
-    }
-  }
-  bool ok() {
-    return result == RPC_E_CHANGED_MODE || SUCCEEDED(result);
-  }
-private:
-  HRESULT result;
-};
-
 extern cubeb_ops const wasapi_ops;
 
 int wasapi_stream_stop(cubeb_stream * stm);
@@ -273,9 +247,10 @@ struct cubeb_stream {
   uint32_t output_buffer_frame_count = 0;
   /* Resampler instance. Resampling will only happen if necessary. */
   std::unique_ptr<cubeb_resampler, decltype(&cubeb_resampler_destroy)> resampler = { nullptr, cubeb_resampler_destroy };
-  /* Mixer interface */
-  std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)> mixer = { nullptr, cubeb_mixer_destroy };
-  /* A buffer for up/down mixing multi-channel audio. */
+  /* Mixer interfaces */
+  std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)> output_mixer = { nullptr, cubeb_mixer_destroy };
+  std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)> input_mixer = { nullptr, cubeb_mixer_destroy };
+  /* A buffer for up/down mixing multi-channel audio output. */
   std::vector<BYTE> mix_buffer;
   /* WASAPI input works in "packets". We re-linearize the audio packets
    * into this buffer before handing it to the resampler. */
@@ -425,61 +400,11 @@ double stream_to_mix_samplerate_ratio(cubeb_stream_params & stream, cubeb_stream
 
 /* Convert the channel layout into the corresponding KSAUDIO_CHANNEL_CONFIG.
    See more: https://msdn.microsoft.com/en-us/library/windows/hardware/ff537083(v=vs.85).aspx */
-#define MASK_DUAL_MONO      (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
-#define MASK_DUAL_MONO_LFE  (MASK_DUAL_MONO | SPEAKER_LOW_FREQUENCY)
-#define MASK_MONO           (KSAUDIO_SPEAKER_MONO)
-#define MASK_MONO_LFE       (MASK_MONO | SPEAKER_LOW_FREQUENCY)
-#define MASK_STEREO         (KSAUDIO_SPEAKER_STEREO)
-#define MASK_STEREO_LFE     (MASK_STEREO | SPEAKER_LOW_FREQUENCY)
-#define MASK_3F             (MASK_STEREO | SPEAKER_FRONT_CENTER)
-#define MASK_3F_LFE         (MASK_3F | SPEAKER_LOW_FREQUENCY)
-#define MASK_2F1            (MASK_STEREO | SPEAKER_BACK_CENTER)
-#define MASK_2F1_LFE        (MASK_2F1 | SPEAKER_LOW_FREQUENCY)
-#define MASK_3F1            (KSAUDIO_SPEAKER_SURROUND)
-#define MASK_3F1_LFE        (MASK_3F1 | SPEAKER_LOW_FREQUENCY)
-#define MASK_2F2            (MASK_STEREO | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
-#define MASK_2F2_LFE        (MASK_2F2 | SPEAKER_LOW_FREQUENCY)
-#define MASK_3F2            (MASK_3F | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
-#define MASK_3F2_LFE        (KSAUDIO_SPEAKER_5POINT1_SURROUND)
-#define MASK_3F3R_LFE       (MASK_3F2_LFE | SPEAKER_BACK_CENTER)
-#define MASK_3F4_LFE        (KSAUDIO_SPEAKER_7POINT1_SURROUND)
-
-static DWORD
-channel_layout_to_mask(cubeb_channel_layout layout)
-{
-  XASSERT(layout < CUBEB_LAYOUT_MAX && "invalid conversion.");
-
-  // This variable may be used for multiple times, so we should avoid to
-  // allocate it in stack, or it will be created and removed repeatedly.
-  // Use static to allocate this local variable in data space instead of stack.
-  static DWORD map[CUBEB_LAYOUT_MAX] = {
-    KSAUDIO_SPEAKER_DIRECTOUT, // CUBEB_LAYOUT_UNDEFINED
-    MASK_DUAL_MONO,            // CUBEB_LAYOUT_DUAL_MONO
-    MASK_DUAL_MONO_LFE,        // CUBEB_LAYOUT_DUAL_MONO_LFE
-    MASK_MONO,                 // CUBEB_LAYOUT_MONO
-    MASK_MONO_LFE,             // CUBEB_LAYOUT_MONO_LFE
-    MASK_STEREO,               // CUBEB_LAYOUT_STEREO
-    MASK_STEREO_LFE,           // CUBEB_LAYOUT_STEREO_LFE
-    MASK_3F,                   // CUBEB_LAYOUT_3F
-    MASK_3F_LFE,               // CUBEB_LAYOUT_3F_LFE
-    MASK_2F1,                  // CUBEB_LAYOUT_2F1
-    MASK_2F1_LFE,              // CUBEB_LAYOUT_2F1_LFE
-    MASK_3F1,                  // CUBEB_LAYOUT_3F1
-    MASK_3F1_LFE,              // CUBEB_LAYOUT_3F1_LFE
-    MASK_2F2,                  // CUBEB_LAYOUT_2F2
-    MASK_2F2_LFE,              // CUBEB_LAYOUT_2F2_LFE
-    MASK_3F2,                  // CUBEB_LAYOUT_3F2
-    MASK_3F2_LFE,              // CUBEB_LAYOUT_3F2_LFE
-    MASK_3F3R_LFE,             // CUBEB_LAYOUT_3F3R_LFE
-    MASK_3F4_LFE,              // CUBEB_LAYOUT_3F4_LFE
-  };
-  return map[layout];
-}
 
 cubeb_channel_layout
 mask_to_channel_layout(WAVEFORMATEX const * fmt)
 {
-  DWORD mask = 0;
+  cubeb_channel_layout mask = 0;
 
   if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
     WAVEFORMATEXTENSIBLE const * ext = reinterpret_cast<WAVEFORMATEXTENSIBLE const *>(fmt);
@@ -487,44 +412,12 @@ mask_to_channel_layout(WAVEFORMATEX const * fmt)
   } else if (fmt->wFormatTag == WAVE_FORMAT_PCM ||
              fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
     if (fmt->nChannels == 1) {
-      mask = MASK_MONO;
+      mask = CHANNEL_FRONT_CENTER;
     } else if (fmt->nChannels == 2) {
-      mask = MASK_STEREO;
+      mask = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT;
     }
   }
-
-  switch (mask) {
-    // MASK_DUAL_MONO(_LFE) is same as STEREO(_LFE), so we skip it.
-    case MASK_MONO: return CUBEB_LAYOUT_MONO;
-    case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
-    case MASK_STEREO: return CUBEB_LAYOUT_STEREO;
-    case MASK_STEREO_LFE: return CUBEB_LAYOUT_STEREO_LFE;
-    case MASK_3F: return CUBEB_LAYOUT_3F;
-    case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
-    case MASK_2F1: return CUBEB_LAYOUT_2F1;
-    case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
-    case MASK_3F1: return CUBEB_LAYOUT_3F1;
-    case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
-    case MASK_2F2: return CUBEB_LAYOUT_2F2;
-    // Special case similar to MASK_2F2 but with rear left and right
-    // speakers instead of side left and right. This mapping is a band-aid as
-    // cubeb does not current have an enum to differentiate this and MASK_2F2,
-    // but is preferred to returning an undefined layout.
-    // See: https://github.com/kinetiknz/cubeb/issues/178 and https://bugzilla.mozilla.org/show_bug.cgi?id=1325023
-    case KSAUDIO_SPEAKER_QUAD: return CUBEB_LAYOUT_2F2;
-    case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
-    case MASK_3F2: return CUBEB_LAYOUT_3F2;
-    case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
-    // Special case similar to MASK_3F2_LFE but with rear left and right
-    // speakers instead of side left and right. his mapping is a band-aid as
-    // cubeb does not current have an enum to differentiate this and MASK_3F2_LFE,
-    // but is preferred to returning an undefined layout.
-    // See: https://github.com/kinetiknz/cubeb/issues/178 and https://bugzilla.mozilla.org/show_bug.cgi?id=1325023
-    case KSAUDIO_SPEAKER_5POINT1: return CUBEB_LAYOUT_3F2_LFE;
-    case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
-    case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
-    default: return CUBEB_LAYOUT_UNDEFINED;
-  }
+  return mask;
 }
 
 uint32_t
@@ -574,7 +467,7 @@ refill(cubeb_stream * stm, void * input_buffer, long input_frames_count,
      avoid a copy. Avoid exposing output if it is a dummy stream. */
   void * dest = nullptr;
   if (has_output(stm) && !stm->has_dummy_output) {
-    if (cubeb_should_mix(&stm->output_stream_params, &stm->output_mix_params)) {
+    if (stm->output_mixer) {
       dest = stm->mix_buffer.data();
     } else {
       dest = output_buffer;
@@ -594,8 +487,11 @@ refill(cubeb_stream * stm, void * input_buffer, long input_frames_count,
     stm->frames_written += out_frames;
   }
 
-  /* Go in draining mode if we got fewer frames than requested. */
-  if (out_frames < output_frames_needed) {
+  /* Go in draining mode if we got fewer frames than requested. If the stream
+     has no output we still expect the callback to return number of frames read
+     from input, otherwise we stop. */
+  if ((out_frames < output_frames_needed) ||
+      (!has_output(stm) && out_frames < input_frames_count)) {
     LOG("start draining.");
     stm->draining = true;
   }
@@ -605,14 +501,22 @@ refill(cubeb_stream * stm, void * input_buffer, long input_frames_count,
   XASSERT(out_frames == output_frames_needed || stm->draining || !has_output(stm) || stm->has_dummy_output);
 
   // We don't bother mixing dummy output as it will be silenced, otherwise mix output if needed
-  if (!stm->has_dummy_output && has_output(stm) && cubeb_should_mix(&stm->output_stream_params, &stm->output_mix_params)) {
+  if (!stm->has_dummy_output && has_output(stm) && stm->output_mixer) {
     XASSERT(dest == stm->mix_buffer.data());
-    unsigned long dest_len = out_frames * stm->output_stream_params.channels;
-    XASSERT(dest_len <= stm->mix_buffer.size() / stm->bytes_per_sample);
-    unsigned long output_buffer_len = out_frames * stm->output_mix_params.channels;
-    cubeb_mixer_mix(stm->mixer.get(), out_frames,
-                    dest, dest_len, output_buffer, output_buffer_len,
-                    &stm->output_stream_params, &stm->output_mix_params);
+    size_t dest_size =
+      out_frames * stm->output_stream_params.channels * stm->bytes_per_sample;
+    XASSERT(dest_size <= stm->mix_buffer.size());
+    size_t output_buffer_size =
+      out_frames * stm->output_mix_params.channels * stm->bytes_per_sample;
+    int ret = cubeb_mixer_mix(stm->output_mixer.get(),
+                              out_frames,
+                              dest,
+                              dest_size,
+                              output_buffer,
+                              output_buffer_size);
+    if (ret < 0) {
+      LOG("Error remixing content (%d)", ret);
+    }
   }
 
   return out_frames;
@@ -655,9 +559,9 @@ bool get_input_buffer(cubeb_stream * stm)
       return false;
     }
 
-    UINT32 packet_size;
+    UINT32 frames;
     hr = stm->capture_client->GetBuffer(&input_packet,
-                                        &packet_size,
+                                        &frames,
                                         &flags,
                                         &dev_pos,
                                         NULL);
@@ -665,7 +569,9 @@ bool get_input_buffer(cubeb_stream * stm)
       LOG("GetBuffer failed for capture: %lx", hr);
       return false;
     }
-    XASSERT(packet_size == next);
+    XASSERT(frames == next);
+
+    UINT32 input_stream_samples = frames * stm->input_stream_params.channels;
     // We do not explicitly handle the AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY
     // flag. There a two primary (non exhaustive) scenarios we anticipate this
     // flag being set in:
@@ -682,32 +588,38 @@ bool get_input_buffer(cubeb_stream * stm)
     // For more info: https://msdn.microsoft.com/en-us/library/windows/desktop/dd370859(v=vs.85).aspx,
     // https://msdn.microsoft.com/en-us/library/windows/desktop/dd371458(v=vs.85).aspx
     if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
-      LOG("insert silence: ps=%u", packet_size);
-      stm->linear_input_buffer->push_silence(packet_size * stm->input_stream_params.channels);
+      LOG("insert silence: ps=%u", frames);
+      stm->linear_input_buffer->push_silence(input_stream_samples);
     } else {
-      if (cubeb_should_mix(&stm->input_mix_params, &stm->input_stream_params)) {
-        bool ok = stm->linear_input_buffer->reserve(stm->linear_input_buffer->length() +
-                                                   packet_size * stm->input_stream_params.channels);
+      if (stm->input_mixer) {
+        bool ok = stm->linear_input_buffer->reserve(
+          stm->linear_input_buffer->length() + input_stream_samples);
         XASSERT(ok);
-        unsigned long input_packet_length = packet_size * stm->input_mix_params.channels;
-        unsigned long linear_input_buffer_length = packet_size * stm->input_stream_params.channels;
-        cubeb_mixer_mix(stm->mixer.get(), packet_size,
-                        input_packet, input_packet_length,
-                        stm->linear_input_buffer->end(), linear_input_buffer_length,
-                        &stm->input_mix_params,
-                        &stm->input_stream_params);
-        stm->linear_input_buffer->set_length(stm->linear_input_buffer->length() + linear_input_buffer_length);
+        size_t input_packet_size =
+          frames * stm->input_mix_params.channels *
+          cubeb_sample_size(stm->input_mix_params.format);
+        size_t linear_input_buffer_size =
+          input_stream_samples *
+          cubeb_sample_size(stm->input_stream_params.format);
+        cubeb_mixer_mix(stm->input_mixer.get(),
+                        frames,
+                        input_packet,
+                        input_packet_size,
+                        stm->linear_input_buffer->end(),
+                        linear_input_buffer_size);
+        stm->linear_input_buffer->set_length(
+          stm->linear_input_buffer->length() + input_stream_samples);
       } else {
-        stm->linear_input_buffer->push(input_packet,
-                                      packet_size * stm->input_stream_params.channels);
+        stm->linear_input_buffer->push(
+          input_packet, input_stream_samples);
       }
     }
-    hr = stm->capture_client->ReleaseBuffer(packet_size);
+    hr = stm->capture_client->ReleaseBuffer(frames);
     if (FAILED(hr)) {
       LOG("FAILED to release intput buffer");
       return false;
     }
-    offset += packet_size;
+    offset += input_stream_samples;
   }
 
   XASSERT(stm->linear_input_buffer->length() >= offset);
@@ -904,7 +816,7 @@ refill_callback_output(cubeb_stream * stm)
         output_frames, got);
 
   XASSERT(got >= 0);
-  XASSERT((unsigned long) got == output_frames || stm->draining);
+  XASSERT(size_t(got) == output_frames || stm->draining);
 
   hr = stm->render_client->ReleaseBuffer(got, 0);
   if (FAILED(hr)) {
@@ -912,7 +824,7 @@ refill_callback_output(cubeb_stream * stm)
     return false;
   }
 
-  return (unsigned long) got == output_frames || stm->draining;
+  return size_t(got) == output_frames || stm->draining;
 }
 
 static unsigned int __stdcall
@@ -931,12 +843,15 @@ wasapi_stream_render_loop(LPVOID stream)
   HANDLE mmcss_handle = NULL;
   HRESULT hr = 0;
   DWORD mmcss_task_index = 0;
-  auto_com com;
-  if (!com.ok()) {
-    LOG("COM initialization failed on render_loop thread.");
-    stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
-    return 0;
-  }
+  struct auto_com {
+    auto_com() {
+      HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+      XASSERT(SUCCEEDED(hr));
+    }
+    ~auto_com() {
+      CoUninitialize();
+    }
+  } com;
 
   /* We could consider using "Pro Audio" here for WebAudio and
      maybe WebRTC. */
@@ -1079,6 +994,7 @@ HRESULT register_notification_client(cubeb_stream * stm)
                                 IID_PPV_ARGS(stm->device_enumerator.receive()));
   if (FAILED(hr)) {
     LOG("Could not get device enumerator: %lx", hr);
+    XASSERT(hr != CO_E_NOTINITIALIZED);
     return hr;
   }
 
@@ -1125,6 +1041,7 @@ HRESULT get_endpoint(com_ptr<IMMDevice> & device, LPCWSTR devid)
                                 IID_PPV_ARGS(enumerator.receive()));
   if (FAILED(hr)) {
     LOG("Could not get device enumerator: %lx", hr);
+    XASSERT(hr != CO_E_NOTINITIALIZED);
     return hr;
   }
 
@@ -1145,6 +1062,7 @@ HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction)
                                 IID_PPV_ARGS(enumerator.receive()));
   if (FAILED(hr)) {
     LOG("Could not get device enumerator: %lx", hr);
+    XASSERT(hr != CO_E_NOTINITIALIZED);
     return hr;
   }
   hr = enumerator->GetDefaultAudioEndpoint(direction, eConsole, device.receive());
@@ -1229,17 +1147,11 @@ stream_set_volume(cubeb_stream * stm, float volume)
 extern "C" {
 int wasapi_init(cubeb ** context, char const * context_name)
 {
-  HRESULT hr;
-  auto_com com;
-  if (!com.ok()) {
-    return CUBEB_ERROR;
-  }
-
   /* We don't use the device yet, but need to make sure we can initialize one
      so that this backend is not incorrectly enabled on platforms that don't
      support WASAPI. */
   com_ptr<IMMDevice> device;
-  hr = get_default_endpoint(device, eRender);
+  HRESULT hr = get_default_endpoint(device, eRender);
   if (FAILED(hr)) {
     LOG("Could not get device: %lx", hr);
     return CUBEB_ERROR;
@@ -1334,16 +1246,10 @@ char const * wasapi_get_backend_id(cubeb * context)
 int
 wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
 {
-  HRESULT hr;
-  auto_com com;
-  if (!com.ok()) {
-    return CUBEB_ERROR;
-  }
-
   XASSERT(ctx && max_channels);
 
   com_ptr<IMMDevice> device;
-  hr = get_default_endpoint(device, eRender);
+  HRESULT hr = get_default_endpoint(device, eRender);
   if (FAILED(hr)) {
     return CUBEB_ERROR;
   }
@@ -1371,19 +1277,12 @@ wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
 int
 wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
 {
-  HRESULT hr;
-  REFERENCE_TIME default_period;
-  auto_com com;
-  if (!com.ok()) {
-    return CUBEB_ERROR;
-  }
-
   if (params.format != CUBEB_SAMPLE_FLOAT32NE && params.format != CUBEB_SAMPLE_S16NE) {
     return CUBEB_ERROR_INVALID_FORMAT;
   }
 
   com_ptr<IMMDevice> device;
-  hr = get_default_endpoint(device, eRender);
+  HRESULT hr = get_default_endpoint(device, eRender);
   if (FAILED(hr)) {
     LOG("Could not get default endpoint: %lx", hr);
     return CUBEB_ERROR;
@@ -1399,6 +1298,7 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
   }
 
   /* The second parameter is for exclusive mode, that we don't use. */
+  REFERENCE_TIME default_period;
   hr = client->GetDevicePeriod(&default_period, NULL);
   if (FAILED(hr)) {
     LOG("Could not get device period: %lx", hr);
@@ -1421,14 +1321,8 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
 int
 wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
 {
-  HRESULT hr;
-  auto_com com;
-  if (!com.ok()) {
-    return CUBEB_ERROR;
-  }
-
   com_ptr<IMMDevice> device;
-  hr = get_default_endpoint(device, eRender);
+  HRESULT hr = get_default_endpoint(device, eRender);
   if (FAILED(hr)) {
     return CUBEB_ERROR;
   }
@@ -1455,43 +1349,6 @@ wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
   return CUBEB_OK;
 }
 
-int
-wasapi_get_preferred_channel_layout(cubeb * context, cubeb_channel_layout * layout)
-{
-  HRESULT hr;
-  auto_com com;
-  if (!com.ok()) {
-    return CUBEB_ERROR;
-  }
-
-  com_ptr<IMMDevice> device;
-  hr = get_default_endpoint(device, eRender);
-  if (FAILED(hr)) {
-    return CUBEB_ERROR;
-  }
-
-  com_ptr<IAudioClient> client;
-  hr = device->Activate(__uuidof(IAudioClient),
-                        CLSCTX_INPROC_SERVER,
-                        NULL, client.receive_vpp());
-  if (FAILED(hr)) {
-    return CUBEB_ERROR;
-  }
-
-  WAVEFORMATEX * tmp = nullptr;
-  hr = client->GetMixFormat(&tmp);
-  if (FAILED(hr)) {
-    return CUBEB_ERROR;
-  }
-  com_heap_ptr<WAVEFORMATEX> mix_format(tmp);
-
-  *layout = mask_to_channel_layout(mix_format.get());
-
-  LOG("Preferred channel layout: %s", CUBEB_CHANNEL_LAYOUT_MAPS[*layout].name);
-
-  return CUBEB_OK;
-}
-
 void wasapi_stream_destroy(cubeb_stream * stm);
 
 static void
@@ -1528,7 +1385,7 @@ handle_channel_layout(cubeb_stream * stm,  EDataFlow direction, com_heap_ptr<WAV
 
   /* Get the channel mask by the channel layout.
      If the layout is not supported, we will get a closest settings below. */
-  format_pcm->dwChannelMask = channel_layout_to_mask(stream_params->layout);
+  format_pcm->dwChannelMask = stream_params->layout;
   mix_format->nChannels = stream_params->channels;
   waveformatex_update_derived_properties(mix_format.get());
 
@@ -1648,6 +1505,7 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
     format_pcm->SubFormat = stm->waveformatextensible_sub_format;
   }
   waveformatex_update_derived_properties(mix_format.get());
+
   /* Set channel layout only when there're more than two channels. Otherwise,
    * use the default setting retrieved from the stream format of the audio
    * engine's internal processing by GetMixFormat. */
@@ -1659,20 +1517,12 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
   mix_params->rate = mix_format->nSamplesPerSec;
   mix_params->channels = mix_format->nChannels;
   mix_params->layout = mask_to_channel_layout(mix_format.get());
-  if (mix_params->layout == CUBEB_LAYOUT_UNDEFINED) {
-    LOG("Stream using undefined layout! Any mixing may be unpredictable!\n");
-  } else if (mix_format->nChannels != CUBEB_CHANNEL_LAYOUT_MAPS[mix_params->layout].channels) {
-    // The CUBEB_CHANNEL_LAYOUT_MAPS[mix_params->layout].channels may be
-    // different from the mix_params->channels. 6 channel ouput with stereo
-    // layout is acceptable in Windows. If this happens, it should not downmix
-    // audio according to layout.
-    LOG("Channel count is different from the layout standard!\n");
-  }
-  LOG("Setup requested=[f=%d r=%u c=%u l=%s] mix=[f=%d r=%u c=%u l=%s]",
+
+  LOG("Setup requested=[f=%d r=%u c=%u l=%u] mix=[f=%d r=%u c=%u l=%u]",
       stream_params->format, stream_params->rate, stream_params->channels,
-      CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].name,
+      stream_params->layout,
       mix_params->format, mix_params->rate, mix_params->channels,
-      CUBEB_CHANNEL_LAYOUT_MAPS[mix_params->layout].name);
+      mix_params->layout);
 
   DWORD flags = AUDCLNT_STREAMFLAGS_NOPERSIST;
 
@@ -1701,10 +1551,6 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
         " for %s %lx.", DIRECTION_NAME, hr);
     return CUBEB_ERROR;
   }
-  // Input is up/down mixed when depacketized in get_input_buffer.
-  if (has_output(stm) && cubeb_should_mix(stream_params, mix_params)) {
-    stm->mix_buffer.resize(frames_to_bytes_before_mix(stm, *buffer_frame_count));
-  }
 
   // Events are used if not looping back
   if (!is_loopback) {
@@ -1729,17 +1575,10 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
 
 int setup_wasapi_stream(cubeb_stream * stm)
 {
-  HRESULT hr;
   int rv;
 
   stm->stream_reset_lock.assert_current_thread_owns();
 
-  auto_com com;
-  if (!com.ok()) {
-    LOG("Failure to initialize COM.");
-    return CUBEB_ERROR;
-  }
-
   XASSERT((!stm->output_client || !stm->input_client) && "WASAPI stream already setup, close it first.");
 
   if (has_input(stm)) {
@@ -1812,8 +1651,8 @@ int setup_wasapi_stream(cubeb_stream * stm)
       return rv;
     }
 
-    hr = stm->output_client->GetService(__uuidof(IAudioStreamVolume),
-                                        stm->audio_stream_volume.receive_vpp());
+    HRESULT hr = stm->output_client->GetService(__uuidof(IAudioStreamVolume),
+                                                stm->audio_stream_volume.receive_vpp());
     if (FAILED(hr)) {
       LOG("Could not get the IAudioStreamVolume: %lx", hr);
       return CUBEB_ERROR;
@@ -1881,6 +1720,39 @@ int setup_wasapi_stream(cubeb_stream * stm)
     stm->refill_callback = refill_callback_output;
   }
 
+  // Create input mixer.
+  if (has_input(stm) &&
+      ((stm->input_mix_params.layout != CUBEB_LAYOUT_UNDEFINED &&
+        stm->input_mix_params.layout != stm->input_stream_params.layout) ||
+       (stm->input_mix_params.channels != stm->input_stream_params.channels))) {
+    if (stm->input_mix_params.layout == CUBEB_LAYOUT_UNDEFINED) {
+      LOG("Input stream using undefined layout! Any mixing may be "
+          "unpredictable!\n");
+    }
+    stm->input_mixer.reset(cubeb_mixer_create(stm->input_stream_params.format,
+                                              stm->input_mix_params.channels,
+                                              stm->input_mix_params.layout,
+                                              stm->input_stream_params.channels,
+                                              stm->input_stream_params.layout));
+    assert(stm->input_mixer);
+  }
+
+  // Create output mixer.
+  if (has_output(stm) && stm->output_mix_params.layout != stm->output_stream_params.layout) {
+    if (stm->output_mix_params.layout == CUBEB_LAYOUT_UNDEFINED) {
+      LOG("Output stream using undefined layout! Any mixing may be unpredictable!\n");
+    }
+    stm->output_mixer.reset(cubeb_mixer_create(stm->output_stream_params.format,
+                                               stm->output_stream_params.channels,
+                                               stm->output_stream_params.layout,
+                                               stm->output_mix_params.channels,
+                                               stm->output_mix_params.layout));
+    assert(stm->output_mixer);
+    // Input is up/down mixed when depacketized in get_input_buffer.
+    stm->mix_buffer.resize(
+      frames_to_bytes_before_mix(stm, stm->output_buffer_frame_count));
+  }
+
   return CUBEB_OK;
 }
 
@@ -1894,12 +1766,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
                    unsigned int latency_frames, cubeb_data_callback data_callback,
                    cubeb_state_callback state_callback, void * user_ptr)
 {
-  HRESULT hr;
   int rv;
-  auto_com com;
-  if (!com.ok()) {
-    return CUBEB_ERROR;
-  }
 
   XASSERT(context && stream && (input_stream_params || output_stream_params));
 
@@ -1917,16 +1784,10 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
   if (input_stream_params) {
     stm->input_stream_params = *input_stream_params;
     stm->input_device = utf8_to_wstr(reinterpret_cast<char const *>(input_device));
-    // Make sure the layout matches the channel count.
-    XASSERT(stm->input_stream_params.layout == CUBEB_LAYOUT_UNDEFINED ||
-            stm->input_stream_params.channels == CUBEB_CHANNEL_LAYOUT_MAPS[stm->input_stream_params.layout].channels);
   }
   if (output_stream_params) {
     stm->output_stream_params = *output_stream_params;
     stm->output_device = utf8_to_wstr(reinterpret_cast<char const *>(output_device));
-    // Make sure the layout matches the channel count.
-    XASSERT(stm->output_stream_params.layout == CUBEB_LAYOUT_UNDEFINED ||
-            stm->output_stream_params.channels == CUBEB_CHANNEL_LAYOUT_MAPS[stm->output_stream_params.layout].channels);
   }
 
   switch (output_stream_params ? output_stream_params->format : input_stream_params->format) {
@@ -1943,9 +1804,6 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
     default:
       return CUBEB_ERROR_INVALID_FORMAT;
   }
-  stm->mixer.reset(cubeb_mixer_create(output_stream_params ? output_stream_params->format :
-                                                             input_stream_params->format,
-                                      CUBEB_MIXER_DIRECTION_DOWNMIX | CUBEB_MIXER_DIRECTION_UPMIX));
 
   stm->latency = latency_frames;
 
@@ -1979,7 +1837,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
     return rv;
   }
 
-  hr = register_notification_client(stm.get());
+  HRESULT hr = register_notification_client(stm.get());
   if (FAILED(hr)) {
     /* this is not fatal, we can still play audio, but we won't be able
        to keep using the default audio endpoint if it changes. */
@@ -2011,7 +1869,8 @@ void close_wasapi_stream(cubeb_stream * stm)
   stm->frames_written = 0;
 
   stm->resampler.reset();
-
+  stm->output_mixer.reset();
+  stm->input_mixer.reset();
   stm->mix_buffer.clear();
 }
 
@@ -2036,7 +1895,6 @@ void wasapi_stream_destroy(cubeb_stream * stm)
 
   // The variables intialized in wasapi_stream_init,
   // must be destroyed in wasapi_stream_destroy.
-  stm->mixer.reset();
   stm->linear_input_buffer.reset();
 
   {
@@ -2442,20 +2300,17 @@ static int
 wasapi_enumerate_devices(cubeb * context, cubeb_device_type type,
                          cubeb_device_collection * out)
 {
-  auto_com com;
   com_ptr<IMMDeviceEnumerator> enumerator;
   com_ptr<IMMDeviceCollection> collection;
   HRESULT hr;
   UINT cc, i;
   EDataFlow flow;
 
-  if (!com.ok())
-    return CUBEB_ERROR;
-
   hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
-      CLSCTX_INPROC_SERVER, IID_PPV_ARGS(enumerator.receive()));
+                        CLSCTX_INPROC_SERVER, IID_PPV_ARGS(enumerator.receive()));
   if (FAILED(hr)) {
     LOG("Could not get device enumerator: %lx", hr);
+    XASSERT(hr != CO_E_NOTINITIALIZED);
     return CUBEB_ERROR;
   }
 
@@ -2519,7 +2374,6 @@ cubeb_ops const wasapi_ops = {
   /*.get_max_channel_count =*/ wasapi_get_max_channel_count,
   /*.get_min_latency =*/ wasapi_get_min_latency,
   /*.get_preferred_sample_rate =*/ wasapi_get_preferred_sample_rate,
-  /*.get_preferred_channel_layout =*/ wasapi_get_preferred_channel_layout,
   /*.enumerate_devices =*/ wasapi_enumerate_devices,
   /*.device_collection_destroy =*/ wasapi_device_collection_destroy,
   /*.destroy =*/ wasapi_destroy,
diff --git a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_winmm.c b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_winmm.c
index 20dff4c7a1c87d8e29a5c82e6e3b452691142055..40c80b3e8c315f88d7e4e10a210c2252b801fa42 100644
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_winmm.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_winmm.c
@@ -1050,7 +1050,6 @@ static struct cubeb_ops const winmm_ops = {
   /*.get_max_channel_count=*/ winmm_get_max_channel_count,
   /*.get_min_latency=*/ winmm_get_min_latency,
   /*.get_preferred_sample_rate =*/ winmm_get_preferred_sample_rate,
-  /*.get_preferred_channel_layout =*/ NULL,
   /*.enumerate_devices =*/ winmm_enumerate_devices,
   /*.device_collection_destroy =*/ winmm_device_collection_destroy,
   /*.destroy =*/ winmm_destroy,
diff --git a/third_party/rust/cubeb-sys/libcubeb/test/common.h b/third_party/rust/cubeb-sys/libcubeb/test/common.h
index 1419528871c699f95e7d5273df49721c6932ae5a..43af6a95f1da2e0ce59ad28c3ba9c7fdb2003819 100644
--- a/third_party/rust/cubeb-sys/libcubeb/test/common.h
+++ b/third_party/rust/cubeb-sys/libcubeb/test/common.h
@@ -11,6 +11,7 @@
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
 #endif
+#include <objbase.h>
 #include <windows.h>
 #else
 #include <unistd.h>
@@ -44,31 +45,9 @@ void delay(unsigned int ms)
 typedef struct {
   char const * name;
   unsigned int const channels;
-  cubeb_channel_layout const layout;
+  uint32_t const layout;
 } layout_info;
 
-layout_info const layout_infos[CUBEB_LAYOUT_MAX] = {
-  { "undefined",      0,  CUBEB_LAYOUT_UNDEFINED },
-  { "dual mono",      2,  CUBEB_LAYOUT_DUAL_MONO },
-  { "dual mono lfe",  3,  CUBEB_LAYOUT_DUAL_MONO_LFE },
-  { "mono",           1,  CUBEB_LAYOUT_MONO },
-  { "mono lfe",       2,  CUBEB_LAYOUT_MONO_LFE },
-  { "stereo",         2,  CUBEB_LAYOUT_STEREO },
-  { "stereo lfe",     3,  CUBEB_LAYOUT_STEREO_LFE },
-  { "3f",             3,  CUBEB_LAYOUT_3F },
-  { "3f lfe",         4,  CUBEB_LAYOUT_3F_LFE },
-  { "2f1",            3,  CUBEB_LAYOUT_2F1 },
-  { "2f1 lfe",        4,  CUBEB_LAYOUT_2F1_LFE },
-  { "3f1",            4,  CUBEB_LAYOUT_3F1 },
-  { "3f1 lfe",        5,  CUBEB_LAYOUT_3F1_LFE },
-  { "2f2",            4,  CUBEB_LAYOUT_2F2 },
-  { "2f2 lfe",        5,  CUBEB_LAYOUT_2F2_LFE },
-  { "3f2",            5,  CUBEB_LAYOUT_3F2 },
-  { "3f2 lfe",        6,  CUBEB_LAYOUT_3F2_LFE },
-  { "3f3r lfe",       7,  CUBEB_LAYOUT_3F3R_LFE },
-  { "3f4 lfe",        8,  CUBEB_LAYOUT_3F4_LFE }
-};
-
 int has_available_input_device(cubeb * ctx)
 {
   cubeb_device_collection devices;
@@ -131,4 +110,24 @@ int common_init(cubeb ** ctx, char const * ctx_name)
   return r;
 }
 
+#if defined( _WIN32)
+class TestEnvironment : public ::testing::Environment {
+public:
+  void SetUp() override {
+    hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+  }
+
+  void TearDown() override {
+    if (SUCCEEDED(hr)) {
+      CoUninitialize();
+    }
+  }
+
+private:
+  HRESULT hr;
+};
+
+::testing::Environment* const foo_env = ::testing::AddGlobalTestEnvironment(new TestEnvironment);
+#endif
+
 #endif /* TEST_COMMON */
diff --git a/third_party/rust/cubeb-sys/libcubeb/test/test_audio.cpp b/third_party/rust/cubeb-sys/libcubeb/test/test_audio.cpp
index df513669517dd315e3d87d44d53f52f0d9b33cc4..2e6c34aafd4ef2616a52e3627789b743fb497a14 100644
--- a/third_party/rust/cubeb-sys/libcubeb/test/test_audio.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/test/test_audio.cpp
@@ -94,7 +94,7 @@ int supports_channel_count(string backend_id, int nchannels)
     (backend_id != "opensl" && backend_id != "audiotrack");
 }
 
-int run_test(int num_channels, layout_info layout, int sampling_rate, int is_float)
+int run_test(int num_channels, int sampling_rate, int is_float)
 {
   int r = CUBEB_OK;
 
@@ -116,13 +116,13 @@ int run_test(int num_channels, layout_info layout, int sampling_rate, int is_flo
     return CUBEB_OK;
   }
 
-  fprintf(stderr, "Testing %d channel(s), layout: %s, %d Hz, %s (%s)\n", num_channels, layout.name, sampling_rate, is_float ? "float" : "short", cubeb_get_backend_id(ctx));
+  fprintf(stderr, "Testing %d channel(s), %d Hz, %s (%s)\n", num_channels, sampling_rate, is_float ? "float" : "short", cubeb_get_backend_id(ctx));
 
   cubeb_stream_params params;
   params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE;
   params.rate = sampling_rate;
   params.channels = num_channels;
-  params.layout = layout.layout;
+  params.layout = CUBEB_LAYOUT_UNDEFINED;
   params.prefs = CUBEB_STREAM_PREF_NONE;
 
   synth_state synth(params.channels, params.rate);
@@ -246,12 +246,8 @@ TEST(cubeb, run_channel_rate_test)
     for(auto freq : freq_values) {
       ASSERT_TRUE(channels < MAX_NUM_CHANNELS);
       fprintf(stderr, "--------------------------\n");
-      for (auto layout : layout_infos) {
-        if (layout.channels == channels) {
-          ASSERT_EQ(run_test(channels, layout, freq, 0), CUBEB_OK);
-          ASSERT_EQ(run_test(channels, layout, freq, 1), CUBEB_OK);
-        }
-      }
+      ASSERT_EQ(run_test(channels, freq, 0), CUBEB_OK);
+      ASSERT_EQ(run_test(channels, freq, 1), CUBEB_OK);
     }
   }
 }
diff --git a/third_party/rust/cubeb-sys/libcubeb/test/test_callback_ret.cpp b/third_party/rust/cubeb-sys/libcubeb/test/test_callback_ret.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc0a89e7ebcf72460f0576ad178a0ba5d7cc702b
--- /dev/null
+++ b/third_party/rust/cubeb-sys/libcubeb/test/test_callback_ret.cpp
@@ -0,0 +1,204 @@
+/*
+* Copyright © 2017 Mozilla Foundation
+*
+* This program is made available under an ISC-style license.  See the
+* accompanying file LICENSE for details.
+*/
+
+/* libcubeb api/function test. Test that different return values from user
+   specified callbacks are handled correctly. */
+#include "gtest/gtest.h"
+#if !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 600
+#endif
+#include <memory>
+#include <atomic>
+#include <string>
+#include "cubeb/cubeb.h"
+#include "common.h"
+
+const uint32_t SAMPLE_FREQUENCY = 48000;
+const cubeb_sample_format SAMPLE_FORMAT = CUBEB_SAMPLE_S16NE;
+
+enum test_direction {
+  INPUT_ONLY,
+  OUTPUT_ONLY,
+  DUPLEX
+};
+
+// Structure which is used by data callbacks to track the total callbacks
+// executed vs the number of callbacks expected.
+struct user_state_callback_ret {
+  std::atomic<int> cb_count{ 0 };
+  std::atomic<int> expected_cb_count{ 0 };
+};
+
+// Data callback that always returns 0
+long data_cb_ret_zero(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
+{
+  user_state_callback_ret * u = (user_state_callback_ret *) user;
+  // If this is the first time the callback has been called set our expected
+  // callback count
+  if (u->cb_count == 0) {
+    u->expected_cb_count = 1;
+  }
+  u->cb_count++;
+  if (nframes < 1) {
+    // This shouldn't happen
+    EXPECT_TRUE(false) << "nframes should not be 0 in data callback!";
+  }
+  return 0;
+}
+
+// Data callback that always returns nframes - 1
+long data_cb_ret_nframes_minus_one(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
+{
+  user_state_callback_ret * u = (user_state_callback_ret *)user;
+  // If this is the first time the callback has been called set our expected
+  // callback count
+  if (u->cb_count == 0) {
+    u->expected_cb_count = 1;
+  }
+  u->cb_count++;
+  if (nframes < 1) {
+    // This shouldn't happen
+    EXPECT_TRUE(false) << "nframes should not be 0 in data callback!";
+  }
+  if (outputbuffer != NULL) {
+    // If we have an output buffer insert silence
+    short * ob = (short *) outputbuffer;
+    for (long i = 0; i < nframes - 1; i++) {
+      ob[i] = 0;
+    }
+  }
+  return nframes - 1;
+}
+
+// Data callback that always returns nframes
+long data_cb_ret_nframes(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
+{
+  user_state_callback_ret * u = (user_state_callback_ret *)user;
+  u->cb_count++;
+  // Every callback returns nframes, so every callback is expected
+  u->expected_cb_count++;
+  if (nframes < 1) {
+    // This shouldn't happen
+    EXPECT_TRUE(false) << "nframes should not be 0 in data callback!";
+  }
+  if (outputbuffer != NULL) {
+    // If we have an output buffer insert silence
+    short * ob = (short *) outputbuffer;
+    for (long i = 0; i < nframes; i++) {
+      ob[i] = 0;
+    }
+  }
+  return nframes;
+}
+
+void state_cb_ret(cubeb_stream * stream, void * /*user*/, cubeb_state state)
+{
+  if (stream == NULL)
+    return;
+
+  switch (state) {
+  case CUBEB_STATE_STARTED:
+    fprintf(stderr, "stream started\n"); break;
+  case CUBEB_STATE_STOPPED:
+    fprintf(stderr, "stream stopped\n"); break;
+  case CUBEB_STATE_DRAINED:
+    fprintf(stderr, "stream drained\n"); break;
+  default:
+    fprintf(stderr, "unknown stream state %d\n", state);
+  }
+
+  return;
+}
+
+void run_test_callback(test_direction direction,
+                       cubeb_data_callback data_cb,
+                       const std::string & test_desc) {
+  cubeb * ctx;
+  cubeb_stream * stream;
+  cubeb_stream_params input_params;
+  cubeb_stream_params output_params;
+  int r;
+  user_state_callback_ret user_state;
+  uint32_t latency_frames = 0;
+
+  r = common_init(&ctx, "Cubeb callback return value example");
+  ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
+
+  std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
+    cleanup_cubeb_at_exit(ctx, cubeb_destroy);
+
+  if ((direction == INPUT_ONLY || direction == DUPLEX) &&
+      !has_available_input_device(ctx)) {
+    /* This test needs an available input device, skip it if this host does not
+    * have one. */
+    return;
+  }
+
+  // Setup all params, but only pass them later as required by direction
+  input_params.format = SAMPLE_FORMAT;
+  input_params.rate = SAMPLE_FREQUENCY;
+  input_params.channels = 1;
+  input_params.layout = CUBEB_LAYOUT_MONO;
+  input_params.prefs = CUBEB_STREAM_PREF_NONE;
+  output_params = input_params;
+
+  r = cubeb_get_min_latency(ctx, &input_params, &latency_frames);
+  ASSERT_EQ(r, CUBEB_OK) << "Could not get minimal latency";
+
+  switch (direction)
+  {
+  case INPUT_ONLY:
+    r = cubeb_stream_init(ctx, &stream, "Cubeb callback ret input",
+                          NULL, &input_params, NULL, NULL,
+                          latency_frames, data_cb, state_cb_ret, &user_state);
+    break;
+  case OUTPUT_ONLY:
+    r = cubeb_stream_init(ctx, &stream, "Cubeb callback ret output",
+                          NULL, NULL, NULL, &output_params,
+                          latency_frames, data_cb, state_cb_ret, &user_state);
+    break;
+  case DUPLEX:
+    r = cubeb_stream_init(ctx, &stream, "Cubeb callback ret duplex",
+                          NULL, &input_params, NULL, &output_params,
+                          latency_frames, data_cb, state_cb_ret, &user_state);
+    break;
+  default:
+    ASSERT_TRUE(false) << "Unrecognized test direction!";
+  }
+  EXPECT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
+
+  std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
+    cleanup_stream_at_exit(stream, cubeb_stream_destroy);
+
+  cubeb_stream_start(stream);
+  delay(100);
+  cubeb_stream_stop(stream);
+
+  ASSERT_EQ(user_state.expected_cb_count, user_state.cb_count) <<
+    "Callback called unexpected number of times for " << test_desc << "!";
+}
+
+TEST(cubeb, test_input_callback)
+{
+  run_test_callback(INPUT_ONLY, data_cb_ret_zero, "input only, return 0");
+  run_test_callback(INPUT_ONLY, data_cb_ret_nframes_minus_one, "input only, return nframes - 1");
+  run_test_callback(INPUT_ONLY, data_cb_ret_nframes, "input only, return nframes");
+}
+
+TEST(cubeb, test_output_callback)
+{
+  run_test_callback(OUTPUT_ONLY, data_cb_ret_zero, "output only, return 0");
+  run_test_callback(OUTPUT_ONLY, data_cb_ret_nframes_minus_one, "output only, return nframes - 1");
+  run_test_callback(OUTPUT_ONLY, data_cb_ret_nframes, "output only, return nframes");
+}
+
+TEST(cubeb, test_duplex_callback)
+{
+  run_test_callback(DUPLEX, data_cb_ret_zero, "duplex, return 0");
+  run_test_callback(DUPLEX, data_cb_ret_nframes_minus_one, "duplex, return nframes - 1");
+  run_test_callback(DUPLEX, data_cb_ret_nframes, "duplex, return nframes");
+}
diff --git a/third_party/rust/cubeb-sys/libcubeb/test/test_loopback.cpp b/third_party/rust/cubeb-sys/libcubeb/test/test_loopback.cpp
index 4fe513708fa65ea878650dce12ac25fb5bc224c4..41624b7df9afcd6dd24782e247fc09da89d057a5 100644
--- a/third_party/rust/cubeb-sys/libcubeb/test/test_loopback.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/test/test_loopback.cpp
@@ -294,7 +294,7 @@ void run_loopback_duplex_test(bool is_float)
     cleanup_stream_at_exit(stream, cubeb_stream_destroy);
 
   cubeb_stream_start(stream);
-  delay(150);
+  delay(300);
   cubeb_stream_stop(stream);
 
   /* access after stop should not happen, but lock just in case and to appease sanitization tools */
@@ -377,7 +377,7 @@ void run_loopback_separate_streams_test(bool is_float)
 
   cubeb_stream_start(input_stream);
   cubeb_stream_start(output_stream);
-  delay(150);
+  delay(300);
   cubeb_stream_stop(output_stream);
   cubeb_stream_stop(input_stream);
 
@@ -444,7 +444,7 @@ void run_loopback_silence_test(bool is_float)
     cleanup_input_stream_at_exit(input_stream, cubeb_stream_destroy);
 
   cubeb_stream_start(input_stream);
-  delay(50);
+  delay(300);
   cubeb_stream_stop(input_stream);
 
   /* access after stop should not happen, but lock just in case and to appease sanitization tools */
@@ -453,7 +453,7 @@ void run_loopback_silence_test(bool is_float)
 
   /* expect to have at least ~50ms of frames */
   ASSERT_GE(input_frames.size(), SAMPLE_FREQUENCY / 20);
-  double EPISILON = 0.000001;
+  double EPISILON = 0.0001;
   /* frames should be 0.0, but use epsilon to avoid possible issues with impls
   that may use ~0.0 silence values. */
   for (double frame : input_frames) {
@@ -544,7 +544,7 @@ void run_loopback_device_selection_test(bool is_float)
 
   cubeb_stream_start(input_stream);
   cubeb_stream_start(output_stream);
-  delay(150);
+  delay(300);
   cubeb_stream_stop(output_stream);
   cubeb_stream_stop(input_stream);
 
diff --git a/third_party/rust/cubeb-sys/libcubeb/test/test_mixer.cpp b/third_party/rust/cubeb-sys/libcubeb/test/test_mixer.cpp
deleted file mode 100644
index b7daea9a9a4ac413d14fe20d8a2cc00f828a3342..0000000000000000000000000000000000000000
--- a/third_party/rust/cubeb-sys/libcubeb/test/test_mixer.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright © 2016 Mozilla Foundation
- *
- * This program is made available under an ISC-style license.  See the
- * accompanying file LICENSE for details.
- */
-#include "gtest/gtest.h"
-#include "cubeb/cubeb.h"
-#include "cubeb_mixer.h"
-#include "common.h"
-#include <memory>
-#include <vector>
-
-using std::vector;
-
-#define STREAM_FREQUENCY 48000
-#define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
-
-float const M = 1.0f;     // Mono
-float const L = 2.0f;     // Left
-float const R = 3.0f;     // Right
-float const C = 4.0f;     // Center
-float const LS = 5.0f;    // Left Surround
-float const RS = 6.0f;    // Right Surround
-float const RLS = 7.0f;   // Rear Left Surround
-float const RC = 8.0f;    // Rear Center
-float const RRS = 9.0f;   // Rear Right Surround
-float const LFE = 10.0f;  // Low Frequency Effects
-
-float const INV_SQRT_2 = 0.707106f; // 1/sqrt(2)
-static float const DOWNMIX_3F2_RESULTS[2][12][5] = {
-  // 3F2
-  {
-    { INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS) },                          // Mono
-    { INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS), 0 },                       // Mono-LFE
-    { L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS) },                 // Stereo
-    { L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS), 0 },              // Stereo-LFE
-    { L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C },                      // 3F
-    { L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C, 0 },                   // 3F-LFE
-    { L + C*INV_SQRT_2, R + C*INV_SQRT_2, INV_SQRT_2*(LS+RS) },       // 2F1
-    { L + C*INV_SQRT_2, R + C*INV_SQRT_2, 0, INV_SQRT_2*(LS+RS) },    // 2F1-LFE
-    { L, R, C, INV_SQRT_2*(LS+RS) },                                  // 3F1
-    { L, R, C, 0, INV_SQRT_2*(LS+RS) },                               // 3F1-LFE
-    { L + INV_SQRT_2*C, R + INV_SQRT_2*C, LS, RS },                   // 2F2
-    { L + INV_SQRT_2*C, R + INV_SQRT_2*C, 0, LS, RS }                 // 2F2-LFE
-  },
-  // 3F2-LFE
-  {
-    { INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS) },                          // Mono
-    { INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS), LFE },                     // Mono-LFE
-    { L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS) },                 // Stereo
-    { L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS), LFE },            // Stereo-LFE
-    { L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C },                      // 3F
-    { L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C, LFE },                 // 3F-LFE
-    { L + C*INV_SQRT_2, R + C*INV_SQRT_2, INV_SQRT_2*(LS+RS) },       // 2F1
-    { L + C*INV_SQRT_2, R + C*INV_SQRT_2, LFE, INV_SQRT_2*(LS+RS) },  // 2F1-LFE
-    { L, R, C, INV_SQRT_2*(LS+RS) },                                  // 3F1
-    { L, R, C, LFE, INV_SQRT_2*(LS+RS) },                             // 3F1-LFE
-    { L + INV_SQRT_2*C, R + INV_SQRT_2*C, LS, RS },                   // 2F2
-    { L + INV_SQRT_2*C, R + INV_SQRT_2*C, LFE, LS, RS }               // 2F2-LFE
-  }
-};
-
-typedef struct {
-  cubeb_channel_layout layout;
-  float data[10];
-} audio_input;
-
-audio_input audio_inputs[CUBEB_LAYOUT_MAX] = {
-  { CUBEB_LAYOUT_UNDEFINED,     { } },
-  { CUBEB_LAYOUT_DUAL_MONO,     { L, R } },
-  { CUBEB_LAYOUT_DUAL_MONO_LFE, { L, R, LFE } },
-  { CUBEB_LAYOUT_MONO,          { M } },
-  { CUBEB_LAYOUT_MONO_LFE,      { M, LFE } },
-  { CUBEB_LAYOUT_STEREO,        { L, R } },
-  { CUBEB_LAYOUT_STEREO_LFE,    { L, R, LFE } },
-  { CUBEB_LAYOUT_3F,            { L, R, C } },
-  { CUBEB_LAYOUT_3F_LFE,        { L, R, C, LFE } },
-  { CUBEB_LAYOUT_2F1,           { L, R, RC } },
-  { CUBEB_LAYOUT_2F1_LFE,       { L, R, LFE, RC } },
-  { CUBEB_LAYOUT_3F1,           { L, R, C, RC } },
-  { CUBEB_LAYOUT_3F1_LFE,       { L, R, C, LFE, RC } },
-  { CUBEB_LAYOUT_2F2,           { L, R, LS, RS } },
-  { CUBEB_LAYOUT_2F2_LFE,       { L, R, LFE, LS, RS } },
-  { CUBEB_LAYOUT_3F2,           { L, R, C, LS, RS } },
-  { CUBEB_LAYOUT_3F2_LFE,       { L, R, C, LFE, LS, RS } },
-  { CUBEB_LAYOUT_3F3R_LFE,      { L, R, C, LFE, RC, LS, RS } },
-  { CUBEB_LAYOUT_3F4_LFE,       { L, R, C, LFE, RLS, RRS, LS, RS } }
-};
-
-char const * channel_names[CHANNEL_UNMAPPED + 1] = {
-  "mono",                   // CHANNEL_MONO
-  "left",                   // CHANNEL_LEFT
-  "right",                  // CHANNEL_RIGHT
-  "center",                 // CHANNEL_CENTER
-  "left surround",          // CHANNEL_LS
-  "right surround",         // CHANNEL_RS
-  "rear left surround",     // CHANNEL_RLS
-  "rear center",            // CHANNEL_RCENTER
-  "rear right surround",    // CHANNEL_RRS
-  "low frequency effects",  // CHANNEL_LFE
-  "unmapped"                // CHANNEL_UNMAPPED
-};
-
-// The test cases must be aligned with cubeb_downmix.
-void
-downmix_test(float const * data, cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
-{
-  if (in_layout == CUBEB_LAYOUT_UNDEFINED) {
-    return; // Only possible output layout would be UNDEFINED.
-  }
-
-  cubeb_stream_params in_params = {
-    STREAM_FORMAT,
-    STREAM_FREQUENCY,
-    layout_infos[in_layout].channels,
-    in_layout,
-    CUBEB_STREAM_PREF_NONE
-  };
-
-  cubeb_stream_params out_params = {
-    STREAM_FORMAT,
-    STREAM_FREQUENCY,
-    // To downmix audio data with undefined layout, its channel number must be
-    // smaller than or equal to the input channels.
-    (out_layout == CUBEB_LAYOUT_UNDEFINED) ?
-      layout_infos[in_layout].channels : layout_infos[out_layout].channels,
-    out_layout,
-    CUBEB_STREAM_PREF_NONE
-   };
-
-  if (!cubeb_should_downmix(&in_params, &out_params)) {
-    return;
-  }
-
-  fprintf(stderr, "Downmix from %s to %s\n", layout_infos[in_layout].name, layout_infos[out_layout].name);
-
-  unsigned int const inframes = 10;
-  vector<float> in(in_params.channels * inframes);
-#if defined(__APPLE__)
-  // The mixed buffer size doesn't be changed based on the channel layout set on OSX.
-  // Please see the comment above downmix_3f2 in cubeb_mixer.cpp.
-  vector<float> out(in_params.channels * inframes);
-#else
-  // In normal case, the mixed buffer size is based on the mixing channel layout.
-  vector<float> out(out_params.channels * inframes);
-#endif
-
-  for (unsigned int offset = 0 ; offset < inframes * in_params.channels ; offset += in_params.channels) {
-    for (unsigned int i = 0 ; i < in_params.channels ; ++i) {
-      in[offset + i] = data[i];
-    }
-  }
-
-  // Create a mixer for downmix only.
-  std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)>
-    mixer(cubeb_mixer_create(in_params.format, CUBEB_MIXER_DIRECTION_DOWNMIX), cubeb_mixer_destroy);
-
-  assert(!in.empty() && !out.empty() && out.size() <= in.size());
-  cubeb_mixer_mix(mixer.get(), inframes, in.data(), in.size(), out.data(), out.size(), &in_params, &out_params);
-
-  uint32_t in_layout_mask = 0;
-  for (unsigned int i = 0 ; i < in_params.channels; ++i) {
-    in_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[in_layout][i];
-  }
-
-  uint32_t out_layout_mask = 0;
-  for (unsigned int i = 0 ; out_layout != CUBEB_LAYOUT_UNDEFINED && i < out_params.channels; ++i) {
-    out_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[out_layout][i];
-  }
-
-  for (unsigned int i = 0 ; i < out.size() ; ++i) {
-    assert(in_params.channels && out_params.channels); // to pass the scan-build warning: Division by zero.
-#if defined(__APPLE__)
-    // The size of audio mix buffer(vector out above) on OS X is same as input,
-    // so we need to check whether the out[i] will be dropped or not.
-    unsigned int index = i % in_params.channels;
-    if (index >= out_params.channels) {
-      // The out[i] will be dropped, so we don't care the data inside.
-      fprintf(stderr, "\tOS X: %d will be dropped. Ignore it.\n", i);
-      continue;
-    }
-#else
-    unsigned int index = i % out_params.channels;
-#endif
-
-    // downmix_3f2
-    if ((in_layout == CUBEB_LAYOUT_3F2 || in_layout == CUBEB_LAYOUT_3F2_LFE) &&
-        out_layout >= CUBEB_LAYOUT_MONO && out_layout <= CUBEB_LAYOUT_2F2_LFE) {
-      auto & downmix_results = DOWNMIX_3F2_RESULTS[in_layout - CUBEB_LAYOUT_3F2][out_layout - CUBEB_LAYOUT_MONO];
-      fprintf(stderr, "\t[3f2] %d(%s) - Expect: %lf, Get: %lf\n", i, channel_names[ CHANNEL_INDEX_TO_ORDER[out_layout][index] ], downmix_results[index], out[i]);
-      ASSERT_EQ(downmix_results[index], out[i]);
-      continue;
-    }
-
-#if defined(__APPLE__)
-    fprintf(stderr, "\tOS X: We only support downmix for audio 5.1 currently.\n");
-    return;
-#endif
-
-    // mix_remap
-    if (out_layout_mask & in_layout_mask) {
-      uint32_t mask = 1 << CHANNEL_INDEX_TO_ORDER[out_layout][index];
-      fprintf(stderr, "\t[remap] %d(%s) - Expect: %lf, Get: %lf\n", i, channel_names[ CHANNEL_INDEX_TO_ORDER[out_layout][index] ], (mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[i]);
-      ASSERT_EQ((mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[i]);
-      continue;
-    }
-
-    // downmix_fallback
-    fprintf(stderr, "\t[fallback] %d - Expect: %lf, Get: %lf\n", i, audio_inputs[in_layout].data[index], out[i]);
-    ASSERT_EQ(audio_inputs[in_layout].data[index], out[i]);
-  }
-}
-
-TEST(cubeb, mixer)
-{
-  for (auto audio_input : audio_inputs) {
-    for (auto audio_output : layout_infos) {
-      downmix_test(audio_input.data, audio_input.layout, audio_output.layout);
-    }
-  }
-}
diff --git a/third_party/rust/cubeb-sys/libcubeb/test/test_sanity.cpp b/third_party/rust/cubeb-sys/libcubeb/test/test_sanity.cpp
index d3546d6f0cbbb6c73f99cf7584b65bbae4ce22cb..d33666f22f52a5e842554b5eb13a8c8d60655a34 100644
--- a/third_party/rust/cubeb-sys/libcubeb/test/test_sanity.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/test/test_sanity.cpp
@@ -114,7 +114,6 @@ TEST(cubeb, context_variables)
   int r;
   cubeb * ctx;
   uint32_t value;
-  cubeb_channel_layout layout;
   cubeb_stream_params params;
 
   r = common_init(&ctx, "test_context_variables");
@@ -139,11 +138,6 @@ TEST(cubeb, context_variables)
     ASSERT_TRUE(value > 0);
   }
 
-  r = cubeb_get_preferred_channel_layout(ctx, &layout);
-  ASSERT_TRUE(r == CUBEB_ERROR_NOT_SUPPORTED ||
-              (r == CUBEB_OK && layout != CUBEB_LAYOUT_UNDEFINED) ||
-              (r == CUBEB_ERROR && layout == CUBEB_LAYOUT_UNDEFINED));
-
   cubeb_destroy(ctx);
 }
 
diff --git a/third_party/rust/cubeb-sys/src/channel.rs b/third_party/rust/cubeb-sys/src/channel.rs
index ba7cda852fbeaae095ada617ad2d80d15385f661..d802c1f1e328477b97c640e2c462f35e72813761 100644
--- a/third_party/rust/cubeb-sys/src/channel.rs
+++ b/third_party/rust/cubeb-sys/src/channel.rs
@@ -3,78 +3,67 @@
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
-use std::{fmt, mem};
-use std::os::raw::{c_int, c_uint};
+use std::os::raw::c_uint;
 
 cubeb_enum! {
-    pub enum cubeb_channel : c_int {
-        CHANNEL_INVALID = -1,
-        CHANNEL_MONO = 0,
-        CHANNEL_LEFT,
-        CHANNEL_RIGHT,
-        CHANNEL_CENTER,
-        CHANNEL_LS,
-        CHANNEL_RS,
-        CHANNEL_RLS,
-        CHANNEL_RCENTER,
-        CHANNEL_RRS,
-        CHANNEL_LFE,
-        CHANNEL_UNMAPPED,
-        CHANNEL_MAX = 256,
+    pub enum cubeb_channel : c_uint {
+        CHANNEL_UNKNOWN = 0,
+        CHANNEL_FRONT_LEFT = 1 << 0,
+        CHANNEL_FRONT_RIGHT = 1 << 1,
+        CHANNEL_FRONT_CENTER = 1 << 2,
+        CHANNEL_LOW_FREQUENCY = 1 << 3,
+        CHANNEL_BACK_LEFT = 1 << 4,
+        CHANNEL_BACK_RIGHT = 1 << 5,
+        CHANNEL_FRONT_LEFT_OF_CENTER = 1 << 6,
+        CHANNEL_FRONT_RIGHT_OF_CENTER = 1 << 7,
+        CHANNEL_BACK_CENTER = 1 << 8,
+        CHANNEL_SIDE_LEFT = 1 << 9,
+        CHANNEL_SIDE_RIGHT = 1 << 10,
+        CHANNEL_TOP_CENTER = 1 << 11,
+        CHANNEL_TOP_FRONT_LEFT = 1 << 12,
+        CHANNEL_TOP_FRONT_CENTER = 1 << 13,
+        CHANNEL_TOP_FRONT_RIGHT = 1 << 14,
+        CHANNEL_TOP_BACK_LEFT = 1 << 15,
+        CHANNEL_TOP_BACK_CENTER = 1 << 16,
+        CHANNEL_TOP_BACK_RIGHT = 1 << 17,
     }
 }
 
 cubeb_enum! {
     pub enum cubeb_channel_layout {
-        CUBEB_LAYOUT_UNDEFINED,
-
-        CUBEB_LAYOUT_DUAL_MONO,
-        CUBEB_LAYOUT_DUAL_MONO_LFE,
-        CUBEB_LAYOUT_MONO,
-        CUBEB_LAYOUT_MONO_LFE,
-        CUBEB_LAYOUT_STEREO,
-        CUBEB_LAYOUT_STEREO_LFE,
-        CUBEB_LAYOUT_3F,
-        CUBEB_LAYOUT_3F_LFE,
-        CUBEB_LAYOUT_2F1,
-        CUBEB_LAYOUT_2F1_LFE,
-        CUBEB_LAYOUT_3F1,
-        CUBEB_LAYOUT_3F1_LFE,
-        CUBEB_LAYOUT_2F2,
-        CUBEB_LAYOUT_2F2_LFE,
-        CUBEB_LAYOUT_3F2,
-        CUBEB_LAYOUT_3F2_LFE,
-        CUBEB_LAYOUT_3F3R_LFE,
-        CUBEB_LAYOUT_3F4_LFE,
-        CUBEB_LAYOUT_MAX,
-    }
-}
-
-#[repr(C)]
-#[derive(Clone, Copy)]
-pub struct cubeb_channel_map {
-    pub channels: c_uint,
-    pub map: [cubeb_channel; CHANNEL_MAX as usize],
-}
-
-impl Default for cubeb_channel_map {
-    fn default() -> Self {
-        unsafe { mem::zeroed() }
+        CUBEB_LAYOUT_UNDEFINED = 0,
+        CUBEB_LAYOUT_MONO = CHANNEL_FRONT_CENTER,
+        CUBEB_LAYOUT_MONO_LFE = CUBEB_LAYOUT_MONO | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_STEREO = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT,
+        CUBEB_LAYOUT_STEREO_LFE = CUBEB_LAYOUT_STEREO | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_3F = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                          CHANNEL_FRONT_CENTER,
+        CUBEB_LAYOUT_3F_LFE = CUBEB_LAYOUT_3F | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_2F1 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                           CHANNEL_BACK_CENTER,
+        CUBEB_LAYOUT_2F1_LFE = CUBEB_LAYOUT_2F1 | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_3F1 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                           CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER,
+        CUBEB_LAYOUT_3F1_LFE = CUBEB_LAYOUT_3F1 | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_2F2 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                           CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT,
+        CUBEB_LAYOUT_2F2_LFE = CUBEB_LAYOUT_2F2 | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_QUAD = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                            CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT,
+        CUBEB_LAYOUT_QUAD_LFE = CUBEB_LAYOUT_QUAD | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_3F2 = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                           CHANNEL_FRONT_CENTER | CHANNEL_SIDE_LEFT |
+                           CHANNEL_SIDE_RIGHT,
+        CUBEB_LAYOUT_3F2_LFE = CUBEB_LAYOUT_3F2 | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_3F2_BACK = CUBEB_LAYOUT_QUAD | CHANNEL_FRONT_CENTER,
+        CUBEB_LAYOUT_3F2_LFE_BACK = CUBEB_LAYOUT_3F2_BACK | CHANNEL_LOW_FREQUENCY,
+        CUBEB_LAYOUT_3F3R_LFE = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                                CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
+                                CHANNEL_BACK_CENTER | CHANNEL_SIDE_LEFT |
+                                CHANNEL_SIDE_RIGHT,
+        CUBEB_LAYOUT_3F4_LFE = CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+                               CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
+                               CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT |
+                               CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT,
     }
 }
-
-// Explicit Debug impl to work around bug in ctest
-impl fmt::Debug for cubeb_channel_map {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_struct("cubeb_channel_map")
-            .field("channels", &self.channels)
-            .field("map", &self.map.iter().take(self.channels as usize))
-            .finish()
-    }
-}
-
-extern "C" {
-    pub fn cubeb_channel_map_to_layout(
-        channel_map: *const cubeb_channel_map,
-    ) -> cubeb_channel_layout;
-}
diff --git a/third_party/rust/cubeb-sys/src/context.rs b/third_party/rust/cubeb-sys/src/context.rs
index 4afe2a7a799d37f0fccf61884eca02dccb7bcf11..b7f6e1193e7f963aa85355e93a587958fdedf4db 100644
--- a/third_party/rust/cubeb-sys/src/context.rs
+++ b/third_party/rust/cubeb-sys/src/context.rs
@@ -4,7 +4,6 @@
 // accompanying file LICENSE for details.
 
 use callbacks::{cubeb_data_callback, cubeb_state_callback};
-use channel::cubeb_channel_layout;
 use device::cubeb_devid;
 use std::os::raw::{c_char, c_int, c_uint, c_void};
 use stream::{cubeb_stream, cubeb_stream_params};
@@ -25,10 +24,6 @@ extern "C" {
         latency_frames: *mut c_uint,
     ) -> c_int;
     pub fn cubeb_get_preferred_sample_rate(context: *mut cubeb, rate: *mut c_uint) -> c_int;
-    pub fn cubeb_get_preferred_channel_layout(
-        context: *mut cubeb,
-        layout: *mut cubeb_channel_layout,
-    ) -> c_int;
     pub fn cubeb_destroy(context: *mut cubeb);
     pub fn cubeb_stream_init(
         context: *mut cubeb,
diff --git a/third_party/rust/cubeb-sys/src/mixer.rs b/third_party/rust/cubeb-sys/src/mixer.rs
index 99a39804f62932ddeb8abd98172e578f2b50b23a..25597cdbd4103a6cd93976604bec4b5266ed40cb 100644
--- a/third_party/rust/cubeb-sys/src/mixer.rs
+++ b/third_party/rust/cubeb-sys/src/mixer.rs
@@ -3,47 +3,29 @@
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
-use channel::{cubeb_channel, CHANNEL_MAX, CUBEB_LAYOUT_MAX};
+use channel::cubeb_channel_layout;
 use format::cubeb_sample_format;
-use std::os::raw::{c_long, c_uchar, c_ulong, c_void};
-use stream::cubeb_stream_params;
-
-cubeb_enum! {
-    pub enum cubeb_mixer_direction {
-        CUBEB_MIXER_DIRECTION_DOWNMIX = 0x01,
-        CUBEB_MIXER_DIRECTION_UPMIX = 0x02,
-    }
-}
+use std::os::raw::{c_int, c_uint, c_void};
 
 pub enum cubeb_mixer {}
 
 extern "C" {
-    pub fn cubeb_should_upmix(
-        stream: *const cubeb_stream_params,
-        mixer: *const cubeb_stream_params,
-    ) -> bool;
-    pub fn cubeb_should_downmix(
-        stream: *const cubeb_stream_params,
-        mixer: *const cubeb_stream_params,
-    ) -> bool;
-    pub fn cubeb_should_mix(
-        stream: *const cubeb_stream_params,
-        mixer: *const cubeb_stream_params,
-    ) -> bool;
-
-    pub fn cubeb_mixer_create(format: cubeb_sample_format, direction: c_uchar) -> *mut cubeb_mixer;
+    pub fn cubeb_mixer_create(
+        format: cubeb_sample_format,
+        in_channels: u32,
+        in_layout: cubeb_channel_layout,
+        out_channels: u32,
+        out_layout: cubeb_channel_layout,
+    ) -> *mut cubeb_mixer;
     pub fn cubeb_mixer_destroy(mixer: *mut cubeb_mixer);
     pub fn cubeb_mixer_mix(
         mixer: *mut cubeb_mixer,
-        frames: c_long,
+        frames: usize,
         input_buffer: *mut c_void,
-        input_buffer_length: c_ulong,
+        input_buffer_length: usize,
         output_buffer: *mut c_void,
-        output_buffer_length: c_ulong,
-        stream_params: *const cubeb_stream_params,
-        mixer_params: *const cubeb_stream_params,
-    );
+        output_buffer_length: usize,
+    ) -> c_int;
 
-    pub static CHANNEL_INDEX_TO_ORDER:
-        [[cubeb_channel; CHANNEL_MAX as usize]; CUBEB_LAYOUT_MAX as usize];
+    pub fn cubeb_channel_layout_nb_channels(channel_layout: cubeb_channel_layout) -> c_uint;
 }
diff --git a/third_party/rust/cubeb/.cargo-checksum.json b/third_party/rust/cubeb/.cargo-checksum.json
index ef537054d2e35fda8496a8990cf6937d359e3eac..e770624abdf4350bf7f8ed6048d7397b8b1d7606 100644
--- a/third_party/rust/cubeb/.cargo-checksum.json
+++ b/third_party/rust/cubeb/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"bbdd7a6000f97f9dda6fd9234dd39eead1ab035994fc0423529bba952a927e89","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","README.md":"408c573ec240927cf5b9c036098e94e374ec41f71991415422586f450586b214","examples/common/mod.rs":"a5e1b79fc2b4addff1e442879ba3dbcb1cf5973e76b9a62d97dd0042597480db","examples/devices.rs":"89e13542853995d1ae4a49d6829156efb29dd25c6caffdf22496c28c8263ffeb","examples/tone.rs":"ca5f609374c891c2134e7b208a3b2c31e433e6fc9121c7f9b755c1a38121bd67","src/context.rs":"03511fa960a411728163e700edc2fd6cfbfcf09766ffe62ee82a2cbd08fdf243","src/frame.rs":"ed1e8f4576022d0c23106bb115125e5a2967b0375a10d0c54bbe99f04a70cc3f","src/lib.rs":"98e9280890551ac9305f2f808e315b6aa6bcd5781b8e96a078787ded0ef91e2a","src/log.rs":"af1d787754706e34d6b8f4ac88aa89078ae9a16970b168ad8dc17cc4180688c2","src/sample.rs":"e23be3b691052001916f920ce9c1a0051bd097e39c9d34cbcb80ab8120265f45","src/stream.rs":"b01bcdce3b89b5f93d485c52350129a8ca7a98d2255246eab9d0b0184dca7986","src/try_call.rs":"37701edc461178fc2025c282ca0e5691bcb4dabeec916204a6eb9f0f439c0af4","src/util.rs":"9b09a4247c2eace2da1e7a946d2319cc95563040a05862acb73d2688bed268a8"},"package":"ed237804b9799d1c29089e6cab3f4b7160186179981a61865feff13d55a902f8"}
\ No newline at end of file
+{"files":{"Cargo.toml":"a2c6655c60b3df90ea552b24c6316cbfdf7b2b915e960ce7c03abdcdb73c92ff","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","README.md":"408c573ec240927cf5b9c036098e94e374ec41f71991415422586f450586b214","examples/common/mod.rs":"a5e1b79fc2b4addff1e442879ba3dbcb1cf5973e76b9a62d97dd0042597480db","examples/devices.rs":"89e13542853995d1ae4a49d6829156efb29dd25c6caffdf22496c28c8263ffeb","examples/tone.rs":"8f5f9851b6d99f6f16c597fcb9312e3ef81769cbfb89341d2ea2522ca2e2214e","src/context.rs":"03511fa960a411728163e700edc2fd6cfbfcf09766ffe62ee82a2cbd08fdf243","src/frame.rs":"ed1e8f4576022d0c23106bb115125e5a2967b0375a10d0c54bbe99f04a70cc3f","src/lib.rs":"98e9280890551ac9305f2f808e315b6aa6bcd5781b8e96a078787ded0ef91e2a","src/log.rs":"af1d787754706e34d6b8f4ac88aa89078ae9a16970b168ad8dc17cc4180688c2","src/sample.rs":"e23be3b691052001916f920ce9c1a0051bd097e39c9d34cbcb80ab8120265f45","src/stream.rs":"3e2c7ec590bed0eb740057a89a4dc254fe962f402e6ed316308152d96bd1288a"},"package":"7923bed2d5a1a64ba0c3e8b6badc360508ba488d1f2f59f16a688802e755bb85"}
\ No newline at end of file
diff --git a/third_party/rust/cubeb/Cargo.toml b/third_party/rust/cubeb/Cargo.toml
index 2b574c7c75c8abf660f264e17d5ba74bfe96548b..9f5e1dcd775d8920054326e1af840b9cc873ff15 100644
--- a/third_party/rust/cubeb/Cargo.toml
+++ b/third_party/rust/cubeb/Cargo.toml
@@ -12,7 +12,7 @@
 
 [package]
 name = "cubeb"
-version = "0.4.1"
+version = "0.5.0"
 authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
 description = "Bindings to libcubeb for interacting with system audio from rust.\n"
 homepage = "https://github.com/djg/cubeb-rs"
@@ -22,7 +22,7 @@ categories = ["api-bindings"]
 license = "ISC"
 repository = "https://github.com/djg/cubeb-rs"
 [dependencies.cubeb-core]
-version = "0.4.1"
+version = "0.5.0"
 
 [features]
 gecko-in-tree = ["cubeb-core/gecko-in-tree"]
diff --git a/third_party/rust/cubeb/examples/tone.rs b/third_party/rust/cubeb/examples/tone.rs
index 0fb6e3f402779df5aed5ea6902ae897103b070e7..97e940bc9490f37aa4175546cc104d4bc6abdfef 100644
--- a/third_party/rust/cubeb/examples/tone.rs
+++ b/third_party/rust/cubeb/examples/tone.rs
@@ -25,7 +25,7 @@ fn main() {
         .format(STREAM_FORMAT)
         .rate(SAMPLE_FREQUENCY)
         .channels(1)
-        .layout(cubeb::ChannelLayout::Mono)
+        .layout(cubeb::ChannelLayout::MONO)
         .take();
 
     let mut position = 0u32;
diff --git a/third_party/rust/cubeb/src/stream.rs b/third_party/rust/cubeb/src/stream.rs
index e02a063abeeaebe6864f4d6aee6bb0e777160baa..a5329a5ba6317b510beb9ef269557ebb2baef990 100644
--- a/third_party/rust/cubeb/src/stream.rs
+++ b/third_party/rust/cubeb/src/stream.rs
@@ -20,7 +20,7 @@
 //!         .format(cubeb::SampleFormat::Float32LE)
 //!         .rate(44_100)
 //!         .channels(1)
-//!         .layout(cubeb::ChannelLayout::Mono)
+//!         .layout(cubeb::ChannelLayout::MONO)
 //!         .prefs(cubeb::StreamPrefs::NONE)
 //!         .take();
 //!
diff --git a/third_party/rust/cubeb/src/try_call.rs b/third_party/rust/cubeb/src/try_call.rs
deleted file mode 100644
index 9d49c5b12dfde256dc4168b5712030905ad18973..0000000000000000000000000000000000000000
--- a/third_party/rust/cubeb/src/try_call.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright © 2017-2018 Mozilla Foundation
-//
-// This program is made available under an ISC-style license.  See the
-// accompanying file LICENSE for details.
-
-use Error;
-use std::os::raw::c_int;
-
-pub fn cvt_r(ret: c_int) -> Result<(), Error> {
-    match ret {
-        n if n < 0 => Err(unsafe { Error::from_raw(n) }),
-        _ => Ok(()),
-    }
-}
-
-macro_rules! try_call {
-    (raw::$p:ident ($($e:expr),*)) => ({
-        match ::try_call::cvt_r(ffi::$p($($e),*)) {
-            Ok(o) => o,
-            Err(e) => { return Err(e) }
-        }
-    })
-}
diff --git a/third_party/rust/cubeb/src/util.rs b/third_party/rust/cubeb/src/util.rs
deleted file mode 100644
index 5aedf9aa330e8b7eb055fbba3a7f9ee1a4ddcca6..0000000000000000000000000000000000000000
--- a/third_party/rust/cubeb/src/util.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright © 2017 Mozilla Foundation
-//
-// This program is made available under an ISC-style license.  See the
-// accompanying file LICENSE for details.
-
-use cubeb_core::Error;
-use ffi;
-use std::ffi::CString;
-
-/// A class of types that can be converted to C strings.
-///
-/// These types are represented internally as byte slices and it is quite rare
-/// for them to contain an interior 0 byte.
-pub trait IntoCString {
-    /// Consume this container, converting it into a CString
-    fn into_c_string(self) -> Result<CString, Error>;
-}
-
-impl<'a, T: IntoCString + Clone> IntoCString for &'a T {
-    fn into_c_string(self) -> Result<CString, Error> { self.clone().into_c_string() }
-}
-
-impl<'a> IntoCString for &'a str {
-    fn into_c_string(self) -> Result<CString, Error> {
-        match CString::new(self) {
-            Ok(s) => Ok(s),
-            Err(_) => Err(unsafe { Error::from_raw(ffi::CUBEB_ERROR) }),
-        }
-    }
-}
-
-impl IntoCString for String {
-    fn into_c_string(self) -> Result<CString, Error> {
-        match CString::new(self.into_bytes()) {
-            Ok(s) => Ok(s),
-            Err(_) => Err(unsafe { Error::from_raw(ffi::CUBEB_ERROR) }),
-        }
-    }
-}
-
-impl IntoCString for CString {
-    fn into_c_string(self) -> Result<CString, Error> { Ok(self) }
-}
-
-impl IntoCString for Vec<u8> {
-    fn into_c_string(self) -> Result<CString, Error> { Ok(try!(CString::new(self))) }
-}
diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml
index e02d948a0afe771b6776758e4cded9a45401fa29..55b150887507323efc7a7b2cc7bc909baa330dac 100644
--- a/toolkit/library/rust/shared/Cargo.toml
+++ b/toolkit/library/rust/shared/Cargo.toml
@@ -16,7 +16,7 @@ prefs_parser = { path = "../../../../modules/libpref/parser" }
 rust_url_capi = { path = "../../../../netwerk/base/rust-url-capi" }
 webrender_bindings = { path = "../../../../gfx/webrender_bindings", optional = true }
 cubeb-pulse = { path = "../../../../media/libcubeb/cubeb-pulse-rs", optional = true, features=["pulse-dlopen"] }
-cubeb-sys = { version = "0.4.1", optional = true, features=["gecko-in-tree"] }
+cubeb-sys = { version = "0.5.0", optional = true, features=["gecko-in-tree"] }
 encoding_c = "0.8.0"
 encoding_glue = { path = "../../../../intl/encoding_glue" }
 audioipc-client = { path = "../../../../media/audioipc/client", optional = true }