Bug 1432779 - Rust vendor. r=jya
authorDan Glastonbury <dan.glastonbury@gmail.com>
Thu, 22 Mar 2018 20:10:19 +1000
changeset 465876 2bbfded200e002b399c3fc2ed208b8bbe02291b9
parent 465875 b98af64fa15c8e3ab4b5a7c13d25cb41723e098b
child 465877 0b1a55a9b166defe144d6b11a8e4adff29709a5a
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1432779
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1432779 - Rust vendor. r=jya MozReview-Commit-ID: 5FQjIPBWTEZ
Cargo.lock
third_party/rust/cubeb-backend/.cargo-checksum.json
third_party/rust/cubeb-backend/Cargo.toml
third_party/rust/cubeb-backend/src/capi.rs
third_party/rust/cubeb-backend/src/ops.rs
third_party/rust/cubeb-backend/src/traits.rs
third_party/rust/cubeb-backend/tests/test_capi.rs
third_party/rust/cubeb-core/.cargo-checksum.json
third_party/rust/cubeb-core/Cargo.toml
third_party/rust/cubeb-core/src/builders.rs
third_party/rust/cubeb-core/src/channel.rs
third_party/rust/cubeb-core/src/context.rs
third_party/rust/cubeb-core/src/stream.rs
third_party/rust/cubeb-sys/.cargo-checksum.json
third_party/rust/cubeb-sys/Cargo.toml
third_party/rust/cubeb-sys/libcubeb/CMakeLists.txt
third_party/rust/cubeb-sys/libcubeb/include/cubeb/cubeb.h
third_party/rust/cubeb-sys/libcubeb/src/android/cubeb-output-latency.h
third_party/rust/cubeb-sys/libcubeb/src/android/cubeb_media_library.h
third_party/rust/cubeb-sys/libcubeb/src/cubeb-internal.h
third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni-instances.h
third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni.cpp
third_party/rust/cubeb-sys/libcubeb/src/cubeb-jni.h
third_party/rust/cubeb-sys/libcubeb/src/cubeb.c
third_party/rust/cubeb-sys/libcubeb/src/cubeb_alsa.c
third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiotrack.c
third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiounit.cpp
third_party/rust/cubeb-sys/libcubeb/src/cubeb_jack.cpp
third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.cpp
third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.h
third_party/rust/cubeb-sys/libcubeb/src/cubeb_opensl.c
third_party/rust/cubeb-sys/libcubeb/src/cubeb_pulse.c
third_party/rust/cubeb-sys/libcubeb/src/cubeb_sndio.c
third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.cpp
third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.h
third_party/rust/cubeb-sys/libcubeb/src/cubeb_wasapi.cpp
third_party/rust/cubeb-sys/libcubeb/src/cubeb_winmm.c
third_party/rust/cubeb-sys/libcubeb/test/common.h
third_party/rust/cubeb-sys/libcubeb/test/test_audio.cpp
third_party/rust/cubeb-sys/libcubeb/test/test_callback_ret.cpp
third_party/rust/cubeb-sys/libcubeb/test/test_loopback.cpp
third_party/rust/cubeb-sys/libcubeb/test/test_mixer.cpp
third_party/rust/cubeb-sys/libcubeb/test/test_sanity.cpp
third_party/rust/cubeb-sys/src/channel.rs
third_party/rust/cubeb-sys/src/context.rs
third_party/rust/cubeb-sys/src/mixer.rs
third_party/rust/cubeb/.cargo-checksum.json
third_party/rust/cubeb/Cargo.toml
third_party/rust/cubeb/examples/tone.rs
third_party/rust/cubeb/src/stream.rs
third_party/rust/cubeb/src/try_call.rs
third_party/rust/cubeb/src/util.rs
toolkit/library/rust/shared/Cargo.toml
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -45,57 +45,57 @@ source = "registry+https://github.com/ru
 dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[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)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[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)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 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)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -401,52 +401,52 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[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)",
 ]
 
 [[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)",
  "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -719,21 +719,21 @@ dependencies = [
  "nsstring-gtest 0.1.0",
  "xpcom-gtest 0.1.0",
 ]
 
 [[package]]
 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",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "mp4parse_capi 0.10.0",
  "netwerk_helper 0.0.1",
  "nserror 0.1.0",
  "nsstring 0.1.0",
@@ -2217,20 +2217,20 @@ dependencies = [
 "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
 "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
 "checksum crossbeam-epoch 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "59796cc6cbbdc6bb319161349db0c3250ec73ec7fcb763a51065ec4e2e158552"
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
 "checksum cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a807ac3ab7a217829c2a3b65732b926b2befe6a35f33b4bf8b503692430f223"
 "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"
 "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
 "checksum dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a207eb7b40e25d1d28dc679f451d321fb6954b73ceaa47986702575865469461"
 "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
--- a/third_party/rust/cubeb-backend/.cargo-checksum.json
+++ b/third_party/rust/cubeb-backend/.cargo-checksum.json
@@ -1,1 +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
--- a/third_party/rust/cubeb-backend/Cargo.toml
+++ b/third_party/rust/cubeb-backend/Cargo.toml
@@ -7,23 +7,23 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [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"
 keywords = ["cubeb"]
 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"]
 [badges.circle-ci]
 repository = "djg/cubeb-rs"
--- a/third_party/rust/cubeb-backend/src/capi.rs
+++ b/third_party/rust/cubeb-backend/src/capi.rs
@@ -33,18 +33,16 @@ macro_rules! as_opt_ref {
 macro_rules! capi_new(
     ($ctx:ident, $stm:ident) => (
         Ops {
             init: Some($crate::capi::capi_init::<$ctx>),
             get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
             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>),
             stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
             stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
             stream_start: Some($crate::capi::capi_stream_start::<$stm>),
             stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
             stream_reset_default_device:
@@ -104,26 +102,16 @@ pub unsafe extern "C" fn capi_get_prefer
     rate: *mut u32,
 ) -> c_int {
     let ctx = &mut *(c as *mut CTX);
 
     *rate = _try!(ctx.preferred_sample_rate());
     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,
     collection: *mut ffi::cubeb_device_collection,
 ) -> c_int {
     let ctx = &mut *(c as *mut CTX);
     let devtype = DeviceType::from_bits_truncate(devtype);
     let collection = DeviceCollectionRef::from_ptr(collection);
--- a/third_party/rust/cubeb-backend/src/ops.rs
+++ b/third_party/rust/cubeb-backend/src/ops.rs
@@ -20,20 +20,16 @@ pub struct Ops {
         unsafe extern "C" fn(
             context: *mut ffi::cubeb,
             params: ffi::cubeb_stream_params,
             latency_ms: *mut c_uint,
         ) -> c_int,
     >,
     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,
             devtype: ffi::cubeb_device_type,
             collection: *mut ffi::cubeb_device_collection,
         ) -> c_int,
     >,
     pub device_collection_destroy: Option<
--- a/third_party/rust/cubeb-backend/src/traits.rs
+++ b/third_party/rust/cubeb-backend/src/traits.rs
@@ -1,26 +1,25 @@
 // Copyright © 2017 Mozilla Foundation
 //
 // 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;
 
 pub trait ContextOps {
     fn init(context_name: Option<&CStr>) -> Result<Context>;
     fn backend_id(&mut self) -> &'static CStr;
     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,
         collection: &DeviceCollectionRef,
     ) -> Result<()>;
     fn device_collection_destroy(&mut self, collection: &mut DeviceCollectionRef) -> Result<()>;
     #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
     fn stream_init(
--- a/third_party/rust/cubeb-backend/tests/test_capi.rs
+++ b/third_party/rust/cubeb-backend/tests/test_capi.rs
@@ -3,19 +3,18 @@
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details
 
 #![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
 
 #[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;
 
 pub const OPS: Ops = capi_new!(TestContext, TestStream);
 
 struct TestContext {
     pub ops: *const Ops,
@@ -36,19 +35,16 @@ impl ContextOps for TestContext {
         Ok(0u32)
     }
     fn min_latency(&mut self, _params: StreamParams) -> Result<u32> {
         Ok(0u32)
     }
     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,
         collection: &DeviceCollectionRef,
     ) -> Result<()> {
         let coll = unsafe { &mut *collection.as_ptr() };
         coll.device = 0xDEAD_BEEF as *mut _;
         coll.count = usize::max_value();
@@ -167,27 +163,16 @@ fn test_ops_context_preferred_sample_rat
     assert_eq!(
         unsafe { OPS.get_preferred_sample_rate.unwrap()(c, &mut rate) },
         ffi::CUBEB_OK
     );
     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();
     let mut coll = ffi::cubeb_device_collection {
         device: ptr::null_mut(),
         count: 0,
     };
     assert_eq!(
         unsafe { OPS.enumerate_devices.unwrap()(c, 0, &mut coll) },
--- a/third_party/rust/cubeb-core/.cargo-checksum.json
+++ b/third_party/rust/cubeb-core/.cargo-checksum.json
@@ -1,1 +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
--- a/third_party/rust/cubeb-core/Cargo.toml
+++ b/third_party/rust/cubeb-core/Cargo.toml
@@ -7,26 +7,26 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [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"
 keywords = ["cubeb"]
 categories = ["api-bindings"]
 license = "ISC"
 repository = "https://github.com/djg/cubeb-rs"
 [dependencies.bitflags]
 version = "1.0"
 
 [dependencies.cubeb-sys]
-version = "0.4.1"
+version = "0.5.0"
 
 [features]
 gecko-in-tree = ["cubeb-sys/gecko-in-tree"]
 [badges.circle-ci]
 repository = "djg/cubeb-rs"
--- a/third_party/rust/cubeb-core/src/builders.rs
+++ b/third_party/rust/cubeb-core/src/builders.rs
@@ -112,34 +112,37 @@ mod tests {
                 $(let params = StreamParamsBuilder::new()
                   .layout(super::ChannelLayout::$real)
                   .take();
                 assert_eq!(params.layout(), super::ChannelLayout::$real);
                 )*
             ) );
 
         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
         );
     }
 
     #[test]
     fn stream_params_builder_rate() {
         let params = StreamParamsBuilder::new().rate(44100).take();
         assert_eq!(params.rate(), 44100);
     }
@@ -205,35 +208,37 @@ mod tests {
                 $(let params = super::StreamParamsBuilder::new()
                   .layout(super::ChannelLayout::$real)
                   .take();
                   let raw = unsafe { &*params.as_ptr() };
                   assert_eq!(raw.layout, ffi::$raw);
                 )*
             ) );
 
-        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]
     fn stream_params_builder_to_raw_rate() {
         let params = StreamParamsBuilder::new().rate(44100).take();
         let raw = unsafe { &*params.as_ptr() };
         assert_eq!(raw.rate, 44100);
     }
--- a/third_party/rust/cubeb-core/src/channel.rs
+++ b/third_party/rust/cubeb-core/src/channel.rs
@@ -1,105 +1,151 @@
 // Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 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 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 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 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);
+    }
+}
--- a/third_party/rust/cubeb-core/src/context.rs
+++ b/third_party/rust/cubeb-core/src/context.rs
@@ -1,14 +1,14 @@
 // Copyright © 2017-2018 Mozilla Foundation
 //
 // 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;
 use std::os::raw::c_void;
 use util::opt_bytes;
 
 macro_rules! as_ptr {
     ($e:expr) => { $e.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()) }
@@ -71,27 +71,16 @@ impl ContextRef {
             let _ = try_call!(ffi::cubeb_get_preferred_sample_rate(
                 self.as_ptr(),
                 &mut rate
             ));
         }
         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,
         stream_name: Option<&CStr>,
         input_device: DeviceId,
         input_stream_params: Option<&StreamParamsRef>,
         output_device: DeviceId,
         output_stream_params: Option<&StreamParamsRef>,
--- a/third_party/rust/cubeb-core/src/stream.rs
+++ b/third_party/rust/cubeb-core/src/stream.rs
@@ -80,45 +80,17 @@ impl StreamParamsRef {
     pub fn rate(&self) -> u32 {
         self.get_ref().rate
     }
     pub fn channels(&self) -> u32 {
         self.get_ref().channels
     }
 
     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 {
         StreamPrefs::from_bits_truncate(self.get_ref().prefs)
     }
 }
 
 ffi_type_heap! {
@@ -292,35 +264,37 @@ mod tests {
                 $(raw.layout = super::ffi::$raw;
                   let params = unsafe {
                       StreamParamsRef::from_ptr(&mut raw)
                   };
                   assert_eq!(params.layout(), super::ChannelLayout::$real);
                 )*
             ) );
 
-        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]
     fn stream_params_raw_rate() {
         let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
         raw.rate = 44_100;
         let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
         assert_eq!(params.rate(), 44_100);
--- a/third_party/rust/cubeb-sys/.cargo-checksum.json
+++ b/third_party/rust/cubeb-sys/.cargo-checksum.json
@@ -1,1 +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
--- a/third_party/rust/cubeb-sys/Cargo.toml
+++ b/third_party/rust/cubeb-sys/Cargo.toml
@@ -7,17 +7,17 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "cubeb-sys"
-version = "0.4.1"
+version = "0.5.0"
 authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
 build = "build.rs"
 links = "cubeb"
 description = "Native bindings to the cubeb library"
 license = "ISC"
 repository = "https://github.com/djg/cubeb-rs"
 [build-dependencies.cmake]
 version = "0.1.2"
--- a/third_party/rust/cubeb-sys/libcubeb/CMakeLists.txt
+++ b/third_party/rust/cubeb-sys/libcubeb/CMakeLists.txt
@@ -54,16 +54,17 @@ endif()
 
 add_library(cubeb
   src/cubeb.c
   src/cubeb_mixer.cpp
   src/cubeb_resampler.cpp
   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>
 )
 target_include_directories(cubeb PRIVATE src)
 target_compile_definitions(cubeb PRIVATE OUTSIDE_SPEEX)
 target_compile_definitions(cubeb PRIVATE FLOATING_POINT)
 target_compile_definitions(cubeb PRIVATE EXPORT=)
@@ -176,17 +177,18 @@ if(USE_WINMM)
     src/cubeb_winmm.c)
   target_compile_definitions(cubeb PRIVATE USE_WINMM)
   target_link_libraries(cubeb PRIVATE winmm)
 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()
 
 check_include_files(android/log.h USE_AUDIOTRACK)
 if(USE_AUDIOTRACK)
   target_sources(cubeb PRIVATE
     src/cubeb_audiotrack.c)
@@ -232,16 +234,17 @@ if(BUILD_TESTS)
     install(TARGETS test_${NAME} DESTINATION ${CMAKE_INSTALL_PREFIX})
   endmacro(cubeb_add_test)
 
   cubeb_add_test(sanity)
   cubeb_add_test(tone)
   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)
   target_include_directories(test_resampler PRIVATE src)
   target_compile_definitions(test_resampler PRIVATE OUTSIDE_SPEEX)
   target_compile_definitions(test_resampler PRIVATE FLOATING_POINT)
   target_compile_definitions(test_resampler PRIVATE EXPORT=)
   target_compile_definitions(test_resampler PRIVATE RANDOM_PREFIX=speex)
@@ -255,32 +258,11 @@ if(BUILD_TESTS)
   if (USE_WASAPI)
     cubeb_add_test(overload_callback)
     cubeb_add_test(loopback)
   endif()
 
   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()
--- a/third_party/rust/cubeb-sys/libcubeb/include/cubeb/cubeb.h
+++ b/third_party/rust/cubeb-sys/libcubeb/include/cubeb/cubeb.h
@@ -152,90 +152,93 @@ typedef void const * cubeb_devid;
 
 /** Level (verbosity) of logging for a particular cubeb context. */
 typedef enum {
   CUBEB_LOG_DISABLED = 0, /** < Logging disabled */
   CUBEB_LOG_NORMAL = 1, /**< Logging lifetime operation (creation/destruction). */
   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 {
+  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 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;
+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 {
   CUBEB_STREAM_PREF_NONE     = 0x00, /**< No stream preferences are requested. */
   CUBEB_STREAM_PREF_LOOPBACK = 0x01 /**< Request a loopback stream. Should be
                                          specified on the input params and an
                                          output device to loopback from should
                                          be passed in place of an input device. */
 } cubeb_stream_prefs;
 
 /** Stream format initialization parameters. */
 typedef struct {
   cubeb_sample_format format;   /**< Requested sample format.  One of
                                      #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;
 
 /** Audio device description */
 typedef struct {
   char * output_name; /**< The name of the output device */
   char * input_name; /**< The name of the input device */
 } cubeb_device;
@@ -361,18 +364,22 @@ typedef struct {
       all the frames have been output.
     @param stream The stream for which this callback fired.
     @param user_ptr The pointer passed to cubeb_stream_init.
     @param input_buffer A pointer containing the input data, or nullptr
                         if this is an output-only stream.
     @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,
                                      void * user_ptr,
                                      void const * input_buffer,
                                      void * output_buffer,
                                      long nframes);
 
@@ -396,16 +403,20 @@ typedef void (* cubeb_device_changed_cal
 typedef void (* cubeb_device_collection_changed_callback)(cubeb * context,
                                                           void * user_ptr);
 
 /** User supplied callback called when a message needs logging. */
 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
                         can appear in different locations.
     @param backend_name The name of the cubeb backend user desires to select.
                         Accepted values self-documented in cubeb.c: init_oneshot
                         If NULL, a default ordering is used for backend choice.
                         A valid choice overrides all other possible backends,
@@ -449,25 +460,16 @@ CUBEB_EXPORT int cubeb_get_min_latency(c
     platform dependent, and can avoid resampling, and/or trigger fastpaths.
     @param context A pointer to the cubeb context.
     @param rate The samplerate (in Hz) the current configuration prefers.
     @retval CUBEB_OK
     @retval CUBEB_ERROR_INVALID_PARAMETER
     @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.*/
 CUBEB_EXPORT void cubeb_destroy(cubeb * context);
 
 /** Initialize a stream associated with the supplied application context.
     @param context A pointer to the cubeb context.
     @param stream An out parameter to be filled with the an opaque pointer to a
new file mode 100644
--- /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_
new file mode 100644
--- /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_
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb-internal.h
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb-internal.h
@@ -28,33 +28,24 @@
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
 #if defined(__cplusplus)
 }
 #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);
   int (* get_max_channel_count)(cubeb * context, uint32_t * max_channels);
   int (* get_min_latency)(cubeb * context,
                           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,
                                     cubeb_device_collection * collection);
   void (* destroy)(cubeb * context);
   int (* stream_init)(cubeb * context,
                       cubeb_stream ** stream,
                       char const * stream_name,
new file mode 100644
--- /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_
new file mode 100644
--- /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;
+}
new file mode 100644
--- /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_
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb.c
@@ -272,30 +272,16 @@ cubeb_get_preferred_sample_rate(cubeb * 
 
   if (!context->ops->get_preferred_sample_rate) {
     return CUBEB_ERROR_NOT_SUPPORTED;
   }
 
   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)
 {
   if (!context) {
     return;
   }
 
   context->ops->destroy(context);
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_alsa.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_alsa.c
@@ -1353,17 +1353,16 @@ alsa_device_collection_destroy(cubeb * c
 }
 
 static struct cubeb_ops const alsa_ops = {
   .init = alsa_init,
   .get_backend_id = alsa_get_backend_id,
   .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,
   .stream_init = alsa_stream_init,
   .stream_destroy = alsa_stream_destroy,
   .stream_start = alsa_stream_start,
   .stream_stop = alsa_stream_stop,
   .stream_reset_default_device = NULL,
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiotrack.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiotrack.c
@@ -418,17 +418,16 @@ audiotrack_stream_set_volume(cubeb_strea
 }
 
 static struct cubeb_ops const audiotrack_ops = {
   .init = audiotrack_init,
   .get_backend_id = audiotrack_get_backend_id,
   .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,
   .stream_init = audiotrack_stream_init,
   .stream_destroy = audiotrack_stream_destroy,
   .stream_start = audiotrack_stream_start,
   .stream_stop = audiotrack_stream_stop,
   .stream_reset_default_device = NULL,
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiounit.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_audiounit.cpp
@@ -82,16 +82,17 @@ struct cubeb {
   void * collection_changed_user_ptr = nullptr;
   /* Differentiate input from output devices. */
   cubeb_device_type collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN;
   vector<AudioObjectID> devtype_device_array;
   // The queue is asynchronously deallocated once all references to it are released
   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)>
 make_sized_audio_channel_layout(size_t sz)
 {
     assert(sz >= sizeof(AudioChannelLayout));
     AudioChannelLayout * acl = reinterpret_cast<AudioChannelLayout *>(calloc(1, sz));
     assert(acl); // Assert the allocation works.
@@ -183,63 +184,119 @@ struct cubeb_stream {
   unique_ptr<cubeb_resampler, decltype(&cubeb_resampler_destroy)> resampler;
   /* This is true if a device change callback is currently running.  */
   atomic<bool> switching_device{ false };
   atomic<bool> buffer_size_change_state{ false };
   AudioDeviceID aggregate_device_id = 0;    // the aggregate device id
   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)
 {
   return stm->input_stream_params.rate != 0;
 }
 
 bool has_output(cubeb_stream * stm)
 {
   return stm->output_stream_params.rate != 0;
 }
 
 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;
   }
 }
 
 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;
   }
 }
 
 #if TARGET_OS_IPHONE
 typedef UInt32 AudioDeviceID;
 typedef UInt32 AudioObjectID;
 
 #define AudioGetCurrentHostTime mach_absolute_time
@@ -377,16 +434,22 @@ audiounit_input_callback(void * user_ptr
     auto_lock l(stm->input_linear_buffer_lock);
     assert(input_frames <= stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame);
     long total_input_frames = stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame;
     long outframes = cubeb_resampler_fill(stm->resampler.get(),
                                           stm->input_linear_buffer->data(),
                                           &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
     stm->input_linear_buffer->clear();
   }
 
   return noErr;
 }
@@ -406,34 +469,36 @@ is_extra_input_needed(cubeb_stream * stm
     * switching, we add some silence as well to compensate for the fact that
     * we're lacking some input data. */
   return stm->frames_read == 0 ||
          stm->available_input_frames.load() < minimum_resampling_input_frames(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)
+                            size_t output_buffer_size)
 {
-  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
-  };
-
-  // 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);
+  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);
+
+  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
 audiounit_output_callback(void * user_ptr,
                           AudioUnitRenderActionFlags * /* flags */,
                           AudioTimeStamp const * tstamp,
                           UInt32 bus,
                           UInt32 output_frames,
@@ -468,18 +533,32 @@ audiounit_output_callback(void * user_pt
     if (stm->input_unit) {
       r = AudioOutputUnitStop(stm->input_unit);
       assert(r == 0);
     }
     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
     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)) {
       uint32_t min_input_frames = minimum_resampling_input_frames(stm);
       {
         auto_lock l(stm->input_linear_buffer_lock);
         stm->input_linear_buffer->push_silence(min_input_frames * stm->input_desc.mChannelsPerFrame);
       }
@@ -520,43 +599,49 @@ audiounit_output_callback(void * user_pt
       r = AudioOutputUnitStop(stm->input_unit);
       assert(r == 0);
     }
     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
     audiounit_make_silent(&outBufferList->mBuffers[0]);
     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;
 
   AudioFormatFlags outaff = stm->output_desc.mFormatFlags;
   float panning = (stm->output_desc.mChannelsPerFrame == 2) ?
       stm->panning.load(memory_order_relaxed) : 0.0f;
 
   /* 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;
 }
 
 extern "C" {
 int
 audiounit_init(cubeb ** context, char const * /* context_name */)
@@ -1115,38 +1200,41 @@ audiounit_get_preferred_sample_rate(cube
   *rate = static_cast<uint32_t>(fsamplerate);
 #endif
   return CUBEB_OK;
 }
 
 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
     // kAudioChannelLayoutTag_Stereo
     // ....
     LOG("Only handle UseChannelDescriptions for now.\n");
     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_layout cl = 0;
+  for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) {
+    cl |= channel_label_to_cubeb_channel(
+      layout->mChannelDescriptions[i].mChannelLabel);
   }
 
-  cubeb_channel_map cm;
-  cm.channels = layout->mNumberChannelDescriptions;
-  for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) {
-    cm.map[i] = channel_label_to_cubeb_channel(layout->mChannelDescriptions[i].mChannelLabel);
-  }
-
-  return cubeb_channel_map_to_layout(&cm);
+  return cl;
 }
 
 static cubeb_channel_layout
 audiounit_get_current_channel_layout(AudioUnit output_unit)
 {
   OSStatus rv = noErr;
   UInt32 size = 0;
   rv = AudioUnitGetPropertyInfo(output_unit,
@@ -1171,86 +1259,18 @@ audiounit_get_current_channel_layout(Aud
   if (rv != noErr) {
     LOG("AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout rv=%d", rv);
     return CUBEB_LAYOUT_UNDEFINED;
   }
 
   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
 audiounit_destroy(cubeb * ctx)
 {
   // Disabling this assert for bug 1083664 -- we seem to leak a stream
   // assert(ctx->active_streams == 0);
   if (ctx->active_streams > 0) {
@@ -1309,90 +1329,70 @@ audio_stream_desc_init(AudioStreamBasicD
   ss->mReserved = 0;
 
   return CUBEB_OK;
 }
 
 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);
+  if (layout == CUBEB_LAYOUT_UNDEFINED) {
+    // We leave everything as-is...
+    return CUBEB_OK;
+  }
+
 
   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;
-  }
-
-  // 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;
+  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);
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
@@ -1400,24 +1400,19 @@ audiounit_set_channel_layout(AudioUnit u
 void
 audiounit_layout_init(cubeb_stream * stm, io_side side)
 {
   // We currently don't support the input layout setting.
   if (side == INPUT) {
     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>
 audiounit_get_sub_devices(AudioDeviceID device_id)
 {
   vector<AudioDeviceID> sub_devices;
   AudioObjectPropertyAddress property_address = { kAudioAggregateDevicePropertyActiveSubDeviceList,
                                                   kAudioObjectPropertyScopeGlobal,
@@ -2305,16 +2300,35 @@ audiounit_configure_output(cubeb_stream 
                            &output_hw_desc,
                            &size);
   if (r != noErr) {
     LOG("AudioUnitGetProperty/output/kAudioUnitProperty_StreamFormat rv=%d", r);
     return CUBEB_ERROR;
   }
   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,
                            kAudioUnitScope_Input,
                            AU_OUT_BUS,
                            &stm->output_desc,
                            sizeof(AudioStreamBasicDescription));
   if (r != noErr) {
@@ -2348,20 +2362,16 @@ audiounit_configure_output(cubeb_stream 
                            AU_OUT_BUS,
                            &aurcbs_out,
                            sizeof(aurcbs_out));
   if (r != noErr) {
     LOG("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback rv=%d", r);
     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;
 }
 
 static int
 audiounit_setup_stream(cubeb_stream * stm)
 {
   stm->mutex.assert_current_thread_owns();
@@ -3463,17 +3473,16 @@ int audiounit_register_device_collection
 }
 
 cubeb_ops const audiounit_ops = {
   /*.init =*/ audiounit_init,
   /*.get_backend_id =*/ audiounit_get_backend_id,
   /*.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,
   /*.stream_init =*/ audiounit_stream_init,
   /*.stream_destroy =*/ audiounit_stream_destroy,
   /*.stream_start =*/ audiounit_stream_start,
   /*.stream_stop =*/ audiounit_stream_stop,
   /*.stream_reset_default_device =*/ nullptr,
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_jack.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_jack.cpp
@@ -114,17 +114,16 @@ static int cbjack_stream_get_position(cu
 static int cbjack_stream_set_volume(cubeb_stream * stm, float volume);
 
 static struct cubeb_ops const cbjack_ops = {
   .init = jack_init,
   .get_backend_id = cbjack_get_backend_id,
   .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,
   .stream_init = cbjack_stream_init,
   .stream_destroy = cbjack_stream_destroy,
   .stream_start = cbjack_stream_start,
   .stream_stop = cbjack_stream_stop,
   .stream_reset_default_device = NULL,
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.cpp
@@ -1,571 +1,661 @@
 /*
  * Copyright © 2016 Mozilla Foundation
  *
  * 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"
 
-// 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))
+#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) */
+
+#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
 
-cubeb_channel_layout cubeb_channel_map_to_layout(cubeb_channel_map const * channel_map)
+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;
-  }
-}
-
-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 }
-};
-
-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
-};
-
-// 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
+  static bool even(cubeb_channel_layout layout)
   {
-    { 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
-  {
-    { 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
-  }
-};
-
-// 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)
-{
-  if ((in_layout != CUBEB_LAYOUT_3F2 && in_layout != CUBEB_LAYOUT_3F2_LFE) ||
-      out_layout < CUBEB_LAYOUT_MONO || out_layout > CUBEB_LAYOUT_2F2_LFE) {
+    if (!layout) {
+      return true;
+    }
+    if (layout & (layout - 1)) {
+      return true;
+    }
     return false;
   }
 
-  unsigned int in_channels = CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels;
-  unsigned int out_channels = CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels;
+  // 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;
+    }
+
+    return layout;
+  }
 
-  // Conversion from 3F2 to 2F2-LFE or 3F1-LFE is allowed, so we use '<=' instead of '<'.
-  assert(out_channels <= in_channels);
+  static bool sane_layout(cubeb_channel_layout layout)
+  {
+    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();
 
-  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;
+  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.
+};
+
+int MixerContext::auto_matrix()
+{
+  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;
+  }
+
+  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;
+    }
+  }
+
+  cubeb_channel_layout unaccounted = in_ch_layout & ~out_ch_layout;
+
+  // 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.
+
+  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;
       }
-      assert(out_index + j < out_len);
-      out[out_index + j] = sample;
     }
-#if defined(USE_AUDIOUNIT)
-    out_index += in_channels;
-#else
-    out_index += out_channels;
-#endif
+  }
+  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;
+    }
   }
 
-  return true;
-}
-
-/* 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);
-
-  // 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_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 (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;
+    }
   }
 
-  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 & 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 {
+        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;
+    }
   }
 
-  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_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;
+    }
+  }
+  /* 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;
+    }
   }
 
-  // If there is no matched channel, then do nothing.
-  if (!(out_layout_mask & in_layout_mask)) {
-    return false;
+  // 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++;
   }
 
-  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];
-      } else {
-        assert(channel_index == -1);
-        out[out_index + j] = 0;
+  if (_format == CUBEB_SAMPLE_S16NE) {
+    maxval = 1.0;
+  } else {
+    maxval = INT_MAX;
+  }
+
+  // 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];
       }
     }
   }
 
-  return true;
+  return 0;
 }
 
-/* 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)
+int MixerContext::init()
 {
-  assert(in_channels >= out_channels && inframes >= 0);
+  int r = auto_matrix();
+  if (r) {
+    return r;
+  }
+
+  // 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;
 
-  if (in_channels == out_channels && in == out) {
-    return;
+      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;
+    }
   }
 
-  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];
+  // 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;
+}
+
+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)
+{
+  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;
   }
 }
 
-
-template<typename T>
+template<typename TYPE_SAMPLE, typename TYPE_COEFF, typename F>
 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)
+copy(TYPE_SAMPLE * out,
+     uint32_t stride_out,
+     const TYPE_SAMPLE * in,
+     uint32_t stride_in,
+     TYPE_COEFF coeff,
+     F&& operand,
+     uint32_t frames)
 {
-  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;
-    }
-
-#if defined(USE_AUDIOUNIT)
-  // We only support downmix for audio 5.1 on OS X currently.
-  return;
-#endif
-
-    if (mix_remap(inframes, in, in_len, out, out_len, in_layout, out_layout)) {
-      return;
-    }
-  }
-
-  downmix_fallback(inframes, in, in_len, out, out_len, in_channels, out_channels);
-}
-
-/* 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)
-{
-  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];
+  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;
   }
 }
 
-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)
+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)
 {
-  assert(in && out);
-  assert(inframes);
-  assert(mixer_params->channels >= stream_params->channels &&
-         stream_params->channels > 0);
+  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");
 
-  unsigned int in_channels = stream_params->channels;
-  unsigned int out_channels = mixer_params->channels;
+  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;
+}
 
-  /* 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];
+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>
+  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;
       }
     }
   }
 
-  /* Check if more channels. */
-  if (out_channels <= 2) {
-    return;
-  }
+  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 || _context._out_ch_count == 0) {
+      return 0;
+    }
 
-  /* 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;
+    // 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;
+    }
+
+    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;
     }
-  }
-}
 
-bool
-cubeb_should_upmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
-{
-  return mixer->channels > stream->channels;
-}
+    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;
+    }
 
-bool
-cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
-{
-  if (mixer->channels > stream->channels || mixer->layout == stream->layout) {
-    return false;
+    return -1;
   }
 
-  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));
-}
+  // Return false if any of the input or ouput layout were invalid.
+  bool valid() const { return _context._valid; }
 
-bool
-cubeb_should_mix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
-{
-  return stream->layout != CUBEB_LAYOUT_UNDEFINED &&
-         (cubeb_should_upmix(stream, mixer) || cubeb_should_downmix(stream, mixer));
-}
+  virtual ~cubeb_mixer(){};
 
-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() {};
+  MixerContext _context;
 };
 
-template<typename T>
-struct cubeb_mixer_impl : public cubeb_mixer {
-  explicit cubeb_mixer_impl(unsigned int d)
-    : direction(d)
-  {
-  }
-
-  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)
-  {
-    if (frames <= 0) {
-      return;
-    }
-
-    T * in = static_cast<T*>(input_buffer);
-    T * out = static_cast<T*>(output_buffer);
-
-    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);
-    }
-  }
-
-  ~cubeb_mixer_impl() {};
-
-  unsigned char const direction;
-};
-
-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)
 {
   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);
 }
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.h
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_mixer.h
@@ -3,88 +3,35 @@
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 
 #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)
 }
 #endif
 
 #endif // CUBEB_MIXER
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_opensl.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_opensl.c
@@ -21,16 +21,17 @@
 #include <android/log.h>
 #include <android/api-level.h>
 #endif
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 #include "cubeb_resampler.h"
 #include "cubeb-sles.h"
 #include "cubeb_array_queue.h"
+#include "android/cubeb-output-latency.h"
 
 #if defined(__ANDROID__)
 #ifdef LOG
 #undef LOG
 #endif
 //#define LOGGING_ENABLED
 #ifdef LOGGING_ENABLED
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Cubeb_OpenSL" , ## args)
@@ -56,40 +57,39 @@
 #endif
 
 #define ANDROID_VERSION_GINGERBREAD_MR1 10
 #define ANDROID_VERSION_LOLLIPOP 21
 #define ANDROID_VERSION_MARSHMALLOW 23
 #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__)
   SLInterfaceID SL_IID_ANDROIDCONFIGURATION;
   SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
 #endif
   SLInterfaceID SL_IID_VOLUME;
   SLInterfaceID SL_IID_RECORD;
   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. */
   cubeb * context;
   void * user_ptr;
   /**/
   pthread_mutex_t mutex;
   SLObjectItf playerObj;
@@ -148,17 +148,17 @@ struct cubeb_stream {
    * stream::mutex lock. */
   uint32_t shutdown;
   /* Store user callback. */
   cubeb_data_callback data_callback;
   /* Store state callback. */
   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;
   int64_t lastPositionTimeStamp;
   int64_t lastCompensativePosition;
 };
 
 /* Forward declaration. */
@@ -231,17 +231,16 @@ opensl_set_shutdown(cubeb_stream * stm, 
   assert(value == 0 || value == 1);
   stm->shutdown = value;
 }
 
 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:
       opensl_notify_drained(stm);
     break;
   default:
     break;
   }
@@ -663,40 +662,21 @@ opensl_init(cubeb ** context, char const
   *context = NULL;
 
   ctx = calloc(1, sizeof(*ctx));
   assert(ctx);
 
   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 *,
                                        SLuint32,
                                        const SLInterfaceID *,
                                        const SLboolean *);
   slCreateEngine_t f_slCreateEngine =
     (slCreateEngine_t)dlsym(ctx->lib, "slCreateEngine");
@@ -756,16 +736,21 @@ opensl_init(cubeb ** context, char const
   }
 
   res = (*ctx->outmixObj)->Realize(ctx->outmixObj, SL_BOOLEAN_FALSE);
   if (res != SL_RESULT_SUCCESS) {
     opensl_destroy(ctx);
     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);
   return CUBEB_OK;
 }
 
 static char const *
 opensl_get_backend_id(cubeb * ctx)
@@ -779,143 +764,26 @@ opensl_get_max_channel_count(cubeb * ctx
   assert(ctx && max_channels);
   /* The android mixer handles up to two channels, see
      http://androidxref.com/4.2.2_r1/xref/frameworks/av/services/audioflinger/AudioFlinger.h#67 */
   *max_channels = 2;
 
   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)
 {
   if (ctx->outmixObj)
     (*ctx->outmixObj)->Destroy(ctx->outmixObj);
   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);
 }
 
 static void opensl_stream_destroy(cubeb_stream * stm);
 
 static int
 opensl_set_format(SLDataFormat_PCM * format, cubeb_stream_params * params)
 {
@@ -992,23 +860,19 @@ opensl_configure_capture(cubeb_stream * 
                                                            lSoundRecorderReqs);
   // Sample rate not supported. Try again with default sample rate!
   if (res == SL_RESULT_CONTENT_UNSUPPORTED) {
     if (stm->output_enabled && stm->output_configured_rate != 0) {
       // Set the same with the player. Since there is no
       // 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,
                                                     &stm->recorderObj,
                                                     &lDataSource,
                                                     &lDataSink,
                                                     lSoundRecorderIIDCount,
                                                     lSoundRecorderIIDs,
@@ -1109,17 +973,17 @@ opensl_configure_capture(cubeb_stream * 
   return CUBEB_OK;
 }
 
 static int
 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;
   stm->lastCompensativePosition = -1;
 
   SLDataFormat_PCM format;
   int r = opensl_set_format(&format, params);
   if (r != CUBEB_OK) {
@@ -1146,48 +1010,32 @@ opensl_configure_playback(cubeb_stream *
                                stm->context->SL_IID_ANDROIDCONFIGURATION};
   const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
 #else
   const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE, ctx->SL_IID_VOLUME};
   const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
 #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,
                                                   &stm->playerObj,
                                                   &source,
                                                   &sink,
                                                   NELEMS(ids),
                                                   ids,
                                                   req);
   }
 
   // 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,
                                                   &source,
                                                   &sink,
                                                   NELEMS(ids),
                                                   ids,
                                                   req);
@@ -1195,17 +1043,17 @@ opensl_configure_playback(cubeb_stream *
 
   if (res != SL_RESULT_SUCCESS) {
     LOG("Failed to create audio player. Error code: %lu", res);
     return CUBEB_ERROR;
   }
 
   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;
   if (stm->output_enabled) {
     // Full duplex, update capacity to hold 1 sec of data
     stm->queuebuf_capacity = 1 * stm->output_configured_rate / stm->queuebuf_len;
   }
   // Allocate input array
@@ -1332,17 +1180,17 @@ opensl_stream_init(cubeb * ctx, cubeb_st
 
   stm = calloc(1, sizeof(*stm));
   assert(stm);
 
   stm->context = ctx;
   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;
 
 #ifdef DEBUG
   pthread_mutexattr_t attr;
   pthread_mutexattr_init(&attr);
   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
@@ -1596,45 +1444,42 @@ opensl_stream_destroy(cubeb_stream * stm
   LOG("Cubeb stream (%p) destroyed", stm);
   free(stm);
 }
 
 static int
 opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
 {
   SLmillisecond msec;
-  uint64_t samplerate;
+  uint32_t compensation_msec = 0;
   SLresult res;
-  int r;
-  uint32_t mixer_latency;
-  uint32_t compensation_msec = 0;
+
+  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)
     return CUBEB_ERROR;
 
   struct timespec t;
   clock_gettime(CLOCK_MONOTONIC, &t);
   if(stm->lastPosition == msec) {
     compensation_msec =
       (t.tv_sec*1000000000LL + t.tv_nsec - stm->lastPositionTimeStamp) / 1000000;
   } else {
     stm->lastPositionTimeStamp = t.tv_sec*1000000000LL + t.tv_nsec;
     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);
 
   if (msec > mixer_latency) {
     int64_t unadjusted_position;
     if (stm->lastCompensativePosition > msec + compensation_msec) {
       // Over compensation, use lastCompensativePosition.
       unadjusted_position =
@@ -1648,34 +1493,16 @@ opensl_stream_get_position(cubeb_stream 
       unadjusted_position : maximum_position;
   } else {
     *position = 0;
   }
   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)
 {
   SLresult res;
   SLmillibel max_level, millibels;
   float unclamped_millibels;
 
   res = (*stm->volume)->GetMaxVolumeLevel(stm->volume, &max_level);
 
@@ -1700,28 +1527,27 @@ opensl_stream_set_volume(cubeb_stream * 
   }
   return CUBEB_OK;
 }
 
 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,
   .stream_init = opensl_stream_init,
   .stream_destroy = opensl_stream_destroy,
   .stream_start = opensl_stream_start,
   .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,
   .stream_device_destroy = NULL,
   .stream_register_device_changed_callback = NULL,
   .register_device_collection_changed = NULL
 };
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_pulse.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_pulse.c
@@ -2,24 +2,24 @@
  * Copyright © 2011 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 #undef NDEBUG
 #include <assert.h>
 #include <dlfcn.h>
+#include <pulse/pulseaudio.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include <pulse/pulseaudio.h>
 #include <string.h>
+#include "cubeb-internal.h"
 #include "cubeb/cubeb.h"
-#include "cubeb-internal.h"
 #include "cubeb_mixer.h"
 #include "cubeb_strings.h"
-#include <stdio.h>
 
 #ifdef DISABLE_LIBPULSE_DLOPEN
 #define WRAP(x) x
 #else
 #define WRAP(x) cubeb_##x
 #define LIBPULSE_API_VISIT(X)                   \
   X(pa_channel_map_can_balance)                 \
   X(pa_channel_map_init)                        \
@@ -506,78 +506,76 @@ stream_update_timing_info(cubeb_stream *
   }
 
   return r;
 }
 
 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;
   }
 }
 
 static void
 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]);
+
+  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;
   }
-}
-
-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]);
-  }
-  return cubeb_channel_map_to_layout(&cubeb_map);
+  cm->channels = cubeb_channel_layout_nb_channels(layout);
 }
 
 static void pulse_context_destroy(cubeb * ctx);
 static void pulse_destroy(cubeb * ctx);
 
 static int
 pulse_context_init(cubeb * ctx)
 {
@@ -710,30 +708,16 @@ pulse_get_preferred_sample_rate(cubeb * 
     return CUBEB_ERROR;
 
   *rate = ctx->default_sink_info->sample_spec_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)
 {
   (void)ctx;
   // According to PulseAudio developers, this is a safe minimum.
   *latency_frames = 25 * params.rate / 1000;
 
   return CUBEB_OK;
 }
@@ -803,17 +787,17 @@ create_pa_stream(cubeb_stream * stm,
                  pa_stream ** pa_stm,
                  cubeb_stream_params * stream_params,
                  char const * stream_name)
 {
   assert(stm && stream_params);
   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;
   }
   *pa_stm = NULL;
   pa_sample_spec ss;
   ss.format = to_pulse_format(stream_params->format);
   if (ss.format == PA_SAMPLE_INVALID)
     return CUBEB_ERROR_INVALID_FORMAT;
@@ -1274,17 +1258,17 @@ pulse_sink_info_cb(pa_context * context,
     return;
   }
 
   if (info == NULL)
     return;
 
   device_id = info->name;
   if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
-    assert(false);
+    assert(NULL);
     return;
   }
 
   pulse_ensure_dev_list_data_list_size(list_data);
   devinfo = &list_data->devinfo[list_data->count];
   memset(devinfo, 0, sizeof(cubeb_device_info));
 
   devinfo->device_id = device_id;
@@ -1343,17 +1327,17 @@ pulse_source_info_cb(pa_context * contex
 
   if (eol) {
     WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
     return;
   }
 
   device_id = info->name;
   if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
-    assert(false);
+    assert(NULL);
     return;
   }
 
   pulse_ensure_dev_list_data_list_size(list_data);
   devinfo = &list_data->devinfo[list_data->count];
   memset(devinfo, 0, sizeof(cubeb_device_info));
 
   devinfo->device_id = device_id;
@@ -1583,17 +1567,16 @@ pulse_register_device_collection_changed
 }
 
 static struct cubeb_ops const pulse_ops = {
   .init = pulse_init,
   .get_backend_id = pulse_get_backend_id,
   .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,
   .stream_init = pulse_stream_init,
   .stream_destroy = pulse_stream_destroy,
   .stream_start = pulse_stream_start,
   .stream_stop = pulse_stream_stop,
   .stream_reset_default_device = NULL,
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_sndio.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_sndio.c
@@ -531,17 +531,16 @@ sndio_device_collection_destroy(cubeb * 
 }
 
 static struct cubeb_ops const sndio_ops = {
   .init = sndio_init,
   .get_backend_id = sndio_get_backend_id,
   .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,
   .stream_init = sndio_stream_init,
   .stream_destroy = sndio_stream_destroy,
   .stream_start = sndio_stream_start,
   .stream_stop = sndio_stream_stop,
   .stream_reset_default_device = NULL,
new file mode 100644
--- /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);
+  }
+}
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.h
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_utils.h
@@ -328,12 +328,16 @@ struct auto_array_wrapper_impl : public 
   ~auto_array_wrapper_impl() {
     ar.clear();
   }
 
 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
 
 #endif /* CUBEB_UTILS */
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_wasapi.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_wasapi.cpp
@@ -130,42 +130,16 @@ private:
       ptr = nullptr;
       temp->Release();
     }
   }
 
   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);
 int wasapi_stream_start(cubeb_stream * stm);
 void close_wasapi_stream(cubeb_stream * stm);
 int setup_wasapi_stream(cubeb_stream * stm);
 static char const * wstr_to_utf8(wchar_t const * str);
 static std::unique_ptr<wchar_t const []> utf8_to_wstr(char const * str);
@@ -268,19 +242,20 @@ struct cubeb_stream {
      client, frames_written, mix_params, total_frames_written, prev_position. */
   owned_critical_section stream_reset_lock;
   /* Maximum number of frames that can be passed down in a callback. */
   uint32_t input_buffer_frame_count = 0;
   /* Maximum number of frames that can be requested in a callback. */
   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. */
   std::unique_ptr<auto_array_wrapper> linear_input_buffer;
   /* Bytes per sample. This multiplied by the number of channels is the number
    * of bytes per frame. */
   size_t bytes_per_sample = 0;
   /* WAVEFORMATEXTENSIBLE sub-format: either PCM or float. */
@@ -420,116 +395,34 @@ bool has_output(cubeb_stream * stm)
 
 double stream_to_mix_samplerate_ratio(cubeb_stream_params & stream, cubeb_stream_params & mixer)
 {
   return double(stream.rate) / mixer.rate;
 }
 
 /* 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);
     mask = ext->dwChannelMask;
   } 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
 get_rate(cubeb_stream * stm)
 {
   return has_input(stm) ? stm->input_stream_params.rate
                         : stm->output_stream_params.rate;
 }
@@ -569,17 +462,17 @@ long
 refill(cubeb_stream * stm, void * input_buffer, long input_frames_count,
        void * output_buffer, long output_frames_needed)
 {
   XASSERT(!stm->draining);
   /* If we need to upmix after resampling, resample into the mix buffer to
      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;
     }
   }
 
   long out_frames = cubeb_resampler_fill(stm->resampler.get(),
                                          input_buffer,
@@ -589,35 +482,46 @@ refill(cubeb_stream * stm, void * input_
   /* TODO: Report out_frames < 0 as an error via the API. */
   XASSERT(out_frames >= 0);
 
   {
     auto_lock lock(stm->stream_reset_lock);
     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;
   }
 
   /* If this is not true, there will be glitches.
      It is alright to have produced less frames if we are draining, though. */
   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;
 }
 
 int wasapi_stream_reset_default_device(cubeb_stream * stm);
 
 /* This helper grabs all the frames available from a capture client, put them in
@@ -650,69 +554,77 @@ bool get_input_buffer(cubeb_stream * stm
       return true;
     }
 
     if (FAILED(hr)) {
       LOG("cannot get next packet size: %lx", hr);
       return false;
     }
 
-    UINT32 packet_size;
+    UINT32 frames;
     hr = stm->capture_client->GetBuffer(&input_packet,
-                                        &packet_size,
+                                        &frames,
                                         &flags,
                                         &dev_pos,
                                         NULL);
     if (FAILED(hr)) {
       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:
     //   - The first GetBuffer after Start has this flag undefined. In this
     //     case the flag may be set but is meaningless and can be ignored.
     //   - If a glitch is introduced into the input. This should not happen
     //     for event based inputs, and should be mitigated by using a dummy
     //     stream to drive input in the case of input only loopback. Without
     //     a dummy output, input only loopback would glitch on silence. However,
     //     the dummy input should push silence to the loopback and prevent
     //     discontinuities. See https://blogs.msdn.microsoft.com/matthew_van_eerde/2008/12/16/sample-wasapi-loopback-capture-record-what-you-hear/
     // As the first scenario can be ignored, and we anticipate the second
     // scenario is mitigated, we ignore the flag.
     // 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);
 
   return true;
 }
 
 /* Get an output buffer from the render_client. It has to be released before
@@ -899,25 +811,25 @@ refill_callback_output(cubeb_stream * st
                     0,
                     output_buffer,
                     output_frames);
 
   ALOGV("Output callback: output frames requested: %Iu, got %ld",
         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)) {
     LOG("failed to release buffer: %lx", hr);
     return false;
   }
 
-  return (unsigned long) got == output_frames || stm->draining;
+  return size_t(got) == output_frames || stm->draining;
 }
 
 static unsigned int __stdcall
 wasapi_stream_render_loop(LPVOID stream)
 {
   cubeb_stream * stm = static_cast<cubeb_stream *>(stream);
   std::atomic<bool> * emergency_bailout = stm->emergency_bailout;
 
@@ -926,22 +838,25 @@ wasapi_stream_render_loop(LPVOID stream)
     stm->shutdown_event,
     stm->reconfigure_event,
     stm->refill_event,
     stm->input_available_event
   };
   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. */
   mmcss_handle = AvSetMmThreadCharacteristicsA("Audio", &mmcss_task_index);
   if (!mmcss_handle) {
     /* This is not fatal, but we might glitch under heavy load. */
     LOG("Unable to use mmcss to bump the render thread priority: %lx", GetLastError());
   }
@@ -1074,16 +989,17 @@ void wasapi_destroy(cubeb * context);
 
 HRESULT register_notification_client(cubeb_stream * stm)
 {
   HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                                 NULL, CLSCTX_INPROC_SERVER,
                                 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;
   }
 
   stm->notification_client.reset(new wasapi_endpoint_notification_client(stm->reconfigure_event));
 
   hr = stm->device_enumerator->RegisterEndpointNotificationCallback(stm->notification_client.get());
   if (FAILED(hr)) {
     LOG("Could not register endpoint notification callback: %lx", hr);
@@ -1120,16 +1036,17 @@ HRESULT unregister_notification_client(c
 HRESULT get_endpoint(com_ptr<IMMDevice> & device, LPCWSTR devid)
 {
   com_ptr<IMMDeviceEnumerator> enumerator;
   HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                                 NULL, 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 hr;
   }
 
   hr = enumerator->GetDevice(devid, device.receive());
   if (FAILED(hr)) {
     LOG("Could not get device: %lx", hr);
     return hr;
   }
@@ -1140,16 +1057,17 @@ HRESULT get_endpoint(com_ptr<IMMDevice> 
 HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction)
 {
   com_ptr<IMMDeviceEnumerator> enumerator;
   HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                                 NULL, 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 hr;
   }
   hr = enumerator->GetDefaultAudioEndpoint(direction, eConsole, device.receive());
   if (FAILED(hr)) {
     LOG("Could not get default audio endpoint: %lx", hr);
     return hr;
   }
 
@@ -1224,27 +1142,21 @@ stream_set_volume(cubeb_stream * stm, fl
 
   return CUBEB_OK;
 }
 } // namespace anonymous
 
 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;
   }
 
   cubeb * ctx = new cubeb();
 
   ctx->ops = &wasapi_ops;
@@ -1329,26 +1241,20 @@ void wasapi_destroy(cubeb * context)
 char const * wasapi_get_backend_id(cubeb * context)
 {
   return "wasapi";
 }
 
 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;
   }
 
   com_ptr<IAudioClient> client;
   hr = device->Activate(__uuidof(IAudioClient),
                         CLSCTX_INPROC_SERVER,
                         NULL, client.receive_vpp());
@@ -1366,44 +1272,38 @@ wasapi_get_max_channel_count(cubeb * ctx
   *max_channels = mix_format->nChannels;
 
   return CUBEB_OK;
 }
 
 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;
   }
 
   com_ptr<IAudioClient> client;
   hr = device->Activate(__uuidof(IAudioClient),
                         CLSCTX_INPROC_SERVER,
                         NULL, client.receive_vpp());
   if (FAILED(hr)) {
     LOG("Could not activate device for latency: %lx", hr);
     return CUBEB_ERROR;
   }
 
   /* 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);
     return CUBEB_ERROR;
   }
 
   LOG("default device period: %I64d", default_period);
 
@@ -1416,24 +1316,18 @@ wasapi_get_min_latency(cubeb * ctx, cube
   LOG("Minimum latency in frames: %u", *latency_frames);
 
   return CUBEB_OK;
 }
 
 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;
   }
 
   com_ptr<IAudioClient> client;
   hr = device->Activate(__uuidof(IAudioClient),
                         CLSCTX_INPROC_SERVER,
                         NULL, client.receive_vpp());
@@ -1450,53 +1344,16 @@ wasapi_get_preferred_sample_rate(cubeb *
 
   *rate = mix_format->nSamplesPerSec;
 
   LOG("Preferred sample rate for output: %u", *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
 waveformatex_update_derived_properties(WAVEFORMATEX * format)
 {
   format->nBlockAlign = format->wBitsPerSample * format->nChannels / 8;
   format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign;
   if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
@@ -1523,17 +1380,17 @@ handle_channel_layout(cubeb_stream * stm
 
   WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.get());
 
   /* Stash a copy of the original mix format in case we need to restore it later. */
   WAVEFORMATEXTENSIBLE hw_mix_format = *format_pcm;
 
   /* 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());
 
   /* Check if wasapi will accept our channel layout request. */
   WAVEFORMATEX * closest;
   HRESULT hr = audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,
                                                mix_format.get(),
                                                &closest);
@@ -1643,41 +1500,34 @@ int setup_wasapi_stream_one_side(cubeb_s
   com_heap_ptr<WAVEFORMATEX> mix_format(tmp);
 
   mix_format->wBitsPerSample = stm->bytes_per_sample * 8;
   if (mix_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
     WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.get());
     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. */
   if (mix_format->nChannels > 2) {
     handle_channel_layout(stm, direction, mix_format, stream_params);
   }
 
   mix_params->format = stream_params->format;
   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;
 
   // Check if a loopback device should be requested. Note that event callbacks
   // do not work with loopback devices, so only request these if not looping.
   if (is_loopback) {
     flags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
   } else {
@@ -1696,20 +1546,16 @@ int setup_wasapi_stream_one_side(cubeb_s
   }
 
   hr = audio_client->GetBufferSize(buffer_frame_count);
   if (FAILED(hr)) {
     LOG("Could not get the buffer size from the client"
         " 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) {
     hr = audio_client->SetEventHandle(event);
     if (FAILED(hr)) {
       LOG("Could set the event handle for the %s client %lx.",
           DIRECTION_NAME, hr);
       return CUBEB_ERROR;
@@ -1724,27 +1570,20 @@ int setup_wasapi_stream_one_side(cubeb_s
 
   return CUBEB_OK;
 }
 
 #undef DIRECTION_NAME
 
 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)) {
     LOG("(%p) Setup capture: device=%p", stm, stm->input_device.get());
     rv = setup_wasapi_stream_one_side(stm,
                                       &stm->input_stream_params,
                                       stm->input_device.get(),
                                       eCapture,
@@ -1807,18 +1646,18 @@ int setup_wasapi_stream(cubeb_stream * s
                                       stm->refill_event,
                                       stm->render_client,
                                       &stm->output_mix_params);
     if (rv != CUBEB_OK) {
       LOG("Failure to open the output side.");
       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;
     }
 
     XASSERT(stm->frames_written == 0);
     hr = stm->output_client->GetService(__uuidof(IAudioClock),
                                         stm->audio_clock.receive_vpp());
@@ -1876,35 +1715,63 @@ int setup_wasapi_stream(cubeb_stream * s
   if (has_input(stm) && has_output(stm)) {
     stm->refill_callback = refill_callback_duplex;
   } else if (has_input(stm)) {
     stm->refill_callback = refill_callback_input;
   } else if (has_output(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;
 }
 
 int
 wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
                    char const * stream_name,
                    cubeb_devid input_device,
                    cubeb_stream_params * input_stream_params,
                    cubeb_devid output_device,
                    cubeb_stream_params * output_stream_params,
                    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));
 
   if (output_stream_params && input_stream_params &&
       output_stream_params->format != input_stream_params->format) {
     return CUBEB_ERROR_INVALID_FORMAT;
   }
 
@@ -1912,45 +1779,36 @@ wasapi_stream_init(cubeb * context, cube
 
   stm->context = context;
   stm->data_callback = data_callback;
   stm->state_callback = state_callback;
   stm->user_ptr = user_ptr;
   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) {
     case CUBEB_SAMPLE_S16NE:
       stm->bytes_per_sample = sizeof(short);
       stm->waveformatextensible_sub_format = KSDATAFORMAT_SUBTYPE_PCM;
       stm->linear_input_buffer.reset(new auto_array_wrapper_impl<short>);
       break;
     case CUBEB_SAMPLE_FLOAT32NE:
       stm->bytes_per_sample = sizeof(float);
       stm->waveformatextensible_sub_format = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
       stm->linear_input_buffer.reset(new auto_array_wrapper_impl<float>);
       break;
     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;
 
   stm->reconfigure_event = CreateEvent(NULL, 0, 0, NULL);
   if (!stm->reconfigure_event) {
     LOG("Can't create the reconfigure event, error: %lx", GetLastError());
     return CUBEB_ERROR;
   }
@@ -1974,17 +1832,17 @@ wasapi_stream_init(cubeb * context, cube
        assert that the lock is held in the function. */
     auto_lock lock(stm->stream_reset_lock);
     rv = setup_wasapi_stream(stm.get());
   }
   if (rv != CUBEB_OK) {
     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. */
     LOG("failed to register notification client, %lx", hr);
   }
 
   *stream = stm.release();
 
@@ -2006,17 +1864,18 @@ void close_wasapi_stream(cubeb_stream * 
 
   stm->audio_stream_volume = nullptr;
 
   stm->audio_clock = nullptr;
   stm->total_frames_written += static_cast<UINT64>(round(stm->frames_written * stream_to_mix_samplerate_ratio(stm->output_stream_params, stm->output_mix_params)));
   stm->frames_written = 0;
 
   stm->resampler.reset();
-
+  stm->output_mixer.reset();
+  stm->input_mixer.reset();
   stm->mix_buffer.clear();
 }
 
 void wasapi_stream_destroy(cubeb_stream * stm)
 {
   XASSERT(stm);
   LOG("Stream destroy (%p)", stm);
 
@@ -2031,17 +1890,16 @@ void wasapi_stream_destroy(cubeb_stream 
   unregister_notification_client(stm);
 
   CloseHandle(stm->reconfigure_event);
   CloseHandle(stm->refill_event);
   CloseHandle(stm->input_available_event);
 
   // The variables intialized in wasapi_stream_init,
   // must be destroyed in wasapi_stream_destroy.
-  stm->mixer.reset();
   stm->linear_input_buffer.reset();
 
   {
     auto_lock lock(stm->stream_reset_lock);
     close_wasapi_stream(stm);
   }
 
   delete stm;
@@ -2437,30 +2295,27 @@ wasapi_create_device(cubeb * ctx, cubeb_
 
   return CUBEB_OK;
 }
 
 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;
   }
 
   if (type == CUBEB_DEVICE_TYPE_OUTPUT) flow = eRender;
   else if (type == CUBEB_DEVICE_TYPE_INPUT) flow = eCapture;
   else if (type & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) flow = eAll;
   else return CUBEB_ERROR;
 
@@ -2514,17 +2369,16 @@ wasapi_device_collection_destroy(cubeb *
 }
 
 cubeb_ops const wasapi_ops = {
   /*.init =*/ wasapi_init,
   /*.get_backend_id =*/ wasapi_get_backend_id,
   /*.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,
   /*.stream_init =*/ wasapi_stream_init,
   /*.stream_destroy =*/ wasapi_stream_destroy,
   /*.stream_start =*/ wasapi_stream_start,
   /*.stream_stop =*/ wasapi_stream_stop,
   /*.stream_reset_default_device =*/ wasapi_stream_reset_default_device,
--- a/third_party/rust/cubeb-sys/libcubeb/src/cubeb_winmm.c
+++ b/third_party/rust/cubeb-sys/libcubeb/src/cubeb_winmm.c
@@ -1045,17 +1045,16 @@ winmm_device_collection_destroy(cubeb * 
 }
 
 static struct cubeb_ops const winmm_ops = {
   /*.init =*/ winmm_init,
   /*.get_backend_id =*/ winmm_get_backend_id,
   /*.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,
   /*.stream_init =*/ winmm_stream_init,
   /*.stream_destroy =*/ winmm_stream_destroy,
   /*.stream_start =*/ winmm_stream_start,
   /*.stream_stop =*/ winmm_stream_stop,
   /*.stream_reset_default_device =*/ NULL,
--- a/third_party/rust/cubeb-sys/libcubeb/test/common.h
+++ b/third_party/rust/cubeb-sys/libcubeb/test/common.h
@@ -6,16 +6,17 @@
  */
 #if !defined(TEST_COMMON)
 #define TEST_COMMON
 
 #if defined( _WIN32)
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
 #endif
+#include <objbase.h>
 #include <windows.h>
 #else
 #include <unistd.h>
 #endif
 
 #include <cstdarg>
 #include "cubeb/cubeb.h"
 #include "cubeb_mixer.h"
@@ -39,41 +40,19 @@ void delay(unsigned int ms)
 
 #if !defined(M_PI)
 #define M_PI 3.14159265358979323846
 #endif
 
 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;
   int input_device_available = 0;
   int r;
   /* Bail out early if the host does not have input devices. */
   r = cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_INPUT, &devices);
   if (r != CUBEB_OK) {
@@ -126,9 +105,29 @@ int common_init(cubeb ** ctx, char const
       fprintf(stderr, "Requested backend `%s', got `%s'\n",
               backend, ctx_backend);
     }
   }
 
   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 */
--- a/third_party/rust/cubeb-sys/libcubeb/test/test_audio.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/test/test_audio.cpp
@@ -89,17 +89,17 @@ int supports_float32(string backend_id)
 
 /* Some backends don't have code to deal with more than mono or stereo. */
 int supports_channel_count(string backend_id, int nchannels)
 {
   return nchannels <= 2 ||
     (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;
 
   cubeb *ctx = NULL;
 
   r = common_init(&ctx, "Cubeb audio test: channels");
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb library\n");
@@ -111,23 +111,23 @@ int run_test(int num_channels, layout_in
   const char * backend_id = cubeb_get_backend_id(ctx);
 
   if ((is_float && !supports_float32(backend_id)) ||
       !supports_channel_count(backend_id, num_channels)) {
     /* don't treat this as a test failure. */
     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);
 
   cubeb_stream *stream = NULL;
   r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, &params,
       4096, is_float ? &data_cb<float> : &data_cb<short>, state_cb_audio, &synth);
   if (r != CUBEB_OK) {
@@ -241,17 +241,13 @@ TEST(cubeb, run_channel_rate_test)
     44100,
     48000,
   };
 
   for(auto channels : channel_values) {
     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);
     }
   }
 }
new file mode 100644
--- /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");
+}
--- a/third_party/rust/cubeb-sys/libcubeb/test/test_loopback.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/test/test_loopback.cpp
@@ -289,17 +289,17 @@ void run_loopback_duplex_test(bool is_fl
                         is_float ? data_cb_loop_duplex<float> : data_cb_loop_duplex<short>,
                         state_cb_loop, user_data.get());
   ASSERT_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(150);
+  delay(300);
   cubeb_stream_stop(stream);
 
   /* access after stop should not happen, but lock just in case and to appease sanitization tools */
   std::lock_guard<std::mutex> lock(user_data->user_state_mutex);
   std::vector<double> & output_frames = user_data->output_frames;
   std::vector<double> & input_frames = user_data->input_frames;
   ASSERT_EQ(output_frames.size(), input_frames.size())
     << "#Output frames != #input frames";
@@ -372,17 +372,17 @@ void run_loopback_separate_streams_test(
                         state_cb_loop, user_data.get());
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
 
   std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
     cleanup_output_stream_at_exit(output_stream, cubeb_stream_destroy);
 
   cubeb_stream_start(input_stream);
   cubeb_stream_start(output_stream);
-  delay(150);
+  delay(300);
   cubeb_stream_stop(output_stream);
   cubeb_stream_stop(input_stream);
 
   /* access after stop should not happen, but lock just in case and to appease sanitization tools */
   std::lock_guard<std::mutex> lock(user_data->user_state_mutex);
   std::vector<double> & output_frames = user_data->output_frames;
   std::vector<double> & input_frames = user_data->input_frames;
   ASSERT_LE(output_frames.size(), input_frames.size())
@@ -439,26 +439,26 @@ void run_loopback_silence_test(bool is_f
                         is_float ? data_cb_loop_input_only<float> : data_cb_loop_input_only<short>,
                         state_cb_loop, user_data.get());
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
 
   std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
     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 */
   std::lock_guard<std::mutex> lock(user_data->user_state_mutex);
   std::vector<double> & input_frames = user_data->input_frames;
 
   /* 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) {
     ASSERT_LT(abs(frame), EPISILON);
   }
 }
 
 TEST(cubeb, loopback_silence)
@@ -539,17 +539,17 @@ void run_loopback_device_selection_test(
                         state_cb_loop, user_data.get());
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
 
   std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
     cleanup_output_stream_at_exit(output_stream, cubeb_stream_destroy);
 
   cubeb_stream_start(input_stream);
   cubeb_stream_start(output_stream);
-  delay(150);
+  delay(300);
   cubeb_stream_stop(output_stream);
   cubeb_stream_stop(input_stream);
 
   /* access after stop should not happen, but lock just in case and to appease sanitization tools */
   std::lock_guard<std::mutex> lock(user_data->user_state_mutex);
   std::vector<double> & output_frames = user_data->output_frames;
   std::vector<double> & input_frames = user_data->input_frames;
   ASSERT_LE(output_frames.size(), input_frames.size())
deleted file mode 100644
--- 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);
-    }
-  }
-}
--- a/third_party/rust/cubeb-sys/libcubeb/test/test_sanity.cpp
+++ b/third_party/rust/cubeb-sys/libcubeb/test/test_sanity.cpp
@@ -109,17 +109,16 @@ TEST(cubeb, init_destroy_multiple_contex
   }
 }
 
 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");
   ASSERT_EQ(r, CUBEB_OK);
   ASSERT_NE(ctx, nullptr);
 
   params.channels = STREAM_CHANNELS;
   params.format = STREAM_FORMAT;
@@ -134,21 +133,16 @@ TEST(cubeb, context_variables)
   }
 
   r = cubeb_get_preferred_sample_rate(ctx, &value);
   ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
   if (r == CUBEB_OK) {
     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);
 }
 
 TEST(cubeb, init_destroy_stream)
 {
   int r;
   cubeb * ctx;
   cubeb_stream * stream;
--- a/third_party/rust/cubeb-sys/src/channel.rs
+++ b/third_party/rust/cubeb-sys/src/channel.rs
@@ -1,80 +1,69 @@
 // Copyright © 2017-2018 Mozilla Foundation
 //
 // 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,
+        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,
     }
 }
-
-#[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() }
-    }
-}
-
-// 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;
-}
--- a/third_party/rust/cubeb-sys/src/context.rs
+++ b/third_party/rust/cubeb-sys/src/context.rs
@@ -1,15 +1,14 @@
 // Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // 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};
 
 pub enum cubeb {}
 
 extern "C" {
     pub fn cubeb_init(
@@ -20,20 +19,16 @@ extern "C" {
     pub fn cubeb_get_backend_id(context: *mut cubeb) -> *const c_char;
     pub fn cubeb_get_max_channel_count(context: *mut cubeb, max_channels: *mut c_uint) -> c_int;
     pub fn cubeb_get_min_latency(
         context: *mut cubeb,
         params: *mut cubeb_stream_params,
         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,
         stream: *mut *mut cubeb_stream,
         stream_name: *const c_char,
         input_device: cubeb_devid,
         input_stream_params: *mut cubeb_stream_params,
         output_device: cubeb_devid,
--- a/third_party/rust/cubeb-sys/src/mixer.rs
+++ b/third_party/rust/cubeb-sys/src/mixer.rs
@@ -1,49 +1,31 @@
 // Copyright © 2017-2018 Mozilla Foundation
 //
 // 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;
 }
--- a/third_party/rust/cubeb/.cargo-checksum.json
+++ b/third_party/rust/cubeb/.cargo-checksum.json
@@ -1,1 +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
--- a/third_party/rust/cubeb/Cargo.toml
+++ b/third_party/rust/cubeb/Cargo.toml
@@ -7,24 +7,24 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [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"
 readme = "README.md"
 keywords = ["cubeb"]
 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"]
 [badges.circle-ci]
 repository = "djg/cubeb-rs"
--- a/third_party/rust/cubeb/examples/tone.rs
+++ b/third_party/rust/cubeb/examples/tone.rs
@@ -20,17 +20,17 @@ type Frame = MonoFrame<i16>;
 
 fn main() {
     let ctx = common::init("Cubeb tone example").expect("Failed to create cubeb context");
 
     let params = cubeb::StreamParamsBuilder::new()
         .format(STREAM_FORMAT)
         .rate(SAMPLE_FREQUENCY)
         .channels(1)
-        .layout(cubeb::ChannelLayout::Mono)
+        .layout(cubeb::ChannelLayout::MONO)
         .take();
 
     let mut position = 0u32;
 
     let mut builder = cubeb::StreamBuilder::<Frame>::new();
     builder
         .name("Cubeb tone (mono)")
         .default_output(&params)
--- a/third_party/rust/cubeb/src/stream.rs
+++ b/third_party/rust/cubeb/src/stream.rs
@@ -15,17 +15,17 @@
 //!
 //! fn main() {
 //!     let ctx = cubeb::init("Cubeb tone example").unwrap();
 //!
 //!     let params = cubeb::StreamParamsBuilder::new()
 //!         .format(cubeb::SampleFormat::Float32LE)
 //!         .rate(44_100)
 //!         .channels(1)
-//!         .layout(cubeb::ChannelLayout::Mono)
+//!         .layout(cubeb::ChannelLayout::MONO)
 //!         .prefs(cubeb::StreamPrefs::NONE)
 //!         .take();
 //!
 //!     let phase_inc = 440.0 / 44_100.0;
 //!     let mut phase = 0.0;
 //!     let volume = 0.25;
 //!
 //!     let mut builder = cubeb::StreamBuilder::<Frame>::new();
deleted file mode 100644
--- 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) }
-        }
-    })
-}
deleted file mode 100644
--- 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))) }
-}
--- a/toolkit/library/rust/shared/Cargo.toml
+++ b/toolkit/library/rust/shared/Cargo.toml
@@ -11,17 +11,17 @@ mp4parse_capi = { path = "../../../../me
 nsstring = { path = "../../../../servo/support/gecko/nsstring" }
 nserror = { path = "../../../../xpcom/rust/nserror" }
 netwerk_helper = { path = "../../../../netwerk/base/rust-helper" }
 xpcom = { path = "../../../../xpcom/rust/xpcom" }
 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 }
 audioipc-server = { path = "../../../../media/audioipc/server", optional = true }
 u2fhid = { path = "../../../../dom/webauthn/u2f-hid-rs" }
 rsdparsa_capi = { path = "../../../../media/webrtc/signaling/src/sdp/rsdparsa_capi" }
 # We have these to enforce common feature sets for said crates.
 log = {version = "0.3", features = ["release_max_level_info"]}