Bug 1895787 - Update cubeb rust repos to support audio dumping and more. r=cubeb-reviewers,supply-chain-reviewers,padenot

The "more" is mainly some fixes in the coreaudio backend, including:
- serializing more audio operations onto the serial queue
- using the correct audio unit scope when querying for its stream format
- tightening up some potential races around reinit on certain errors

Differential Revision: https://phabricator.services.mozilla.com/D211042
This commit is contained in:
Andreas Pehrson 2024-05-22 20:43:23 +00:00
parent 5fdd6bd754
commit e71ae3a83f
51 changed files with 1030 additions and 281 deletions

View file

@ -65,19 +65,19 @@ git = "https://github.com/mozilla/application-services"
rev = "e0563d725f852f617878ecc13a03cdf50c85cd5a"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/audioipc?rev=409e11f8de6288e9ddfe269654523735302e59e6"]
[source."git+https://github.com/mozilla/audioipc?rev=3495905752a4263827f5d43737f9ca3ed0243ce0"]
git = "https://github.com/mozilla/audioipc"
rev = "409e11f8de6288e9ddfe269654523735302e59e6"
rev = "3495905752a4263827f5d43737f9ca3ed0243ce0"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4ca174cf83ebe32b3198478c2211d69678845bc7"]
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=0989726a1b9b640a30dfdf3ea005a12c73ab8155"]
git = "https://github.com/mozilla/cubeb-coreaudio-rs"
rev = "4ca174cf83ebe32b3198478c2211d69678845bc7"
rev = "0989726a1b9b640a30dfdf3ea005a12c73ab8155"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=8ff972c8e2ec1782ff262ac4071c0415e69b1367"]
[source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2"]
git = "https://github.com/mozilla/cubeb-pulse-rs"
rev = "8ff972c8e2ec1782ff262ac4071c0415e69b1367"
rev = "8678dcab1c287de79c4c184ccc2e065bc62b70e2"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/midir.git?rev=85156e360a37d851734118104619f86bd18e94c6"]

32
Cargo.lock generated
View file

@ -260,7 +260,7 @@ dependencies = [
[[package]]
name = "audioipc2"
version = "0.6.0"
source = "git+https://github.com/mozilla/audioipc?rev=409e11f8de6288e9ddfe269654523735302e59e6#409e11f8de6288e9ddfe269654523735302e59e6"
source = "git+https://github.com/mozilla/audioipc?rev=3495905752a4263827f5d43737f9ca3ed0243ce0#3495905752a4263827f5d43737f9ca3ed0243ce0"
dependencies = [
"arrayvec",
"ashmem",
@ -288,7 +288,7 @@ dependencies = [
[[package]]
name = "audioipc2-client"
version = "0.6.0"
source = "git+https://github.com/mozilla/audioipc?rev=409e11f8de6288e9ddfe269654523735302e59e6#409e11f8de6288e9ddfe269654523735302e59e6"
source = "git+https://github.com/mozilla/audioipc?rev=3495905752a4263827f5d43737f9ca3ed0243ce0#3495905752a4263827f5d43737f9ca3ed0243ce0"
dependencies = [
"audio_thread_priority",
"audioipc2",
@ -299,7 +299,7 @@ dependencies = [
[[package]]
name = "audioipc2-server"
version = "0.6.0"
source = "git+https://github.com/mozilla/audioipc?rev=409e11f8de6288e9ddfe269654523735302e59e6#409e11f8de6288e9ddfe269654523735302e59e6"
source = "git+https://github.com/mozilla/audioipc?rev=3495905752a4263827f5d43737f9ca3ed0243ce0#3495905752a4263827f5d43737f9ca3ed0243ce0"
dependencies = [
"audio_thread_priority",
"audioipc2",
@ -941,7 +941,7 @@ dependencies = [
[[package]]
name = "coreaudio-sys-utils"
version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4ca174cf83ebe32b3198478c2211d69678845bc7#4ca174cf83ebe32b3198478c2211d69678845bc7"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=0989726a1b9b640a30dfdf3ea005a12c73ab8155#0989726a1b9b640a30dfdf3ea005a12c73ab8155"
dependencies = [
"core-foundation-sys",
"coreaudio-sys",
@ -1160,27 +1160,27 @@ dependencies = [
[[package]]
name = "cubeb"
version = "0.12.0"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db57570f2617f0214c11721e8d2325816d9dc936c2c472661ac5d90a30fba98"
checksum = "3d105547cf8036cdb30e796ce0d06832af4766106a44574402fa2fd3c861a042"
dependencies = [
"cubeb-core",
]
[[package]]
name = "cubeb-backend"
version = "0.12.0"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b00b0f3b84e315571bd8c4e18794180633066267a413f2f05bca65001adc8410"
checksum = "67361fe9b49b4599e2a230ce322529b6ddd91df14897c872dcede716f8fbca81"
dependencies = [
"cubeb-core",
]
[[package]]
name = "cubeb-core"
version = "0.12.0"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2380c03a7df0ea3744f6a210d6340f423935e53cbf2fd68ada84b5e808e46ac7"
checksum = "ac08d314dd1ec6d41d9ccdeec70899c98ed3b89845367000dd6096099481bc73"
dependencies = [
"bitflags 1.999.999",
"cubeb-sys",
@ -1189,7 +1189,7 @@ dependencies = [
[[package]]
name = "cubeb-coreaudio"
version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4ca174cf83ebe32b3198478c2211d69678845bc7#4ca174cf83ebe32b3198478c2211d69678845bc7"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=0989726a1b9b640a30dfdf3ea005a12c73ab8155#0989726a1b9b640a30dfdf3ea005a12c73ab8155"
dependencies = [
"atomic",
"audio-mixer",
@ -1208,7 +1208,7 @@ dependencies = [
[[package]]
name = "cubeb-pulse"
version = "0.5.0"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=8ff972c8e2ec1782ff262ac4071c0415e69b1367#8ff972c8e2ec1782ff262ac4071c0415e69b1367"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2#8678dcab1c287de79c4c184ccc2e065bc62b70e2"
dependencies = [
"cubeb-backend",
"pulse",
@ -1219,9 +1219,9 @@ dependencies = [
[[package]]
name = "cubeb-sys"
version = "0.12.0"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c20c457d7b34dad6e0c1a9c759c96b4420b9e9917a572998b81835799a07e1d"
checksum = "26073cd50c7b6ba4272204839f56921557609a0d67e092882cbb903df94cab39"
dependencies = [
"cmake",
"pkg-config",
@ -4649,7 +4649,7 @@ dependencies = [
[[package]]
name = "pulse"
version = "0.3.0"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=8ff972c8e2ec1782ff262ac4071c0415e69b1367#8ff972c8e2ec1782ff262ac4071c0415e69b1367"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2#8678dcab1c287de79c4c184ccc2e065bc62b70e2"
dependencies = [
"bitflags 2.5.0",
"pulse-ffi",
@ -4658,7 +4658,7 @@ dependencies = [
[[package]]
name = "pulse-ffi"
version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=8ff972c8e2ec1782ff262ac4071c0415e69b1367#8ff972c8e2ec1782ff262ac4071c0415e69b1367"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2#8678dcab1c287de79c4c184ccc2e065bc62b70e2"
dependencies = [
"libc",
]

View file

@ -1288,6 +1288,11 @@ who = "Andreas Pehrson <apehrson@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.10.3 -> 0.12.0"
[[audits.cubeb]]
who = "Andreas Pehrson <apehrson@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.12.0 -> 0.13.0"
[[audits.cubeb-backend]]
who = "Matthew Gregan <kinetik@flim.org>"
criteria = "safe-to-deploy"
@ -1319,6 +1324,11 @@ who = "Andreas Pehrson <apehrson@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.10.7 -> 0.12.0"
[[audits.cubeb-backend]]
who = "Andreas Pehrson <apehrson@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.12.0 -> 0.13.0"
[[audits.cubeb-core]]
who = "Matthew Gregan <kinetik@flim.org>"
criteria = "safe-to-deploy"
@ -1355,6 +1365,11 @@ who = "Andreas Pehrson <apehrson@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.10.7 -> 0.12.0"
[[audits.cubeb-core]]
who = "Andreas Pehrson <apehrson@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.12.0 -> 0.13.0"
[[audits.cubeb-sys]]
who = "Matthew Gregan <kinetik@flim.org>"
criteria = "safe-to-deploy"
@ -1386,6 +1401,11 @@ who = "Andreas Pehrson <apehrson@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.10.7 -> 0.12.0"
[[audits.cubeb-sys]]
who = "Andreas Pehrson <apehrson@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.12.0 -> 0.13.0"
[[audits.d3d12]]
who = "Jim Blandy <jimb@red-bean.com>"
criteria = "safe-to-deploy"

View file

@ -1 +1 @@
{"files":{"Cargo.toml":"e94c46bbd290f02adccc7ae932285416d7e021bfde80abb2fb31a2c05426e732","cbindgen.toml":"fb6abe1671497f432a06e40b1db7ed7cd2cceecbd9a2382193ad7534e8855e34","src/context.rs":"a0559e92b554ef3156ab2bf2f1424555c8ef4a7977b9f43ac8500a9f399f8d99","src/lib.rs":"c87d9d57a16a9286cde730978db692df0fbc70cc69dd4f4677198d6843031fd8","src/send_recv.rs":"859abe75b521eb4297c84b30423814b5b87f3c7741ad16fe72189212e123e1ac","src/stream.rs":"90dc6a85552f3569ab1847de4247a46bcff2f5aef0c4d43fa2376589df015b25"},"package":null}
{"files":{"Cargo.toml":"b4fad65749eb0988ce4e6b6a2aae51e58ae22eca97cf61dfb011e951a0909f0e","cbindgen.toml":"fb6abe1671497f432a06e40b1db7ed7cd2cceecbd9a2382193ad7534e8855e34","src/context.rs":"a0559e92b554ef3156ab2bf2f1424555c8ef4a7977b9f43ac8500a9f399f8d99","src/lib.rs":"c87d9d57a16a9286cde730978db692df0fbc70cc69dd4f4677198d6843031fd8","src/send_recv.rs":"859abe75b521eb4297c84b30423814b5b87f3c7741ad16fe72189212e123e1ac","src/stream.rs":"90dc6a85552f3569ab1847de4247a46bcff2f5aef0c4d43fa2376589df015b25"},"package":null}

View file

@ -21,7 +21,7 @@ description = "Cubeb Backend for talking to remote cubeb server."
license = "ISC"
[dependencies]
cubeb-backend = "0.12"
cubeb-backend = "0.13"
log = "0.4"
[dependencies.audio_thread_priority]

View file

@ -1 +1 @@
{"files":{"Cargo.toml":"77997660e305851d9c0e656aac7159b999452a36f3436d8b2f402edd36fef853","cbindgen.toml":"fb6abe1671497f432a06e40b1db7ed7cd2cceecbd9a2382193ad7534e8855e34","src/lib.rs":"d70079c66de72c3469504f1f0c9cf5e510644cac17f2d8300b8d12218740e07b","src/server.rs":"187e2236aa9f2fb6cc4a533d40714a71504afa5ef9d849ac28b7f26032859c29"},"package":null}
{"files":{"Cargo.toml":"62eab883f31c0c088ff865fe2e4305d987b7b534f6cdfe1e5812072a2ec13f8b","cbindgen.toml":"fb6abe1671497f432a06e40b1db7ed7cd2cceecbd9a2382193ad7534e8855e34","src/lib.rs":"d70079c66de72c3469504f1f0c9cf5e510644cac17f2d8300b8d12218740e07b","src/server.rs":"187e2236aa9f2fb6cc4a533d40714a71504afa5ef9d849ac28b7f26032859c29"},"package":null}

View file

@ -21,7 +21,7 @@ description = "Remote cubeb server"
license = "ISC"
[dependencies]
cubeb-core = "0.12.0"
cubeb-core = "0.13"
log = "0.4"
once_cell = "1.2.0"
slab = "0.4"

View file

@ -1 +1 @@
{"files":{"Cargo.toml":"dff67ba050be15275d357b7f001df6caa6ae1f93b2acd61ac7d6ee269a1f5960","benches/serialization.rs":"d56855d868dab6aa22c8b03a61084535351b76c94b68d8b1d20764e352fe473f","build.rs":"65df9a97c6cdaa3faf72581f04ac289197b0b1797d69d22c1796e957ff1089e2","src/codec.rs":"86068272e220696d8d7e369072326349e7598e5a24223d98179c3251bb7b3ff1","src/errors.rs":"67a4a994d0724397657581cde153bdfc05ce86e7efc467f23fafc8f64df80fa4","src/ipccore.rs":"db73e916468c54d3497d75ffcab3bf23067771ed7b2e1a23c714429f56f59ec3","src/lib.rs":"a6fcac8b44318435db60313d3ef32ff3fada390bea8978c8414c40744998b98b","src/messages.rs":"d4f6d4f41b7fd3cc7deae726657e1100f315f4cd10c5fe6ce8a57c03c8e26ca9","src/rpccore.rs":"025b6614f1c42b96b0a8e74fd7881032d338c66e0d67ec0af70f910a9e30ebe1","src/shm.rs":"c00d16f4af510d12e704ae865f7348ad64ddef180e42b18e7dd95c4be35a9c80","src/sys/mod.rs":"e6fa1d260abf093e1f7b50185195e2d3aee0eb8c9774c6f253953b5896d838f3","src/sys/unix/cmsg.rs":"9529e8f8429db86f7c5df132953d3054e603852270f3c6938cdb5f630b2711f1","src/sys/unix/cmsghdr.c":"d7344b3dc15cdce410c68669b848bb81f7fe36362cd3699668cb613fa05180f8","src/sys/unix/mod.rs":"59835f0d5509940078b1820a54f49fc5514adeb3e45e7d21e3ab917431da2e74","src/sys/unix/msg.rs":"0e297d73bae9414184f85c2209cca0a3fde6d999a3f1d3f42faa3f56b6d57233","src/sys/windows/mod.rs":"7eaabb76e62c6962b636320e2bbf79a78fce61659c799a798f7dd6d56b0be8a1"},"package":null}
{"files":{"Cargo.toml":"5dc7153bf7291eea52bdc5561440c1c646272f8c913e8782bc2c84b7ed2f8b76","benches/serialization.rs":"d56855d868dab6aa22c8b03a61084535351b76c94b68d8b1d20764e352fe473f","build.rs":"65df9a97c6cdaa3faf72581f04ac289197b0b1797d69d22c1796e957ff1089e2","src/codec.rs":"86068272e220696d8d7e369072326349e7598e5a24223d98179c3251bb7b3ff1","src/errors.rs":"67a4a994d0724397657581cde153bdfc05ce86e7efc467f23fafc8f64df80fa4","src/ipccore.rs":"db73e916468c54d3497d75ffcab3bf23067771ed7b2e1a23c714429f56f59ec3","src/lib.rs":"a6fcac8b44318435db60313d3ef32ff3fada390bea8978c8414c40744998b98b","src/messages.rs":"d4f6d4f41b7fd3cc7deae726657e1100f315f4cd10c5fe6ce8a57c03c8e26ca9","src/rpccore.rs":"025b6614f1c42b96b0a8e74fd7881032d338c66e0d67ec0af70f910a9e30ebe1","src/shm.rs":"c00d16f4af510d12e704ae865f7348ad64ddef180e42b18e7dd95c4be35a9c80","src/sys/mod.rs":"e6fa1d260abf093e1f7b50185195e2d3aee0eb8c9774c6f253953b5896d838f3","src/sys/unix/cmsg.rs":"9529e8f8429db86f7c5df132953d3054e603852270f3c6938cdb5f630b2711f1","src/sys/unix/cmsghdr.c":"d7344b3dc15cdce410c68669b848bb81f7fe36362cd3699668cb613fa05180f8","src/sys/unix/mod.rs":"59835f0d5509940078b1820a54f49fc5514adeb3e45e7d21e3ab917431da2e74","src/sys/unix/msg.rs":"25244de3eba920fa42e032f8fa4ea4913a9fdeb5124ade61e707f6cc6dd946b0","src/sys/windows/mod.rs":"7eaabb76e62c6962b636320e2bbf79a78fce61659c799a798f7dd6d56b0be8a1"},"package":null}

View file

@ -29,7 +29,7 @@ bincode = "1.3"
byteorder = "1"
bytes = "1"
crossbeam-queue = "0.3"
cubeb = "0.12"
cubeb = "0.13"
log = "0.4"
scopeguard = "1.1.0"
serde = "1"

View file

@ -34,7 +34,7 @@ pub(crate) fn recv_msg_with_flags(
flags: libc::c_int,
) -> io::Result<(usize, usize, libc::c_int)> {
let slice = unix::as_os_slice_mut(bufs);
let len = cmp::min(<libc::c_int>::max_value() as usize, slice.len());
let len = cmp::min(<libc::c_int>::MAX as usize, slice.len());
let (control, controllen) = if cmsg.len() == 0 {
(ptr::null_mut(), 0)
} else {
@ -63,7 +63,7 @@ pub(crate) fn send_msg_with_flags(
flags: libc::c_int,
) -> io::Result<usize> {
let slice = unix::as_os_slice(bufs);
let len = cmp::min(<libc::c_int>::max_value() as usize, slice.len());
let len = cmp::min(<libc::c_int>::MAX as usize, slice.len());
let (control, controllen) = if cmsg.is_empty() {
(ptr::null_mut(), 0)
} else {

View file

@ -1 +1 @@
{"files":{"Cargo.toml":"b3a6e03dbc48515bbca791eba64096ab43dddafa6c60eec2b824369e2afb31b8","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/capi.rs":"d9bc993ea8bb51220c5cdc54488bc795f74411fe688332bd80dbb062c41342bb","src/lib.rs":"4ce6db20f88487e99057ebeae0615fa1c99e82cfee0ab0825936da2e108fc73e","src/log.rs":"968b839a8a5a56fe42e372678fdd580e2777e1dba8c4f0bee6fbfe5e3f03b860","src/ops.rs":"e631eba0d1ef8c13287361be32c0806d7869f598f58266bab0a45642521fa07e","src/traits.rs":"45e3e58772dd0ff40bf36d56dd9f1fc682cc08cea570022fa50eae1c34d43a3a","tests/test_capi.rs":"783c8321dceb33a414168ae64e162f934015144f49118d868557009819a20e06"},"package":"b00b0f3b84e315571bd8c4e18794180633066267a413f2f05bca65001adc8410"}
{"files":{"Cargo.toml":"ea3e08eb6e9fd52717bf756cf2a7063afeb3af617df0dee2f14591f45b9e6f62","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/capi.rs":"d9bc993ea8bb51220c5cdc54488bc795f74411fe688332bd80dbb062c41342bb","src/lib.rs":"4ce6db20f88487e99057ebeae0615fa1c99e82cfee0ab0825936da2e108fc73e","src/log.rs":"968b839a8a5a56fe42e372678fdd580e2777e1dba8c4f0bee6fbfe5e3f03b860","src/ops.rs":"e631eba0d1ef8c13287361be32c0806d7869f598f58266bab0a45642521fa07e","src/traits.rs":"876ea164c03d198c92a61d9b11d2839c3a257ae48042b9cd2d9ececcf00d373a","tests/test_capi.rs":"783c8321dceb33a414168ae64e162f934015144f49118d868557009819a20e06"},"package":"67361fe9b49b4599e2a230ce322529b6ddd91df14897c872dcede716f8fbca81"}

View file

@ -11,7 +11,7 @@
[package]
name = "cubeb-backend"
version = "0.12.0"
version = "0.13.0"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
description = """
Bindings to libcubeb internals to facilitate implementing cubeb backends in rust.
@ -23,7 +23,7 @@ license = "ISC"
repository = "https://github.com/mozilla/cubeb-rs"
[dependencies.cubeb-core]
version = "0.12.0"
version = "0.13.0"
[features]
gecko-in-tree = ["cubeb-core/gecko-in-tree"]

View file

@ -24,7 +24,7 @@ pub trait ContextOps {
collection: &DeviceCollectionRef,
) -> Result<()>;
fn device_collection_destroy(&mut self, collection: &mut DeviceCollectionRef) -> Result<()>;
#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
#[allow(clippy::too_many_arguments)]
fn stream_init(
&mut self,
stream_name: Option<&CStr>,

View file

@ -1 +1 @@
{"files":{"Cargo.toml":"9f1c5d546cc66c991eafd6369bb8799f6021e677217b86f092d08c6a1e6fee6a","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/builders.rs":"87adbbdd63fde848eeaae4a79a04859ed02ca982fb644f6b8b5fe7c158a8944c","src/call.rs":"cf8949c2cf53f5418d8e5222f570b9301a98a476a18c734fc2ebbc8b53ac0165","src/channel.rs":"c88b8846e53bbec6b125a4fa6a3787c48312be958bd08cc5ee773b218d93d683","src/context.rs":"ac5937037e69f32bb3ef5985d1921f53a2651d0068c12f90762eb0e18489e93e","src/device.rs":"86fd507bf1cd97b13b8cf3e92519b3be11904be68d4997658b276d5054162cd7","src/device_collection.rs":"f86535ffeee73b889bdbac1c5a3432b01cca86df819a7cc26eaa0c983d30cbbe","src/error.rs":"3693bf575e9504b9b1ab114de3e2ce7132039acf27ec68967dae66c2ce1581aa","src/ffi_types.rs":"71948d0949675df876e18c4340f4e693fc6a14c4de9d63a3885450c95577596b","src/format.rs":"7162c1550be53f5fe94b0bba4c71fea2f0304462108657c62a20ea47207ca413","src/lib.rs":"57ecf793ab1cc052c021ccbf9ad011ea52d1303e2dbc54adea90a95b5d7a36cf","src/log.rs":"4bef74d7a7fd9ffdf249be5ef95781969f00a7ecff2d3a190d5b1536d1635a73","src/stream.rs":"9fbfc65f77fb1009f8578c530744276828a6d6778f53b96decb698d937c2b098","src/util.rs":"308cfbaacd615ff600e74415c52daeef007fff34a4a0648a73c0042f6067f84f"},"package":"2380c03a7df0ea3744f6a210d6340f423935e53cbf2fd68ada84b5e808e46ac7"}
{"files":{"Cargo.toml":"23878f9ab656986033932729656b52e131f3fc186be68fa7bbef288d6d7590d8","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","src/builders.rs":"584d3e911d55746ab6ff9aed4c5901a73a9518ac14fa2e589fe169541ec78e33","src/call.rs":"cf8949c2cf53f5418d8e5222f570b9301a98a476a18c734fc2ebbc8b53ac0165","src/channel.rs":"c88b8846e53bbec6b125a4fa6a3787c48312be958bd08cc5ee773b218d93d683","src/context.rs":"f58f8562599d27ab4a9bf76d429a5b7dc971449c20245803fc857ddb6e3090cc","src/device.rs":"86fd507bf1cd97b13b8cf3e92519b3be11904be68d4997658b276d5054162cd7","src/device_collection.rs":"f86535ffeee73b889bdbac1c5a3432b01cca86df819a7cc26eaa0c983d30cbbe","src/error.rs":"3693bf575e9504b9b1ab114de3e2ce7132039acf27ec68967dae66c2ce1581aa","src/ffi_types.rs":"71948d0949675df876e18c4340f4e693fc6a14c4de9d63a3885450c95577596b","src/format.rs":"7162c1550be53f5fe94b0bba4c71fea2f0304462108657c62a20ea47207ca413","src/lib.rs":"57ecf793ab1cc052c021ccbf9ad011ea52d1303e2dbc54adea90a95b5d7a36cf","src/log.rs":"4bef74d7a7fd9ffdf249be5ef95781969f00a7ecff2d3a190d5b1536d1635a73","src/stream.rs":"9fbfc65f77fb1009f8578c530744276828a6d6778f53b96decb698d937c2b098","src/util.rs":"308cfbaacd615ff600e74415c52daeef007fff34a4a0648a73c0042f6067f84f"},"package":"ac08d314dd1ec6d41d9ccdeec70899c98ed3b89845367000dd6096099481bc73"}

View file

@ -11,7 +11,7 @@
[package]
name = "cubeb-core"
version = "0.12.0"
version = "0.13.0"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
description = """
Common types and definitions for cubeb rust and C bindings. Not intended for direct use.
@ -26,7 +26,7 @@ repository = "https://github.com/mozilla/cubeb-rs"
version = "1.2.0"
[dependencies.cubeb-sys]
version = "0.12.0"
version = "0.13"
[features]
gecko-in-tree = ["cubeb-sys/gecko-in-tree"]

View file

@ -6,7 +6,6 @@
use ffi;
use {ChannelLayout, SampleFormat, StreamParams, StreamPrefs};
///
#[derive(Debug)]
pub struct StreamParamsBuilder(ffi::cubeb_stream_params);

View file

@ -95,7 +95,7 @@ impl ContextRef {
///
/// This function is unsafe because it dereferences the given `data_callback`, `state_callback`, and `user_ptr` pointers.
/// The caller should ensure those pointers are valid.
#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
#[allow(clippy::too_many_arguments)]
pub unsafe fn stream_init(
&self,
stream_name: Option<&CStr>,

View file

@ -1 +1 @@
{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"ac8f4cf5b7631b5c738d50c0cf78113bd395940b9e76593904bbaf2d02d16a70",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"a16b883e4fb41bdbbe5f68158040f181aeeffb4573ab0d493e9452f7c6f00541","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"0007782a05a5330f739ad789c19c82562c82e32386b0447000fc72c0d48405bc","build-audiounit-rust-in-cubeb.sh":"d228a05985dcd02ec1ecac66a2b64dae5a530804a25a7054ccc95905aedfb7ef","install_git_hook.sh":"d38c8e51e636f6b90b489621ac34ccd1d1b1f40dccce3d178ed1da1c5068f16d","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"90c2542fa3ff8a35fed894fae3a1aa0157117b7f0e28df14b8e6f7b1f1f43797","run_sanitizers.sh":"84e93a0da137803018f37403511e8c92760be730426bf6cea34419d93d1a7ff8","run_tests.sh":"bae82f66dd47a060b6fdcc238520084aec1079d5b1b1d66d103baa1ffaa8773d","src/backend/aggregate_device.rs":"db7d644358090b1d65ff2d53ad854369790ae4ad7dfa12b79888c0002c1b4950","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"e9bcf964347daa8952f98caa2746e34a31ea8908375204896593f56e4b6147ca","src/backend/device_property.rs":"a7622feaa41db1cd76fd35a85a022e44f4894e396a104a59008d5b8757d2ab4e","src/backend/mixer.rs":"c4d09291598cbffb2217b551770ec590f34b6dd6b461dd99b019d5bb70f0eef3","src/backend/mod.rs":"d75e116a58d63c6a7cb281d160066f48c8c449702dad58c762ad50d9512d7bd3","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"770cf90f32b5ab2203476031c1fbc8379b713baa97bec36f7fd0d77fef1efd60","src/backend/tests/api.rs":"773e88b506efccf0eacbf408d34dea1fb2c5a8500e7fe8a494a97f15f1ea41fc","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"babf50326fb38db24fe80f24f546e1b6ad04319ae8835bb372d893fc9b3038a2","src/backend/tests/device_property.rs":"73c25f579a995e8a59c9b7d391813afb75f739b5e2f825480cba04499a1d46e8","src/backend/tests/interfaces.rs":"654333cd6d6023e72ba392d98872d33bc55f8f052205a9f701aec72069449e24","src/backend/tests/manual.rs":"e550cc8bb7619bb80b68e49bf7f475c029e0f1b34323d1d30edcbe322cf4efc7","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"a7ebd579339c40ca64c0757cc9da6baec641e670f226e1b2ec5049894700bd7a","src/backend/tests/tone.rs":"b028c67777b6453a26190b6a49785dfe28556adcbe179cb10862ce0d47ee8509","src/backend/tests/utils.rs":"80d7e4ebc06b23c63a4d2867e0c80e0bfe05449fa55edd21e785ed2c089bf7d5","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"package":null}
{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"cf6ebe6d41b022897360866b526d19ba8843aa82ae99a1d28393985576b6a782",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"2698cf87581d8d551ed3ac5875564720ed23d7b788e8d145d4281c8026203cd2","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"0007782a05a5330f739ad789c19c82562c82e32386b0447000fc72c0d48405bc","build-audiounit-rust-in-cubeb.sh":"d228a05985dcd02ec1ecac66a2b64dae5a530804a25a7054ccc95905aedfb7ef","install_git_hook.sh":"d38c8e51e636f6b90b489621ac34ccd1d1b1f40dccce3d178ed1da1c5068f16d","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"90c2542fa3ff8a35fed894fae3a1aa0157117b7f0e28df14b8e6f7b1f1f43797","run_sanitizers.sh":"84e93a0da137803018f37403511e8c92760be730426bf6cea34419d93d1a7ff8","run_tests.sh":"bae82f66dd47a060b6fdcc238520084aec1079d5b1b1d66d103baa1ffaa8773d","src/backend/aggregate_device.rs":"6e94c36c09081a728b1ab748b460fe8f538cf5f50bc62fd47171a393fe2d609a","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"e9bcf964347daa8952f98caa2746e34a31ea8908375204896593f56e4b6147ca","src/backend/device_property.rs":"0714b90c3187b0b1709f5e4b7757e1b434659276e00db48a3f3270fbfd429640","src/backend/mixer.rs":"c4d09291598cbffb2217b551770ec590f34b6dd6b461dd99b019d5bb70f0eef3","src/backend/mod.rs":"cfda5e4d5f7d3f6fda65fbcbf19bb114cdd2d9b6750c03967a4432bd1bfb788e","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"48e291b355a7c0c643fc58e9d238ed00234b4f1ac0f4c26737cc74862d4f2ac8","src/backend/tests/api.rs":"ef3babcd3410394b8d5bcdaf0ea526486b14d8e42f33211997aafe179430bf4a","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"babf50326fb38db24fe80f24f546e1b6ad04319ae8835bb372d893fc9b3038a2","src/backend/tests/device_property.rs":"73c25f579a995e8a59c9b7d391813afb75f739b5e2f825480cba04499a1d46e8","src/backend/tests/interfaces.rs":"cd58614435574444d8a1f039dc201cf371cccacd58efbae8ed8fbff919550d0a","src/backend/tests/manual.rs":"16dca201d7a7c6d37186aafdee277d437fc2ce5bbd215f33e660c6cb971395de","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"a7ebd579339c40ca64c0757cc9da6baec641e670f226e1b2ec5049894700bd7a","src/backend/tests/tone.rs":"b028c67777b6453a26190b6a49785dfe28556adcbe179cb10862ce0d47ee8509","src/backend/tests/utils.rs":"21c8e7f6f18da0f8d33733ad0fc981041b43586db6a637c3f7aec7e7b3936aed","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"package":null}

View file

@ -33,10 +33,13 @@ jobs:
rustc --version
cargo --version
- name: Setup Audio
- name: Setup switchaudio
if: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }}
run: |
brew install switchaudio-osx
- name: Setup blackhole-2ch
run: |
brew install blackhole-2ch
SwitchAudioSource -s "BlackHole 2ch" -t input
SwitchAudioSource -s "BlackHole 2ch" -t output

View file

@ -29,7 +29,7 @@ crate-type = [
atomic = "0.4"
audio-mixer = "0.2"
bitflags = "2"
cubeb-backend = "0.12.0"
cubeb-backend = "0.13"
float-cmp = "0.6"
lazy_static = "1.2"
libc = "0.2"

View file

@ -149,11 +149,12 @@ impl AggregateDevice {
pub fn create_blank_device_sync(
plugin_id: AudioObjectID,
) -> std::result::Result<AudioObjectID, Error> {
debug_assert_running_serially();
let waiting_time = Duration::new(5, 0);
let condvar_pair = Arc::new((Mutex::new(Vec::<AudioObjectID>::new()), Condvar::new()));
let condvar_pair = Arc::new((Mutex::new(()), Condvar::new()));
let mut cloned_condvar_pair = condvar_pair.clone();
let data_ptr = &mut cloned_condvar_pair as *mut Arc<(Mutex<Vec<AudioObjectID>>, Condvar)>;
let data_ptr = &mut cloned_condvar_pair as *mut Arc<(Mutex<()>, Condvar)>;
let address = get_property_address(
Property::HardwareDevices,
@ -182,19 +183,19 @@ impl AggregateDevice {
// Wait until the aggregate is created.
let (lock, cvar) = &*condvar_pair;
let devices = lock.lock().unwrap();
if !devices.contains(&device) {
let (devs, timeout_res) = cvar.wait_timeout(devices, waiting_time).unwrap();
let guard = lock.lock().unwrap();
let (_guard, timeout_res) = cvar
.wait_timeout_while(guard, waiting_time, |()| {
!audiounit_get_devices().contains(&device)
})
.unwrap();
if timeout_res.timed_out() {
cubeb_log!(
"Time out for waiting the creation of aggregate device {}!",
device
);
}
if !devs.contains(&device) {
return Err(Error::from(waiting_time));
}
}
extern "C" fn devices_changed_callback(
id: AudioObjectID,
@ -203,10 +204,9 @@ impl AggregateDevice {
data: *mut c_void,
) -> OSStatus {
assert_eq!(id, kAudioObjectSystemObject);
let pair = unsafe { &mut *(data as *mut Arc<(Mutex<Vec<AudioObjectID>>, Condvar)>) };
let pair = unsafe { &mut *(data as *mut Arc<(Mutex<()>, Condvar)>) };
let (lock, cvar) = &**pair;
let mut devices = lock.lock().unwrap();
*devices = audiounit_get_devices();
let _guard = lock.lock().unwrap();
cvar.notify_one();
NO_ERR
}
@ -218,6 +218,7 @@ impl AggregateDevice {
plugin_id: AudioObjectID,
) -> std::result::Result<AudioObjectID, Error> {
assert_ne!(plugin_id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = AudioObjectPropertyAddress {
mSelector: kAudioPlugInCreateAggregateDevice,
@ -306,6 +307,7 @@ impl AggregateDevice {
input_id: AudioDeviceID,
output_id: AudioDeviceID,
) -> std::result::Result<(), Error> {
debug_assert_running_serially();
let address = AudioObjectPropertyAddress {
mSelector: kAudioAggregateDevicePropertyFullSubDeviceList,
mScope: kAudioObjectPropertyScopeGlobal,
@ -392,6 +394,7 @@ impl AggregateDevice {
assert_ne!(input_id, kAudioObjectUnknown);
assert_ne!(output_id, kAudioObjectUnknown);
assert_ne!(input_id, output_id);
debug_assert_running_serially();
let output_sub_devices = Self::get_sub_devices(output_id)?;
let input_sub_devices = Self::get_sub_devices(input_id)?;
@ -431,6 +434,7 @@ impl AggregateDevice {
device_id: AudioDeviceID,
) -> std::result::Result<Vec<AudioObjectID>, Error> {
assert_ne!(device_id, kAudioObjectUnknown);
debug_assert_running_serially();
let mut sub_devices = Vec::new();
let address = AudioObjectPropertyAddress {
@ -468,6 +472,7 @@ impl AggregateDevice {
}
pub fn get_master_device_uid(device_id: AudioDeviceID) -> std::result::Result<String, Error> {
debug_assert_running_serially();
let address = AudioObjectPropertyAddress {
mSelector: kAudioAggregateDevicePropertyMainSubDevice,
mScope: kAudioObjectPropertyScopeGlobal,
@ -495,6 +500,7 @@ impl AggregateDevice {
) -> std::result::Result<(), Error> {
assert_ne!(device_id, kAudioObjectUnknown);
assert_ne!(primary_id, kAudioObjectUnknown);
debug_assert_running_serially();
cubeb_log!(
"Set master device of the aggregate device {} to device {}",
@ -526,6 +532,7 @@ impl AggregateDevice {
device_id: AudioObjectID,
) -> std::result::Result<(), Error> {
assert_ne!(device_id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = AudioObjectPropertyAddress {
mSelector: kAudioObjectPropertyOwnedObjects,
mScope: kAudioObjectPropertyScopeGlobal,
@ -609,6 +616,7 @@ impl AggregateDevice {
) -> std::result::Result<(), Error> {
assert_ne!(plugin_id, kAudioObjectUnknown);
assert_ne!(device_id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = AudioObjectPropertyAddress {
mSelector: kAudioPlugInDestroyAggregateDevice,
@ -640,6 +648,7 @@ impl AggregateDevice {
assert_ne!(input_id, kAudioObjectUnknown);
assert_ne!(output_id, kAudioObjectUnknown);
assert_ne!(input_id, output_id);
debug_assert_running_serially();
let label = get_device_label(input_id, DeviceType::INPUT)?;
let input_label = label.into_string();

View file

@ -5,6 +5,7 @@ pub fn get_device_uid(
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceUID, devtype);
let mut size = mem::size_of::<CFStringRef>();
@ -22,6 +23,7 @@ pub fn get_device_model_uid(
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::ModelUID, devtype);
let mut size = mem::size_of::<CFStringRef>();
@ -39,6 +41,7 @@ pub fn get_device_transport_type(
devtype: DeviceType,
) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::TransportType, devtype);
let mut size = mem::size_of::<u32>();
@ -56,6 +59,7 @@ pub fn get_device_source(
devtype: DeviceType,
) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceSource, devtype);
let mut size = mem::size_of::<u32>();
@ -73,6 +77,7 @@ pub fn get_device_source_name(
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let mut source: u32 = get_device_source(id, devtype)?;
let address = get_property_address(Property::DeviceSourceName, devtype);
@ -97,6 +102,7 @@ pub fn get_device_name(
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceName, devtype);
let mut size = mem::size_of::<CFStringRef>();
@ -114,6 +120,7 @@ pub fn get_device_manufacturer(
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceManufacturer, devtype);
let mut size = mem::size_of::<CFStringRef>();
@ -131,6 +138,7 @@ pub fn get_device_buffer_frame_size_range(
devtype: DeviceType,
) -> std::result::Result<AudioValueRange, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceBufferFrameSizeRange, devtype);
let mut size = mem::size_of::<AudioValueRange>();
@ -148,6 +156,7 @@ pub fn get_device_latency(
devtype: DeviceType,
) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceLatency, devtype);
let mut size = mem::size_of::<u32>();
@ -165,6 +174,7 @@ pub fn get_device_streams(
devtype: DeviceType,
) -> std::result::Result<Vec<AudioStreamID>, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceStreams, devtype);
@ -188,6 +198,7 @@ pub fn get_device_sample_rate(
devtype: DeviceType,
) -> std::result::Result<f64, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceSampleRate, devtype);
let mut size = mem::size_of::<f64>();
@ -205,6 +216,7 @@ pub fn get_ranges_of_device_sample_rate(
devtype: DeviceType,
) -> std::result::Result<Vec<AudioValueRange>, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::DeviceSampleRates, devtype);
@ -225,6 +237,7 @@ pub fn get_ranges_of_device_sample_rate(
pub fn get_stream_latency(id: AudioStreamID) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(
Property::StreamLatency,
@ -242,6 +255,7 @@ pub fn get_stream_latency(id: AudioStreamID) -> std::result::Result<u32, OSStatu
pub fn get_stream_terminal_type(id: AudioStreamID) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(
Property::StreamTerminalType,
@ -261,6 +275,7 @@ pub fn get_stream_virtual_format(
id: AudioStreamID,
) -> std::result::Result<AudioStreamBasicDescription, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(
Property::StreamVirtualFormat,
@ -281,6 +296,7 @@ pub fn get_clock_domain(
devtype: DeviceType,
) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
debug_assert_running_serially();
let address = get_property_address(Property::ClockDomain, devtype);
let mut size = mem::size_of::<u32>();

View file

@ -33,7 +33,7 @@ use self::mixer::*;
use self::resampler::*;
use self::utils::*;
use backend::ringbuf::RingBuffer;
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
use cubeb_backend::ffi::cubeb_audio_dump_stream_t;
use cubeb_backend::{
ffi, ChannelLayout, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType,
@ -116,7 +116,7 @@ lazy_static! {
};
}
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
fn dump_audio(stream: cubeb_audio_dump_stream_t, audio_samples: *mut c_void, count: u32) {
unsafe {
let rv = ffi::cubeb_audio_dump_write(stream, audio_samples, count);
@ -569,7 +569,7 @@ extern "C" fn audiounit_input_callback(
} else {
assert_eq!(status, NO_ERR);
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
dump_audio(
stm.core_stream_data.audio_dump_input,
@ -628,15 +628,15 @@ extern "C" fn audiounit_input_callback(
0,
);
if outframes < 0 {
stm.stopped.store(true, Ordering::SeqCst);
if !stm.stopped.swap(true, Ordering::SeqCst) {
stm.notify_state_changed(State::Error);
let queue = stm.queue.clone();
// Use a new thread, through the queue, to avoid deadlock when calling
// AudioOutputUnitStop method from inside render callback
queue.run_async(move || {
stm.queue.clone().run_async(move || {
stm.core_stream_data.stop_audiounits();
});
return handle;
}
return ErrorHandle::Return(status);
}
if outframes < total_input_frames {
stm.draining.store(true, Ordering::SeqCst);
@ -654,15 +654,16 @@ extern "C" fn audiounit_input_callback(
// If the input (input-only stream) is drained, cancel this callback. Whenever an output
// is involved, the output callback handles stopping all units and notifying of state.
if stm.core_stream_data.output_unit.is_null() && stm.draining.load(Ordering::SeqCst) {
stm.stopped.store(true, Ordering::SeqCst);
if stm.core_stream_data.output_unit.is_null()
&& stm.draining.load(Ordering::SeqCst)
&& !stm.stopped.swap(true, Ordering::SeqCst)
{
cubeb_alog!("({:p}) Input-only drained.", stm as *const AudioUnitStream);
stm.notify_state_changed(State::Drained);
let queue = stm.queue.clone();
// Use a new thread, through the queue, to avoid deadlock when calling
// AudioOutputUnitStop method from inside render callback
let stm_ptr = user_ptr as usize;
queue.run_async(move || {
stm.queue.clone().run_async(move || {
let stm = unsafe { &mut *(stm_ptr as *mut AudioUnitStream) };
stm.core_stream_data.stop_audiounits();
});
@ -735,7 +736,7 @@ extern "C" fn audiounit_output_callback(
if stm.stopped.load(Ordering::SeqCst) {
cubeb_alog!("({:p}) output stopped.", stm as *const AudioUnitStream);
audiounit_make_silent(&buffers[0]);
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
dump_audio(
stm.core_stream_data.audio_dump_output,
@ -749,12 +750,8 @@ extern "C" fn audiounit_output_callback(
if stm.draining.load(Ordering::SeqCst) {
// Cancel all callbacks. For input-only streams, the input callback handles
// cancelling itself.
stm.stopped.store(true, Ordering::SeqCst);
cubeb_alog!("({:p}) output drained.", stm as *const AudioUnitStream);
stm.notify_state_changed(State::Drained);
let queue = stm.queue.clone();
audiounit_make_silent(&buffers[0]);
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
dump_audio(
stm.core_stream_data.audio_dump_output,
@ -762,11 +759,15 @@ extern "C" fn audiounit_output_callback(
output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame,
);
}
if !stm.stopped.swap(true, Ordering::SeqCst) {
cubeb_alog!("({:p}) output drained.", stm as *const AudioUnitStream);
stm.notify_state_changed(State::Drained);
// Use a new thread, through the queue, to avoid deadlock when calling
// AudioOutputUnitStop method from inside render callback
queue.run_async(move || {
stm.queue.clone().run_async(move || {
stm.core_stream_data.stop_audiounits();
});
}
return NO_ERR;
}
@ -886,12 +887,9 @@ extern "C" fn audiounit_output_callback(
);
if outframes < 0 || outframes > i64::from(output_frames) {
stm.stopped.store(true, Ordering::SeqCst);
stm.notify_state_changed(State::Error);
let queue = stm.queue.clone();
audiounit_make_silent(&buffers[0]);
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
dump_audio(
stm.core_stream_data.audio_dump_output,
@ -899,11 +897,14 @@ extern "C" fn audiounit_output_callback(
output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame,
);
}
if !stm.stopped.swap(true, Ordering::SeqCst) {
stm.notify_state_changed(State::Error);
// Use a new thread, through the queue, to avoid deadlock when calling
// AudioOutputUnitStop method from inside render callback
queue.run_async(move || {
stm.queue.clone().run_async(move || {
stm.core_stream_data.stop_audiounits();
});
}
return NO_ERR;
}
@ -951,7 +952,7 @@ extern "C" fn audiounit_output_callback(
);
}
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
dump_audio(
stm.core_stream_data.audio_dump_output,
@ -1001,8 +1002,8 @@ extern "C" fn audiounit_property_listener_callback(
// Handle the events
if explicit_device_dead {
if !stm.stopped.swap(true, Ordering::SeqCst) {
cubeb_log!("The user-selected input or output device is dead, entering error state");
stm.stopped.store(true, Ordering::SeqCst);
// Use a different thread, through the queue, to avoid deadlock when calling
// Get/SetProperties method from inside notify callback
@ -1010,6 +1011,7 @@ extern "C" fn audiounit_property_listener_callback(
stm.core_stream_data.stop_audiounits();
stm.close_on_error();
});
}
return NO_ERR;
}
{
@ -1026,6 +1028,7 @@ extern "C" fn audiounit_property_listener_callback(
}
fn get_default_device(devtype: DeviceType) -> Option<AudioObjectID> {
debug_assert_running_serially();
match get_default_device_id(devtype) {
Err(e) => {
cubeb_log!("Cannot get default {:?} device. Error: {}", devtype, e);
@ -1040,6 +1043,7 @@ fn get_default_device(devtype: DeviceType) -> Option<AudioObjectID> {
}
fn get_default_device_id(devtype: DeviceType) -> std::result::Result<AudioObjectID, OSStatus> {
debug_assert_running_serially();
let address = get_property_address(
match devtype {
DeviceType::INPUT => Property::HardwareDefaultInputDevice,
@ -1087,6 +1091,7 @@ fn audiounit_convert_channel_layout(layout: &AudioChannelLayout) -> Result<Vec<m
}
fn audiounit_get_preferred_channel_layout(output_unit: AudioUnit) -> Result<Vec<mixer::Channel>> {
debug_assert_running_serially();
let mut rv = NO_ERR;
let mut size: usize = 0;
rv = audio_unit_get_property_info(
@ -1129,6 +1134,7 @@ fn audiounit_get_preferred_channel_layout(output_unit: AudioUnit) -> Result<Vec<
// This is for output AudioUnit only. Calling this by input-only AudioUnit is prone
// to crash intermittently.
fn audiounit_get_current_channel_layout(output_unit: AudioUnit) -> Result<Vec<mixer::Channel>> {
debug_assert_running_serially();
let mut rv = NO_ERR;
let mut size: usize = 0;
rv = audio_unit_get_property_info(
@ -1169,6 +1175,7 @@ fn audiounit_get_current_channel_layout(output_unit: AudioUnit) -> Result<Vec<mi
}
fn get_channel_layout(output_unit: AudioUnit) -> Result<Vec<mixer::Channel>> {
debug_assert_running_serially();
audiounit_get_current_channel_layout(output_unit)
.or_else(|_| {
// The kAudioUnitProperty_AudioChannelLayout property isn't known before
@ -1208,6 +1215,7 @@ fn create_audiounit(device: &device_info) -> Result<AudioUnit> {
assert!(!device
.flags
.contains(device_flags::DEV_INPUT | device_flags::DEV_OUTPUT));
debug_assert_running_serially();
let unit = create_blank_audiounit()?;
let mut bus = AU_OUT_BUS;
@ -1610,6 +1618,7 @@ fn get_channel_count(
devtype: DeviceType,
) -> std::result::Result<u32, OSStatus> {
assert_ne!(devid, kAudioObjectUnknown);
debug_assert_running_serially();
let mut streams = get_device_streams(devid, devtype)?;
let model_uid =
@ -1691,6 +1700,7 @@ fn get_range_of_sample_rates(
devid: AudioObjectID,
devtype: DeviceType,
) -> std::result::Result<(f64, f64), String> {
debug_assert_running_serially();
let result = get_ranges_of_device_sample_rate(devid, devtype);
if let Err(e) = result {
return Err(format!("status {}", e));
@ -1712,6 +1722,7 @@ fn get_range_of_sample_rates(
}
fn get_fixed_latency(devid: AudioObjectID, devtype: DeviceType) -> u32 {
debug_assert_running_serially();
let device_latency = match get_device_latency(devid, devtype) {
Ok(latency) => latency,
Err(e) => {
@ -1754,6 +1765,7 @@ fn get_device_group_id(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<CString, OSStatus> {
debug_assert_running_serially();
match get_device_transport_type(id, devtype) {
Ok(kAudioDeviceTransportTypeBuiltIn) => {
cubeb_log!(
@ -1789,6 +1801,8 @@ fn get_device_group_id(
}
fn get_custom_group_id(id: AudioDeviceID, devtype: DeviceType) -> Option<CString> {
debug_assert_running_serially();
const IMIC: u32 = 0x696D_6963; // "imic" (internal microphone)
const ISPK: u32 = 0x6973_706B; // "ispk" (internal speaker)
const EMIC: u32 = 0x656D_6963; // "emic" (external microphone)
@ -1830,10 +1844,12 @@ fn get_device_label(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<StringRef, OSStatus> {
debug_assert_running_serially();
get_device_source_name(id, devtype).or_else(|_| get_device_name(id, devtype))
}
fn get_device_global_uid(id: AudioDeviceID) -> std::result::Result<StringRef, OSStatus> {
debug_assert_running_serially();
get_device_uid(id, DeviceType::INPUT | DeviceType::OUTPUT)
}
@ -2016,6 +2032,7 @@ fn destroy_cubeb_device_info(device: &mut ffi::cubeb_device_info) {
}
fn audiounit_get_devices() -> Vec<AudioObjectID> {
debug_assert_running_serially();
let mut size: usize = 0;
let address = get_property_address(
Property::HardwareDevices,
@ -2042,6 +2059,7 @@ fn audiounit_get_devices() -> Vec<AudioObjectID> {
fn audiounit_get_devices_of_type(devtype: DeviceType) -> Vec<AudioObjectID> {
assert!(devtype.intersects(DeviceType::INPUT | DeviceType::OUTPUT));
debug_assert_running_serially();
let mut devices = audiounit_get_devices();
@ -2708,6 +2726,8 @@ impl ContextOps for AudioUnitContext {
}
#[cfg(not(target_os = "ios"))]
fn max_channel_count(&mut self) -> Result<u32> {
self.serial_queue
.run_sync(|| {
let device = match get_default_device(DeviceType::OUTPUT) {
None => {
cubeb_log!("Could not get default output device");
@ -2719,6 +2739,8 @@ impl ContextOps for AudioUnitContext {
cubeb_log!("Cannot get the channel count. Error: {}", e);
Error::error()
})
})
.unwrap()
}
#[cfg(target_os = "ios")]
fn min_latency(&mut self, _params: StreamParams) -> Result<u32> {
@ -2726,6 +2748,8 @@ impl ContextOps for AudioUnitContext {
}
#[cfg(not(target_os = "ios"))]
fn min_latency(&mut self, _params: StreamParams) -> Result<u32> {
self.serial_queue
.run_sync(|| {
let device = match get_default_device(DeviceType::OUTPUT) {
None => {
cubeb_log!("Could not get default output device");
@ -2734,13 +2758,15 @@ impl ContextOps for AudioUnitContext {
Some(id) => id,
};
let range =
get_device_buffer_frame_size_range(device, DeviceType::OUTPUT).map_err(|e| {
let range = get_device_buffer_frame_size_range(device, DeviceType::OUTPUT)
.map_err(|e| {
cubeb_log!("Could not get acceptable latency range. Error: {}", e);
Error::error()
})?;
Ok(cmp::max(range.mMinimum as u32, SAFE_MIN_LATENCY_FRAMES))
})
.unwrap()
}
#[cfg(target_os = "ios")]
fn preferred_sample_rate(&mut self) -> Result<u32> {
@ -2748,6 +2774,8 @@ impl ContextOps for AudioUnitContext {
}
#[cfg(not(target_os = "ios"))]
fn preferred_sample_rate(&mut self) -> Result<u32> {
self.serial_queue
.run_sync(|| {
let device = match get_default_device(DeviceType::OUTPUT) {
None => {
cubeb_log!("Could not get default output device");
@ -2763,6 +2791,8 @@ impl ContextOps for AudioUnitContext {
Error::error()
})?;
Ok(rate as u32)
})
.unwrap()
}
fn supported_input_processing_params(&mut self) -> Result<InputProcessingParams> {
Ok(InputProcessingParams::ECHO_CANCELLATION
@ -2774,19 +2804,27 @@ impl ContextOps for AudioUnitContext {
devtype: DeviceType,
collection: &DeviceCollectionRef,
) -> Result<()> {
let mut device_infos = Vec::new();
let dev_types = [DeviceType::INPUT, DeviceType::OUTPUT];
for dev_type in dev_types.iter() {
if !devtype.contains(*dev_type) {
continue;
}
let devices = audiounit_get_devices_of_type(*dev_type);
for device in devices {
if let Ok(info) = create_cubeb_device_info(device, *dev_type) {
let device_infos = self
.serial_queue
.run_sync(|| {
let mut dev_types = vec![DeviceType::INPUT, DeviceType::OUTPUT];
dev_types.retain(|&dt| devtype.contains(dt));
let device_ids: Vec<(DeviceType, Vec<AudioObjectID>)> = dev_types
.iter()
.map(|&dt| (dt, audiounit_get_devices_of_type(dt)))
.collect();
let count = device_ids.iter().map(|(_dt, ids)| ids.len()).sum();
let mut device_infos = Vec::with_capacity(count);
for (dt, dev_ids) in device_ids {
for dev_id in dev_ids {
if let Ok(info) = create_cubeb_device_info(dev_id, dt) {
device_infos.push(info);
}
}
}
device_infos
})
.unwrap();
let (ptr, len) = if device_infos.is_empty() {
(ptr::null_mut(), 0)
} else {
@ -3071,13 +3109,13 @@ struct CoreStreamData<'ctx> {
output_alive_listener: Option<device_property_listener>,
output_source_listener: Option<device_property_listener>,
input_logging: Option<InputCallbackLogger>,
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_session: ffi::cubeb_audio_dump_session_t,
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_session_running: bool,
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_input: ffi::cubeb_audio_dump_stream_t,
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_output: ffi::cubeb_audio_dump_stream_t,
}
@ -3119,13 +3157,13 @@ impl<'ctx> Default for CoreStreamData<'ctx> {
output_alive_listener: None,
output_source_listener: None,
input_logging: None,
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_session: ptr::null_mut(),
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_session_running: false,
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_input: ptr::null_mut(),
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_output: ptr::null_mut(),
}
}
@ -3174,13 +3212,13 @@ impl<'ctx> CoreStreamData<'ctx> {
output_alive_listener: None,
output_source_listener: None,
input_logging: None,
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_session: ptr::null_mut(),
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_session_running: false,
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_input: ptr::null_mut(),
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
audio_dump_output: ptr::null_mut(),
}
}
@ -3539,7 +3577,7 @@ impl<'ctx> CoreStreamData<'ctx> {
assert!(!self.stm_ptr.is_null());
let stream = unsafe { &(*self.stm_ptr) };
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
unsafe {
ffi::cubeb_audio_dump_init(&mut self.audio_dump_session);
}
@ -3584,7 +3622,7 @@ impl<'ctx> CoreStreamData<'ctx> {
let r = audio_unit_get_property(
self.input_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kAudioUnitScope_Output,
AU_IN_BUS,
&mut input_hw_desc,
&mut size,
@ -3601,9 +3639,6 @@ impl<'ctx> CoreStreamData<'ctx> {
self.stm_ptr,
input_hw_desc
);
// In some cases with VPIO the stream format's mChannelsPerFrame is higher than
// expected. Use get_channel_count as source of truth.
input_hw_desc.mChannelsPerFrame = device_channel_count;
// Notice: when we are using aggregate device, the input_hw_desc.mChannelsPerFrame is
// the total of all the input channel count of the devices added in the aggregate device.
// Due to our aggregate device settings, the data captured by the output device's input
@ -3613,12 +3648,7 @@ impl<'ctx> CoreStreamData<'ctx> {
// channels to the audio callback.
let params = unsafe {
let mut p = *self.input_stream_params.as_ptr();
p.channels = if using_voice_processing_unit {
// VPIO is always MONO.
1
} else {
input_hw_desc.mChannelsPerFrame
};
p.channels = input_hw_desc.mChannelsPerFrame;
// Input AudioUnit must be configured with device's sample rate.
// we will resample inside input callback.
p.rate = input_hw_desc.mSampleRate as _;
@ -3633,7 +3663,7 @@ impl<'ctx> CoreStreamData<'ctx> {
e
})?;
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
let name = format!("input-{:p}.wav", self.stm_ptr);
let cname = CString::new(name).expect("OK");
@ -3789,7 +3819,7 @@ impl<'ctx> CoreStreamData<'ctx> {
let r = audio_unit_get_property(
self.output_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kAudioUnitScope_Input,
AU_OUT_BUS,
&mut output_hw_desc,
&mut size,
@ -3807,11 +3837,6 @@ impl<'ctx> CoreStreamData<'ctx> {
output_hw_desc
);
// In some cases with (other streams using) VPIO the stream format's mChannelsPerFrame
// is higher than expected. Use get_channel_count as source of truth.
output_hw_desc.mChannelsPerFrame =
get_channel_count(self.output_device.id, DeviceType::OUTPUT).unwrap_or(0);
// This has been observed in the wild.
if output_hw_desc.mChannelsPerFrame == 0 {
cubeb_log!(
@ -3827,12 +3852,7 @@ impl<'ctx> CoreStreamData<'ctx> {
// channels will be appended at the end of the raw data given by the output callback.
let params = unsafe {
let mut p = *self.output_stream_params.as_ptr();
p.channels = if using_voice_processing_unit {
// VPIO is always MONO.
1
} else {
output_hw_desc.mChannelsPerFrame
};
p.channels = output_hw_desc.mChannelsPerFrame;
if using_voice_processing_unit {
// VPIO will always use the sample rate of the input hw for both input and output,
// as reported to us. (We can override it but we cannot improve quality this way).
@ -3849,7 +3869,7 @@ impl<'ctx> CoreStreamData<'ctx> {
e
})?;
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
let name = format!("output-{:p}.wav", self.stm_ptr);
let cname = CString::new(name).expect("OK");
@ -4038,7 +4058,7 @@ impl<'ctx> CoreStreamData<'ctx> {
self.input_logging = Some(InputCallbackLogger::new());
}
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
unsafe { ffi::cubeb_audio_dump_start(self.audio_dump_session) };
self.audio_dump_session_running = true;
@ -4217,7 +4237,7 @@ impl<'ctx> CoreStreamData<'ctx> {
// Return the VPIO unit if present.
self.voiceprocessing_unit_handle = None;
#[cfg(feature = "audio_dump")]
#[cfg(feature = "audio-dump")]
{
if !self.audio_dump_session.is_null() {
unsafe {
@ -4682,6 +4702,11 @@ impl<'ctx> AudioUnitStream<'ctx> {
self.core_stream_data.stop_audiounits();
}
if self.stopped.load(Ordering::SeqCst) {
// Something stopped the stream, we must not reinit.
return Ok(());
}
debug_assert!(
!self.core_stream_data.input_unit.is_null()
|| !self.core_stream_data.output_unit.is_null()
@ -4840,9 +4865,8 @@ impl<'ctx> AudioUnitStream<'ctx> {
// which locks a mutex inside CoreAudio framework, then this call will block the current
// thread until the callback is finished since this call asks to lock a mutex inside
// CoreAudio framework that is used by the data callback.
if !self.stopped.load(Ordering::SeqCst) {
if !self.stopped.swap(true, Ordering::SeqCst) {
self.core_stream_data.stop_audiounits();
self.stopped.store(true, Ordering::SeqCst);
}
self.destroy_internal();
@ -4886,8 +4910,7 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> {
Ok(())
}
fn stop(&mut self) -> Result<()> {
self.stopped.store(true, Ordering::SeqCst);
if !self.stopped.swap(true, Ordering::SeqCst) {
// Execute stop in serial queue to avoid racing with destroy or reinit.
self.queue
.run_sync(|| self.core_stream_data.stop_audiounits());
@ -4898,6 +4921,7 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> {
"Cubeb stream ({:p}) stopped successfully.",
self as *const AudioUnitStream
);
}
Ok(())
}
fn position(&mut self) -> Result<u64> {

View file

@ -352,7 +352,7 @@ fn test_aggregate_activate_clock_drift_compensation() {
assert_eq!(devices.len(), compensations.len());
for (device, compensation) in zip(devices, compensations) {
let uid = get_device_uid(device);
let uid = run_serially(|| get_device_uid(device));
assert_eq!(
compensation,
if uid == master_device_uid {

View file

@ -1123,7 +1123,11 @@ fn test_get_channel_count_of_unknwon_type() {
fn test_channel_count(scope: Scope) {
if let Some(device) = test_get_default_device(scope.clone()) {
assert!(get_channel_count(device, DeviceType::UNKNOWN).is_err());
assert!(run_serially_forward_panics(|| get_channel_count(
device,
DeviceType::UNKNOWN
)
.is_err()));
} else {
panic!("Panic by default: No device for {:?}.", scope);
}
@ -1181,7 +1185,8 @@ fn test_get_device_presentation_latency() {
fn test_get_device_presentation_latencies_in_scope(scope: Scope) {
if let Some(device) = test_get_default_device(scope.clone()) {
// TODO: The latencies very from devices to devices. Check nothing here.
let latency = run_serially(|| get_fixed_latency(device, scope.clone().into()));
let latency =
run_serially_forward_panics(|| get_fixed_latency(device, scope.clone().into()));
println!(
"present latency on the device {} in scope {:?}: {}",
device, scope, latency
@ -1197,7 +1202,7 @@ fn test_get_device_presentation_latency() {
#[test]
fn test_get_device_group_id() {
if let Some(device) = test_get_default_device(Scope::Input) {
match run_serially(|| get_device_group_id(device, DeviceType::INPUT)) {
match run_serially_forward_panics(|| get_device_group_id(device, DeviceType::INPUT)) {
Ok(id) => println!("input group id: {:?}", id),
Err(e) => println!("No input group id. Error: {}", e),
}
@ -1206,7 +1211,7 @@ fn test_get_device_group_id() {
}
if let Some(device) = test_get_default_device(Scope::Output) {
match run_serially(|| get_device_group_id(device, DeviceType::OUTPUT)) {
match run_serially_forward_panics(|| get_device_group_id(device, DeviceType::OUTPUT)) {
Ok(id) => println!("output group id: {:?}", id),
Err(e) => println!("No output group id. Error: {}", e),
}
@ -1229,8 +1234,10 @@ fn test_get_same_group_id_for_builtin_device_pairs() {
let mut input_group_ids = HashMap::<u32, String>::new();
let input_devices = test_get_devices_in_scope(Scope::Input);
for device in input_devices.iter() {
match run_serially(|| get_device_source(*device, DeviceType::INPUT)) {
Ok(source) => match run_serially(|| get_device_group_id(*device, DeviceType::INPUT)) {
match run_serially_forward_panics(|| get_device_source(*device, DeviceType::INPUT)) {
Ok(source) => match run_serially_forward_panics(|| {
get_device_group_id(*device, DeviceType::INPUT)
}) {
Ok(id) => assert!(input_group_ids
.insert(source, id.into_string().unwrap())
.is_none()),
@ -1245,8 +1252,10 @@ fn test_get_same_group_id_for_builtin_device_pairs() {
let mut output_group_ids = HashMap::<u32, String>::new();
let output_devices = test_get_devices_in_scope(Scope::Output);
for device in output_devices.iter() {
match run_serially(|| get_device_source(*device, DeviceType::OUTPUT)) {
Ok(source) => match run_serially(|| get_device_group_id(*device, DeviceType::OUTPUT)) {
match run_serially_forward_panics(|| get_device_source(*device, DeviceType::OUTPUT)) {
Ok(source) => match run_serially_forward_panics(|| {
get_device_group_id(*device, DeviceType::OUTPUT)
}) {
Ok(id) => assert!(output_group_ids
.insert(source, id.into_string().unwrap())
.is_none()),
@ -1286,14 +1295,16 @@ fn test_get_device_group_id_by_unknown_device() {
#[test]
fn test_get_device_label() {
if let Some(device) = test_get_default_device(Scope::Input) {
let name = run_serially(|| get_device_label(device, DeviceType::INPUT)).unwrap();
let name =
run_serially_forward_panics(|| get_device_label(device, DeviceType::INPUT)).unwrap();
println!("input device label: {}", name.into_string());
} else {
println!("No input device.");
}
if let Some(device) = test_get_default_device(Scope::Output) {
let name = run_serially(|| get_device_label(device, DeviceType::OUTPUT)).unwrap();
let name =
run_serially_forward_panics(|| get_device_label(device, DeviceType::OUTPUT)).unwrap();
println!("output device label: {}", name.into_string());
} else {
println!("No output device.");
@ -1316,14 +1327,14 @@ fn test_get_device_label_by_unknown_device() {
fn test_get_device_global_uid() {
// Input device.
if let Some(input) = test_get_default_device(Scope::Input) {
let uid = run_serially(|| get_device_global_uid(input)).unwrap();
let uid = run_serially_forward_panics(|| get_device_global_uid(input)).unwrap();
let uid = uid.into_string();
assert!(!uid.is_empty());
}
// Output device.
if let Some(output) = test_get_default_device(Scope::Output) {
let uid = run_serially(|| get_device_global_uid(output)).unwrap();
let uid = run_serially_forward_panics(|| get_device_global_uid(output)).unwrap();
let uid = uid.into_string();
assert!(!uid.is_empty());
}
@ -1333,7 +1344,7 @@ fn test_get_device_global_uid() {
#[should_panic]
fn test_get_device_global_uid_by_unknwon_device() {
// Unknown device.
assert!(get_device_global_uid(kAudioObjectUnknown).is_err());
assert!(run_serially_forward_panics(|| get_device_global_uid(kAudioObjectUnknown)).is_err());
}
// create_cubeb_device_info
@ -1381,7 +1392,9 @@ fn test_create_cubeb_device_info() {
let dev_types = [DeviceType::INPUT, DeviceType::OUTPUT];
let mut results = VecDeque::new();
for dev_type in dev_types.iter() {
results.push_back(run_serially(|| create_cubeb_device_info(id, *dev_type)));
results.push_back(run_serially_forward_panics(|| {
create_cubeb_device_info(id, *dev_type)
}));
}
results
}
@ -1441,9 +1454,11 @@ fn test_create_device_info_with_unknown_type() {
fn test_create_device_info_with_unknown_type_by_scope(scope: Scope) {
if let Some(device) = test_get_default_device(scope.clone()) {
assert!(
run_serially(|| create_cubeb_device_info(device, DeviceType::UNKNOWN)).is_err()
);
assert!(run_serially_forward_panics(|| create_cubeb_device_info(
device,
DeviceType::UNKNOWN
))
.is_err());
}
}
}
@ -1475,7 +1490,7 @@ fn test_create_device_from_hwdev_with_inout_type() {
fn test_create_device_from_hwdev_with_inout_type_by_scope(scope: Scope) {
if let Some(device) = test_get_default_device(scope.clone()) {
// Get a kAudioHardwareUnknownPropertyError in get_channel_count actually.
assert!(run_serially(|| create_cubeb_device_info(
assert!(run_serially_forward_panics(|| create_cubeb_device_info(
device,
DeviceType::INPUT | DeviceType::OUTPUT
))
@ -1492,10 +1507,13 @@ fn test_create_device_from_hwdev_with_inout_type() {
fn test_get_devices_of_type() {
use std::collections::HashSet;
let all_devices =
run_serially(|| audiounit_get_devices_of_type(DeviceType::INPUT | DeviceType::OUTPUT));
let input_devices = run_serially(|| audiounit_get_devices_of_type(DeviceType::INPUT));
let output_devices = run_serially(|| audiounit_get_devices_of_type(DeviceType::OUTPUT));
let all_devices = run_serially_forward_panics(|| {
audiounit_get_devices_of_type(DeviceType::INPUT | DeviceType::OUTPUT)
});
let input_devices =
run_serially_forward_panics(|| audiounit_get_devices_of_type(DeviceType::INPUT));
let output_devices =
run_serially_forward_panics(|| audiounit_get_devices_of_type(DeviceType::OUTPUT));
let mut expected_all = test_get_all_devices(DeviceFilter::ExcludeCubebAggregateAndVPIO);
expected_all.sort();

View file

@ -2,9 +2,9 @@ extern crate itertools;
use self::itertools::iproduct;
use super::utils::{
draining_data_callback, get_devices_info_in_scope, noop_data_callback,
draining_data_callback, get_devices_info_in_scope, noop_data_callback, state_tracking_cb,
test_device_channels_in_scope, test_get_default_device, test_ops_context_operation,
test_ops_stream_operation, test_ops_stream_operation_on_context, Scope,
test_ops_stream_operation, test_ops_stream_operation_on_context, Scope, StateCallbackData,
};
use super::*;
use std::thread;
@ -1177,6 +1177,77 @@ fn test_ops_stream_device_destroy() {
});
}
pub extern "C" fn reiniting_and_erroring_data_callback(
stream: *mut ffi::cubeb_stream,
_user_ptr: *mut c_void,
_input_buffer: *const c_void,
output_buffer: *mut c_void,
nframes: i64,
) -> i64 {
assert!(!stream.is_null());
let stm = unsafe { &mut *(stream as *mut AudioUnitStream) };
// Feed silence data to output buffer
if !output_buffer.is_null() {
let channels = stm.core_stream_data.output_stream_params.channels();
let samples = nframes as usize * channels as usize;
let sample_size = cubeb_sample_size(stm.core_stream_data.output_stream_params.format());
unsafe {
ptr::write_bytes(output_buffer, 0, samples * sample_size);
}
}
// Trigger an async reinit before the backend handles the error below.
// This scenario could happen in the backend's internal input callback.
stm.reinit_async();
ffi::CUBEB_ERROR.into()
}
#[test]
fn test_ops_stream_racy_reinit() {
// Make sure the parameters meet the requirements of AudioUnitContext::stream_init
// (in the comments).
let mut input_params = ffi::cubeb_stream_params::default();
input_params.format = ffi::CUBEB_SAMPLE_FLOAT32NE;
input_params.rate = 48000;
input_params.channels = 1;
input_params.layout = ffi::CUBEB_LAYOUT_UNDEFINED;
input_params.prefs = ffi::CUBEB_STREAM_PREF_NONE;
let mut output_params = ffi::cubeb_stream_params::default();
output_params.format = ffi::CUBEB_SAMPLE_FLOAT32NE;
output_params.rate = 44100;
output_params.channels = 2;
output_params.layout = ffi::CUBEB_LAYOUT_UNDEFINED;
output_params.prefs = ffi::CUBEB_STREAM_PREF_NONE;
let mut data = StateCallbackData::default();
test_ops_stream_operation(
"stream: racy reinit",
ptr::null_mut(), // Use default input device.
&mut input_params,
ptr::null_mut(), // Use default output device.
&mut output_params,
4096, // TODO: Get latency by get_min_latency instead ?
Some(reiniting_and_erroring_data_callback),
Some(state_tracking_cb),
&mut data as *mut StateCallbackData as *mut c_void,
|stream| {
assert_eq!(unsafe { OPS.stream_start.unwrap()(stream) }, ffi::CUBEB_OK);
while data.error_cnt() == 0 && data.stopped_cnt() == 0 {
thread::sleep(Duration::from_millis(1));
}
assert_eq!(unsafe { OPS.stream_stop.unwrap()(stream) }, ffi::CUBEB_OK);
},
);
assert_eq!(data.started_cnt(), 1);
assert_eq!(data.stopped_cnt(), 0);
assert_eq!(data.drained_cnt(), 0);
assert_eq!(data.error_cnt(), 1);
}
#[test]
fn test_ops_stream_register_device_changed_callback() {
extern "C" fn callback(_: *mut c_void) {}

View file

@ -441,7 +441,7 @@ fn test_stream_tester() {
return;
}
let mut params = InputProcessingParams::NONE;
{
run_serially(|| {
let mut bypass = u32::from(true);
let mut size: usize = mem::size_of::<u32>();
assert_eq!(
@ -477,7 +477,7 @@ fn test_stream_tester() {
if agc == 1 {
params.set(InputProcessingParams::AUTOMATIC_GAIN_CONTROL, true);
}
}
});
let mut done = false;
while !done {
println!(

View file

@ -48,6 +48,56 @@ pub extern "C" fn draining_data_callback(
nframes - 1
}
#[derive(Default)]
pub struct StateCallbackData {
started_cnt: AtomicU32,
stopped_cnt: AtomicU32,
drained_cnt: AtomicU32,
error_cnt: AtomicU32,
}
impl StateCallbackData {
pub fn started_cnt(&self) -> u32 {
self.started_cnt.load(Ordering::SeqCst)
}
pub fn stopped_cnt(&self) -> u32 {
self.stopped_cnt.load(Ordering::SeqCst)
}
pub fn drained_cnt(&self) -> u32 {
self.drained_cnt.load(Ordering::SeqCst)
}
pub fn error_cnt(&self) -> u32 {
self.error_cnt.load(Ordering::SeqCst)
}
}
pub extern "C" fn state_tracking_cb(
stream: *mut ffi::cubeb_stream,
_usr_ptr: *mut c_void,
state: u32,
) {
let data = unsafe { (_usr_ptr as *mut StateCallbackData).as_mut() }.unwrap();
match state {
ffi::CUBEB_STATE_STARTED => {
data.started_cnt.fetch_add(1, Ordering::SeqCst);
cubeb_log!("({:p}) state is now started", stream);
}
ffi::CUBEB_STATE_STOPPED => {
data.stopped_cnt.fetch_add(1, Ordering::SeqCst);
cubeb_log!("({:p}) state is now stopped", stream);
}
ffi::CUBEB_STATE_DRAINED => {
data.drained_cnt.fetch_add(1, Ordering::SeqCst);
cubeb_log!("({:p}) state is now drained", stream);
}
ffi::CUBEB_STATE_ERROR => {
data.error_cnt.fetch_add(1, Ordering::SeqCst);
cubeb_log!("({:p}) state is now error", stream);
}
_ => unreachable!("unknown state"),
};
}
#[derive(Clone, Debug, PartialEq)]
pub enum Scope {
Input,
@ -357,14 +407,14 @@ impl TestDeviceInfo {
}
fn get_label(id: AudioObjectID, scope: Scope) -> String {
match get_device_uid(id, scope.into()) {
match run_serially_forward_panics(|| get_device_uid(id, scope.into())) {
Ok(uid) => uid.into_string(),
Err(status) => format!("Unknow. Error: {}", status).to_string(),
}
}
fn get_uid(id: AudioObjectID, scope: Scope) -> String {
match get_device_label(id, scope.into()) {
match run_serially_forward_panics(|| get_device_label(id, scope.into())) {
Ok(label) => label.into_string(),
Err(status) => format!("Unknown. Error: {}", status).to_string(),
}

View file

@ -1 +1 @@
{"files":{".editorconfig":"bf047bd1da10cabb99eea666d1e57c321eba4716dccb3e4ed0e2c5fe3ca53858",".github/workflows/build.yml":"477366d58c9dc059dbe4a158a6e910f23a3e9ecac7411f73616e06375583b764","AUTHORS":"0e0ac930a68ce2f6b876126b195add177f0d3886facb9260f4d9b69f1988f0cc","Cargo.toml":"4bdd3962429c676eda59de96cad567478bb20b01c785c9ce3ba03b2e7837dd67","LICENSE":"44c6b5ae5ec3fe2fbc608b00e6f4896f4d2d5c7e525fcbaa3eaa3cf2f3d5a983","README.md":"0079450bb4b013bac065ed1750851e461a3710ebad1f323817da1cb82db0bc4f","src/backend/context.rs":"51dbf887e78aed5cd5e2255ac98f50c287960d8949ea3f66f2b05214b76800d8","src/backend/cork_state.rs":"4a0f1afc7d9f333dac89218cc56d7d32fbffb487cd48c1c9a4e03d79cb3b5e28","src/backend/intern.rs":"11ca424e4eb77f8eb9fd5a6717d1e791facf9743156a8534f0016fcf64d57b0f","src/backend/mod.rs":"dfb30ec497d6215e4535e936fea8fe3a407ef24dc1cec43b52c0ffa923d9229c","src/backend/stream.rs":"b3dcaa382981cbaa3af3c445b0ed6b5012b61d420d2e52a5ebd3cb0dd09a917c","src/capi.rs":"fa0fa020f0d0efe55aa0fc3596405e8407bbe2cbe6c7a558345304e6da87994e","src/lib.rs":"b41bbdc562cbfb130ed7c1e53fe69944774f515705341d8ce48a2f82c8c0c2c5"},"package":null}
{"files":{".editorconfig":"bf047bd1da10cabb99eea666d1e57c321eba4716dccb3e4ed0e2c5fe3ca53858",".github/workflows/build.yml":"477366d58c9dc059dbe4a158a6e910f23a3e9ecac7411f73616e06375583b764","AUTHORS":"0e0ac930a68ce2f6b876126b195add177f0d3886facb9260f4d9b69f1988f0cc","Cargo.toml":"8a0a450ae4990e1df322464867212e48587b474dfdc7f8c270fac06980be176a","LICENSE":"44c6b5ae5ec3fe2fbc608b00e6f4896f4d2d5c7e525fcbaa3eaa3cf2f3d5a983","README.md":"0079450bb4b013bac065ed1750851e461a3710ebad1f323817da1cb82db0bc4f","src/backend/context.rs":"c0db5f2447de1d6df5aa2812fa342a085e73156a072c221c7379b9a6a9b86786","src/backend/cork_state.rs":"4a0f1afc7d9f333dac89218cc56d7d32fbffb487cd48c1c9a4e03d79cb3b5e28","src/backend/intern.rs":"11ca424e4eb77f8eb9fd5a6717d1e791facf9743156a8534f0016fcf64d57b0f","src/backend/mod.rs":"dfb30ec497d6215e4535e936fea8fe3a407ef24dc1cec43b52c0ffa923d9229c","src/backend/stream.rs":"dfe5b747e100cae4aeae36cf2ebb9dc4715b411b4116721a40eec2944eb0ec23","src/capi.rs":"fa0fa020f0d0efe55aa0fc3596405e8407bbe2cbe6c7a558345304e6da87994e","src/lib.rs":"b41bbdc562cbfb130ed7c1e53fe69944774f515705341d8ce48a2f82c8c0c2c5"},"package":null}

View file

@ -24,7 +24,7 @@ crate-type = [
]
[dependencies]
cubeb-backend = "0.12.0"
cubeb-backend = "0.13"
ringbuf = "0.2"
semver = "1.0"

View file

@ -515,7 +515,7 @@ impl ContextOps for PulseContext {
Ok(())
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
#[allow(clippy::too_many_arguments)]
fn stream_init(
&mut self,
stream_name: Option<&CStr>,

View file

@ -283,7 +283,7 @@ pub struct PulseStream<'ctx> {
}
impl<'ctx> PulseStream<'ctx> {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
#[allow(clippy::too_many_arguments)]
pub fn new(
context: &'ctx PulseContext,
stream_name: Option<&CStr>,
@ -447,9 +447,9 @@ impl<'ctx> PulseStream<'ctx> {
latency_frames * stm.output_sample_spec.frame_size() as u32;
let battr = pa_buffer_attr {
maxlength: u32::max_value(),
prebuf: u32::max_value(),
fragsize: u32::max_value(),
maxlength: u32::MAX,
prebuf: u32::MAX,
fragsize: u32::MAX,
tlength: buffer_size_bytes * 2,
minreq: buffer_size_bytes / 4,
};
@ -490,8 +490,8 @@ impl<'ctx> PulseStream<'ctx> {
let buffer_size_bytes =
latency_frames * stm.input_sample_spec.frame_size() as u32;
let battr = pa_buffer_attr {
maxlength: u32::max_value(),
prebuf: u32::max_value(),
maxlength: u32::MAX,
prebuf: u32::MAX,
fragsize: buffer_size_bytes,
tlength: buffer_size_bytes,
minreq: buffer_size_bytes,
@ -1033,7 +1033,7 @@ impl<'ctx> PulseStream<'ctx> {
true
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cognitive_complexity))]
#[allow(clippy::cognitive_complexity)]
fn trigger_user_callback(&mut self, input_data: *const c_void, nbytes: usize) {
fn drained_cb(
a: &pulse::MainloopApi,
@ -1074,7 +1074,7 @@ impl<'ctx> PulseStream<'ctx> {
read_offset
);
let read_ptr = unsafe { (input_data as *const u8).add(read_offset) };
#[cfg_attr(feature = "cargo-clippy", allow(clippy::unnecessary_cast))]
#[allow(clippy::unnecessary_cast)]
let mut got = unsafe {
self.data_callback.unwrap()(
self as *const _ as *mut _,

File diff suppressed because one or more lines are too long

View file

@ -11,7 +11,7 @@
[package]
name = "cubeb-sys"
version = "0.12.0"
version = "0.13.0"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
build = "build.rs"
links = "cubeb"

View file

@ -78,6 +78,7 @@ endif()
add_library(cubeb
src/cubeb.c
src/cubeb_audio_dump.cpp
src/cubeb_mixer.cpp
src/cubeb_resampler.cpp
src/cubeb_log.cpp
@ -264,7 +265,7 @@ if(USE_WASAPI)
target_sources(cubeb PRIVATE
src/cubeb_wasapi.cpp)
target_compile_definitions(cubeb PRIVATE USE_WASAPI)
target_link_libraries(cubeb PRIVATE avrt ole32 ksuser)
target_link_libraries(cubeb PRIVATE ole32 ksuser)
endif()
check_include_files("windows.h;mmsystem.h" USE_WINMM)
@ -406,6 +407,7 @@ if(BUILD_TESTS)
cubeb_add_test(duplex)
cubeb_add_test(logging)
cubeb_add_test(triple_buffer)
cubeb_add_test(audio_dump)
if (USE_WASAPI)
cubeb_add_test(overload_callback)

View file

@ -274,7 +274,7 @@ typedef enum {
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 rate; /**< Requested sample rate. Valid range is [1000, 384000]. */
uint32_t channels; /**< Requested channel count. Valid range is [1, 8]. */
cubeb_channel_layout
layout; /**< Requested channel layout. This must be consistent with the

View file

@ -95,7 +95,7 @@ validate_stream_params(cubeb_stream_params * input_stream_params,
XASSERT(input_stream_params || output_stream_params);
if (output_stream_params) {
if (output_stream_params->rate < 1000 ||
output_stream_params->rate > 192000 ||
output_stream_params->rate > 768000 ||
output_stream_params->channels < 1 ||
output_stream_params->channels > UINT8_MAX) {
return CUBEB_ERROR_INVALID_FORMAT;
@ -103,7 +103,7 @@ validate_stream_params(cubeb_stream_params * input_stream_params,
}
if (input_stream_params) {
if (input_stream_params->rate < 1000 ||
input_stream_params->rate > 192000 ||
input_stream_params->rate > 768000 ||
input_stream_params->channels < 1 ||
input_stream_params->channels > UINT8_MAX) {
return CUBEB_ERROR_INVALID_FORMAT;
@ -533,7 +533,7 @@ int
cubeb_stream_set_input_processing_params(cubeb_stream * stream,
cubeb_input_processing_params params)
{
if (!stream || !params) {
if (!stream) {
return CUBEB_ERROR_INVALID_PARAMETER;
}

View file

@ -244,13 +244,24 @@ shutdown_with_error(cubeb_stream * stm)
}
int64_t poll_frequency_ns = NS_PER_S * stm->out_frame_size / stm->sample_rate;
int rv;
if (stm->istream) {
wait_for_state_change(stm->istream, AAUDIO_STREAM_STATE_STOPPED,
rv = wait_for_state_change(stm->istream, AAUDIO_STREAM_STATE_STOPPED,
poll_frequency_ns);
if (rv != CUBEB_OK) {
LOG("Failure when waiting for stream change on the input side when "
"shutting down in error");
// Not much we can do, carry on
}
}
if (stm->ostream) {
wait_for_state_change(stm->ostream, AAUDIO_STREAM_STATE_STOPPED,
rv = wait_for_state_change(stm->ostream, AAUDIO_STREAM_STATE_STOPPED,
poll_frequency_ns);
if (rv != CUBEB_OK) {
LOG("Failure when waiting for stream change on the output side when "
"shutting down in error");
// Not much we can do, carry on
}
}
assert(!stm->in_data_callback.load());
@ -920,7 +931,7 @@ aaudio_error_cb(AAudioStream * astream, void * user_data, aaudio_result_t error)
assert(stm->ostream == astream || stm->istream == astream);
// Device change -- reinitialize on the new default device.
if (error == AAUDIO_ERROR_DISCONNECTED) {
if (error == AAUDIO_ERROR_DISCONNECTED || error == AAUDIO_ERROR_TIMEOUT) {
LOG("Audio device change, reinitializing stream");
reinitialize_stream(stm);
return;

View file

@ -0,0 +1,231 @@
/*
* Copyright © 2023 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#define NOMINMAX
#include "cubeb_audio_dump.h"
#include "cubeb/cubeb.h"
#include "cubeb_ringbuffer.h"
#include <chrono>
#include <limits>
#include <thread>
#include <vector>
using std::thread;
using std::vector;
uint32_t
bytes_per_sample(cubeb_stream_params params)
{
switch (params.format) {
case CUBEB_SAMPLE_S16LE:
case CUBEB_SAMPLE_S16BE:
return sizeof(int16_t);
case CUBEB_SAMPLE_FLOAT32LE:
case CUBEB_SAMPLE_FLOAT32BE:
return sizeof(float);
};
}
struct cubeb_audio_dump_stream {
public:
explicit cubeb_audio_dump_stream(cubeb_stream_params params)
: sample_size(bytes_per_sample(params)),
ringbuffer(
static_cast<int>(params.rate * params.channels * sample_size))
{
}
int open(const char * name)
{
file = fopen(name, "wb");
if (!file) {
return CUBEB_ERROR;
}
return CUBEB_OK;
}
int close()
{
if (fclose(file)) {
return CUBEB_ERROR;
}
return CUBEB_OK;
}
// Directly write to the file. Useful to write the header.
size_t write(uint8_t * data, uint32_t count)
{
return fwrite(data, count, 1, file);
}
size_t write_all()
{
size_t written = 0;
const int buf_sz = 16 * 1024;
uint8_t buf[buf_sz];
while (int rv = ringbuffer.dequeue(buf, buf_sz)) {
written += fwrite(buf, rv, 1, file);
}
return written;
}
int dump(void * samples, uint32_t count)
{
int bytes = static_cast<int>(count * sample_size);
int rv = ringbuffer.enqueue(static_cast<uint8_t *>(samples), bytes);
return rv == bytes;
}
private:
uint32_t sample_size;
FILE * file{};
lock_free_queue<uint8_t> ringbuffer;
};
struct cubeb_audio_dump_session {
public:
cubeb_audio_dump_session() = default;
~cubeb_audio_dump_session()
{
assert(streams.empty());
session_thread.join();
}
cubeb_audio_dump_session(const cubeb_audio_dump_session &) = delete;
cubeb_audio_dump_session &
operator=(const cubeb_audio_dump_session &) = delete;
cubeb_audio_dump_session & operator=(cubeb_audio_dump_session &&) = delete;
cubeb_audio_dump_stream_t create_stream(cubeb_stream_params params,
const char * name)
{
if (running) {
return nullptr;
}
auto * stream = new cubeb_audio_dump_stream(params);
streams.push_back(stream);
int rv = stream->open(name);
if (rv != CUBEB_OK) {
delete stream;
return nullptr;
}
struct riff_header {
char chunk_id[4] = {'R', 'I', 'F', 'F'};
int32_t chunk_size = 0;
char format[4] = {'W', 'A', 'V', 'E'};
char subchunk_id_1[4] = {'f', 'm', 't', 0x20};
int32_t subchunk_1_size = 16;
int16_t audio_format{};
int16_t num_channels{};
int32_t sample_rate{};
int32_t byte_rate{};
int16_t block_align{};
int16_t bits_per_sample{};
char subchunk_id_2[4] = {'d', 'a', 't', 'a'};
int32_t subchunkd_2_size = std::numeric_limits<int32_t>::max();
};
riff_header header;
// 1 is integer PCM, 3 is float PCM
header.audio_format = bytes_per_sample(params) == 2 ? 1 : 3;
header.num_channels = params.channels;
header.sample_rate = params.rate;
header.byte_rate = bytes_per_sample(params) * params.rate * params.channels;
header.block_align = params.channels * bytes_per_sample(params);
header.bits_per_sample = bytes_per_sample(params) * 8;
stream->write(reinterpret_cast<uint8_t *>(&header), sizeof(riff_header));
return stream;
}
int delete_stream(cubeb_audio_dump_stream * stream)
{
assert(!running);
stream->close();
streams.erase(std::remove(streams.begin(), streams.end(), stream),
streams.end());
return CUBEB_OK;
}
int start()
{
assert(!running);
running = true;
session_thread = std::thread([this] {
while (running) {
for (auto * stream : streams) {
stream->write_all();
}
const int DUMP_INTERVAL = 10;
std::this_thread::sleep_for(std::chrono::milliseconds(DUMP_INTERVAL));
}
});
return CUBEB_OK;
}
int stop()
{
assert(running);
running = false;
return CUBEB_OK;
}
private:
thread session_thread;
vector<cubeb_audio_dump_stream_t> streams{};
std::atomic<bool> running = false;
};
int
cubeb_audio_dump_init(cubeb_audio_dump_session_t * session)
{
*session = new cubeb_audio_dump_session;
return CUBEB_OK;
}
int
cubeb_audio_dump_shutdown(cubeb_audio_dump_session_t session)
{
delete session;
return CUBEB_OK;
}
int
cubeb_audio_dump_stream_init(cubeb_audio_dump_session_t session,
cubeb_audio_dump_stream_t * stream,
cubeb_stream_params stream_params,
const char * name)
{
*stream = session->create_stream(stream_params, name);
return CUBEB_OK;
}
int
cubeb_audio_dump_stream_shutdown(cubeb_audio_dump_session_t session,
cubeb_audio_dump_stream_t stream)
{
return session->delete_stream(stream);
}
int
cubeb_audio_dump_start(cubeb_audio_dump_session_t session)
{
return session->start();
}
int
cubeb_audio_dump_stop(cubeb_audio_dump_session_t session)
{
return session->stop();
}
int
cubeb_audio_dump_write(cubeb_audio_dump_stream_t stream, void * audio_samples,
uint32_t count)
{
stream->dump(audio_samples, count);
return CUBEB_OK;
}

View file

@ -0,0 +1,108 @@
/*
* Copyright © 2023 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#ifndef CUBEB_AUDIO_DUMP
#define CUBEB_AUDIO_DUMP
#include "cubeb/cubeb.h"
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct cubeb_audio_dump_stream * cubeb_audio_dump_stream_t;
typedef struct cubeb_audio_dump_session * cubeb_audio_dump_session_t;
// Start audio dumping session
// This can only be called if the other API functions
// aren't currently being called: synchronized externally.
// This is not real-time safe.
//
// This is generally called when deciding to start logging some audio.
//
// Returns 0 in case of success.
int
cubeb_audio_dump_init(cubeb_audio_dump_session_t * session);
// End audio dumping session
// This can only be called if the other API functions
// aren't currently being called: synchronized externally.
//
// This is generally called when deciding to stop logging some audio.
//
// This is not real-time safe.
// Returns 0 in case of success.
int
cubeb_audio_dump_shutdown(cubeb_audio_dump_session_t session);
// Register a stream for dumping to a file
// This can only be called if cubeb_audio_dump_write
// isn't currently being called: synchronized externally.
//
// This is generally called when setting up a system-level stream side (either
// input or output).
//
// This is not real-time safe.
// Returns 0 in case of success.
int
cubeb_audio_dump_stream_init(cubeb_audio_dump_session_t session,
cubeb_audio_dump_stream_t * stream,
cubeb_stream_params stream_params,
const char * name);
// Unregister a stream for dumping to a file
// This can only be called if cubeb_audio_dump_write
// isn't currently being called: synchronized externally.
//
// This is generally called when a system-level audio stream side
// (input/output) has been stopped and drained, and the audio callback isn't
// going to be called.
//
// This is not real-time safe.
// Returns 0 in case of success.
int
cubeb_audio_dump_stream_shutdown(cubeb_audio_dump_session_t session,
cubeb_audio_dump_stream_t stream);
// Start dumping.
// cubeb_audio_dump_write can now be called.
//
// This starts dumping the audio to disk. Generally this is called when
// cubeb_stream_start is caled is called, but can be called at the beginning of
// the application.
//
// This is not real-time safe.
// Returns 0 in case of success.
int
cubeb_audio_dump_start(cubeb_audio_dump_session_t session);
// Stop dumping.
// cubeb_audio_dump_write can't be called at this point.
//
// This stops dumping the audio to disk cubeb_stream_stop is caled is called,
// but can be called before exiting the application.
//
// This is not real-time safe.
// Returns 0 in case of success.
int
cubeb_audio_dump_stop(cubeb_audio_dump_session_t session);
// Dump some audio samples for audio stream id.
//
// This is generally called from the real-time audio callback.
//
// This is real-time safe.
// Returns 0 in case of success.
int
cubeb_audio_dump_write(cubeb_audio_dump_stream_t stream, void * audio_samples,
uint32_t count);
#ifdef __cplusplus
};
#endif
#endif

View file

@ -377,6 +377,15 @@ cubeb_channel_to_channel_label(cubeb_channel channel)
}
}
bool
is_common_sample_rate(Float64 sample_rate)
{
/* Some commonly used sample rates and their multiples and divisors. */
return sample_rate == 8000 || sample_rate == 16000 || sample_rate == 22050 ||
sample_rate == 32000 || sample_rate == 44100 || sample_rate == 48000 ||
sample_rate == 88200 || sample_rate == 96000;
}
#if TARGET_OS_IPHONE
typedef UInt32 AudioDeviceID;
typedef UInt32 AudioObjectID;
@ -2502,6 +2511,12 @@ audiounit_configure_output(cubeb_stream * stm)
return CUBEB_ERROR;
}
stm->output_hw_rate = output_hw_desc.mSampleRate;
if (!is_common_sample_rate(stm->output_desc.mSampleRate)) {
/* For uncommon sample rates, we may run into issues with the OS
resampler if we don't do the resampling ourselves, so set the
AudioUnit sample rate to the hardware rate and resample. */
stm->output_desc.mSampleRate = stm->output_hw_rate;
}
LOG("(%p) Output device sampling rate: %.2f", stm,
output_hw_desc.mSampleRate);
stm->context->channels = output_hw_desc.mChannelsPerFrame;
@ -2709,11 +2724,16 @@ audiounit_setup_stream(cubeb_stream * stm)
input_unconverted_params.rate = stm->input_hw_rate;
}
/* Create resampler. Output params are unchanged
* because we do not need conversion on the output. */
cubeb_stream_params output_unconverted_params;
if (has_output(stm)) {
output_unconverted_params = stm->output_stream_params;
output_unconverted_params.rate = stm->output_desc.mSampleRate;
}
/* Create resampler. */
stm->resampler.reset(cubeb_resampler_create(
stm, has_input(stm) ? &input_unconverted_params : NULL,
has_output(stm) ? &stm->output_stream_params : NULL, target_sample_rate,
has_output(stm) ? &output_unconverted_params : NULL, target_sample_rate,
stm->data_callback, stm->user_ptr, CUBEB_RESAMPLER_QUALITY_DESKTOP,
CUBEB_RESAMPLER_RECLOCK_NONE));
if (!stm->resampler) {

View file

@ -204,6 +204,11 @@ struct auto_stream_ref {
cubeb_stream * stm;
};
using set_mm_thread_characteristics_function =
decltype(&AvSetMmThreadCharacteristicsW);
using revert_mm_thread_characteristics_function =
decltype(&AvRevertMmThreadCharacteristics);
extern cubeb_ops const wasapi_ops;
static com_heap_ptr<wchar_t>
@ -301,6 +306,13 @@ struct cubeb {
nullptr;
void * output_collection_changed_user_ptr = nullptr;
UINT64 performance_counter_frequency;
/* Library dynamically opened to increase the render thread priority, and
the two function pointers we need. */
HMODULE mmcss_module = nullptr;
set_mm_thread_characteristics_function set_mm_thread_characteristics =
nullptr;
revert_mm_thread_characteristics_function revert_mm_thread_characteristics =
nullptr;
};
class wasapi_endpoint_notification_client;
@ -1401,7 +1413,8 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
/* We could consider using "Pro Audio" here for WebAudio and
maybe WebRTC. */
mmcss_handle = AvSetMmThreadCharacteristicsA("Audio", &mmcss_task_index);
mmcss_handle =
stm->context->set_mm_thread_characteristics(L"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",
@ -1509,7 +1522,7 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
}
if (mmcss_handle) {
AvRevertMmThreadCharacteristics(mmcss_handle);
stm->context->revert_mm_thread_characteristics(mmcss_handle);
}
if (FAILED(hr)) {
@ -1522,6 +1535,18 @@ static unsigned int __stdcall wasapi_stream_render_loop(LPVOID stream)
void
wasapi_destroy(cubeb * context);
HANDLE WINAPI
set_mm_thread_characteristics_noop(LPCWSTR, LPDWORD mmcss_task_index)
{
return (HANDLE)1;
}
BOOL WINAPI
revert_mm_thread_characteristics_noop(HANDLE mmcss_handle)
{
return true;
}
HRESULT
register_notification_client(cubeb_stream * stm)
{
@ -1757,6 +1782,31 @@ wasapi_init(cubeb ** context, char const * context_name)
ctx->performance_counter_frequency = 0;
}
ctx->mmcss_module = LoadLibraryW(L"Avrt.dll");
bool success = false;
if (ctx->mmcss_module) {
ctx->set_mm_thread_characteristics =
reinterpret_cast<set_mm_thread_characteristics_function>(
GetProcAddress(ctx->mmcss_module, "AvSetMmThreadCharacteristicsW"));
ctx->revert_mm_thread_characteristics =
reinterpret_cast<revert_mm_thread_characteristics_function>(
GetProcAddress(ctx->mmcss_module,
"AvRevertMmThreadCharacteristics"));
success = ctx->set_mm_thread_characteristics &&
ctx->revert_mm_thread_characteristics;
}
if (!success) {
// This is not a fatal error, but we might end up glitching when
// the system is under high load.
LOG("Could not load avrt.dll or fetch AvSetMmThreadCharacteristicsW "
"AvRevertMmThreadCharacteristics: %lx",
GetLastError());
ctx->set_mm_thread_characteristics = &set_mm_thread_characteristics_noop;
ctx->revert_mm_thread_characteristics =
&revert_mm_thread_characteristics_noop;
}
*context = ctx;
return CUBEB_OK;
@ -1813,6 +1863,10 @@ wasapi_destroy(cubeb * context)
}
}
if (context->mmcss_module) {
FreeLibrary(context->mmcss_module);
}
delete context;
}

View file

@ -0,0 +1,74 @@
/*
* Copyright © 2023 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#define NOMINMAX
#define _USE_MATH_DEFINES
#include "cubeb/cubeb.h"
#include <ratio>
#include "cubeb_audio_dump.h"
#include "gtest/gtest.h"
#include <chrono>
#include <cmath>
#include <fstream>
#include <iostream>
#include <thread>
TEST(cubeb, audio_dump)
{
cubeb_audio_dump_session_t session;
int rv = cubeb_audio_dump_init(&session);
ASSERT_EQ(rv, 0);
cubeb_stream_params params;
params.rate = 44100;
params.channels = 2;
params.format = CUBEB_SAMPLE_FLOAT32NE;
cubeb_audio_dump_stream_t dump_stream;
rv = cubeb_audio_dump_stream_init(session, &dump_stream, params, "test.wav");
ASSERT_EQ(rv, 0);
rv = cubeb_audio_dump_start(session);
ASSERT_EQ(rv, 0);
float phase = 0;
const size_t buf_sz = 2 * 44100 / 50;
float buf[buf_sz];
for (uint32_t iteration = 0; iteration < 50; iteration++) {
uint32_t write_idx = 0;
for (uint32_t i = 0; i < buf_sz / params.channels; i++) {
for (uint32_t j = 0; j < params.channels; j++) {
buf[write_idx++] = sin(phase);
}
phase += 440 * M_PI * 2 / 44100;
if (phase > 2 * M_PI) {
phase -= 2 * M_PI;
}
}
rv = cubeb_audio_dump_write(dump_stream, buf, 2 * 44100 / 50);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
ASSERT_EQ(rv, 0);
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
rv = cubeb_audio_dump_stop(session);
ASSERT_EQ(rv, 0);
rv = cubeb_audio_dump_stream_shutdown(session, dump_stream);
ASSERT_EQ(rv, 0);
rv = cubeb_audio_dump_shutdown(session);
ASSERT_EQ(rv, 0);
std::ifstream file("test.wav");
ASSERT_TRUE(file.good());
}
#undef NOMINMAX

View file

@ -201,6 +201,7 @@ TEST(cubeb, duplex_collection_change)
ASSERT_EQ(r, CUBEB_OK);
}
#ifdef GTEST_HAS_DEATH_TEST
TEST(cubeb, duplex_collection_change_no_unregister)
{
cubeb * ctx;
@ -221,6 +222,7 @@ TEST(cubeb, duplex_collection_change_no_unregister)
duplex_collection_change_impl(ctx);
}
#endif
long
data_cb_input(cubeb_stream * stream, void * user, const void * inputbuffer,

View file

@ -0,0 +1,35 @@
// Copyright © 2017-2023 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
use std::os::raw::{c_char, c_int, c_void};
use stream::cubeb_stream_params;
pub enum cubeb_audio_dump_stream {}
pub enum cubeb_audio_dump_session {}
pub type cubeb_audio_dump_stream_t = *mut cubeb_audio_dump_stream;
pub type cubeb_audio_dump_session_t = *mut cubeb_audio_dump_session;
extern "C" {
pub fn cubeb_audio_dump_init(session: *mut cubeb_audio_dump_session_t) -> c_int;
pub fn cubeb_audio_dump_shutdown(session: cubeb_audio_dump_session_t) -> c_int;
pub fn cubeb_audio_dump_stream_init(
session: cubeb_audio_dump_session_t,
stream: *mut cubeb_audio_dump_stream_t,
stream_params: cubeb_stream_params,
name: *const c_char,
) -> c_int;
pub fn cubeb_audio_dump_stream_shutdown(
session: cubeb_audio_dump_session_t,
stream: cubeb_audio_dump_stream_t,
) -> c_int;
pub fn cubeb_audio_dump_start(session: cubeb_audio_dump_session_t) -> c_int;
pub fn cubeb_audio_dump_stop(session: cubeb_audio_dump_session_t) -> c_int;
pub fn cubeb_audio_dump_write(
stream: cubeb_audio_dump_stream_t,
audio_samples: *mut c_void,
count: u32,
) -> c_int;
}

View file

@ -8,6 +8,7 @@
#[macro_use]
mod macros;
mod audio_dump;
mod callbacks;
mod channel;
mod context;
@ -19,6 +20,7 @@ mod mixer;
mod resampler;
mod stream;
pub use audio_dump::*;
pub use callbacks::*;
pub use channel::*;
pub use context::*;

View file

@ -1 +1 @@
{"files":{"Cargo.lock":"d3b573eee37b0b0f709f168d4026071803c499f8c0d3efb830367d762c40754f","Cargo.toml":"8b0bd9b5b8f74492a893f3281dd14ca6ebd0f47ce3368c9927f16b76498fc340","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","README.md":"408c573ec240927cf5b9c036098e94e374ec41f71991415422586f450586b214","examples/common/mod.rs":"3363405f3d21ad120617473a0288c337a7b15eb79f5bb1035cfd258bd9bedf2b","examples/devices.rs":"ff5dcd588e7036165c4b4c20ec355d036e0ae90cf88b3b0f5cd86621fe2ce61d","examples/tone.rs":"8f5f9851b6d99f6f16c597fcb9312e3ef81769cbfb89341d2ea2522ca2e2214e","src/context.rs":"176f0923c13245acdc3934f649608fea1c17ad254daa3396d8929f38374e932e","src/frame.rs":"649cedaa2e9e1c5d2c3146bd0d66fd28bb230e68142493a9ea7dbab4a15f5adc","src/lib.rs":"58c78cad9541ebaef0ea96c67bc1db7d25e68e4e3d2f9a90f371c473e25c181f","src/sample.rs":"0d4645cc1d6ac26f198f6f59a44e193422e5646ecef0de46224653bef79d1a10","src/stream.rs":"0f51eab71d08685afdd0e748b85513541b9a612da1cad329c8c897dc0f79607c"},"package":"6db57570f2617f0214c11721e8d2325816d9dc936c2c472661ac5d90a30fba98"}
{"files":{"Cargo.lock":"d86a793ee92e01a15c886f5f73c9823eead21298f88455fa71717aeefa9b1af3","Cargo.toml":"4642a8d5f6fce1799a16b9e43d326e5aee5b886f51c2dded8617c6d6b659f81c","LICENSE":"8c044baa5d883274736eeece0b955249076c2697b826e576fce59496235b2cf5","README.md":"408c573ec240927cf5b9c036098e94e374ec41f71991415422586f450586b214","examples/common/mod.rs":"3363405f3d21ad120617473a0288c337a7b15eb79f5bb1035cfd258bd9bedf2b","examples/devices.rs":"ff5dcd588e7036165c4b4c20ec355d036e0ae90cf88b3b0f5cd86621fe2ce61d","examples/tone.rs":"8f5f9851b6d99f6f16c597fcb9312e3ef81769cbfb89341d2ea2522ca2e2214e","src/context.rs":"176f0923c13245acdc3934f649608fea1c17ad254daa3396d8929f38374e932e","src/frame.rs":"649cedaa2e9e1c5d2c3146bd0d66fd28bb230e68142493a9ea7dbab4a15f5adc","src/lib.rs":"58c78cad9541ebaef0ea96c67bc1db7d25e68e4e3d2f9a90f371c473e25c181f","src/sample.rs":"a8ed35c007541722e4322df82035086f160072ce549b34a73d54052148bcae07","src/stream.rs":"0f51eab71d08685afdd0e748b85513541b9a612da1cad329c8c897dc0f79607c"},"package":"3d105547cf8036cdb30e796ce0d06832af4766106a44574402fa2fd3c861a042"}

18
third_party/rust/cubeb/Cargo.lock generated vendored
View file

@ -10,9 +10,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cc"
version = "1.0.79"
version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
[[package]]
name = "cmake"
@ -25,16 +25,16 @@ dependencies = [
[[package]]
name = "cubeb"
version = "0.12.0"
version = "0.13.0"
dependencies = [
"cubeb-core",
]
[[package]]
name = "cubeb-core"
version = "0.12.0"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2380c03a7df0ea3744f6a210d6340f423935e53cbf2fd68ada84b5e808e46ac7"
checksum = "ac08d314dd1ec6d41d9ccdeec70899c98ed3b89845367000dd6096099481bc73"
dependencies = [
"bitflags",
"cubeb-sys",
@ -42,9 +42,9 @@ dependencies = [
[[package]]
name = "cubeb-sys"
version = "0.12.0"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c20c457d7b34dad6e0c1a9c759c96b4420b9e9917a572998b81835799a07e1d"
checksum = "26073cd50c7b6ba4272204839f56921557609a0d67e092882cbb903df94cab39"
dependencies = [
"cmake",
"pkg-config",
@ -52,6 +52,6 @@ dependencies = [
[[package]]
name = "pkg-config"
version = "0.3.27"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"

View file

@ -11,7 +11,7 @@
[package]
name = "cubeb"
version = "0.12.0"
version = "0.13.0"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
description = """
Bindings to libcubeb for interacting with system audio from rust.
@ -24,7 +24,7 @@ license = "ISC"
repository = "https://github.com/mozilla/cubeb-rs"
[dependencies.cubeb-core]
version = "0.12.0"
version = "0.13.0"
[features]
gecko-in-tree = ["cubeb-core/gecko-in-tree"]

View file

@ -13,7 +13,7 @@ pub trait Sample: Send + Copy {
impl Sample for i16 {
fn from_float(x: f32) -> i16 {
(x * f32::from(i16::max_value())) as i16
(x * f32::from(i16::MAX)) as i16
}
}

View file

@ -22,11 +22,11 @@ static_prefs = { path = "../../../../modules/libpref/init/static_prefs" }
profiler_helper = { path = "../../../../tools/profiler/rust-helper", optional = true }
mozurl = { path = "../../../../netwerk/base/mozurl" }
webrender_bindings = { path = "../../../../gfx/webrender_bindings" }
cubeb-coreaudio = { git = "https://github.com/mozilla/cubeb-coreaudio-rs", rev = "4ca174cf83ebe32b3198478c2211d69678845bc7", optional = true }
cubeb-pulse = { git = "https://github.com/mozilla/cubeb-pulse-rs", rev="8ff972c8e2ec1782ff262ac4071c0415e69b1367", optional = true, features=["pulse-dlopen"] }
cubeb-sys = { version = "0.12.0", optional = true, features=["gecko-in-tree"] }
audioipc2-client = { git = "https://github.com/mozilla/audioipc", rev = "409e11f8de6288e9ddfe269654523735302e59e6", optional = true }
audioipc2-server = { git = "https://github.com/mozilla/audioipc", rev = "409e11f8de6288e9ddfe269654523735302e59e6", optional = true }
cubeb-coreaudio = { git = "https://github.com/mozilla/cubeb-coreaudio-rs", rev = "0989726a1b9b640a30dfdf3ea005a12c73ab8155", optional = true }
cubeb-pulse = { git = "https://github.com/mozilla/cubeb-pulse-rs", rev="8678dcab1c287de79c4c184ccc2e065bc62b70e2", optional = true, features=["pulse-dlopen"] }
cubeb-sys = { version = "0.13", optional = true, features=["gecko-in-tree"] }
audioipc2-client = { git = "https://github.com/mozilla/audioipc", rev = "3495905752a4263827f5d43737f9ca3ed0243ce0", optional = true }
audioipc2-server = { git = "https://github.com/mozilla/audioipc", rev = "3495905752a4263827f5d43737f9ca3ed0243ce0", optional = true }
encoding_glue = { path = "../../../../intl/encoding_glue" }
authrs_bridge = { path = "../../../../dom/webauthn/authrs_bridge" }
gkrust_utils = { path = "../../../../xpcom/rust/gkrust_utils" }