Use libmpv-rs instead of mpv-rs

This commit is contained in:
Vladimir Borisov 2021-08-27 19:09:05 +03:00
parent 4d05ec1a5d
commit 98a079db82
5 changed files with 174 additions and 284 deletions

178
Cargo.lock generated
View file

@ -107,6 +107,16 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]] [[package]]
name = "embed-resource" name = "embed-resource"
version = "1.6.3" version = "1.6.3"
@ -118,21 +128,6 @@ dependencies = [
"winreg", "winreg",
] ]
[[package]]
name = "enum_primitive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
dependencies = [
"num-traits 0.1.43",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.3.3" version = "0.3.3"
@ -185,14 +180,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
[[package]] [[package]]
name = "log" name = "libmpv"
version = "0.3.9" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" checksum = "61a58e2d19b34775e81e0fdca194b3b8ee8de973b092e7582b416343979e22e7"
dependencies = [ dependencies = [
"log 0.4.14", "libmpv-sys",
] ]
[[package]]
name = "libmpv-sys"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0df938d3145cd8f134572721a27afa3a51f9bc1c26ae30a1d5077162f96d074b"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.14" version = "0.4.14"
@ -208,17 +209,6 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "mpv"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e57fd944655bbef6aaab8a154b0f78ed55aaaaf211edf956330c56309236f82"
dependencies = [
"enum_primitive",
"log 0.3.9",
"num",
]
[[package]] [[package]]
name = "muldiv" name = "muldiv"
version = "0.2.1" version = "0.2.1"
@ -253,84 +243,6 @@ dependencies = [
"winapi-build", "winapi-build",
] ]
[[package]]
name = "num"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits 0.2.14",
]
[[package]]
name = "num-bigint"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
dependencies = [
"num-integer",
"num-traits 0.2.14",
"rand",
"rustc-serialize",
]
[[package]]
name = "num-complex"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656"
dependencies = [
"num-traits 0.2.14",
"rustc-serialize",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits 0.2.14",
]
[[package]]
name = "num-iter"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.14",
]
[[package]]
name = "num-rational"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
dependencies = [
"num-bigint",
"num-integer",
"num-traits 0.2.14",
"rustc-serialize",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
dependencies = [
"num-traits 0.2.14",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.14" version = "0.2.14"
@ -394,7 +306,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
dependencies = [ dependencies = [
"num-traits 0.2.14", "num-traits",
"plotters-backend", "plotters-backend",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
@ -457,43 +369,6 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.4" version = "1.5.4"
@ -511,12 +386,6 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.5"
@ -568,8 +437,9 @@ name = "stremio-shell-ng"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"crossbeam-utils",
"embed-resource", "embed-resource",
"mpv", "libmpv",
"native-windows-derive", "native-windows-derive",
"native-windows-gui", "native-windows-gui",
"once_cell", "once_cell",
@ -772,7 +642,7 @@ checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"lazy_static", "lazy_static",
"log 0.4.14", "log",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",

View file

@ -5,14 +5,22 @@ edition = "2018"
[dependencies] [dependencies]
once_cell = "1.3.1" once_cell = "1.3.1"
native-windows-gui = { version = "1.0.4", features = ["high-dpi", "notice", "tray-notification", "menu"] } native-windows-gui = { version = "1.0.4", features = [
"high-dpi",
"notice",
"tray-notification",
"menu",
] }
native-windows-derive = "1.0.3" native-windows-derive = "1.0.3"
winapi = { version = "0.3.9", features = [ winapi = { version = "0.3.9", features = [
"libloaderapi", "handleapi", "wincon", "winuser" "libloaderapi",
"handleapi",
"wincon",
"winuser",
] } ] }
webview2 = "0.1.0" webview2 = "0.1.0"
webview2-sys = "0.1.0-beta.1" webview2-sys = "0.1.0-beta.1"
mpv = "0.2.3" libmpv = { version = "2.0.1", features = [] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
structopt = "0.3" structopt = "0.3"
@ -21,8 +29,9 @@ urlencoding = "2.1.0"
bitflags = "1.2.1" bitflags = "1.2.1"
win32job = "1" win32job = "1"
parse-display = "0.5.1" parse-display = "0.5.1"
crossbeam-utils = "0.8.5"
[build-dependencies] [build-dependencies]
embed-resource = "1.3" embed-resource = "1.3"
[dev-dependencies] [dev-dependencies]
serde_test = "1.0.*" serde_test = "1.0.*"

View file

@ -1,4 +1,5 @@
use core::convert::TryFrom; use core::convert::TryFrom;
use libmpv::events::PropertyData;
use parse_display::{Display, FromStr}; use parse_display::{Display, FromStr};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
@ -12,26 +13,27 @@ pub struct PlayerProprChange {
data: serde_json::Value, data: serde_json::Value,
} }
impl PlayerProprChange { impl PlayerProprChange {
fn value_from_format(data: mpv::Format, as_json: bool) -> serde_json::Value { fn value_from_format(data: PropertyData, as_json: bool) -> serde_json::Value {
match data { match data {
mpv::Format::Flag(d) => serde_json::Value::Bool(d), PropertyData::Flag(d) => serde_json::Value::Bool(d),
mpv::Format::Int(d) => serde_json::Value::Number( PropertyData::Int64(d) => serde_json::Value::Number(
serde_json::Number::from_f64(d as f64).expect("MPV returned invalid number"), serde_json::Number::from_f64(d as f64).expect("MPV returned invalid number"),
), ),
mpv::Format::Double(d) => serde_json::Value::Number( PropertyData::Double(d) => serde_json::Value::Number(
serde_json::Number::from_f64(d).expect("MPV returned invalid number"), serde_json::Number::from_f64(d).expect("MPV returned invalid number"),
), ),
mpv::Format::OsdStr(s) => serde_json::Value::String(s.to_string()), PropertyData::OsdStr(s) => serde_json::Value::String(s.to_string()),
mpv::Format::Str(s) => { PropertyData::Str(s) => {
if as_json { if as_json {
serde_json::from_str(s).expect("MPV returned invalid JSON data") serde_json::from_str(s).expect("MPV returned invalid JSON data")
} else { } else {
serde_json::Value::String(s.to_string()) serde_json::Value::String(s.to_string())
} }
} }
_ => serde_json::Value::Null,
} }
} }
pub fn from_name_value(name: String, value: mpv::Format) -> Self { pub fn from_name_value(name: String, value: PropertyData) -> Self {
let is_json = JSON_RESPONSES.contains(&name.as_str()); let is_json = JSON_RESPONSES.contains(&name.as_str());
Self { Self {
name, name,
@ -44,14 +46,15 @@ pub struct PlayerEnded {
reason: String, reason: String,
} }
impl PlayerEnded { impl PlayerEnded {
fn string_from_end_reason(data: mpv::EndFileReason) -> String { fn string_from_end_reason(data: u32) -> String {
// defined here https://github.com/mpv-player/mpv/blob/master/libmpv/client.h#L1585
match data { match data {
mpv::EndFileReason::MPV_END_FILE_REASON_ERROR => "error".to_string(), 4 => "error".to_string(),
mpv::EndFileReason::MPV_END_FILE_REASON_QUIT => "quit".to_string(), 3 => "quit".to_string(),
_ => "other".to_string(), _ => "other".to_string(),
} }
} }
pub fn from_end_reason(data: mpv::EndFileReason) -> Self { pub fn from_end_reason(data: u32) -> Self {
Self { Self {
reason: Self::string_from_end_reason(data), reason: Self::string_from_end_reason(data),
} }

View file

@ -4,6 +4,7 @@ use crate::stremio_app::stremio_player::communication::{
}; };
use serde_test::{assert_tokens, Token}; use serde_test::{assert_tokens, Token};
use libmpv::events::PropertyData;
#[test] #[test]
fn propr_change_tokens() { fn propr_change_tokens() {
@ -20,7 +21,7 @@ fn propr_change_tokens() {
Token::StructEnd, Token::StructEnd,
]; ];
fn tokens_by_type(tokens: &[Token; 6], name: &'static str, val: mpv::Format, token: Token) { fn tokens_by_type(tokens: &[Token; 6], name: &'static str, val: PropertyData, token: Token) {
let mut typed_tokens = tokens.clone(); let mut typed_tokens = tokens.clone();
typed_tokens[2] = Token::Str(name); typed_tokens[2] = Token::Str(name);
typed_tokens[4] = token; typed_tokens[4] = token;
@ -29,29 +30,29 @@ fn propr_change_tokens() {
&typed_tokens, &typed_tokens,
); );
} }
tokens_by_type(&tokens, prop, mpv::Format::Flag(true), Token::Bool(true)); tokens_by_type(&tokens, prop, PropertyData::Flag(true), Token::Bool(true));
tokens_by_type(&tokens, prop, mpv::Format::Int(1), Token::F64(1.0)); tokens_by_type(&tokens, prop, PropertyData::Int64(1), Token::F64(1.0));
tokens_by_type(&tokens, prop, mpv::Format::Double(1.0), Token::F64(1.0)); tokens_by_type(&tokens, prop, PropertyData::Double(1.0), Token::F64(1.0));
tokens_by_type(&tokens, prop, mpv::Format::OsdStr("ok"), Token::Str("ok")); tokens_by_type(&tokens, prop, PropertyData::OsdStr("ok"), Token::Str("ok"));
tokens_by_type(&tokens, prop, mpv::Format::Str("ok"), Token::Str("ok")); tokens_by_type(&tokens, prop, PropertyData::Str("ok"), Token::Str("ok"));
// JSON response // JSON response
tokens_by_type( tokens_by_type(
&tokens, &tokens,
"track-list", "track-list",
mpv::Format::Str(r#""ok""#), PropertyData::Str(r#""ok""#),
Token::Str("ok"), Token::Str("ok"),
); );
tokens_by_type( tokens_by_type(
&tokens, &tokens,
"video-params", "video-params",
mpv::Format::Str(r#""ok""#), PropertyData::Str(r#""ok""#),
Token::Str("ok"), Token::Str("ok"),
); );
tokens_by_type( tokens_by_type(
&tokens, &tokens,
"metadata", "metadata",
mpv::Format::Str(r#""ok""#), PropertyData::Str(r#""ok""#),
Token::Str("ok"), Token::Str("ok"),
); );
} }
@ -70,13 +71,13 @@ fn ended_tokens() {
let mut typed_tokens = tokens.clone(); let mut typed_tokens = tokens.clone();
typed_tokens[2] = Token::Str("error"); typed_tokens[2] = Token::Str("error");
assert_tokens( assert_tokens(
&PlayerEnded::from_end_reason(mpv::EndFileReason::MPV_END_FILE_REASON_ERROR), &PlayerEnded::from_end_reason(4),
&typed_tokens, &typed_tokens,
); );
let mut typed_tokens = tokens.clone(); let mut typed_tokens = tokens.clone();
typed_tokens[2] = Token::Str("quit"); typed_tokens[2] = Token::Str("quit");
assert_tokens( assert_tokens(
&PlayerEnded::from_end_reason(mpv::EndFileReason::MPV_END_FILE_REASON_QUIT), &PlayerEnded::from_end_reason(3),
&typed_tokens, &typed_tokens,
); );
} }

View file

@ -1,5 +1,7 @@
use crate::stremio_app::ipc; use crate::stremio_app::ipc;
use crate::stremio_app::RPCResponse; use crate::stremio_app::RPCResponse;
use libmpv::events::Event;
use libmpv::{Format, Mpv};
use native_windows_gui::{self as nwg, PartialUi}; use native_windows_gui::{self as nwg, PartialUi};
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::mpsc; use std::sync::mpsc;
@ -30,115 +32,120 @@ impl PartialUi for Player {
.hwnd() .hwnd()
.expect("Cannot obtain window handle") as i64; .expect("Cannot obtain window handle") as i64;
thread::spawn(move || { thread::spawn(move || {
let mut mpv_builder = // builder thread
mpv::MpvHandlerBuilder::new().expect("Error while creating MPV builder"); let mpv = Mpv::with_initializer(|init| {
mpv_builder init.set_property("wid", hwnd)?;
.set_option("wid", hwnd) init.set_property("gpu-context", "angle")?;
.expect("failed setting wid"); init.set_property("gpu-api", "auto")?;
// mpv_builder.set_option("vo", "gpu").expect("unable to set vo"); init.set_property("title", "Stremio")?;
// win, opengl: works but least performancy, 10-15% CPU init.set_property("terminal", "yes")?;
// winvk, vulkan: works as good as d3d11 init.set_property("msg-level", "all=no,cplayer=debug")?;
// d3d11, d1d11: works great init.set_property("quiet", "yes")?;
// dxinterop, auto: works, slightly more cpu use than d3d11 Ok(())
// default (auto) seems to be d3d11 (vo/gpu/d3d11) })
mpv_builder .expect("Cannot create MPV");
.set_option("gpu-context", "angle") let ev_ctx = Arc::new(Mutex::new(mpv.create_event_context()));
.and_then(|_| mpv_builder.set_option("gpu-api", "auto")) crossbeam_utils::thread::scope(|scope| {
.expect("setting gpu options failed"); scope.spawn(|_| {
mpv_builder let rx = rx;
.try_hardware_decoding() for msg in rx.iter() {
.expect("failed setting hwdec"); match serde_json::from_str::<InMsg>(msg.as_str()) {
mpv_builder Ok(InMsg(
.set_option("title", "Stremio") InMsgFn::MpvObserveProp,
.expect("failed setting title"); InMsgArgs::ObProp(PropKey::Bool(prop)),
mpv_builder )) => {
.set_option("terminal", "yes") let ev_ctx = ev_ctx.lock().unwrap();
.expect("failed setting terminal"); ev_ctx.observe_property(prop.to_string().as_str(), Format::Flag, 0)
mpv_builder }
.set_option("msg-level", "all=no,cplayer=debug") Ok(InMsg(
.expect("failed setting msg-level"); InMsgFn::MpvObserveProp,
mpv_builder InMsgArgs::ObProp(PropKey::Int(prop)),
.set_option("quiet", "yes") )) => {
.expect("failed setting msg-level"); let ev_ctx = ev_ctx.lock().unwrap();
let mut mpv = mpv_builder.build().expect("Cannot build MPV"); ev_ctx.observe_property(prop.to_string().as_str(), Format::Int64, 0)
}
Ok(InMsg(
InMsgFn::MpvObserveProp,
InMsgArgs::ObProp(PropKey::Fp(prop)),
)) => {
let ev_ctx = ev_ctx.lock().unwrap();
ev_ctx.observe_property(
prop.to_string().as_str(),
Format::Double,
0,
)
}
Ok(InMsg(
InMsgFn::MpvObserveProp,
InMsgArgs::ObProp(PropKey::Str(prop)),
)) => {
let ev_ctx = ev_ctx.lock().unwrap();
ev_ctx.observe_property(
prop.to_string().as_str(),
Format::String,
0,
)
}
Ok(InMsg(
InMsgFn::MpvSetProp,
InMsgArgs::StProp(prop, PropVal::Bool(val)),
)) => mpv.set_property(prop.to_string().as_str(), val),
Ok(InMsg(
InMsgFn::MpvSetProp,
InMsgArgs::StProp(prop, PropVal::Num(val)),
)) => mpv.set_property(prop.to_string().as_str(), val),
Ok(InMsg(
InMsgFn::MpvSetProp,
InMsgArgs::StProp(prop, PropVal::Str(val)),
)) => mpv.set_property(prop.to_string().as_str(), val.as_str()),
Ok(InMsg(InMsgFn::MpvCommand, InMsgArgs::Cmd(cmd))) => {
let cmd: Vec<String> = cmd.into();
let cmd = cmd.iter().map(|s| s.as_str()).collect::<Vec<_>>();
mpv.command(cmd[0], &cmd[1..])
}
_ => {
eprintln!("MPV unsupported message {}", msg);
Ok(())
}
}
.ok();
} // incoming message drain loop
});
'main: loop { 'main: loop {
// wait up to X seconds for an event. // Give time for observe_property commands to be processed before locking the mutex
while let Some(event) = mpv.wait_event(0.0) { thread::sleep(std::time::Duration::from_millis(30));
// even if you don't do anything with the events, it is still necessary to empty // even if you don't do anything with the events, it is still necessary to empty
// the event loop // the event loop
let mut ev_ctx = ev_ctx.lock().unwrap();
// wait up to X seconds for an event. -1 means forever; 0 returns event isntantly
while let Some(event) = ev_ctx.wait_event(1.0) {
let resp_event = match event {
Ok(Event::PropertyChange { name, change, .. }) => PlayerResponse(
"mpv-prop-change",
PlayerEvent::PropChange(PlayerProprChange::from_name_value(
name.to_string(),
change,
)),
)
.to_value(),
let resp_event = match event { Ok(Event::EndFile(reason)) => PlayerResponse(
mpv::Event::PropertyChange { "mpv-event-ended",
name, PlayerEvent::End(PlayerEnded::from_end_reason(reason)),
change, )
reply_userdata: _, .to_value(),
} => PlayerResponse( Ok(Event::Shutdown) => {
"mpv-prop-change", break 'main;
PlayerEvent::PropChange(PlayerProprChange::from_name_value( }
name.to_string(), _ => None,
change, };
)), if resp_event.is_some() {
) tx1.send(RPCResponse::response_message(resp_event)).ok();
.to_value(),
mpv::Event::EndFile(Ok(reason)) => PlayerResponse(
"mpv-event-ended",
PlayerEvent::End(PlayerEnded::from_end_reason(reason)),
)
.to_value(),
mpv::Event::Shutdown => {
break 'main;
} }
_ => None, } // event processing loop
}; } // main loop
if resp_event.is_some() { }) // crossbeam scope
tx1.send(RPCResponse::response_message(resp_event)).ok();
}
} // event processing
thread::sleep(std::time::Duration::from_millis(30));
for msg in rx.try_iter() {
match serde_json::from_str::<InMsg>(msg.as_str()) {
Ok(InMsg(
InMsgFn::MpvObserveProp,
InMsgArgs::ObProp(PropKey::Bool(prop)),
)) => mpv.observe_property::<bool>(prop.to_string().as_str(), 0),
Ok(InMsg(
InMsgFn::MpvObserveProp,
InMsgArgs::ObProp(PropKey::Int(prop)),
)) => mpv.observe_property::<i64>(prop.to_string().as_str(), 0),
Ok(InMsg(
InMsgFn::MpvObserveProp,
InMsgArgs::ObProp(PropKey::Fp(prop)),
)) => mpv.observe_property::<f64>(prop.to_string().as_str(), 0),
Ok(InMsg(
InMsgFn::MpvObserveProp,
InMsgArgs::ObProp(PropKey::Str(prop)),
)) => mpv.observe_property::<&str>(prop.to_string().as_str(), 0),
Ok(InMsg(
InMsgFn::MpvSetProp,
InMsgArgs::StProp(prop, PropVal::Bool(val)),
)) => mpv.set_property(prop.to_string().as_str(), val),
Ok(InMsg(
InMsgFn::MpvSetProp,
InMsgArgs::StProp(prop, PropVal::Num(val)),
)) => mpv.set_property(prop.to_string().as_str(), val),
Ok(InMsg(
InMsgFn::MpvSetProp,
InMsgArgs::StProp(prop, PropVal::Str(val)),
)) => mpv.set_property(prop.to_string().as_str(), val.as_str()),
Ok(InMsg(InMsgFn::MpvCommand, InMsgArgs::Cmd(cmd))) => {
let cmd: Vec<String> = cmd.into();
mpv.command(&cmd.iter().map(|s| s.as_str()).collect::<Vec<_>>())
}
_ => {
eprintln!("MPV unsupported message {}", msg);
Ok(())
}
}
.ok();
} // incoming message drain loop
} // main loop
}); // builder thread }); // builder thread
Ok(()) Ok(())
} }