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}