From 91a5259ccebce1fe4d6f282658a2016365441e94 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Tue, 4 Jul 2023 17:53:38 +0300 Subject: [PATCH] Add vhost-user-sound crate Signed-off-by: Emmanouil Pitsidianakis --- Cargo.lock | 543 +++++++++-------- crates/sound/CHANGELOG.md | 3 + crates/sound/Cargo.toml | 19 +- crates/sound/LICENSE-APACHE | 1 + crates/sound/LICENSE-BSD-3-Clause | 1 + crates/sound/README.md | 40 +- crates/sound/rustfmt.toml | 7 + crates/sound/src/audio_backends.rs | 31 +- crates/sound/src/audio_backends/null.rs | 11 +- crates/sound/src/audio_backends/pipewire.rs | 28 + crates/sound/src/device.rs | 215 +++++++ crates/sound/src/lib.rs | 56 +- crates/sound/src/main.rs | 7 +- crates/sound/src/vhu_sound.rs | 627 -------------------- crates/sound/src/virtio_sound.rs | 34 +- 15 files changed, 612 insertions(+), 1011 deletions(-) create mode 100644 crates/sound/CHANGELOG.md create mode 120000 crates/sound/LICENSE-APACHE create mode 120000 crates/sound/LICENSE-BSD-3-Clause create mode 100644 crates/sound/rustfmt.toml create mode 100644 crates/sound/src/audio_backends/pipewire.rs create mode 100644 crates/sound/src/device.rs delete mode 100644 crates/sound/src/vhu_sound.rs diff --git a/Cargo.lock b/Cargo.lock index a33e345..aae3814 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,67 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] [[package]] -name = "anyhow" -version = "1.0.71" +name = "anstream" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "arc-swap" @@ -35,7 +84,7 @@ version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -47,7 +96,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 1.0.109", "which", ] @@ -57,7 +106,7 @@ version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -69,7 +118,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 1.0.109", "which", ] @@ -79,6 +128,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "byteorder" version = "1.4.3" @@ -102,9 +157,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.1" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8790cf1286da485c72cf5fc7aeba308438800036ec67d89425924c4807268c9" +checksum = "215c0072ecc28f92eeb0eea38ba63ddfcb65c2828c46311d646f1a3ff5f9841c" dependencies = [ "smallvec", "target-lexicon", @@ -118,9 +173,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" dependencies = [ "glob", "libc", @@ -129,40 +184,50 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.8" +version = "4.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +checksum = "5b0827b011f6f8ab38590295339817b0d26f344aa4932c3ced71b45b0c54b4a9" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9441b403be87be858db6a23edb493e7f694761acdc3343d5a0fcaafd304cbc9e" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.8" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.26", ] [[package]] name = "clap_lex" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "cookie-factory" @@ -172,12 +237,12 @@ checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.14.0", "lock_api", "once_cell", "parking_lot_core", @@ -204,11 +269,11 @@ dependencies = [ [[package]] name = "epoll" -version = "4.3.1" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0" +checksum = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79" dependencies = [ - "bitflags", + "bitflags 2.3.3", "libc", ] @@ -231,7 +296,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -255,9 +320,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -270,9 +335,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -280,15 +345,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -298,38 +363,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.26", ] [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -345,9 +410,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -366,6 +431,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "heck" version = "0.4.1" @@ -374,18 +445,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "humantime" @@ -400,7 +462,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -420,25 +482,24 @@ checksum = "ee87fd093563344074bacf24faa0bb0227fb6969fb223e922db798516de924d6" [[package]] name = "io-lifetimes" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd6da19f25979c7270e70fa95ab371ec3b701cd0eefc47667a09785b3c59155" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] name = "is-terminal" -version = "0.4.3" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.45.0", + "hermit-abi", + "rustix 0.38.4", + "windows-sys", ] [[package]] @@ -455,9 +516,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libgpiod" @@ -496,7 +557,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "667dfbb50c3d1f7ee1d33afdc04d1255923ece7642db3303046e7d63d997d77d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cc", "cookie-factory", "errno 0.3.1", @@ -519,15 +580,21 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -535,12 +602,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "memchr" @@ -569,7 +633,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset", @@ -589,25 +653,19 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "parking_lot" @@ -621,15 +679,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] @@ -640,9 +698,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -657,7 +715,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc2180a4a84b855be86e6cd72fa6fd4318278871d2b1082e7cd05fe64b135ccb" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "errno 0.3.1", "libc", "libspa", @@ -691,44 +749,20 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -765,18 +799,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", @@ -785,9 +831,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "rustc-hash" @@ -797,23 +843,36 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.36.9" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ - "bitflags", - "errno 0.2.8", + "bitflags 1.3.2", + "errno 0.3.1", "io-lifetimes", "libc", - "linux-raw-sys", - "windows-sys 0.45.0", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +dependencies = [ + "bitflags 2.3.3", + "errno 0.3.1", + "libc", + "linux-raw-sys 0.4.3", + "windows-sys", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" @@ -852,7 +911,7 @@ checksum = "079a83df15f85d89a68d64ae1238f142f172b1fa915d0d76b26a7cba1b659a69" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -872,9 +931,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "static_assertions" @@ -900,10 +959,21 @@ dependencies = [ ] [[package]] -name = "system-deps" -version = "6.1.0" +name = "syn" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5fa6fb9ee296c0dc2df41a656ca7948546d061958115ddb0bcaae43ad0d17d2" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" dependencies = [ "cfg-expr", "heck", @@ -914,21 +984,22 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.7" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" +checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e" [[package]] name = "tempfile" -version = "3.4.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall", - "rustix", - "windows-sys 0.42.0", + "rustix 0.37.23", + "windows-sys", ] [[package]] @@ -942,22 +1013,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.26", ] [[package]] @@ -996,9 +1067,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "version-compare" @@ -1006,19 +1083,13 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "vhost" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "vm-memory", "vmm-sys-util", @@ -1036,7 +1107,7 @@ dependencies = [ "thiserror", "vhost", "vhost-user-backend", - "virtio-bindings 0.2.0", + "virtio-bindings 0.2.1", "virtio-queue", "vm-memory", "vmm-sys-util", @@ -1053,7 +1124,7 @@ dependencies = [ "thiserror", "vhost", "vhost-user-backend", - "virtio-bindings 0.2.0", + "virtio-bindings 0.2.1", "virtio-queue", "vm-memory", "vmm-sys-util", @@ -1073,7 +1144,7 @@ dependencies = [ "thiserror", "vhost", "vhost-user-backend", - "virtio-bindings 0.2.0", + "virtio-bindings 0.2.1", "virtio-queue", "vm-memory", "vmm-sys-util", @@ -1110,8 +1181,7 @@ dependencies = [ "thiserror", "vhost", "vhost-user-backend", - "virtio-bindings 0.2.0", - "virtio-queue", + "virtio-bindings 0.2.1", "vm-memory", "vmm-sys-util", ] @@ -1130,7 +1200,7 @@ dependencies = [ "thiserror", "vhost", "vhost-user-backend", - "virtio-bindings 0.2.0", + "virtio-bindings 0.2.1", "virtio-queue", "virtio-vsock", "vm-memory", @@ -1145,9 +1215,9 @@ checksum = "3ff512178285488516ed85f15b5d0113a7cdb89e9e8a760b269ae4f02b84bd6b" [[package]] name = "virtio-bindings" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9084faf91b9aa9676ae2cac8f1432df2839d9566e6f19f29dbc13a8b831dff" +checksum = "c18d7b74098a946470ea265b5bacbbf877abc3373021388454de0d47735a5b98" [[package]] name = "virtio-queue" @@ -1189,7 +1259,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", ] @@ -1241,52 +1311,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.1", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.1", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.1", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.1", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.1", + "windows-targets", ] [[package]] @@ -1295,93 +1326,51 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" - [[package]] name = "windows_x86_64_msvc" version = "0.48.0" @@ -1390,9 +1379,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" dependencies = [ "memchr", ] diff --git a/crates/sound/CHANGELOG.md b/crates/sound/CHANGELOG.md new file mode 100644 index 0000000..d471959 --- /dev/null +++ b/crates/sound/CHANGELOG.md @@ -0,0 +1,3 @@ +# Upcoming Release + +- First initial daemon implementation. diff --git a/crates/sound/Cargo.toml b/crates/sound/Cargo.toml index 2a8f621..6809ccd 100644 --- a/crates/sound/Cargo.toml +++ b/crates/sound/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "vhost-user-sound" version = "0.1.0" -authors = ["Stefano Garzarella "] +authors = ["Stefano Garzarella ", "Manos Pitsidianakis "] description = "A virtio-sound device using the vhost-user protocol." repository = "https://github.com/rust-vmm/vhost-device" readme = "README.md" -keywords = ["vhost", "sound", "virtio-sound"] +keywords = ["vhost", "sound", "virtio-sound", "virtio-snd", "virtio"] license = "Apache-2.0 OR BSD-3-Clause" edition = "2018" @@ -15,21 +15,20 @@ null-backend = [] pw-backend = ["pipewire", "libspa", "pipewire-sys", "libspa-sys", "bindgen"] [dependencies] -clap = { version = "4.1", features = ["derive"] } +bindgen = { version = "0.64.0", optional = true } +clap = { version = "4.1", features = ["derive"] } env_logger = "0.10" +libspa = { version = "0.6.0", optional = true } +libspa-sys = { version = "0.6.0", optional = true } log = "0.4" +pipewire = { version = "0.6.0", optional = true } +pipewire-sys = { version = "0.6.0", optional = true } thiserror = "1.0" vhost = { version = "0.6", features = ["vhost-user-slave"] } vhost-user-backend = "0.8" -virtio-bindings = "0.2" -virtio-queue = "0.7" +virtio-bindings = "0.2.1" vm-memory = "0.10" vmm-sys-util = "0.11" -pipewire = { version = "0.6.0", optional = true } -libspa = { version = "0.6.0", optional = true } -pipewire-sys = { version = "0.6.0", optional = true } -libspa-sys = { version = "0.6.0", optional = true } -bindgen = { version = "0.64.0", optional = true } [dev-dependencies] serial_test = "1.0" diff --git a/crates/sound/LICENSE-APACHE b/crates/sound/LICENSE-APACHE new file mode 120000 index 0000000..1cd601d --- /dev/null +++ b/crates/sound/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/sound/LICENSE-BSD-3-Clause b/crates/sound/LICENSE-BSD-3-Clause new file mode 120000 index 0000000..a60f1af --- /dev/null +++ b/crates/sound/LICENSE-BSD-3-Clause @@ -0,0 +1 @@ +../../LICENSE-BSD-3-Clause \ No newline at end of file diff --git a/crates/sound/README.md b/crates/sound/README.md index ea2fbce..faea312 100644 --- a/crates/sound/README.md +++ b/crates/sound/README.md @@ -1,10 +1,44 @@ # vhost-user-sound -## Design + +## Synopsis + vhost-user-sound --socket --backend -## Usage +## Description + A virtio-sound device using the vhost-user protocol. -## Working example +## Options + +```text + --socket + vhost-user Unix domain socket path + + --backend + audio backend to be used (supported: null) + + -h, --help + Print help + + -V, --version + Print version +``` + +## Examples + +Launch the backend on the host machine: + +```shell +host# vhost-user-sound --socket /tmp/snd.sock --backend null +``` + +With QEMU, you can add a `virtio` device that uses the backend's socket with the following flags: + +```text +-chardev socket,id=vsnd,path=/tmp/snd.sock \ +-device vhost-user-snd-pci,chardev=vsnd,id=snd +``` ## License diff --git a/crates/sound/rustfmt.toml b/crates/sound/rustfmt.toml new file mode 100644 index 0000000..c6f0942 --- /dev/null +++ b/crates/sound/rustfmt.toml @@ -0,0 +1,7 @@ +edition = "2018" +format_generated_files = false +format_code_in_doc_comments = true +format_strings = true +imports_granularity = "Crate" +group_imports = "StdExternalCrate" +wrap_comments = true diff --git a/crates/sound/src/audio_backends.rs b/crates/sound/src/audio_backends.rs index 1a49d8f..c8ad633 100644 --- a/crates/sound/src/audio_backends.rs +++ b/crates/sound/src/audio_backends.rs @@ -1,41 +1,22 @@ +// Manos Pitsidianakis // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause #[cfg(feature = "null-backend")] mod null; #[cfg(feature = "pw-backend")] -mod pw_backend; +mod pipewire; #[cfg(feature = "null-backend")] use self::null::NullBackend; -use self::pw_backend::PwBackend; #[cfg(feature = "pw-backend")] -use crate::PCMParams; -use crate::{Error, Result}; +use self::pipewire::PwBackend; +use crate::{Error, Result, SoundRequest}; pub trait AudioBackend { - fn write(&self, stream_id: u32) -> Result<()>; - fn read(&self, stream_id: u32) -> Result<()>; + fn write(&self, req: &SoundRequest) -> Result<()>; - fn set_param(&self, _stream_id: u32, _params: PCMParams) -> Result<()> { - Ok(()) - } - - fn prepare(&self, _stream_id: u32) -> Result<()> { - Ok(()) - } - - fn release(&self, _stream_id: u32) -> Result<()> { - Ok(()) - } - - fn start(&self, _stream_id: u32) -> Result<()> { - Ok(()) - } - - fn stop(&self, _stream_id: u32) -> Result<()> { - Ok(()) - } + fn read(&self, req: &mut SoundRequest) -> Result<()>; } pub fn alloc_audio_backend(name: String) -> Result> { diff --git a/crates/sound/src/audio_backends/null.rs b/crates/sound/src/audio_backends/null.rs index e4cfb2a..07cbb38 100644 --- a/crates/sound/src/audio_backends/null.rs +++ b/crates/sound/src/audio_backends/null.rs @@ -1,30 +1,27 @@ // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause use super::AudioBackend; -use crate::Result; +use crate::{Error, Result, SoundRequest}; pub struct NullBackend {} impl NullBackend { pub fn new() -> Self { - NullBackend {} + Self {} } } impl AudioBackend for NullBackend { - fn write(&self, stream_id: u32) -> Result<()> { - println!("null backend, writting to stream: {}", stream_id); + fn write(&self, _req: &SoundRequest) -> Result<()> { Ok(()) } - fn read(&self, _stream_id: u32) -> Result<()> { - /* + fn read(&self, req: &mut SoundRequest) -> Result<()> { let buf = req.data_slice().ok_or(Error::SoundReqMissingData)?; let zero_mem = vec![0u8; buf.len()]; buf.copy_from(&zero_mem); - */ Ok(()) } } diff --git a/crates/sound/src/audio_backends/pipewire.rs b/crates/sound/src/audio_backends/pipewire.rs new file mode 100644 index 0000000..e288c39 --- /dev/null +++ b/crates/sound/src/audio_backends/pipewire.rs @@ -0,0 +1,28 @@ +// Pipewire backend device +// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause + +use super::AudioBackend; +use crate::{Error, Result, SoundRequest}; + +pub struct PwBackend {} + +impl PwBackend { + pub fn new() -> Self { + Self {} + } +} + +impl AudioBackend for PwBackend { + fn write(&self, _req: &SoundRequest) -> Result<()> { + Ok(()) + } + + fn read(&self, req: &mut SoundRequest) -> Result<()> { + let buf = req.data_slice().ok_or(Error::SoundReqMissingData)?; + let zero_mem = vec![0u8; buf.len()]; + + buf.copy_from(&zero_mem); + + Ok(()) + } +} diff --git a/crates/sound/src/device.rs b/crates/sound/src/device.rs new file mode 100644 index 0000000..9ac2216 --- /dev/null +++ b/crates/sound/src/device.rs @@ -0,0 +1,215 @@ +// Manos Pitsidianakis +// Stefano Garzarella +// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause + +use std::{io::Result as IoResult, sync::RwLock, u16, u32, u64, u8}; + +use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; +use vhost_user_backend::{VhostUserBackend, VringRwLock}; +use virtio_bindings::bindings::{ + virtio_config::{VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_VERSION_1}, + virtio_ring::{VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC}, +}; +use vm_memory::{ByteValued, GuestMemoryAtomic, GuestMemoryMmap}; +use vmm_sys_util::{ + epoll::EventSet, + eventfd::{EventFd, EFD_NONBLOCK}, +}; + +use crate::{ + audio_backends::{alloc_audio_backend, AudioBackend}, + virtio_sound::*, + Error, Result, SoundConfig, +}; + +struct VhostUserSoundThread { + mem: Option>, + event_idx: bool, + queue_indexes: Vec, +} + +impl VhostUserSoundThread { + pub fn new(mut queue_indexes: Vec) -> Result { + queue_indexes.sort(); + + Ok(Self { + event_idx: false, + mem: None, + queue_indexes, + }) + } + + fn queues_per_thread(&self) -> u64 { + let mut queues_per_thread = 0u64; + + for idx in self.queue_indexes.iter() { + queues_per_thread |= 1u64 << idx + } + + queues_per_thread + } + + fn set_event_idx(&mut self, enabled: bool) { + self.event_idx = enabled; + } + + fn update_memory(&mut self, mem: GuestMemoryAtomic) -> IoResult<()> { + self.mem = Some(mem); + Ok(()) + } + + fn handle_event(&self, device_event: u16, vrings: &[VringRwLock]) -> IoResult { + let vring = &vrings[device_event as usize]; + let queue_idx = self.queue_indexes[device_event as usize]; + + match queue_idx { + CONTROL_QUEUE_IDX => self.process_control(vring), + EVENT_QUEUE_IDX => self.process_event(vring), + TX_QUEUE_IDX => self.process_tx(vring), + RX_QUEUE_IDX => self.process_rx(vring), + _ => Err(Error::HandleUnknownEvent.into()), + } + } + + fn process_control(&self, _vring: &VringRwLock) -> IoResult { + Ok(false) + } + + fn process_event(&self, _vring: &VringRwLock) -> IoResult { + Ok(false) + } + + fn process_tx(&self, _vring: &VringRwLock) -> IoResult { + Ok(false) + } + + fn process_rx(&self, _vring: &VringRwLock) -> IoResult { + Ok(false) + } +} + +pub struct VhostUserSoundBackend { + threads: Vec>, + virtio_cfg: VirtioSoundConfig, + exit_event: EventFd, + _audio_backend: RwLock>, +} + +impl VhostUserSoundBackend { + pub fn new(config: SoundConfig) -> Result { + let threads = if config.multi_thread { + vec![ + RwLock::new(VhostUserSoundThread::new(vec![ + CONTROL_QUEUE_IDX, + EVENT_QUEUE_IDX, + ])?), + RwLock::new(VhostUserSoundThread::new(vec![TX_QUEUE_IDX])?), + RwLock::new(VhostUserSoundThread::new(vec![RX_QUEUE_IDX])?), + ] + } else { + vec![RwLock::new(VhostUserSoundThread::new(vec![ + CONTROL_QUEUE_IDX, + EVENT_QUEUE_IDX, + TX_QUEUE_IDX, + RX_QUEUE_IDX, + ])?)] + }; + + let audio_backend = alloc_audio_backend(config.audio_backend_name)?; + + Ok(Self { + threads, + virtio_cfg: VirtioSoundConfig { + jacks: 0.into(), + streams: 1.into(), + chmaps: 0.into(), + }, + exit_event: EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?, + _audio_backend: RwLock::new(audio_backend), + }) + } + + pub fn send_exit_event(&self) { + self.exit_event.write(1).unwrap(); + } +} + +impl VhostUserBackend for VhostUserSoundBackend { + fn num_queues(&self) -> usize { + NUM_QUEUES as usize + } + + fn max_queue_size(&self) -> usize { + 256 + } + + fn features(&self) -> u64 { + 1 << VIRTIO_F_VERSION_1 + | 1 << VIRTIO_F_NOTIFY_ON_EMPTY + | 1 << VIRTIO_RING_F_INDIRECT_DESC + | 1 << VIRTIO_RING_F_EVENT_IDX + | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() + } + + fn protocol_features(&self) -> VhostUserProtocolFeatures { + VhostUserProtocolFeatures::CONFIG + } + + fn set_event_idx(&self, enabled: bool) { + for thread in self.threads.iter() { + thread.write().unwrap().set_event_idx(enabled); + } + } + + fn update_memory(&self, mem: GuestMemoryAtomic) -> IoResult<()> { + for thread in self.threads.iter() { + thread.write().unwrap().update_memory(mem.clone())?; + } + + Ok(()) + } + + fn handle_event( + &self, + device_event: u16, + evset: EventSet, + vrings: &[VringRwLock], + thread_id: usize, + ) -> IoResult { + if evset != EventSet::IN { + return Err(Error::HandleEventNotEpollIn.into()); + } + + self.threads[thread_id] + .read() + .unwrap() + .handle_event(device_event, vrings) + } + + fn get_config(&self, offset: u32, size: u32) -> Vec { + let offset = offset as usize; + let size = size as usize; + + let buf = self.virtio_cfg.as_slice(); + + if offset + size > buf.len() { + return Vec::new(); + } + + buf[offset..offset + size].to_vec() + } + + fn queues_per_thread(&self) -> Vec { + let mut vec = Vec::with_capacity(self.threads.len()); + + for thread in self.threads.iter() { + vec.push(thread.read().unwrap().queues_per_thread()) + } + + vec + } + + fn exit_event(&self, _thread_index: usize) -> Option { + self.exit_event.try_clone().ok() + } +} diff --git a/crates/sound/src/lib.rs b/crates/sound/src/lib.rs index e53cd61..8d20eb7 100644 --- a/crates/sound/src/lib.rs +++ b/crates/sound/src/lib.rs @@ -1,19 +1,22 @@ +// Manos Pitsidianakis // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause -mod audio_backends; -mod vhu_sound; -mod virtio_sound; +pub mod audio_backends; +pub mod device; +pub mod virtio_sound; -use std::io::{Error as IoError, ErrorKind}; -use std::sync::Arc; +use std::{ + io::{Error as IoError, ErrorKind}, + sync::Arc, +}; use log::{info, warn}; use thiserror::Error as ThisError; use vhost::{vhost_user, vhost_user::Listener}; use vhost_user_backend::VhostUserDaemon; -use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap, Le32, VolatileSlice}; +use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap, VolatileSlice}; -use crate::vhu_sound::VhostUserSoundBackend; +use crate::device::VhostUserSoundBackend; pub type Result = std::result::Result; @@ -30,46 +33,14 @@ pub enum Error { SoundReqMissingData, #[error("Audio backend not supported")] AudioBackendNotSupported, - #[error("Descriptor not found")] - DescriptorNotFound, - #[error("Descriptor read failed")] - DescriptorReadFailed, - #[error("Descriptor write failed")] - DescriptorWriteFailed, - #[error("Isufficient descriptor size, required: {0}, found: {1}")] - InsufficientDescriptorSize(usize, usize), - #[error("Failed to send notification")] - SendNotificationFailed, - #[error("Invalid descriptor count {0}")] - UnexpectedDescriptorCount(usize), - #[error("Invalid descriptor size, expected: {0}, found: {1}")] - UnexpectedDescriptorSize(usize, usize), - #[error("Invalid descriptor size, expected at least: {0}, found: {1}")] - UnexpectedMinimumDescriptorSize(usize, usize), - #[error("Received unexpected readable descriptor at index {0}")] - UnexpectedReadableDescriptor(usize), - #[error("Received unexpected write only descriptor at index {0}")] - UnexpectedWriteOnlyDescriptor(usize), } impl std::convert::From for IoError { fn from(e: Error) -> Self { - IoError::new(ErrorKind::Other, e) + Self::new(ErrorKind::Other, e) } } -#[derive(Default, Clone)] -pub struct PCMParams { - pub features: Le32, - /// size of hardware buffer in bytes - pub buffer_bytes: Le32, - /// size of hardware period in bytes - pub period_bytes: Le32, - pub channels: u8, - pub format: u8, - pub rate: u8, -} - #[derive(Debug, Clone)] /// This structure is the public API through which an external program /// is allowed to configure the backend. @@ -133,7 +104,10 @@ pub fn start_backend_server(config: SoundConfig) { info!("Stopping cleanly"); } Err(vhost_user_backend::Error::HandleRequest(vhost_user::Error::PartialMessage)) => { - info!("vhost-user connection closed with partial message. If the VM is shutting down, this is expected behavior; otherwise, it might be a bug."); + info!( + "vhost-user connection closed with partial message. If the VM is shutting down, \ + this is expected behavior; otherwise, it might be a bug." + ); } Err(e) => { warn!("Error running daemon: {:?}", e); diff --git a/crates/sound/src/main.rs b/crates/sound/src/main.rs index 7f3c844..11bed61 100644 --- a/crates/sound/src/main.rs +++ b/crates/sound/src/main.rs @@ -1,9 +1,9 @@ +// Manos Pitsidianakis +// Stefano Garzarella // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause - use std::convert::TryFrom; use clap::Parser; - use vhost_user_sound::{start_backend_server, Error, Result, SoundConfig}; #[derive(Parser, Debug)] @@ -40,9 +40,10 @@ fn main() { #[cfg(test)] mod tests { - use super::*; use serial_test::serial; + use super::*; + impl SoundArgs { fn from_args(socket: &str) -> Self { SoundArgs { diff --git a/crates/sound/src/vhu_sound.rs b/crates/sound/src/vhu_sound.rs deleted file mode 100644 index b98399d..0000000 --- a/crates/sound/src/vhu_sound.rs +++ /dev/null @@ -1,627 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause - -use std::mem::size_of; -use std::sync::Arc; -use std::sync::RwLock; -use std::{io::Result as IoResult, u16, u32, u64, u8}; - -use log::{debug, error}; -use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; -use vhost_user_backend::{VhostUserBackend, VringRwLock, VringT}; -use virtio_bindings::bindings::{ - virtio_config::VIRTIO_F_NOTIFY_ON_EMPTY, virtio_config::VIRTIO_F_VERSION_1, - virtio_ring::VIRTIO_RING_F_EVENT_IDX, virtio_ring::VIRTIO_RING_F_INDIRECT_DESC, -}; -use virtio_queue::{DescriptorChain, QueueOwnedT}; -use vm_memory::{ - ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryLoadGuard, GuestMemoryMmap, -}; -use vmm_sys_util::{ - epoll::EventSet, - eventfd::{EventFd, EFD_NONBLOCK}, -}; - -use crate::audio_backends::{alloc_audio_backend, AudioBackend}; -use crate::virtio_sound::*; -use crate::PCMParams; -use crate::{Error, Result, SoundConfig}; -use vm_memory::{Le32, Le64}; - -pub const SUPPORTED_FORMATS: u64 = 1 << VIRTIO_SND_PCM_FMT_U8 - | 1 << VIRTIO_SND_PCM_FMT_S16 - | 1 << VIRTIO_SND_PCM_FMT_S24 - | 1 << VIRTIO_SND_PCM_FMT_S32; - -pub const SUPPORTED_RATES: u64 = 1 << VIRTIO_SND_PCM_RATE_8000 - | 1 << VIRTIO_SND_PCM_RATE_11025 - | 1 << VIRTIO_SND_PCM_RATE_16000 - | 1 << VIRTIO_SND_PCM_RATE_22050 - | 1 << VIRTIO_SND_PCM_RATE_32000 - | 1 << VIRTIO_SND_PCM_RATE_44100 - | 1 << VIRTIO_SND_PCM_RATE_48000; - -pub const NR_STREAMS: usize = 1; - -pub struct StreamInfo { - pub features: Le32, /* 1 << VIRTIO_SND_PCM_F_XXX */ - pub formats: Le64, /* 1 << VIRTIO_SND_PCM_FMT_XXX */ - pub rates: Le64, /* 1 << VIRTIO_SND_PCM_RATE_XXX */ - pub direction: u8, - pub channels_min: u8, - pub channels_max: u8, -} - -impl StreamInfo { - pub fn output() -> Self { - Self { - features: 0.into(), - formats: SUPPORTED_FORMATS.into(), - rates: SUPPORTED_RATES.into(), - direction: VIRTIO_SND_D_OUTPUT, - channels_min: 1, - channels_max: 6, - } - } -} - -struct VhostUserSoundThread { - mem: Option>, - event_idx: bool, - queue_indexes: Vec, - audio_backend: Arc>, -} - -impl VhostUserSoundThread { - pub fn new( - mut queue_indexes: Vec, - audio_backend: Arc>, - ) -> Result { - queue_indexes.sort(); - - Ok(VhostUserSoundThread { - event_idx: false, - mem: None, - queue_indexes, - audio_backend, - }) - } - - fn queues_per_thread(&self) -> u64 { - let mut queues_per_thread = 0u64; - - for idx in self.queue_indexes.iter() { - queues_per_thread |= 1u64 << idx - } - - queues_per_thread - } - - fn set_event_idx(&mut self, enabled: bool) { - self.event_idx = enabled; - } - - fn update_memory(&mut self, mem: GuestMemoryAtomic) -> IoResult<()> { - debug!("update memory"); - self.mem = Some(mem); - Ok(()) - } - - fn handle_event( - &self, - device_event: u16, - vrings: &[VringRwLock], - stream_info: &[StreamInfo], - ) -> IoResult { - let vring = &vrings[device_event as usize]; - let queue_idx = self.queue_indexes[device_event as usize]; - debug!("handle event call queue: {}", queue_idx); - - match queue_idx { - CONTROL_QUEUE_IDX => { - debug!("control queue: {}", CONTROL_QUEUE_IDX); - let vring = &vrings[0]; - if self.event_idx { - // vm-virtio's Queue implementation only checks avail_index - // once, so to properly support EVENT_IDX we need to keep - // calling process_request_queue() until it stops finding - // new requests on the queue. - loop { - vring.disable_notification().unwrap(); - self.process_control(vring, stream_info)?; - if !vring.enable_notification().unwrap() { - break; - } - } - } else { - // Without EVENT_IDX, a single call is enough. - self.process_control(vring, stream_info)?; - } - } - EVENT_QUEUE_IDX => { - self.process_event(vring)?; - } - TX_QUEUE_IDX => { - let vring = &vrings[2]; - if self.event_idx { - // vm-virtio's Queue implementation only checks avail_index - // once, so to properly support EVENT_IDX we need to keep - // calling process_request_queue() until it stops finding - // new requests on the queue. - loop { - vring.disable_notification().unwrap(); - self.process_tx(vring)?; - if !vring.enable_notification().unwrap() { - break; - } - } - } else { - // Without EVENT_IDX, a single call is enough. - self.process_tx(vring)?; - } - } - RX_QUEUE_IDX => { - self.process_rx(vring)?; - } - _ => { - return Err(Error::HandleUnknownEvent.into()); - } - } - Ok(false) - } - - /// Process the messages in the vring and dispatch replies - fn process_control(&self, vring: &VringRwLock, stream_info: &[StreamInfo]) -> Result { - let requests: Vec = vring - .get_mut() - .get_queue_mut() - .iter(self.mem.as_ref().unwrap().memory()) - .map_err(|_| Error::DescriptorNotFound)? - .collect(); - - let audio_backend = &self.audio_backend; - - debug!("Requests to process: {}", requests.len()); - if requests.is_empty() { - debug!("yes, it's empty"); - return Ok(true); - } - //iterate over each sound request - for desc_chain in requests { - let descriptors: Vec<_> = desc_chain.clone().collect(); - debug!("Sound request with n descriptors: {}", descriptors.len()); - - let desc_request = descriptors[0]; - if desc_request.is_write_only() { - return Err(Error::UnexpectedWriteOnlyDescriptor(0)); - } - let read_desc_len: usize = desc_request.len() as usize; - let header_size = size_of::(); - if read_desc_len < header_size { - return Err(Error::UnexpectedMinimumDescriptorSize( - header_size, - read_desc_len, - )); - } - let hdr_request = desc_chain - .memory() - .read_obj::(desc_request.addr()) - .map_err(|_| Error::DescriptorReadFailed)?; - - let desc_response = descriptors[1]; - if !desc_response.is_write_only() { - return Err(Error::UnexpectedReadableDescriptor(1)); - } - - let mut response = VirtioSoundHeader { - code: VIRTIO_SND_S_OK.into(), - }; - - let mut len = desc_response.len(); - - let request_type = hdr_request.code.to_native(); - match request_type { - VIRTIO_SND_R_JACK_INFO => todo!(), - VIRTIO_SND_R_PCM_INFO => { - if descriptors.len() != 3 { - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } - let desc_pcm = descriptors[2]; - if !desc_pcm.is_write_only() { - return Err(Error::UnexpectedReadableDescriptor(2)); - } - let query_info = desc_chain - .memory() - .read_obj::(desc_request.addr()) - .map_err(|_| Error::DescriptorReadFailed)?; - - let start_id: usize = u32::from(query_info.start_id) as usize; - let count: usize = u32::from(query_info.count) as usize; - - if start_id + count > stream_info.len() { - error!( - "start_id({}) + count({}) must be smaller than the number of streams ({})", - start_id, - count, - stream_info.len() - ); - desc_chain - .memory() - .write_obj(VIRTIO_SND_S_BAD_MSG, desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - } else { - desc_chain - .memory() - .write_obj(response, desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - - let mut buf = vec![]; - - for (i, stream) in stream_info.iter().enumerate().skip(start_id).take(count) - { - let pcm_info = VirtioSoundPcmInfo { - hdr: VirtioSoundInfo { - hda_fn_nid: Le32::from(i as u32), - }, - features: stream.features, - formats: stream.formats, - rates: stream.rates, - direction: stream.direction, - channels_min: stream.channels_min, - channels_max: stream.channels_max, - padding: [0; 5], - }; - buf.extend_from_slice(pcm_info.as_slice()); - } - - // TODO: to support the case when the number of items - // do not fit in a single descriptor - desc_chain - .memory() - .write_slice(&buf, desc_pcm.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - - len += desc_pcm.len(); - } - } - VIRTIO_SND_R_CHMAP_INFO => todo!(), - VIRTIO_SND_R_JACK_REMAP => todo!(), - VIRTIO_SND_R_PCM_SET_PARAMS => { - if descriptors.len() != 2 { - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } - - let set_params = desc_chain - .memory() - .read_obj::(desc_request.addr()) - .map_err(|_| Error::DescriptorReadFailed)?; - - let params = PCMParams { - buffer_bytes: set_params.buffer_bytes, - period_bytes: set_params.period_bytes, - features: set_params.features, - rate: set_params.rate, - format: set_params.format, - channels: set_params.channels, - }; - - let stream_id = set_params.hdr.stream_id.to_native(); - - if params.features != 0 { - error!("No feature is supported"); - response = VirtioSoundHeader { - code: VIRTIO_SND_S_NOT_SUPP.into(), - }; - } else if set_params.buffer_bytes.to_native() - % set_params.period_bytes.to_native() - != 0 - { - response = VirtioSoundHeader { - code: VIRTIO_SND_S_BAD_MSG.into(), - }; - error!( - "buffer_bytes({}) must be dividable by period_bytes({})", - set_params.buffer_bytes.to_native(), - set_params.period_bytes.to_native() - ); - } else if audio_backend.set_param(stream_id, params).is_err() { - error!("IO error during set_param()"); - response = VirtioSoundHeader { - code: VIRTIO_SND_S_IO_ERR.into(), - }; - } - desc_chain - .memory() - .write_obj(response, desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - - len = desc_response.len(); - } - VIRTIO_SND_R_PCM_PREPARE - | VIRTIO_SND_R_PCM_START - | VIRTIO_SND_R_PCM_STOP - | VIRTIO_SND_R_PCM_RELEASE => { - let pcm_hdr = desc_chain - .memory() - .read_obj::(desc_request.addr()) - .map_err(|_| Error::DescriptorReadFailed)?; - let stream_id: usize = u32::from(pcm_hdr.stream_id) as usize; - dbg!("stream_id: {}", stream_id); - - desc_chain - .memory() - .write_obj(response, desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - len = desc_response.len(); - } - _ => { - error!( - "virtio-snd: Unknown control queue message code: {}", - request_type - ); - } - }; - if vring.add_used(desc_chain.head_index(), len).is_err() { - error!("Couldn't return used descriptors to the ring"); - } - } - // Send notification once all the requests are processed - debug!("Sending processed request notification"); - vring - .signal_used_queue() - .map_err(|_| Error::SendNotificationFailed)?; - debug!("Process control queue finished"); - - Ok(false) - } - - fn process_event(&self, _vring: &VringRwLock) -> IoResult { - Ok(false) - } - - fn process_tx(&self, vring: &VringRwLock) -> Result { - let requests: Vec = vring - .get_mut() - .get_queue_mut() - .iter(self.mem.as_ref().unwrap().memory()) - .map_err(|_| Error::DescriptorNotFound)? - .collect(); - - debug!("Requests to tx: {}", requests.len()); - - for desc_chain in requests { - let descriptors: Vec<_> = desc_chain.clone().collect(); - debug!("Sound request with n descriptors: {}", descriptors.len()); - - // TODO: to handle the case in which READ_ONLY descs - // have both the header and the data - - let last_desc = descriptors.len() - 1; - let desc_response = descriptors[last_desc]; - - if desc_response.len() as usize != size_of::() { - return Err(Error::UnexpectedDescriptorSize( - size_of::(), - desc_response.len() as usize, - )); - } - - if !desc_response.is_write_only() { - return Err(Error::UnexpectedReadableDescriptor(1)); - } - - let response = VirtioSoundPcmStatus { - status: VIRTIO_SND_S_OK.into(), - latency_bytes: 0.into(), - }; - - let desc_request = descriptors[0]; - - if desc_request.len() as usize != size_of::() { - return Err(Error::UnexpectedDescriptorSize( - size_of::(), - desc_request.len() as usize, - )); - } - - if desc_request.is_write_only() { - return Err(Error::UnexpectedWriteOnlyDescriptor(1)); - } - - let mut all_bufs = Vec::::new(); - let data_descs = &descriptors[1..descriptors.len() - 1]; - - for data in data_descs { - if data.is_write_only() { - return Err(Error::UnexpectedWriteOnlyDescriptor(1)); - } - - let mut buf = vec![0u8; data.len() as usize]; - - desc_chain - .memory() - .read_slice(&mut buf, data.addr()) - .map_err(|_| Error::DescriptorReadFailed)?; - - all_bufs.extend(buf); - } - - let hdr_request = desc_chain - .memory() - .read_obj::(desc_request.addr()) - .map_err(|_| Error::DescriptorReadFailed)?; - - let _stream_id = hdr_request.stream_id.to_native(); - - // TODO: to invoke audio_backend.write(stream_id, all_bufs, len) - - // 5.14.6.8.1.1 - // The device MUST NOT complete the I/O request until the buffer is - // totally consumed. - desc_chain - .memory() - .write_obj(response, desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - - let len = desc_response.len(); - - if vring.add_used(desc_chain.head_index(), len).is_err() { - error!("Couldn't return used descriptors to the ring"); - } - } - // Send notification once all the requests are processed - debug!("Sending processed tx notification"); - vring - .signal_used_queue() - .map_err(|_| Error::SendNotificationFailed)?; - debug!("Process tx queue finished"); - Ok(false) - } - - fn process_rx(&self, _vring: &VringRwLock) -> IoResult { - Ok(false) - } -} - -pub struct VhostUserSoundBackend { - threads: Vec>, - virtio_cfg: VirtioSoundConfig, - exit_event: EventFd, - streams_info: Vec, -} - -type SndDescriptorChain = DescriptorChain>>; - -impl VhostUserSoundBackend { - pub fn new(config: SoundConfig) -> Result { - let audio_backend = alloc_audio_backend(config.audio_backend_name)?; - let audio_backend_arc = Arc::new(audio_backend); - let threads = if config.multi_thread { - vec![ - RwLock::new(VhostUserSoundThread::new( - vec![CONTROL_QUEUE_IDX, EVENT_QUEUE_IDX], - audio_backend_arc.clone(), - )?), - RwLock::new(VhostUserSoundThread::new( - vec![TX_QUEUE_IDX], - Arc::clone(&audio_backend_arc), - )?), - RwLock::new(VhostUserSoundThread::new( - vec![RX_QUEUE_IDX], - Arc::clone(&audio_backend_arc), - )?), - ] - } else { - vec![RwLock::new(VhostUserSoundThread::new( - vec![ - CONTROL_QUEUE_IDX, - EVENT_QUEUE_IDX, - TX_QUEUE_IDX, - RX_QUEUE_IDX, - ], - Arc::clone(&audio_backend_arc), - )?)] - }; - - let mut streams = Vec::::with_capacity(NR_STREAMS); - - let stream_out_info = StreamInfo::output(); - // TODO: to add a input stream - streams.push(stream_out_info); - - Ok(Self { - threads, - virtio_cfg: VirtioSoundConfig { - jacks: 0.into(), - streams: Le32::from(streams.len() as u32), - chmaps: 0.into(), - }, - streams_info: streams, - exit_event: EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?, - }) - } - - pub fn send_exit_event(&self) { - self.exit_event.write(1).unwrap(); - } -} - -impl VhostUserBackend for VhostUserSoundBackend { - fn num_queues(&self) -> usize { - NUM_QUEUES as usize - } - - fn max_queue_size(&self) -> usize { - 256 - } - - fn features(&self) -> u64 { - 1 << VIRTIO_F_VERSION_1 - | 1 << VIRTIO_F_NOTIFY_ON_EMPTY - | 1 << VIRTIO_RING_F_INDIRECT_DESC - | 1 << VIRTIO_RING_F_EVENT_IDX - | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() - } - - fn protocol_features(&self) -> VhostUserProtocolFeatures { - VhostUserProtocolFeatures::CONFIG - } - - fn set_event_idx(&self, enabled: bool) { - for thread in self.threads.iter() { - thread.write().unwrap().set_event_idx(enabled); - } - } - - fn update_memory(&self, mem: GuestMemoryAtomic) -> IoResult<()> { - for thread in self.threads.iter() { - thread.write().unwrap().update_memory(mem.clone())?; - } - - Ok(()) - } - - fn handle_event( - &self, - device_event: u16, - evset: EventSet, - vrings: &[VringRwLock], - thread_id: usize, - ) -> IoResult { - if evset != EventSet::IN { - return Err(Error::HandleEventNotEpollIn.into()); - } - - self.threads[thread_id].read().unwrap().handle_event( - device_event, - vrings, - &self.streams_info, - ) - } - - fn get_config(&self, offset: u32, size: u32) -> Vec { - let offset = offset as usize; - let size = size as usize; - - let buf = self.virtio_cfg.as_slice(); - - if offset + size > buf.len() { - return Vec::new(); - } - - buf[offset..offset + size].to_vec() - } - - fn queues_per_thread(&self) -> Vec { - let mut vec = Vec::with_capacity(self.threads.len()); - - for thread in self.threads.iter() { - vec.push(thread.read().unwrap().queues_per_thread()) - } - - vec - } - - fn exit_event(&self, _thread_index: usize) -> Option { - self.exit_event.try_clone().ok() - } -} diff --git a/crates/sound/src/virtio_sound.rs b/crates/sound/src/virtio_sound.rs index b605049..5dc11d5 100644 --- a/crates/sound/src/virtio_sound.rs +++ b/crates/sound/src/virtio_sound.rs @@ -1,6 +1,4 @@ // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause -#![allow(dead_code)] //TODO: remove - use vm_memory::{ByteValued, Le32, Le64}; // virtqueues @@ -48,8 +46,8 @@ pub const VIRTIO_SND_S_IO_ERR: u32 = 0x8003; // device data flow directions -pub const VIRTIO_SND_D_OUTPUT: u8 = 0; -pub const VIRTIO_SND_D_INPUT: u8 = 1; +pub const VIRTIO_SND_D_OUTPUT: u32 = 0; +pub const VIRTIO_SND_D_INPUT: u32 = 1; // supported jack features @@ -152,7 +150,7 @@ pub const VIRTIO_SND_CHMAP_BRC: u8 = 40; /* bottom right center */ pub const VIRTIO_SND_CHMAP_MAX_SIZE: usize = 18; /// Virtio Sound Configuration -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundConfig { /// total number of all available jacks @@ -168,7 +166,7 @@ pub struct VirtioSoundConfig { unsafe impl ByteValued for VirtioSoundConfig {} /// Virtio Sound Request / Response common header -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundHeader { /// request type / response status @@ -179,7 +177,7 @@ pub struct VirtioSoundHeader { unsafe impl ByteValued for VirtioSoundHeader {} /// Virtio Sound event notification -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundEvent { /// PCM stream event type @@ -192,7 +190,7 @@ pub struct VirtioSoundEvent { unsafe impl ByteValued for VirtioSoundEvent {} /// Virtio Sound request information about any kind of configuration item -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundQueryInfo { /// item request type (VIRTIO_SND_R_*_INFO) @@ -209,7 +207,7 @@ pub struct VirtioSoundQueryInfo { unsafe impl ByteValued for VirtioSoundQueryInfo {} /// Virtio Sound response common information header -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundInfo { /// function group node identifier @@ -220,7 +218,7 @@ pub struct VirtioSoundInfo { unsafe impl ByteValued for VirtioSoundInfo {} /// Jack control request / Jack common header -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundJackHeader { /// jack request type (VIRTIO_SND_R_JACK_*) @@ -233,7 +231,7 @@ pub struct VirtioSoundJackHeader { unsafe impl ByteValued for VirtioSoundJackHeader {} /// Jack response information about available jacks -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundJackInfo { /// jack response header type @@ -254,7 +252,7 @@ unsafe impl ByteValued for VirtioSoundJackInfo {} ///If the VIRTIO_SND_JACK_F_REMAP feature bit is set in the jack information /// Remap control request -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundJackRemap { pub hdr: VirtioSoundJackHeader, /* .code = VIRTIO_SND_R_JACK_REMAP */ @@ -266,7 +264,7 @@ pub struct VirtioSoundJackRemap { unsafe impl ByteValued for VirtioSoundJackRemap {} /// PCM control request / PCM common header -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundPcmHeader { pub hdr: VirtioSoundHeader, @@ -277,7 +275,7 @@ pub struct VirtioSoundPcmHeader { unsafe impl ByteValued for VirtioSoundPcmHeader {} /// PCM response information -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundPcmInfo { pub hdr: VirtioSoundInfo, @@ -295,7 +293,7 @@ pub struct VirtioSoundPcmInfo { unsafe impl ByteValued for VirtioSoundPcmInfo {} /// Set selected stream parameters for the specified stream ID -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSndPcmSetParams { pub hdr: VirtioSoundPcmHeader, @@ -312,7 +310,7 @@ pub struct VirtioSndPcmSetParams { unsafe impl ByteValued for VirtioSndPcmSetParams {} /// PCM I/O header -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundPcmXfer { pub stream_id: Le32, @@ -322,7 +320,7 @@ pub struct VirtioSoundPcmXfer { unsafe impl ByteValued for VirtioSoundPcmXfer {} /// PCM I/O status -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundPcmStatus { pub status: Le32, @@ -333,7 +331,7 @@ pub struct VirtioSoundPcmStatus { unsafe impl ByteValued for VirtioSoundPcmStatus {} /// channel maps response information -#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[repr(C)] pub struct VirtioSoundChmapInfo { pub hdr: VirtioSoundInfo,