Skip to main content

clack_host/
plugin.rs

1//! Core types and traits to instantiate and interact with CLAP plugins.
2
3use crate::prelude::*;
4use clap_sys::plugin::clap_plugin;
5use std::ffi::CStr;
6use std::marker::PhantomData;
7use std::mem::ManuallyDrop;
8use std::sync::Arc;
9
10mod error;
11mod handle;
12pub(crate) mod instance;
13
14pub use error::PluginInstanceError;
15pub use handle::*;
16use instance::*;
17
18pub use clack_common::plugin::*;
19
20/// A plugin instance.
21///
22/// This type is generic over `H`, the type of the host callback handlers, which the plugin can
23/// call use directly when its own methods are called by the host.
24pub struct PluginInstance<H: HostHandlers> {
25    pub(crate) inner: ManuallyDrop<Arc<PluginInstanceInner<H>>>,
26    _no_send: PhantomData<*const ()>,
27}
28
29impl<H: HostHandlers> PluginInstance<H> {
30    /// Creates a new plugin instance from a given [`PluginEntry`].
31    ///
32    /// The specific plugin to be instantiated is identified by the given `plugin_id`.
33    ///
34    /// This method takes two closures, here named `FS` and `FH`, which will respectively create
35    /// the [`Shared`](HostHandlers::Shared) and [`MainThread`](HostHandlers::MainThread) callback
36    /// handler instances associated with this plugin instance.
37    ///
38    /// The [`MainThread`](HostHandlers::MainThread)-producing callback takes a long-lived reference
39    /// to its [`Shared`](HostHandlers::Shared) counterpart, so that it can be accessed at any time
40    /// from the main thread if needed.
41    ///
42    /// The [`Shared`](HostHandlers::Shared)-producing callback takes a unit reference `&()`. It is
43    /// not used for anything, but is necessary for proper lifetime binding.
44    ///
45    /// This method also takes a reference to a [`HostInfo`], giving the plugin some metadata about
46    /// the host itself.
47    ///
48    /// # Errors
49    ///
50    /// If for some reason the given [`PluginEntry`] does not expose a [`PluginFactory`](crate::factory::plugin::PluginFactory),
51    /// then this will return [`PluginInstanceError::MissingPluginFactory`].
52    ///
53    /// If the `PluginFactory`'s `create_plugin` function pointer is NULL,
54    /// this will return [`PluginInstanceError::NullFactoryCreatePluginFunction`].
55    ///
56    /// If the given `plugin_id` does not exist, or if more generally the
57    /// `PluginFactory`'s `create_plugin` function returned NULL,
58    /// then this will return [`PluginInstanceError::PluginNotFound`].
59    ///
60    /// Otherwise, if the plugin instantiation implementation failed, it will return
61    /// [`PluginInstanceError::InstantiationFailed`].
62    ///
63    /// # Example
64    ///
65    /// ```
66    /// use clack_host::prelude::*;
67    ///
68    /// struct MyHost;
69    ///
70    /// struct MyHostMainThread { /* ... */ }
71    ///
72    /// impl HostHandlers for MyHost {
73    ///     type Shared<'a> = /* ... */
74    /// # ();
75    ///     type AudioProcessor<'a> = /* ... */
76    /// # ();
77    ///     type MainThread<'a> = MyHostMainThread;
78    /// }
79    ///
80    /// impl<'a> MainThreadHandler<'a> for MyHostMainThread {
81    ///     fn initialized(&mut self, instance: InitializedPluginHandle<'a>) {
82    ///         // Called whn the plugin has been fully initialized.
83    ///     }
84    /// }
85    ///
86    /// # mod diva { include!("./entry/diva_stub.rs"); }
87    ///
88    /// let entry = /* ... */
89    /// # PluginEntry::load_from_clack::<diva::Entry>(c"").unwrap();
90    /// let host_info = HostInfo::new("Foo DAW", "Foo Inc.", "https://example.com", "0.0.1").unwrap();
91    ///
92    /// let instance = PluginInstance::<MyHost>::new(
93    ///     |_|(),
94    ///     |_| MyHostMainThread {},
95    ///     &entry,
96    ///     c"com.audio.the-plugin",
97    ///     &host_info
98    /// );
99    ///
100    /// ```
101    pub fn new<FS, FH>(
102        shared: FS,
103        main_thread: FH,
104        entry: &PluginEntry,
105        plugin_id: &CStr,
106        host: &HostInfo,
107    ) -> Result<Self, PluginInstanceError>
108    where
109        FS: for<'b> FnOnce(&'b ()) -> <H as HostHandlers>::Shared<'b>,
110        FH: for<'b> FnOnce(
111            &'b <H as HostHandlers>::Shared<'b>,
112        ) -> <H as HostHandlers>::MainThread<'b>,
113    {
114        let inner = PluginInstanceInner::<H>::instantiate(
115            shared,
116            main_thread,
117            entry,
118            plugin_id,
119            host.clone(),
120        )?;
121
122        Ok(Self {
123            inner: ManuallyDrop::new(inner),
124            _no_send: PhantomData,
125        })
126    }
127
128    /// Activates the plugin instance, preparing it to process audio and events according to the given [`PluginAudioConfiguration`].
129    ///
130    /// This method takes a closure `FA`, which will create
131    /// the [`AudioProcessor`](HostHandlers::AudioProcessor) callback
132    /// handler instance associated with this plugin instance.
133    ///
134    /// This closure takes a long-lived reference to the [`Shared`](HostHandlers::Shared) handler
135    /// so that it can be accessed at any time from the audio thread / audio-processing context if needed.
136    ///
137    /// This closure also provides a temporary, exclusive reference to the [`MainThread`](HostHandlers::MainThread) handler.
138    ///
139    /// # Errors
140    ///
141    /// This will return [`PluginInstanceError::AlreadyActivatedPlugin`] if the plugin has already
142    /// been activated.
143    ///
144    /// If the plugin instance's `activate` function pointer is NULL,
145    /// this will return [`PluginInstanceError::NullActivateFunction`].
146    ///
147    /// Otherwise, if the plugin instance's `activate` function implementation failed for any reason,
148    /// this will return [`PluginInstanceError::ActivationFailed`].
149    pub fn activate<FA>(
150        &mut self,
151        audio_processor: FA,
152        configuration: PluginAudioConfiguration,
153    ) -> Result<StoppedPluginAudioProcessor<H>, PluginInstanceError>
154    where
155        FA: for<'a> FnOnce(
156            &'a <H as HostHandlers>::Shared<'a>,
157            &mut <H as HostHandlers>::MainThread<'a>,
158        ) -> <H as HostHandlers>::AudioProcessor<'a>,
159    {
160        let wrapper =
161            Arc::get_mut(&mut self.inner).ok_or(PluginInstanceError::AlreadyActivatedPlugin)?;
162        wrapper.activate(audio_processor, configuration)?;
163
164        Ok(StoppedPluginAudioProcessor::new(Arc::clone(&self.inner)))
165    }
166
167    /// De-activates the plugin instance, freeing its processing-related resources, and allows it
168    /// to be re-[activated](Self::activate) with a different audio configuration.
169    ///
170    /// This consumes the [`StoppedPluginAudioProcessor`] handle created by [`activate`](Self::activate),
171    /// in order to ensure it cannot be used anymore.
172    ///
173    /// For a version of this method that does not require the [`StoppedPluginAudioProcessor`] handle,
174    /// see [`try_deactivate`](Self::try_deactivate).
175    ///
176    /// # Panics
177    ///
178    /// This will panic if the provided `processor` handle did not come from this plugin instance.
179    #[inline]
180    pub fn deactivate(&mut self, processor: StoppedPluginAudioProcessor<H>) {
181        self.deactivate_with(processor, |_, _| ())
182    }
183
184    /// Attempts to de-activate a plugin instance, which [`PluginAudioProcessor`] handle has been
185    /// dropped.
186    ///
187    /// This is an alternative to [`deactivate`](Self::deactivate) which does not require the associated
188    /// [`PluginAudioProcessorHandle`] to be passed. However, this method is fallible, and will
189    /// return an error if the [`PluginAudioProcessorHandle`] has not been dropped.
190    ///
191    /// This may be useful if it is more practical for you to drop the [`PluginAudioProcessorHandle`]
192    /// (e.g. in another thread) compared to sending it back to the main thread to use with
193    /// [`deactivate`](Self::deactivate).
194    ///
195    /// However, if you can easily access or retrieve [`PluginAudioProcessorHandle`] back to the main
196    /// thread, you should use [`deactivate`](Self::deactivate) instead.
197    ///
198    /// # Errors
199    ///
200    /// This method will return [`PluginInstanceError::StillActivatedPlugin`] if the associated
201    /// [`PluginAudioProcessorHandle`] has not been dropped.
202    #[inline]
203    pub fn try_deactivate(&mut self) -> Result<(), PluginInstanceError> {
204        self.try_deactivate_with(|_, _| ())
205    }
206
207    /// De-activates the plugin instance, freeing its processing-related resources, and allows it
208    /// to be re-[activated](Self::activate) with a different audio configuration.
209    ///
210    /// This consumes the [`StoppedPluginAudioProcessor`] handle created by [`activate`](Self::activate),
211    /// in order to ensure it cannot be used anymore.
212    ///
213    /// This is equivalent to [`Self::deactivate`], except this method also takes a closure type `D`,
214    /// which allows to customize the destruction process of the [`AudioProcessor`](HostHandlers::AudioProcessor) callback
215    /// handler instance that was created during [`activate`](Self::activate).
216    ///
217    /// This may be useful to e.g. reuse or reprocess components or allocations the [`AudioProcessor`](HostHandlers::AudioProcessor) callback
218    /// handler instance owned, either by giving it to the [`MainThread`](HostHandlers::MainThread) handler
219    /// (which is also provided by a temporary, exclusive reference), or by returning it.
220    ///
221    /// This function will return whatever the destructor closure returned.
222    ///
223    /// # Panics
224    ///
225    /// This will panic if the provided `processor` handle did not come from this plugin instance.
226    pub fn deactivate_with<T, D>(
227        &mut self,
228        processor: StoppedPluginAudioProcessor<H>,
229        drop_with: D,
230    ) -> T
231    where
232        D: for<'s> FnOnce(
233            <H as HostHandlers>::AudioProcessor<'s>,
234            &mut <H as HostHandlers>::MainThread<'s>,
235        ) -> T,
236    {
237        if !Arc::ptr_eq(&self.inner, &processor.inner) {
238            panic!("Given plugin audio processor does not match the instance being deactivated")
239        }
240
241        drop(processor);
242
243        // PANIC: we dropped the only processor produced, and checked if it matched
244        self.try_deactivate_with(drop_with).unwrap()
245    }
246
247    /// Attempts to de-activate a plugin instance, which [`PluginAudioProcessor`] handle has been
248    /// dropped.
249    ///
250    /// This is equivalent to [`Self::try_deactivate`], except this method also takes a closure type `D`,
251    /// which allows to customize the destruction process of the [`AudioProcessor`](HostHandlers::AudioProcessor) callback
252    /// handler instance that was created during [`activate`](Self::activate).
253    ///
254    /// This is an alternative to [`deactivate_with`](Self::deactivate_with) which does not require the associated
255    /// [`PluginAudioProcessorHandle`] to be passed. However, this method is fallible, and will
256    /// return an error if the [`PluginAudioProcessorHandle`] has not been dropped.
257    ///
258    /// This may be useful if it is more practical for you to drop the [`PluginAudioProcessorHandle`]
259    /// (e.g. in another thread) compared to sending it back to the main thread to use with
260    /// [`deactivate_with`](Self::deactivate_with).
261    ///
262    /// However, if you can easily access or retrieve [`PluginAudioProcessorHandle`] back to the main
263    /// thread, you should use [`deactivate_with`](Self::deactivate_with) instead.
264    ///
265    /// # Errors
266    ///
267    /// This method will return [`PluginInstanceError::StillActivatedPlugin`] if the associated
268    /// [`PluginAudioProcessorHandle`] has not been dropped.
269    pub fn try_deactivate_with<T, D>(&mut self, drop_with: D) -> Result<T, PluginInstanceError>
270    where
271        D: for<'s> FnOnce(
272            <H as HostHandlers>::AudioProcessor<'s>,
273            &mut <H as HostHandlers>::MainThread<'s>,
274        ) -> T,
275    {
276        let wrapper =
277            Arc::get_mut(&mut self.inner).ok_or(PluginInstanceError::StillActivatedPlugin)?;
278
279        wrapper.deactivate_with(drop_with)
280    }
281
282    /// Calls the plugin's `on_main_thread` callback.
283    ///
284    /// This is usually done in response to the plugin calling [`SharedHandler::request_callback`]
285    /// earlier from a different thread, allowing it to "wake up" its main thread after e.g. another
286    /// of the plugin's threads sent a message to it.
287    #[inline]
288    pub fn call_on_main_thread_callback(&mut self) {
289        // SAFETY: this is done on the main thread, and the &mut reference guarantees no aliasing
290        unsafe { self.inner.on_main_thread() }
291    }
292
293    /// Returns a shared, read-only reference to the raw, C-FFI compatible representation
294    /// of thsi plugin instance.
295    #[inline]
296    pub fn raw_instance(&self) -> &clap_plugin {
297        self.inner.raw_instance()
298    }
299
300    /// Returns the [`PluginEntry`] this plugin instance was loaded from.
301    #[inline]
302    pub fn entry(&self) -> &PluginEntry {
303        self.inner.entry()
304    }
305
306    /// Returns `true` if the current plugin instance has been activated.
307    #[inline]
308    pub fn is_active(&self) -> bool {
309        self.inner.is_active()
310    }
311
312    /// Access the [`SharedHandler`] instance associated to this plugin instance using the given callback.
313    ///
314    /// The callback's return value `R` is returned directly by this method.
315    ///
316    /// Accessing the [`HostHandlers`] types can only be done with accessor callbacks because this
317    /// type is self-referential: both the [`HostHandlers`] and the plugin's instance data hold
318    /// references to each other, and both are owned by this type.
319    #[inline]
320    pub fn access_shared_handler<'s, R>(
321        &'s self,
322        access: impl for<'a> FnOnce(&'s <H as HostHandlers>::Shared<'a>) -> R,
323    ) -> R {
324        access(self.inner.wrapper().shared())
325    }
326
327    /// Access a shared reference to [`MainThreadHandler`] instance associated to this plugin instance using the given callback.
328    ///
329    /// The callback's return value `R` is returned directly by this method.
330    ///
331    /// Accessing the [`HostHandlers`] types can only be done with accessor callbacks because this
332    /// type is self-referential: both the [`HostHandlers`] and the plugin's instance data hold
333    /// references to each other, and both are owned by this type.
334    #[inline]
335    pub fn access_handler<'s, R>(
336        &'s self,
337        access: impl for<'a> FnOnce(&'s <H as HostHandlers>::MainThread<'a>) -> R,
338    ) -> R {
339        // SAFETY: we take &self, the only reference to the wrapper on the main thread, therefore
340        // we can guarantee there are no mutable reference anywhere
341        unsafe { access(self.inner.wrapper().main_thread().as_ref()) }
342    }
343
344    /// Access an exclusive `&mut` reference to [`MainThreadHandler`] instance associated to this plugin instance using the given callback.
345    ///
346    /// The callback's return value `R` is returned directly by this method.
347    ///
348    /// Accessing the [`HostHandlers`] types can only be done with accessor callbacks because this
349    /// type is self-referential: both the [`HostHandlers`] and the plugin's instance data hold
350    /// references to each other, and both are owned by this type.
351    #[inline]
352    pub fn access_handler_mut<'s, R>(
353        &'s mut self,
354        access: impl for<'a> FnOnce(&'s mut <H as HostHandlers>::MainThread<'a>) -> R,
355    ) -> R {
356        // SAFETY: we take &mut self, the only reference to the wrapper on the main thread, therefore
357        // we can guarantee there are no mutable reference anywhere
358        unsafe { access(self.inner.wrapper().main_thread().as_mut()) }
359    }
360
361    /// Returns a thread-safe handle to the plugin.
362    ///
363    /// Unlike the [`PluginMainThreadHandle`] returned by [`plugin_handle`](Self::plugin_handle),
364    /// this handle can be cloned and sent to other threads.
365    ///
366    /// However, it has fewer capabilities, and cannot be used for operations that have to be
367    /// performed on the main-thread (e.g. GUI).
368    #[inline]
369    pub fn plugin_shared_handle(&self) -> PluginSharedHandle<'_> {
370        self.inner.plugin_shared()
371    }
372
373    /// Returns a main-thread handle to the plugin.
374    #[inline]
375    pub fn plugin_handle(&mut self) -> PluginMainThreadHandle<'_> {
376        // SAFETY: this type can only exist on the main thread.
377        unsafe { PluginMainThreadHandle::new(self.inner.raw_instance().into()) }
378    }
379
380    /// Returns a main-thread handle to the plugin, that can only exist while the plugin is in the 'inactive' state.
381    ///
382    /// Calling this method also prevents the plugin instance to be activated as long as the handle exists.
383    ///
384    /// If the plugin is actually activated, this returns `None`.
385    #[inline]
386    pub fn inactive_plugin_handle(&mut self) -> Option<InactivePluginMainThreadHandle<'_>> {
387        if self.inner.is_active() {
388            return None;
389        }
390
391        // SAFETY: this type can only exist on the main thread.
392        // We also checked above that the plugin isn't in the active state, and the handle keeps
393        // this instance mutably borrowed, so it is not possible to activate the plugin while the
394        // handle still exists.
395        Some(unsafe { InactivePluginMainThreadHandle::new(self.inner.raw_instance().into()) })
396    }
397}
398
399impl<H: HostHandlers> Drop for PluginInstance<H> {
400    fn drop(&mut self) {
401        // Only drop our Arc if we are the sole owner.
402        // This leaks the plugin instance, but prevents accidentally transferring ownership to the
403        // audio thread if the audio processor handle is still around somewhere.
404        if Arc::get_mut(&mut self.inner).is_some() {
405            // SAFETY: We can only call this once (as we're in Drop), and we never use the inner
406            // value again afterward.
407            unsafe { ManuallyDrop::drop(&mut self.inner) }
408        };
409    }
410}
411
412#[cfg(test)]
413mod test {
414    extern crate static_assertions as sa;
415    use super::*;
416
417    sa::assert_not_impl_any!(PluginInstance<()>: Send, Sync);
418}