1use crate::{DisplayId, PlatformDisplayLinker, VideoTimestamp};
2use collections::HashMap;
3use parking_lot::Mutex;
4use std::sync::Arc;
5
6type FrameCallback = Box<dyn FnOnce(&VideoTimestamp, &VideoTimestamp) + Send>;
7
8pub struct DisplayLinker {
9 platform_linker: Arc<dyn PlatformDisplayLinker>,
10 next_frame_callbacks: Arc<Mutex<HashMap<DisplayId, Vec<FrameCallback>>>>,
11}
12
13impl DisplayLinker {
14 pub(crate) fn new(platform_linker: Arc<dyn PlatformDisplayLinker>) -> Self {
15 Self {
16 platform_linker,
17 next_frame_callbacks: Default::default(),
18 }
19 }
20
21 pub(crate) fn on_next_frame(
22 &self,
23 display_id: DisplayId,
24 callback: impl FnOnce(&VideoTimestamp, &VideoTimestamp) + Send + 'static,
25 ) {
26 let next_frame_callbacks = self.next_frame_callbacks.clone();
27 let callback = Box::new(callback);
28 match self.next_frame_callbacks.lock().entry(display_id) {
29 collections::hash_map::Entry::Occupied(mut entry) => {
30 if entry.get().is_empty() {
31 self.platform_linker.start(display_id);
32 }
33 entry.get_mut().push(callback)
34 }
35 collections::hash_map::Entry::Vacant(entry) => {
36 // let platform_linker = self.platform_linker.clone();
37 self.platform_linker.set_output_callback(
38 display_id,
39 Box::new(move |current_time, output_time| {
40 for callback in next_frame_callbacks
41 .lock()
42 .get_mut(&display_id)
43 .unwrap()
44 .drain(..)
45 {
46 callback(current_time, output_time);
47 }
48 // platform_linker.stop(display_id);
49 }),
50 );
51 self.platform_linker.start(display_id);
52 entry.insert(vec![callback]);
53 }
54 }
55 }
56}