Skip to main content

servo_media_derive/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5#![recursion_limit = "128"]
6
7extern crate proc_macro;
8extern crate proc_macro2;
9extern crate syn;
10#[macro_use]
11extern crate quote;
12
13use proc_macro::TokenStream;
14
15#[proc_macro_derive(AudioScheduledSourceNode)]
16pub fn audio_scheduled_source_node(input: TokenStream) -> TokenStream {
17    let ast: syn::DeriveInput = syn::parse(input).unwrap();
18    let r#gen = impl_audio_scheduled_source_node(&ast);
19    r#gen.into()
20}
21
22fn impl_audio_scheduled_source_node(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
23    let name = &ast.ident;
24    quote! {
25        impl #name {
26            fn should_play_at(&mut self, tick: Tick) -> ShouldPlay {
27                let start = if let Some(start) = self.start_at {
28                    start
29                } else {
30                    return ShouldPlay::No;
31                };
32
33                let frame_end = tick + Tick::FRAMES_PER_BLOCK;
34                if tick < start {
35                    if frame_end < start {
36                        ShouldPlay::No
37                    } else {
38                        let delta_start = start - tick;
39                        if let Some(stop) = self.stop_at {
40                            if stop <= start {
41                                self.maybe_trigger_onended_callback();
42                                return ShouldPlay::No;
43                            }
44                            if stop > frame_end {
45                                ShouldPlay::Between(delta_start, Tick::FRAMES_PER_BLOCK)
46                            } else {
47                                self.maybe_trigger_onended_callback();
48                                ShouldPlay::Between(delta_start, stop - tick)
49                            }
50                        } else {
51                            ShouldPlay::Between(delta_start, Tick::FRAMES_PER_BLOCK)
52                        }
53                    }
54                } else {
55                    let stop = if let Some(stop) = self.stop_at {
56                        stop
57                    } else {
58                        return ShouldPlay::Between(Tick(0), Tick::FRAMES_PER_BLOCK);
59                    };
60                    if stop > frame_end {
61                        ShouldPlay::Between(Tick(0), Tick::FRAMES_PER_BLOCK)
62                    } else if stop < tick {
63                        self.maybe_trigger_onended_callback();
64                        ShouldPlay::No
65                    } else {
66                        self.maybe_trigger_onended_callback();
67                        ShouldPlay::Between(Tick(0), stop - tick)
68                    }
69                }
70            }
71
72            fn start(&mut self, tick: Tick) -> bool {
73                // We can only allow a single call to `start` and always before
74                // any `stop` calls.
75                if self.start_at.is_some() || self.stop_at.is_some() {
76                    return false;
77                }
78                self.start_at = Some(tick);
79                true
80            }
81
82            fn stop(&mut self, tick: Tick) -> bool {
83                // We can only allow calls to `stop` after `start` is called.
84                if self.start_at.is_none() {
85                    return false;
86                }
87                // If `stop` is called again after already having been called,
88                // the last invocation will be the only one applied.
89                self.stop_at = Some(tick);
90                true
91            }
92
93            fn maybe_trigger_onended_callback(&mut self) {
94                // We cannot have an end without a start.
95                if self.start_at.is_none() {
96                    return;
97                }
98                if let Some(cb) = self.onended_callback.take() {
99                    cb.0()
100                }
101            }
102
103            fn handle_source_node_message(&mut self, message: AudioScheduledSourceNodeMessage, sample_rate: f32) {
104                match message {
105                    AudioScheduledSourceNodeMessage::Start(when) => {
106                        self.start(Tick::from_time(when, sample_rate));
107                    }
108                    AudioScheduledSourceNodeMessage::Stop(when) => {
109                        self.stop(Tick::from_time(when, sample_rate));
110                    }
111                    AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback) => {
112                        self.onended_callback = Some(callback);
113                    }
114                }
115            }
116        }
117    }
118}
119
120#[proc_macro_derive(AudioNodeCommon)]
121pub fn channel_info(input: TokenStream) -> TokenStream {
122    let ast: syn::DeriveInput = syn::parse(input).unwrap();
123    let name = &ast.ident;
124    let r#gen = quote! {
125        impl crate::node::AudioNodeCommon for #name {
126            fn channel_info(&self) -> &crate::node::ChannelInfo {
127                &self.channel_info
128            }
129
130            fn channel_info_mut(&mut self) -> &mut crate::node::ChannelInfo {
131                &mut self.channel_info
132            }
133        }
134    };
135    r#gen.into()
136}