1
0
Fork 0
mirror of https://gitlab.com/futo-org/fcast.git synced 2025-06-24 21:25:23 +00:00

Rust terminal sender fixes

This commit is contained in:
Marcus Hanestad 2025-06-24 13:17:52 +00:00 committed by Michael Hollister
parent a955097989
commit 1435d8a2ea
4 changed files with 46 additions and 14 deletions

View file

@ -58,5 +58,5 @@ cat dash.mpd | ./fcast -h localhost play --mime_type application/dash+xml
cat image_playlist_example.json | ./fcast -h localhost play --mime_type application/json cat image_playlist_example.json | ./fcast -h localhost play --mime_type application/json
# Play from video playlist # Play from video playlist
cat image_playlist_example.json | ./fcast -h localhost play --mime_type application/json cat video_playlist_example.json | ./fcast -h localhost play --mime_type application/json
``` ```

View file

@ -123,9 +123,9 @@ impl<'a> FCastSession<'a> {
if opcode != Opcode::Initial { if opcode != Opcode::Initial {
return Err(format!("Expected Opcode::Initial, got {opcode:?}").into()); return Err(format!("Expected Opcode::Initial, got {opcode:?}").into());
} }
let inital_receiver: v3::InitialReceiverMessage = let initial_receiver: v3::InitialReceiverMessage =
serde_json::from_str(&body.ok_or("InitialReceiverMessage requires body")?)?; serde_json::from_str(&body.ok_or("InitialReceiverMessage requires body")?)?;
println!("Got inital message from sender: {inital_receiver:?}"); println!("Got initial message from sender: {initial_receiver:?}");
session.state = SessionState::Connected(ProtoVersion::V3); session.state = SessionState::Connected(ProtoVersion::V3);
} else { } else {
session.state = SessionState::Connected(ProtoVersion::V2); session.state = SessionState::Connected(ProtoVersion::V2);
@ -259,6 +259,7 @@ impl<'a> FCastSession<'a> {
time: Option<f64>, time: Option<f64>,
speed: Option<f64>, speed: Option<f64>,
headers: Option<HashMap<String, String>>, headers: Option<HashMap<String, String>>,
volume: Option<f64>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
match self.state { match self.state {
SessionState::Connected(ProtoVersion::V2) => { SessionState::Connected(ProtoVersion::V2) => {
@ -278,7 +279,7 @@ impl<'a> FCastSession<'a> {
url, url,
content, content,
time, time,
volume: Some(1.0), volume,
speed, speed,
headers, headers,
metadata: None, metadata: None,

View file

@ -135,6 +135,14 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
.help("Custom request headers in key:value format") .help("Custom request headers in key:value format")
.required(false) .required(false)
.multiple_occurrences(true), .multiple_occurrences(true),
)
.arg(
Arg::with_name("volume")
.short('v')
.long("volume")
.value_name("VOLUME")
.help("The desired volume")
.takes_value(true)
), ),
) )
.subcommand( .subcommand(
@ -301,6 +309,11 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
.collect::<HashMap<String, String>>() .collect::<HashMap<String, String>>()
}); });
let volume = match play_matches.value_of("volume") {
Some(v) => v.parse::<f64>().ok(),
_ => None,
};
#[allow(unused_assignments)] #[allow(unused_assignments)]
let mut url = None; let mut url = None;
let mut content = None; let mut content = None;
@ -313,7 +326,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
ctrlc::set_handler(move || { ctrlc::set_handler(move || {
println!( println!(
"Ctrl+C triggered, server will stop when onging request finishes..." "Ctrl+C triggered, server will stop when ongoing request finishes..."
); );
r.store(false, Ordering::SeqCst); r.store(false, Ordering::SeqCst);
}) })
@ -340,7 +353,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
content = Some(buffer); content = Some(buffer);
} }
session.send_play_message(mime_type, url, content, time, speed, headers)?; session.send_play_message(mime_type, url, content, time, speed, headers, volume)?;
} else if let Some(seek_matches) = matches.subcommand_matches("seek") { } else if let Some(seek_matches) = matches.subcommand_matches("seek") {
let seek_message = SeekMessage::new(match seek_matches.value_of("timestamp") { let seek_message = SeekMessage::new(match seek_matches.value_of("timestamp") {
Some(s) => s.parse::<f64>()?, Some(s) => s.parse::<f64>()?,

View file

@ -15,7 +15,7 @@ pub enum MetadataObject {
Generic { Generic {
title: Option<String>, title: Option<String>,
thumbnail_url: Option<String>, thumbnail_url: Option<String>,
custom: Value, custom: Option<Value>,
}, },
} }
@ -46,7 +46,9 @@ impl Serialize for MetadataObject {
None => Value::Null, None => Value::Null,
}, },
); );
if let Some(custom) = custom {
map.insert("custom".to_owned(), custom.clone()); map.insert("custom".to_owned(), custom.clone());
}
map.serialize(serializer) map.serialize(serializer)
} }
} }
@ -90,8 +92,7 @@ impl<'de> Deserialize<'de> for MetadataObject {
thumbnail_url, thumbnail_url,
custom: rest custom: rest
.get("custom") .get("custom")
.ok_or(de::Error::missing_field("custom"))? .cloned(),
.clone(),
}) })
} }
_ => Err(de::Error::custom(format!("Unknown metadata type {type_}"))), _ => Err(de::Error::custom(format!("Unknown metadata type {type_}"))),
@ -476,7 +477,7 @@ mod tests {
&serde_json::to_string(&MetadataObject::Generic { &serde_json::to_string(&MetadataObject::Generic {
title: Some(s!("abc")), title: Some(s!("abc")),
thumbnail_url: Some(s!("def")), thumbnail_url: Some(s!("def")),
custom: serde_json::Value::Null, custom: Some(serde_json::Value::Null),
}) })
.unwrap(), .unwrap(),
r#"{"custom":null,"thumbnailUrl":"def","title":"abc","type":0}"# r#"{"custom":null,"thumbnailUrl":"def","title":"abc","type":0}"#
@ -485,11 +486,20 @@ mod tests {
&serde_json::to_string(&MetadataObject::Generic { &serde_json::to_string(&MetadataObject::Generic {
title: None, title: None,
thumbnail_url: None, thumbnail_url: None,
custom: serde_json::Value::Null, custom: Some(serde_json::Value::Null),
}) })
.unwrap(), .unwrap(),
r#"{"custom":null,"thumbnailUrl":null,"title":null,"type":0}"# r#"{"custom":null,"thumbnailUrl":null,"title":null,"type":0}"#
); );
assert_eq!(
&serde_json::to_string(&MetadataObject::Generic {
title: Some(s!("abc")),
thumbnail_url: Some(s!("def")),
custom: None,
})
.unwrap(),
r#"{"thumbnailUrl":"def","title":"abc","type":0}"#
);
} }
#[test] #[test]
@ -502,7 +512,7 @@ mod tests {
MetadataObject::Generic { MetadataObject::Generic {
title: Some(s!("abc")), title: Some(s!("abc")),
thumbnail_url: Some(s!("def")), thumbnail_url: Some(s!("def")),
custom: serde_json::Value::Null, custom: Some(serde_json::Value::Null),
} }
); );
assert_eq!( assert_eq!(
@ -510,7 +520,15 @@ mod tests {
MetadataObject::Generic { MetadataObject::Generic {
title: None, title: None,
thumbnail_url: None, thumbnail_url: None,
custom: serde_json::Value::Null, custom: Some(serde_json::Value::Null),
}
);
assert_eq!(
serde_json::from_str::<MetadataObject>(r#"{"type":0}"#).unwrap(),
MetadataObject::Generic {
title: None,
thumbnail_url: None,
custom: None,
} }
); );
assert!(serde_json::from_str::<MetadataObject>(r#"{"type":1"#).is_err()); assert!(serde_json::from_str::<MetadataObject>(r#"{"type":1"#).is_err());