Files
DS4Server/src/native_media.rs

40 lines
1.3 KiB
Rust

use std::ffi::{CString, c_char};
unsafe extern "C" {
fn ds4_media_open(url: *const c_char, title: *const c_char, video: bool) -> bool;
}
pub(crate) fn open(url: &str, title: &str, video: bool) -> Result<(), String> {
let url = playable_url(url)?;
let url = CString::new(url.as_str()).map_err(|error| error.to_string())?;
let title = CString::new(title).map_err(|error| error.to_string())?;
// SAFETY: Both C strings live for the duration of the call; Objective-C copies them.
if unsafe { ds4_media_open(url.as_ptr(), title.as_ptr(), video) } {
Ok(())
} else {
Err("AVKit could not create the media player".into())
}
}
fn playable_url(value: &str) -> Result<url::Url, String> {
let url = url::Url::parse(value).map_err(|error| format!("invalid media URL: {error}"))?;
if matches!(url.scheme(), "http" | "https") {
Ok(url)
} else {
Err("media URLs must use HTTP(S)".into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn media_player_only_accepts_remote_http_urls() {
assert!(playable_url("https://example.com/video.mp4").is_ok());
assert!(playable_url("http://example.com/audio.mp3").is_ok());
assert!(playable_url("file:///tmp/private.mov").is_err());
assert!(playable_url("javascript:alert(1)").is_err());
}
}