use super::{
CaptureCapabilities, CaptureError, CaptureFuture, MediaCaptureProvider, ProviderCaptureRequest,
ProviderCaptureSession, ProviderEventSink, TrackKind, TrackSet,
};
use std::sync::Arc;
pub struct AndroidCaptureProvider {
visual: bool,
system_audio: bool,
microphone: bool,
}
impl AndroidCaptureProvider {
pub fn new(visual: bool, system_audio: bool, microphone: bool) -> Self {
Self {
visual,
system_audio,
microphone,
}
}
}
impl MediaCaptureProvider for AndroidCaptureProvider {
fn id(&self) -> &'static str {
"android-mediaprojection"
}
fn capabilities(&self) -> CaptureCapabilities {
let mut combinations = Vec::new();
if self.visual && self.system_audio {
combinations.push(TrackSet {
tracks: vec![TrackKind::Visual, TrackKind::SystemAudio],
coupled_clock: true,
});
}
if self.visual {
combinations.push(TrackSet {
tracks: vec![TrackKind::Visual],
coupled_clock: false,
});
}
if self.system_audio {
combinations.push(TrackSet {
tracks: vec![TrackKind::SystemAudio],
coupled_clock: false,
});
}
if self.microphone {
combinations.push(TrackSet {
tracks: vec![TrackKind::Microphone],
coupled_clock: false,
});
}
CaptureCapabilities { combinations }
}
fn start(
&self,
request: ProviderCaptureRequest,
_events: Arc<dyn ProviderEventSink>,
) -> CaptureFuture<Result<Box<dyn ProviderCaptureSession>, CaptureError>> {
let needs_projection = request
.tracks
.iter()
.any(|track| matches!(track.kind, TrackKind::Visual | TrackKind::SystemAudio));
if needs_projection {
let authorized = request.authorization.as_ref().is_some_and(|token| {
token.kind == super::AuthorizationKind::AndroidMediaProjection
});
if !authorized {
return Box::pin(async {
Err(CaptureError::AuthorizationRequired {
track: TrackKind::Visual,
})
});
}
}
let track = request.tracks.first().map(|track| track.kind);
Box::pin(async move {
Err(CaptureError::Unavailable {
track,
reason: "android capture has no encoder yet".into(),
})
})
}
}