use crate::{
IdeviceError, ReadWrite, RsdService, obf,
xpc::{Dictionary as XpcDictionary, XPCObject},
};
impl RsdService for DisplayServiceClient<Box<dyn ReadWrite>> {
fn rsd_service_name() -> std::borrow::Cow<'static, str> {
obf!("com.apple.coredevice.displayservice")
}
async fn from_stream(stream: Box<dyn ReadWrite>) -> Result<Self, IdeviceError> {
Ok(Self {
inner: super::super::CoreDeviceServiceClient::new(stream).await?,
})
}
}
#[derive(Debug)]
pub struct DisplayServiceClient<R: ReadWrite> {
inner: super::super::CoreDeviceServiceClient<R>,
}
impl<R: ReadWrite> DisplayServiceClient<R> {
pub fn new(inner: super::super::CoreDeviceServiceClient<R>) -> Self {
Self { inner }
}
pub async fn get_media_support_info(&mut self) -> Result<plist::Value, IdeviceError> {
self.inner
.invoke_with_plist(
obf!("com.apple.coredevice.feature.getmediasupportinfo"),
plist::Dictionary::new(),
)
.await
}
pub async fn get_media_stream_server_status(&mut self) -> Result<plist::Value, IdeviceError> {
self.inner
.invoke_with_plist(
obf!("com.apple.coredevice.feature.getmediastreamserverstatus"),
plist::Dictionary::new(),
)
.await
}
pub async fn stop_media_stream(&mut self) -> Result<plist::Value, IdeviceError> {
let mut input = plist::Dictionary::new();
input.insert("stopAll".into(), plist::Value::Boolean(true));
self.inner
.invoke_with_plist_action(
obf!("com.apple.coredevice.feature.stopmediastream"),
input,
obf!("com.apple.coredevice.action.mediastreamstop"),
)
.await
}
pub async fn start_video_output(
&mut self,
params: XpcDictionary,
) -> Result<plist::Value, IdeviceError> {
self.inner
.invoke(
obf!("com.apple.coredevice.feature.startvideooutput"),
Some(params),
)
.await
}
pub async fn start_media_stream(
&mut self,
params: XpcDictionary,
) -> Result<plist::Value, IdeviceError> {
self.inner
.invoke(
obf!("com.apple.coredevice.feature.startmediastream"),
Some(params),
)
.await
}
}
fn codable_int(v: i64) -> XPCObject {
let mut d = XpcDictionary::new();
d.insert("int".into(), XPCObject::Int64(v));
XPCObject::Dictionary(d)
}
fn codable_string(v: &str) -> XPCObject {
let mut d = XpcDictionary::new();
d.insert("string".into(), XPCObject::String(v.into()));
XPCObject::Dictionary(d)
}
fn codable_uuid(v: uuid::Uuid) -> XPCObject {
let mut d = XpcDictionary::new();
d.insert("uuid".into(), XPCObject::Uuid(v));
XPCObject::Dictionary(d)
}
#[allow(clippy::too_many_arguments)]
pub fn build_start_video_parameters(
receiver_ip: &str,
receiver_port: u16,
sender_ip: &str,
sender_port: u16,
negotiator_offer: Vec<u8>,
client_supported_features: u64,
display_id: i64,
client_session_id: uuid::Uuid,
) -> XpcDictionary {
build_start_parameters(
"video",
receiver_ip,
receiver_port,
sender_ip,
sender_port,
negotiator_offer,
client_supported_features,
client_session_id,
Some(display_id),
)
}
#[allow(clippy::too_many_arguments)]
pub fn build_start_audio_parameters(
receiver_ip: &str,
receiver_port: u16,
sender_ip: &str,
sender_port: u16,
negotiator_offer: Vec<u8>,
client_supported_features: u64,
client_session_id: uuid::Uuid,
) -> XpcDictionary {
build_start_parameters(
"audio",
receiver_ip,
receiver_port,
sender_ip,
sender_port,
negotiator_offer,
client_supported_features,
client_session_id,
None,
)
}
#[allow(clippy::too_many_arguments)]
fn build_start_parameters(
stream_type: &str,
receiver_ip: &str,
receiver_port: u16,
sender_ip: &str,
sender_port: u16,
negotiator_offer: Vec<u8>,
client_supported_features: u64,
client_session_id: uuid::Uuid,
display_id: Option<i64>,
) -> XpcDictionary {
let mut options = XpcDictionary::new();
options.insert(
"AVCMediaStreamNegotiatorTransportProtocolType".into(),
codable_int(2),
);
options.insert(
"AVCMediaStreamNegotiatorAccessNetworkType".into(),
codable_int(1),
);
options.insert(
"avcMediaStreamOptionClientSessionID".into(),
codable_uuid(client_session_id),
);
if let Some(display_id) = display_id {
options.insert(
"CoreDeviceVideoDisplayMode".into(),
codable_string("DisplayByID"),
);
options.insert("VideoStreamForDisplayID".into(), codable_int(display_id));
}
let mut params = XpcDictionary::new();
params.insert("receiverIP".into(), XPCObject::String(receiver_ip.into()));
params.insert(
"receiverPort".into(),
XPCObject::UInt64(receiver_port as u64),
);
params.insert("senderIP".into(), XPCObject::String(sender_ip.into()));
params.insert("senderPort".into(), XPCObject::UInt64(sender_port as u64));
params.insert("timeout".into(), XPCObject::UInt64(3600));
params.insert("type".into(), XPCObject::String(stream_type.into()));
params.insert("direction".into(), XPCObject::String("output".into()));
params.insert("negotiatorOffer".into(), XPCObject::Data(negotiator_offer));
params.insert(
"clientSupportedFeatures".into(),
XPCObject::UInt64(client_supported_features),
);
params.insert("options".into(), XPCObject::Dictionary(options));
params
}