1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Externally loaded modules
//!
//! [Plugins](Plugin) can be provided via
//! [externally loaded components](crate::core::Core::load_component).
//!
//! # Loading a Plugin
//!
//! Once a component is [loaded](crate::Core::load_component), it can be found by its plugin name:
//!
//! ```
//! use wireplumber::plugin::{Plugin, PluginFeatures};
//!
//! # #[cfg(feature = "lua")]
//! # async fn load_lua(core: wireplumber::core::Core) -> wireplumber::Result<()> {
//! core.load_component("libwireplumber-module-lua-scripting", "module", None)?;
//! core.load_lua_script("create-item.lua", ())?;
//! if let Some(p) = Plugin::find(&core, "lua-scripting") {
//!   p.activate_future(PluginFeatures::ENABLED).await?;
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # Implementing and Exporting a Plugin
//!
//! Implementing the [PluginImpl] trait enables a type to be loaded externally as a dynamic library
//! and exported to the wireplumber daemon. [SimplePlugin] is also provided as a utility to ease
//! implementation of the module entry point loader and reduce boilerplate.
//!
//! The plugin module must be compiled as a `cdylib` in your `Cargo.toml`:
//!
//! ```toml
//! [lib]
//! crate-type = ["cdylib"]
//! ```
//!
//! ```no_run
//! use wireplumber::prelude::*;
//! use wireplumber::plugin::{self, SimplePlugin, AsyncPluginImpl};
//! use wireplumber::error;
//! use std::future::Future;
//! use std::cell::RefCell;
//! use std::pin::Pin;
//!
//! const DOMAIN: &'static str = "my-plugin";
//!
//! #[derive(Debug, Default)]
//! struct MyPlugin {
//!   arg: RefCell<Option<i32>>,
//! }
//!
//! impl AsyncPluginImpl for MyPlugin {
//!   type EnableFuture = Pin<Box<dyn Future<Output=wireplumber::Result<()>>>>;
//!   fn enable(&self, this: Self::Type) -> Self::EnableFuture {
//!     let core = this.core().unwrap();
//!     Box::pin(async move {
//!       let arg = this.arg.borrow().unwrap_or_default();
//!       wireplumber::info!(domain: DOMAIN, "enabling on {core:?} with {arg}...");
//!       Ok(())
//!     })
//!   }
//!
//!   fn disable(&self) {
//!     wireplumber::info!(domain: DOMAIN, "disabling...");
//!   }
//! }
//!
//! impl SimplePlugin for MyPlugin {
//!   type Args = Option<i32>;
//!
//!   fn init_args(&self, args: Self::Args) {
//!     self.arg.replace(args);
//!   }
//!
//!   fn decode_args(args: Option<glib::Variant>) -> Result<Self::Args, error::Error> {
//!     args.map(|args| match () {
//!       #[cfg(feature = "serde")]
//!       _ => wireplumber::lua::from_variant(&args),
//!       #[cfg(not(feature = "serde"))]
//!       _ => args.try_get(),
//!     }).transpose().map_err(error::invalid_argument)
//!   }
//! }
//!
//! plugin::simple_plugin_subclass! {
//!   impl ObjectSubclass for DOMAIN as MyPlugin { }
//! }
//!
//! plugin::plugin_export!(MyPlugin);
//! ```
//!
//! The source code of the automatic [PluginImpl](PluginImpl#impl-PluginImpl) for
//! [`T: AsyncPluginImpl`](AsyncPluginImpl) can also serve as an example implementation of a plugin
//! without using async futures.
//!
//! # See also
//!
//! C API docs for:
//!
//! - [Plugin](https://pipewire.pages.freedesktop.org/wireplumber/c_api/plugin_api.html)
//! - [Component Loader](https://pipewire.pages.freedesktop.org/wireplumber/c_api/component_loader_api.html)

pub use {
	self::{
		loader::{ComponentLoaderImpl, ComponentLoaderImplExt},
		subclass::{
			plugin_export, simple_plugin_subclass, AsyncPluginExt, AsyncPluginImpl, ModuleExport, ModuleWrapper, PluginImpl,
			PluginImplExt, SimplePlugin, SimplePluginObject, SourceHandles, SourceHandlesCell,
		},
	},
	crate::auto::{traits::PluginExt, ComponentLoader, LookupDirs, Plugin, PluginFeatures},
};

mod loader;
mod subclass;