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(&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 ///
150 /// # Panics
151 ///
152 /// This function will panic if either `min_frames_count` or `max_frames_count` is 0, or if
153 /// `min_frames_count` is greater than `max_frames_count`.
154 pub fn activate<FA>(
155 &mut self,
156 audio_processor: FA,
157 configuration: PluginAudioConfiguration,
158 ) -> Result<StoppedPluginAudioProcessor<H>, PluginInstanceError>
159 where
160 FA: for<'a> FnOnce(
161 &'a <H as HostHandlers>::Shared<'a>,
162 &<H as HostHandlers>::MainThread<'a>,
163 ) -> <H as HostHandlers>::AudioProcessor<'a>,
164 {
165 configuration.validate();
166 let wrapper =
167 Arc::get_mut(&mut self.inner).ok_or(PluginInstanceError::AlreadyActivatedPlugin)?;
168 wrapper.activate(audio_processor, configuration)?;
169
170 Ok(StoppedPluginAudioProcessor::new(Arc::clone(&self.inner)))
171 }
172
173 /// De-activates the plugin instance, freeing its processing-related resources, and allows it
174 /// to be re-[activated](Self::activate) with a different audio configuration.
175 ///
176 /// This consumes the [`StoppedPluginAudioProcessor`] handle created by [`activate`](Self::activate),
177 /// in order to ensure it cannot be used anymore.
178 ///
179 /// For a version of this method that does not require the [`StoppedPluginAudioProcessor`] handle,
180 /// see [`try_deactivate`](Self::try_deactivate).
181 ///
182 /// # Panics
183 ///
184 /// This will panic if the provided `processor` handle did not come from this plugin instance.
185 #[inline]
186 pub fn deactivate(&mut self, processor: StoppedPluginAudioProcessor<H>) {
187 self.deactivate_with(processor, |_, _| ())
188 }
189
190 /// Attempts to de-activate a plugin instance, which [`PluginAudioProcessor`] handle has been
191 /// dropped.
192 ///
193 /// This is an alternative to [`deactivate`](Self::deactivate) which does not require the associated
194 /// [`PluginAudioProcessorHandle`] to be passed. However, this method is fallible, and will
195 /// return an error if the [`PluginAudioProcessorHandle`] has not been dropped.
196 ///
197 /// This may be useful if it is more practical for you to drop the [`PluginAudioProcessorHandle`]
198 /// (e.g. in another thread) compared to sending it back to the main thread to use with
199 /// [`deactivate`](Self::deactivate).
200 ///
201 /// However, if you can easily access or retrieve [`PluginAudioProcessorHandle`] back to the main
202 /// thread, you should use [`deactivate`](Self::deactivate) instead.
203 ///
204 /// # Errors
205 ///
206 /// This method will return [`PluginInstanceError::StillActivatedPlugin`] if the associated
207 /// [`PluginAudioProcessorHandle`] has not been dropped.
208 #[inline]
209 pub fn try_deactivate(&mut self) -> Result<(), PluginInstanceError> {
210 self.try_deactivate_with(|_, _| ())
211 }
212
213 /// De-activates the plugin instance, freeing its processing-related resources, and allows it
214 /// to be re-[activated](Self::activate) with a different audio configuration.
215 ///
216 /// This consumes the [`StoppedPluginAudioProcessor`] handle created by [`activate`](Self::activate),
217 /// in order to ensure it cannot be used anymore.
218 ///
219 /// This is equivalent to [`Self::deactivate`], except this method also takes a closure type `D`,
220 /// which allows to customize the destruction process of the [`AudioProcessor`](HostHandlers::AudioProcessor) callback
221 /// handler instance that was created during [`activate`](Self::activate).
222 ///
223 /// This may be useful to e.g. reuse or reprocess components or allocations the [`AudioProcessor`](HostHandlers::AudioProcessor) callback
224 /// handler instance owned, either by giving it to the [`MainThread`](HostHandlers::MainThread) handler
225 /// (which is also provided by a temporary, exclusive reference), or by returning it.
226 ///
227 /// This function will return whatever the destructor closure returned.
228 ///
229 /// # Panics
230 ///
231 /// This will panic if the provided `processor` handle did not come from this plugin instance.
232 pub fn deactivate_with<T, D>(
233 &mut self,
234 processor: StoppedPluginAudioProcessor<H>,
235 drop_with: D,
236 ) -> T
237 where
238 D: for<'s> FnOnce(
239 <H as HostHandlers>::AudioProcessor<'s>,
240 &<H as HostHandlers>::MainThread<'s>,
241 ) -> T,
242 {
243 if !Arc::ptr_eq(&self.inner, &processor.inner) {
244 panic!("Given plugin audio processor does not match the instance being deactivated")
245 }
246
247 drop(processor);
248
249 // PANIC: we dropped the only processor produced, and checked if it matched
250 self.try_deactivate_with(drop_with).unwrap()
251 }
252
253 /// Attempts to de-activate a plugin instance, which [`PluginAudioProcessor`] handle has been
254 /// dropped.
255 ///
256 /// This is equivalent to [`Self::try_deactivate`], except this method also takes a closure type `D`,
257 /// which allows to customize the destruction process of the [`AudioProcessor`](HostHandlers::AudioProcessor) callback
258 /// handler instance that was created during [`activate`](Self::activate).
259 ///
260 /// This is an alternative to [`deactivate_with`](Self::deactivate_with) which does not require the associated
261 /// [`PluginAudioProcessorHandle`] to be passed. However, this method is fallible, and will
262 /// return an error if the [`PluginAudioProcessorHandle`] has not been dropped.
263 ///
264 /// This may be useful if it is more practical for you to drop the [`PluginAudioProcessorHandle`]
265 /// (e.g. in another thread) compared to sending it back to the main thread to use with
266 /// [`deactivate_with`](Self::deactivate_with).
267 ///
268 /// However, if you can easily access or retrieve [`PluginAudioProcessorHandle`] back to the main
269 /// thread, you should use [`deactivate_with`](Self::deactivate_with) instead.
270 ///
271 /// # Errors
272 ///
273 /// This method will return [`PluginInstanceError::StillActivatedPlugin`] if the associated
274 /// [`PluginAudioProcessorHandle`] has not been dropped.
275 pub fn try_deactivate_with<T, D>(&mut self, drop_with: D) -> Result<T, PluginInstanceError>
276 where
277 D: for<'s> FnOnce(
278 <H as HostHandlers>::AudioProcessor<'s>,
279 &<H as HostHandlers>::MainThread<'s>,
280 ) -> T,
281 {
282 let wrapper =
283 Arc::get_mut(&mut self.inner).ok_or(PluginInstanceError::StillActivatedPlugin)?;
284
285 wrapper.deactivate_with(drop_with)
286 }
287
288 /// Calls the plugin's `on_main_thread` callback.
289 ///
290 /// This is usually done in response to the plugin calling [`SharedHandler::request_callback`]
291 /// earlier from a different thread, allowing it to "wake up" its main thread after e.g. another
292 /// of the plugin's threads sent a message to it.
293 #[inline]
294 pub fn call_on_main_thread_callback(&mut self) {
295 // SAFETY: this is done on the main thread, and the &mut reference guarantees no aliasing
296 unsafe { self.inner.on_main_thread() }
297 }
298
299 /// Returns a shared, read-only reference to the raw, C-FFI compatible representation
300 /// of thsi plugin instance.
301 #[inline]
302 pub fn raw_instance(&self) -> &clap_plugin {
303 self.inner.raw_instance()
304 }
305
306 /// Returns the [`PluginEntry`] this plugin instance was loaded from.
307 #[inline]
308 pub fn entry(&self) -> &PluginEntry {
309 self.inner.entry()
310 }
311
312 /// Returns `true` if the current plugin instance has been activated.
313 #[inline]
314 pub fn is_active(&self) -> bool {
315 self.inner.is_active()
316 }
317
318 /// Access the [`SharedHandler`] instance associated to this plugin instance using the given callback.
319 ///
320 /// The callback's return value `R` is returned directly by this method.
321 ///
322 /// Accessing the [`HostHandlers`] types can only be done with accessor callbacks because this
323 /// type is self-referential: both the [`HostHandlers`] and the plugin's instance data hold
324 /// references to each other, and both are owned by this type.
325 #[inline]
326 pub fn access_shared_handler<'s, R>(
327 &'s self,
328 access: impl for<'a> FnOnce(&'s <H as HostHandlers>::Shared<'a>) -> R,
329 ) -> R {
330 access(self.inner.wrapper().shared())
331 }
332
333 /// Access a shared reference to [`MainThreadHandler`] instance associated to this plugin instance using the given callback.
334 ///
335 /// The callback's return value `R` is returned directly by this method.
336 ///
337 /// Accessing the [`HostHandlers`] types can only be done with accessor callbacks because this
338 /// type is self-referential: both the [`HostHandlers`] and the plugin's instance data hold
339 /// references to each other, and both are owned by this type.
340 #[inline]
341 pub fn access_handler<R>(
342 &self,
343 access: impl for<'a> FnOnce(&<H as HostHandlers>::MainThread<'a>) -> R,
344 ) -> R {
345 // SAFETY: This type guarantees it can only be called on the main thread
346 let Some(result) = (unsafe { self.inner.wrapper().on_main_thread(access) }) else {
347 // PANIC: main_thread can only be None if called from within init()
348 unreachable!()
349 };
350
351 result
352 }
353
354 /// Returns a thread-safe handle to the plugin.
355 ///
356 /// Unlike the [`PluginMainThreadHandle`] returned by [`plugin_handle`](Self::plugin_handle),
357 /// this handle can be cloned and sent to other threads.
358 ///
359 /// However, it has fewer capabilities, and cannot be used for operations that have to be
360 /// performed on the main-thread (e.g. GUI).
361 #[inline]
362 pub fn plugin_shared_handle(&self) -> PluginSharedHandle<'_> {
363 self.inner.plugin_shared()
364 }
365
366 /// Returns a main-thread handle to the plugin.
367 #[inline]
368 pub fn plugin_handle(&mut self) -> PluginMainThreadHandle<'_> {
369 // SAFETY: this type can only exist on the main thread.
370 unsafe { PluginMainThreadHandle::new(self.inner.raw_instance().into()) }
371 }
372
373 /// Returns a main-thread handle to the plugin, that can only exist while the plugin is in the 'inactive' state.
374 ///
375 /// Calling this method also prevents the plugin instance to be activated as long as the handle exists.
376 ///
377 /// If the plugin is actually activated, this returns `None`.
378 #[inline]
379 pub fn inactive_plugin_handle(&mut self) -> Option<InactivePluginMainThreadHandle<'_>> {
380 if self.inner.is_active() {
381 return None;
382 }
383
384 // SAFETY: this type can only exist on the main thread.
385 // We also checked above that the plugin isn't in the active state, and the handle keeps
386 // this instance mutably borrowed, so it is not possible to activate the plugin while the
387 // handle still exists.
388 Some(unsafe { InactivePluginMainThreadHandle::new(self.inner.raw_instance().into()) })
389 }
390}
391
392impl<H: HostHandlers> Drop for PluginInstance<H> {
393 fn drop(&mut self) {
394 // Only drop our Arc if we are the sole owner.
395 // This leaks the plugin instance, but prevents accidentally transferring ownership to the
396 // audio thread if the audio processor handle is still around somewhere.
397 if Arc::get_mut(&mut self.inner).is_some() {
398 // SAFETY: We can only call this once (as we're in Drop), and we never use the inner
399 // value again afterward.
400 unsafe { ManuallyDrop::drop(&mut self.inner) }
401 };
402 }
403}
404
405#[cfg(test)]
406mod test {
407 extern crate static_assertions as sa;
408 use super::*;
409
410 sa::assert_not_impl_any!(PluginInstance<()>: Send, Sync);
411}