Add music player control interface to CLI
This commit is contained in:
parent
93ab093c2b
commit
2cee3dd223
10 changed files with 393 additions and 285 deletions
267
Cargo.lock
generated
267
Cargo.lock
generated
|
@ -39,9 +39,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "alsa"
|
||||
version = "0.6.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b"
|
||||
checksum = "e2562ad8dcf0f789f65c6fdaad8a8a9708ed6b488e649da28c01656ad66b8b47"
|
||||
dependencies = [
|
||||
"alsa-sys",
|
||||
"bitflags",
|
||||
|
@ -97,12 +97,6 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base-x"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
|
@ -394,6 +388,12 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
|
@ -402,11 +402,12 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
|||
|
||||
[[package]]
|
||||
name = "coreaudio-rs"
|
||||
version = "0.10.0"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88"
|
||||
checksum = "cb17e2d1795b1996419648915df94bc7103c28f7b48062d7acf4652fc371b2ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation-sys 0.6.2",
|
||||
"coreaudio-sys",
|
||||
]
|
||||
|
||||
|
@ -421,24 +422,25 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cpal"
|
||||
version = "0.14.2"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f342c1b63e185e9953584ff2199726bf53850d96610a310e3aca09e9405a2d0b"
|
||||
checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c"
|
||||
dependencies = [
|
||||
"alsa",
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.8.4",
|
||||
"coreaudio-rs",
|
||||
"jni",
|
||||
"dasp_sample",
|
||||
"jni 0.19.0",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"mach",
|
||||
"ndk 0.7.0",
|
||||
"mach2",
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"oboe",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"stdweb",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"windows",
|
||||
]
|
||||
|
@ -541,7 +543,7 @@ dependencies = [
|
|||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset 0.9.0",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
|
@ -595,6 +597,12 @@ dependencies = [
|
|||
"memchr 2.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dasp_sample"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
|
||||
|
||||
[[package]]
|
||||
name = "dbus"
|
||||
version = "0.6.5"
|
||||
|
@ -650,12 +658,6 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "discard"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
|
@ -935,6 +937,20 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
|
@ -1049,10 +1065,10 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach"
|
||||
version = "0.3.2"
|
||||
name = "mach2"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
|
||||
checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -1082,15 +1098,6 @@ version = "2.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
|
@ -1241,19 +1248,6 @@ dependencies = [
|
|||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"jni-sys",
|
||||
"ndk-sys 0.3.0",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.7.0"
|
||||
|
@ -1262,7 +1256,7 @@ checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"jni-sys",
|
||||
"ndk-sys 0.4.1+23.1.7779620",
|
||||
"ndk-sys",
|
||||
"num_enum",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
|
@ -1274,15 +1268,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.4.1+23.1.7779620"
|
||||
|
@ -1294,15 +1279,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.23.2"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
|
||||
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1444,12 +1427,12 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
|||
|
||||
[[package]]
|
||||
name = "oboe"
|
||||
version = "0.4.6"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1"
|
||||
checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0"
|
||||
dependencies = [
|
||||
"jni",
|
||||
"ndk 0.6.0",
|
||||
"jni 0.20.0",
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
|
@ -1458,9 +1441,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "oboe-sys"
|
||||
version = "0.4.5"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd"
|
||||
checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
@ -1913,9 +1896,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rodio"
|
||||
version = "0.16.0"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb10b653d5ec0e9411a2e7d46e2c7f4046fd87d35b9955bd73ba4108d69072b5"
|
||||
checksum = "bdf1d4dea18dff2e9eb6dca123724f8b60ef44ad74a9ad283cdfe025df7e73fa"
|
||||
dependencies = [
|
||||
"cpal",
|
||||
"symphonia",
|
||||
|
@ -1954,15 +1937,6 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustfft"
|
||||
version = "5.1.1"
|
||||
|
@ -2013,21 +1987,6 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.171"
|
||||
|
@ -2080,21 +2039,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
|
||||
dependencies = [
|
||||
"sha1_smol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1_smol"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.7"
|
||||
|
@ -2136,55 +2080,6 @@ dependencies = [
|
|||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
|
||||
dependencies = [
|
||||
"discard",
|
||||
"rustc_version",
|
||||
"stdweb-derive",
|
||||
"stdweb-internal-macros",
|
||||
"stdweb-internal-runtime",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-derive"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-macros"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
||||
dependencies = [
|
||||
"base-x",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-runtime"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||
|
||||
[[package]]
|
||||
name = "strength_reduce"
|
||||
version = "0.2.4"
|
||||
|
@ -2669,6 +2564,18 @@ dependencies = [
|
|||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.87"
|
||||
|
@ -2753,15 +2660,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.37.0"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
|
||||
checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc 0.37.0",
|
||||
"windows_i686_gnu 0.37.0",
|
||||
"windows_i686_msvc 0.37.0",
|
||||
"windows_x86_64_gnu 0.37.0",
|
||||
"windows_x86_64_msvc 0.37.0",
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2815,12 +2718,6 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
|
@ -2833,12 +2730,6 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
|
@ -2851,12 +2742,6 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
|
@ -2869,12 +2754,6 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
|
@ -2899,12 +2778,6 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
|
|
|
@ -7,7 +7,7 @@ repository = "https://git.ngni.us/NGnius/muss"
|
|||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
rodio = { version = "^0.16", features = ["symphonia-all"], default-features = false}
|
||||
rodio = { version = "^0.17", features = ["symphonia-all"], default-features = false}
|
||||
m3u8-rs = { version = "^3.0" }
|
||||
mpd = { version = "0.1", optional = true }
|
||||
|
||||
|
|
|
@ -3,73 +3,85 @@ use std::thread::JoinHandle;
|
|||
|
||||
use muss_interpreter::{InterpreterError, Item};
|
||||
|
||||
use super::os_controls::SystemControlWrapper;
|
||||
use super::player_wrapper::{ControlAction, PlayerAction, PlayerServer};
|
||||
use crate::EventHandlerBuilder;
|
||||
|
||||
use super::player_wrapper::{ControlAction, PlayerAction, PlayerServer, PlaybackAction};
|
||||
use super::PlaybackError;
|
||||
use super::Player;
|
||||
use super::PlayerError;
|
||||
|
||||
/// A controller for a Player running on another thread.
|
||||
/// This receives and sends events like media buttons and script errors for the Player.
|
||||
pub struct Controller {
|
||||
pub struct Controller<H> {
|
||||
control: Sender<ControlAction>,
|
||||
event: Receiver<PlayerAction>,
|
||||
player: Sender<PlayerAction>,
|
||||
handle: JoinHandle<()>,
|
||||
sys_ctrl: SystemControlWrapper,
|
||||
playback: Sender<PlaybackAction>,
|
||||
#[allow(dead_code)]
|
||||
event_handler: H,
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
impl <H> Controller<H> {
|
||||
pub fn create<
|
||||
F: FnOnce() -> Player<I> + Send + 'static,
|
||||
I: std::iter::Iterator<Item = Result<Item, InterpreterError>>,
|
||||
E: EventHandlerBuilder<H>
|
||||
>(
|
||||
player_gen: F,
|
||||
event_handler_builder: E,
|
||||
) -> Self {
|
||||
let (control_tx, control_rx) = channel();
|
||||
let (event_tx, event_rx) = channel();
|
||||
let (playback_tx, playback_rx) = channel();
|
||||
let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone());
|
||||
sys_ctrl.init(playback_rx);
|
||||
let (player_tx, player_rx) = channel();
|
||||
let event_handler = event_handler_builder.with_channels(player_rx, playback_rx, control_tx.clone());
|
||||
let handle = PlayerServer::spawn(
|
||||
player_gen,
|
||||
control_tx.clone(),
|
||||
control_rx,
|
||||
event_tx,
|
||||
playback_tx,
|
||||
playback_tx.clone(),
|
||||
false,
|
||||
);
|
||||
Self {
|
||||
control: control_tx,
|
||||
event: event_rx,
|
||||
player: player_tx,
|
||||
handle: handle,
|
||||
sys_ctrl: sys_ctrl,
|
||||
event_handler: event_handler,
|
||||
playback: playback_tx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_repl<
|
||||
F: FnOnce() -> Player<I> + Send + 'static,
|
||||
I: std::iter::Iterator<Item = Result<Item, InterpreterError>>,
|
||||
E: EventHandlerBuilder<H>
|
||||
>(
|
||||
player_gen: F,
|
||||
event_handler_builder: E,
|
||||
) -> Self {
|
||||
let (control_tx, control_rx) = channel();
|
||||
let (event_tx, event_rx) = channel();
|
||||
let (playback_tx, playback_rx) = channel();
|
||||
let mut sys_ctrl = SystemControlWrapper::new(control_tx.clone());
|
||||
sys_ctrl.init(playback_rx);
|
||||
let (player_tx, player_rx) = channel();
|
||||
let event_handler = event_handler_builder.with_channels(player_rx, playback_rx, control_tx.clone());
|
||||
let handle = PlayerServer::spawn(
|
||||
player_gen,
|
||||
control_tx.clone(),
|
||||
control_rx,
|
||||
event_tx,
|
||||
playback_tx,
|
||||
playback_tx.clone(),
|
||||
true,
|
||||
);
|
||||
Self {
|
||||
control: control_tx,
|
||||
event: event_rx,
|
||||
player: player_tx,
|
||||
handle: handle,
|
||||
sys_ctrl: sys_ctrl,
|
||||
event_handler: event_handler,
|
||||
playback: playback_tx,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,6 +112,7 @@ impl Controller {
|
|||
}
|
||||
|
||||
fn handle_event(&self, event: PlayerAction) -> Result<(), PlayerError> {
|
||||
self.player.send(event.clone()).unwrap_or(());
|
||||
match event {
|
||||
PlayerAction::Acknowledge(_) => Ok(()),
|
||||
PlayerAction::Exception(e) => Err(e),
|
||||
|
@ -142,7 +155,9 @@ impl Controller {
|
|||
|
||||
pub fn exit(self) -> Result<(), PlayerError> {
|
||||
self.send_confirm(ControlAction::Exit { ack: true })?;
|
||||
self.sys_ctrl.exit();
|
||||
self.playback.send(PlaybackAction::Exit).map_err(|e| PlaybackError {
|
||||
msg: format!("Playback exit message did not send successfully: {}", e),
|
||||
})?;
|
||||
match self.handle.join() {
|
||||
Ok(x) => Ok(x),
|
||||
Err(_) => Err(PlaybackError {
|
||||
|
|
115
player/src/event_handler.rs
Normal file
115
player/src/event_handler.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
use super::player_wrapper::{ControlAction, PlaybackAction, PlayerAction};
|
||||
|
||||
pub trait EventHandlerBuilder<T> {
|
||||
fn with_channels(self, player: Receiver<PlayerAction>, playback: Receiver<PlaybackAction>, control: Sender<ControlAction>) -> T;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MultiEventHandler {
|
||||
taps: Vec<Box<dyn EventTap>>,
|
||||
}
|
||||
|
||||
impl MultiEventHandler {
|
||||
pub fn with_taps(taps: Vec<Box<dyn EventTap>>) -> Self {
|
||||
Self {
|
||||
taps: taps,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_sys_ctrl() -> Self {
|
||||
Self {
|
||||
taps: vec![
|
||||
Box::new(super::os_controls::SystemControlWrapper::new()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(mut self, tap: Box<dyn EventTap>) -> Self {
|
||||
self.taps.push(tap);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl EventHandlerBuilder<MultiEventHandlerImpl> for MultiEventHandler {
|
||||
fn with_channels(self, player: Receiver<PlayerAction>, playback: Receiver<PlaybackAction>, control: Sender<ControlAction>) -> MultiEventHandlerImpl {
|
||||
let (event_tx, event_rx) = channel();
|
||||
MultiEventHandlerImpl {
|
||||
player_join: MultiEventHandlerImpl::player_thread(event_tx.clone(), player),
|
||||
playback_join: MultiEventHandlerImpl::playback_thread(event_tx, playback),
|
||||
handler_join: MultiEventHandlerImpl::handler_thread(self.taps, event_rx, control),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Like a wire tap, but for player and playback events. This can also send control events to the player.
|
||||
pub trait EventTap: Send {
|
||||
fn on_playback(&self, playback: &PlaybackAction) -> Option<ControlAction>;
|
||||
|
||||
fn on_player(&self, player: &PlayerAction) -> Option<ControlAction>;
|
||||
|
||||
fn init_control(&mut self, _control: &Sender<ControlAction>) {}
|
||||
}
|
||||
|
||||
pub struct MultiEventHandlerImpl {
|
||||
#[allow(dead_code)]
|
||||
player_join: JoinHandle<()>,
|
||||
#[allow(dead_code)]
|
||||
playback_join: JoinHandle<()>,
|
||||
#[allow(dead_code)]
|
||||
handler_join: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl MultiEventHandlerImpl {
|
||||
fn playback_thread(event_tx: Sender<SomeEvent>, playback: Receiver<PlaybackAction>) -> JoinHandle<()> {
|
||||
std::thread::spawn(move ||
|
||||
while let Ok(playback_event) = playback.recv() {
|
||||
event_tx.send(SomeEvent::Playback(playback_event)).unwrap_or(());
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn player_thread(event_tx: Sender<SomeEvent>, player: Receiver<PlayerAction>) -> JoinHandle<()> {
|
||||
std::thread::spawn(move ||
|
||||
while let Ok(player_event) = player.recv() {
|
||||
event_tx.send(SomeEvent::Player(player_event)).unwrap_or(());
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn handler_thread(mut taps: Vec<Box<dyn EventTap>>, event_rx: Receiver<SomeEvent>, control: Sender<ControlAction>) -> JoinHandle<()> {
|
||||
std::thread::spawn(move || {
|
||||
for t in taps.iter_mut() {
|
||||
t.init_control(&control);
|
||||
}
|
||||
while let Ok(event) = event_rx.recv() {
|
||||
match event {
|
||||
SomeEvent::Playback(p) => {
|
||||
for t in taps.iter() {
|
||||
t.on_playback(&p).map(|c| control.send(c).unwrap_or(()));
|
||||
}
|
||||
},
|
||||
SomeEvent::Player(p) => {
|
||||
for t in taps.iter() {
|
||||
t.on_player(&p).map(|c| control.send(c).unwrap_or(()));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn join(self) -> std::thread::Result<()> {
|
||||
self.player_join.join()?;
|
||||
self.playback_join.join()?;
|
||||
self.handler_join.join()
|
||||
}
|
||||
}
|
||||
|
||||
enum SomeEvent {
|
||||
Playback(PlaybackAction),
|
||||
Player(PlayerAction),
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
mod controller;
|
||||
mod errors;
|
||||
mod event_handler;
|
||||
pub(crate) mod os_controls;
|
||||
mod player;
|
||||
pub(crate) mod player_wrapper;
|
||||
|
@ -16,9 +17,11 @@ pub(crate) mod uri;
|
|||
|
||||
pub use controller::Controller;
|
||||
pub use errors::{PlaybackError, PlayerError, UriError};
|
||||
pub use event_handler::{EventHandlerBuilder, EventTap, MultiEventHandler};
|
||||
#[cfg(feature = "mpd")]
|
||||
pub use player::mpd_connection;
|
||||
pub use player::Player;
|
||||
pub use player_wrapper::{ControlAction, PlaybackAction, PlayerAction};
|
||||
//pub use utility::{play_script};
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -13,17 +13,15 @@ use muss_interpreter::Item;
|
|||
use std::io::Write;
|
||||
|
||||
//use super::Controller;
|
||||
use super::player_wrapper::{ControlAction, PlaybackAction};
|
||||
use super::player_wrapper::{ControlAction, PlaybackAction, PlayerAction};
|
||||
|
||||
/// OS-specific APIs for media controls.
|
||||
/// Currently only Linux (dbus) is supported.
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
||||
pub struct SystemControlWrapper {
|
||||
control: Sender<ControlAction>,
|
||||
dbus_handle: Option<JoinHandle<()>>, //std::sync::Arc<MprisPlayer>,
|
||||
dbus_handle: Option<JoinHandle<()>>,
|
||||
dbus_ctrl: Option<Sender<DbusControl>>,
|
||||
playback_event_handler: Option<JoinHandle<()>>,
|
||||
playback_event_handler_killer: Option<Sender<()>>,
|
||||
state: std::sync::Mutex<State>,
|
||||
}
|
||||
|
||||
/// OS-specific APIs for media controls.
|
||||
|
@ -33,9 +31,6 @@ pub struct SystemControlWrapper {
|
|||
not(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))
|
||||
))]
|
||||
pub struct SystemControlWrapper {
|
||||
#[allow(dead_code)]
|
||||
control: Sender<ControlAction>,
|
||||
playback_receiver: Option<Receiver<PlaybackAction>>,
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
||||
|
@ -47,21 +42,23 @@ enum DbusControl {
|
|||
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
||||
impl SystemControlWrapper {
|
||||
pub fn new(control: Sender<ControlAction>) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
control: control,
|
||||
dbus_handle: None, //MprisPlayer::new("mps".into(), "mps".into(), "null".into())
|
||||
dbus_handle: None,
|
||||
dbus_ctrl: None,
|
||||
playback_event_handler: None,
|
||||
playback_event_handler_killer: None,
|
||||
state: std::sync::Mutex::new(
|
||||
State {
|
||||
playback_time: 0,
|
||||
duration_cache: None,
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self, playback: Receiver<PlaybackAction>) {
|
||||
fn init(&mut self, control: &Sender<ControlAction>) {
|
||||
let (tx, dbus_ctrl) = channel();
|
||||
let dbus_ctrl_tx_clone = tx.clone();
|
||||
self.dbus_ctrl = Some(tx);
|
||||
let control_clone1 = self.control.clone();
|
||||
let control_clone1 = control.clone();
|
||||
self.dbus_handle = Some(std::thread::spawn(move || {
|
||||
let dbus_conn = MprisPlayer::new("muss".into(), "muss".into(), "ngnius.muss".into());
|
||||
//let (msg_tx, msg_rx) = channel();
|
||||
|
@ -155,57 +152,16 @@ impl SystemControlWrapper {
|
|||
}
|
||||
}
|
||||
}));
|
||||
let (tx, rx) = channel();
|
||||
self.playback_event_handler_killer = Some(tx);
|
||||
self.playback_event_handler = Some(std::thread::spawn(move || {
|
||||
let mut playback_time = 0;
|
||||
let mut duration_cache = None;
|
||||
loop {
|
||||
if let Ok(_) = rx.try_recv() {
|
||||
break;
|
||||
}
|
||||
match playback.recv() {
|
||||
Err(_) => break,
|
||||
Ok(PlaybackAction::Exit) => break,
|
||||
Ok(PlaybackAction::Enqueued(item)) => {
|
||||
playback_time = 0;
|
||||
duration_cache = None;
|
||||
Self::enqueued(item, &dbus_ctrl_tx_clone);
|
||||
}
|
||||
Ok(PlaybackAction::Empty) => Self::empty(&dbus_ctrl_tx_clone),
|
||||
Ok(PlaybackAction::Time(item, duration)) => {
|
||||
duration_cache = Some(duration);
|
||||
Self::time(item, duration, &dbus_ctrl_tx_clone);
|
||||
}
|
||||
Ok(PlaybackAction::UpdateTick(item)) => {
|
||||
Self::time_update(
|
||||
item,
|
||||
playback_time,
|
||||
&duration_cache,
|
||||
&dbus_ctrl_tx_clone,
|
||||
);
|
||||
playback_time += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn exit(self) {
|
||||
pub fn exit(&self) {
|
||||
// exit dbus thread
|
||||
if let Some(tx) = self.dbus_ctrl {
|
||||
if let Some(tx) = &self.dbus_ctrl {
|
||||
tx.send(DbusControl::Die).unwrap_or(());
|
||||
}
|
||||
if let Some(handle) = self.dbus_handle {
|
||||
/*if let Some(handle) = &self.dbus_handle {
|
||||
handle.join().unwrap_or(());
|
||||
}
|
||||
// exit playback event thread
|
||||
if let Some(tx) = self.playback_event_handler_killer {
|
||||
tx.send(()).unwrap_or(());
|
||||
}
|
||||
if let Some(handle) = self.playback_event_handler {
|
||||
handle.join().unwrap_or(());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
fn build_metadata(item: Item) -> Metadata {
|
||||
|
@ -327,21 +283,69 @@ impl SystemControlWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
||||
struct State {
|
||||
playback_time: i64,
|
||||
duration_cache: Option<std::time::Duration>,
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
||||
impl super::EventTap for SystemControlWrapper {
|
||||
fn on_playback(&self, playback: &PlaybackAction) -> Option<ControlAction> {
|
||||
match playback {
|
||||
PlaybackAction::Exit => {
|
||||
self.exit();
|
||||
},
|
||||
PlaybackAction::Enqueued(item) => {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
state.playback_time = 0;
|
||||
state.duration_cache = None;
|
||||
Self::enqueued(item.to_owned(), self.dbus_ctrl.as_ref().unwrap());
|
||||
},
|
||||
PlaybackAction::Empty => Self::empty(self.dbus_ctrl.as_ref().unwrap()),
|
||||
PlaybackAction::Time(item, duration) => {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
state.duration_cache = Some(duration.to_owned());
|
||||
Self::time(item.to_owned(), duration.to_owned(), self.dbus_ctrl.as_ref().unwrap());
|
||||
}
|
||||
PlaybackAction::UpdateTick(item) => {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
Self::time_update(
|
||||
item.to_owned(),
|
||||
state.playback_time,
|
||||
&state.duration_cache,
|
||||
self.dbus_ctrl.as_ref().unwrap(),
|
||||
);
|
||||
state.playback_time += 1;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn on_player(&self, _player: &PlayerAction) -> Option<ControlAction> { None }
|
||||
|
||||
fn init_control(&mut self, control: &Sender<ControlAction>) {
|
||||
self.init(control);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
not(feature = "os-controls"),
|
||||
not(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))
|
||||
))]
|
||||
impl SystemControlWrapper {
|
||||
pub fn new(control: Sender<ControlAction>) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
control: control,
|
||||
playback_receiver: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self, playback: Receiver<PlaybackAction>) {
|
||||
self.playback_receiver = Some(playback);
|
||||
}
|
||||
|
||||
pub fn exit(self) {}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
not(feature = "os-controls"),
|
||||
not(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))
|
||||
))]
|
||||
impl super::EventTap for SystemControlWrapper {
|
||||
fn on_playback(&self, _playback: &PlaybackAction) -> Option<ControlAction> { None }
|
||||
|
||||
fn on_player(&self, _player: &PlayerAction) -> Option<ControlAction> { None }
|
||||
}
|
||||
|
|
56
src/debug_state.rs
Normal file
56
src/debug_state.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use muss_interpreter::Item;
|
||||
|
||||
use muss_player::EventTap;
|
||||
use muss_player::{PlaybackAction, PlayerAction, ControlAction};
|
||||
|
||||
pub struct DebugState {
|
||||
pub now_playing: Option<Item>,
|
||||
pub control_tx: Option<std::sync::Mutex<std::sync::mpsc::Sender<ControlAction>>>,
|
||||
}
|
||||
|
||||
impl DebugState {
|
||||
pub fn new() -> std::sync::Arc<std::sync::RwLock<Self>> {
|
||||
std::sync::Arc::new(std::sync::RwLock::new(Self {
|
||||
now_playing: None,
|
||||
control_tx: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DebugEventHandler {
|
||||
state: std::sync::Arc<std::sync::RwLock<DebugState>>,
|
||||
}
|
||||
|
||||
impl DebugEventHandler {
|
||||
pub fn new(debug_state: std::sync::Arc<std::sync::RwLock<DebugState>>) -> Self {
|
||||
Self {
|
||||
state: debug_state,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventTap for DebugEventHandler {
|
||||
fn on_playback(&self, playback: &PlaybackAction) -> Option<ControlAction> {
|
||||
match playback {
|
||||
PlaybackAction::Enqueued(item) => {
|
||||
let mut state = self.state.write().unwrap();
|
||||
state.now_playing = Some(item.to_owned());
|
||||
},
|
||||
PlaybackAction::Empty | PlaybackAction::Exit => {
|
||||
let mut state = self.state.write().unwrap();
|
||||
state.now_playing = None;
|
||||
},
|
||||
PlaybackAction::Time(_item, _dur) => {},
|
||||
PlaybackAction::UpdateTick(_item) => {},
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn on_player(&self, _player: &PlayerAction) -> Option<ControlAction> {
|
||||
None
|
||||
}
|
||||
|
||||
fn init_control(&mut self, control: &std::sync::mpsc::Sender<ControlAction>) {
|
||||
self.state.write().expect("Failed to get write lock on controller debug state").control_tx = Some(std::sync::Mutex::new(control.clone()));
|
||||
}
|
||||
}
|
|
@ -187,5 +187,11 @@ REPL-specific operations to help with writing Muss scripts: ?command
|
|||
normal
|
||||
Cancel any active ?skip or ?list operation.
|
||||
|
||||
now
|
||||
Display the currently-playing item.
|
||||
|
||||
next
|
||||
Skip the rest of the currently-playing item and proceed to the next item.
|
||||
|
||||
verbose
|
||||
Toggle verbose messages, like extra information on items in ?list and other goodies.";
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -45,9 +45,17 @@
|
|||
//! ## Is Muss a scripting language?
|
||||
//! **Yes**. It evolved from a simple query language into something that can do arbitrary calculations. Whether it's Turing-complete is still unproven, but it's powerful enough for what I want it to do.
|
||||
//!
|
||||
//! # Wishlist
|
||||
//!
|
||||
//! - Multithreaded execution (especially filtering)
|
||||
//! - Lazy field value calculation
|
||||
//! - Better dbus integration (duration display improvements, seeking, previous track)
|
||||
//! - Vector type variant
|
||||
//!
|
||||
|
||||
mod channel_io;
|
||||
mod cli;
|
||||
mod debug_state;
|
||||
mod help;
|
||||
mod repl;
|
||||
|
||||
|
@ -122,7 +130,8 @@ fn main() {
|
|||
}
|
||||
} else {
|
||||
// live playback
|
||||
let ctrl = Controller::create(player_builder);
|
||||
let event_handler = muss_player::MultiEventHandler::with_sys_ctrl();
|
||||
let ctrl = Controller::create(player_builder, event_handler);
|
||||
match ctrl.wait_for_done() {
|
||||
Ok(_) => println!("Success: Finished playback from script `{}`", script_file),
|
||||
Err(e) => eprintln!("{}", e),
|
||||
|
|
31
src/repl.rs
31
src/repl.rs
|
@ -41,6 +41,7 @@ struct ReplState {
|
|||
cursor_rightward_position: usize,
|
||||
//debug: Arc<RwLock<DebugState>>,
|
||||
list_rx: Receiver<DebugItem>,
|
||||
controller_debug: std::sync::Arc<std::sync::RwLock<crate::debug_state::DebugState>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -74,6 +75,7 @@ impl ReplState {
|
|||
debug_flag: DebugFlag::Normal,
|
||||
})),*/
|
||||
list_rx: debug_list,
|
||||
controller_debug: crate::debug_state::DebugState::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +298,9 @@ pub fn repl(args: CliArgs) {
|
|||
writeln!(state.terminal, "Playback mode (output: audio device)")
|
||||
.expect(TERMINAL_WRITE_ERROR);
|
||||
}
|
||||
let ctrl = Controller::create_repl(player_builder);
|
||||
let event_handler = muss_player::MultiEventHandler::with_sys_ctrl()
|
||||
.add(Box::new(crate::debug_state::DebugEventHandler::new(state.controller_debug.clone())));
|
||||
let ctrl = Controller::create_repl(player_builder, event_handler);
|
||||
read_loop(&args, &mut state, |state, args| {
|
||||
if args.wait {
|
||||
match ctrl.wait_for_empty() {
|
||||
|
@ -689,7 +693,7 @@ fn error_prompt(error: muss_player::PlayerError, args: &CliArgs) {
|
|||
eprintln!("*E{}{}", args.prompt, error);
|
||||
}
|
||||
|
||||
fn repl_commands(command_str: &str, state: &mut ReplState, _args: &CliArgs) {
|
||||
fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) {
|
||||
let words: Vec<&str> = command_str.split(' ').map(|s| s.trim()).collect();
|
||||
match words[0] {
|
||||
"?help" => {
|
||||
|
@ -747,6 +751,29 @@ fn repl_commands(command_str: &str, state: &mut ReplState, _args: &CliArgs) {
|
|||
}
|
||||
"?commands" => {
|
||||
writeln!(state.terminal, "{}", super::help::REPL_COMMANDS).expect(TERMINAL_WRITE_ERROR)
|
||||
},
|
||||
"?now" => {
|
||||
let data = state.controller_debug.read().expect("Failed to get read lock for debug player data");
|
||||
if let Some(item) = &data.now_playing {
|
||||
let verbose = DEBUG_STATE
|
||||
.read()
|
||||
.expect("Failed to get read lock for debug state")
|
||||
.verbose;
|
||||
pretty_print_item(item, &mut state.terminal, args, verbose);
|
||||
} else {
|
||||
writeln!(state.terminal, "Nothing playing").expect(TERMINAL_WRITE_ERROR)
|
||||
}
|
||||
},
|
||||
"?next" => {
|
||||
state.controller_debug
|
||||
.read()
|
||||
.expect("Failed to get read lock for debug player data")
|
||||
.control_tx.as_ref()
|
||||
.expect("Control action sender shouldn't be None")
|
||||
.lock()
|
||||
.expect("Failed to get lock for control action sender")
|
||||
.send(muss_player::ControlAction::Next { ack: false })
|
||||
.unwrap_or(());
|
||||
}
|
||||
_ => writeln!(state.terminal, "Unknown command, try ?help").expect(TERMINAL_WRITE_ERROR),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue