diff options
| author | Andreas Grois <andi@grois.info> | 2021-05-02 19:37:40 +0200 |
|---|---|---|
| committer | Andreas Grois <andi@grois.info> | 2021-05-02 19:37:40 +0200 |
| commit | 2664e8443069fb25cd31afdef1e55bc18f052bfe (patch) | |
| tree | eb5525c8f2ffe7f496728586bf95b1be4ace69da | |
| parent | e1f0525e4e1dcf674aa7489042a06b7c7d671a2a (diff) | |
Create a pulse context. Seems to be working.
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | pulse/Cargo.toml | 1 | ||||
| -rw-r--r-- | pulse/src/runnable/pulse.rs | 78 | ||||
| -rw-r--r-- | testconfig | 24 |
4 files changed, 96 insertions, 8 deletions
@@ -536,6 +536,7 @@ name = "swaystatus-pulse" version = "0.1.0" dependencies = [ "erased-serde", + "libc", "serde", "swaystatus-plugin", ] diff --git a/pulse/Cargo.toml b/pulse/Cargo.toml index 9aa4520..f1d8925 100644 --- a/pulse/Cargo.toml +++ b/pulse/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" swaystatus-plugin = { path = '../swaystatus-plugin', version = '*'} serde = { version = "1.0", features = ["derive"] } erased-serde = "0.3" +libc = "0.2.0" [lib] crate-type = ["cdylib"] diff --git a/pulse/src/runnable/pulse.rs b/pulse/src/runnable/pulse.rs index 388617f..a28c073 100644 --- a/pulse/src/runnable/pulse.rs +++ b/pulse/src/runnable/pulse.rs @@ -2,13 +2,19 @@ //! It is the only place in this plugin that explicitly includes unsafe code. use std::sync::{Arc, Weak}; +use std::ffi::{c_void, CString}; +use libc::{c_int, size_t}; +use std::os::raw::c_char; + use crate::config::Sink; use std::marker::PhantomData; pub(super) struct Pulse { main_loop : Arc<PulseMainLoop>, //Beware: Never ever clone this except for PulseWakeUp! + context : *mut PaContext, + + sink_name : Option<String>, //if None, still waiting for default sink name to become known. - //Pulse is _definitely_ not sync. It is supposed to be Send though. marker : PhantomData<std::cell::RefCell<i8>> } @@ -19,16 +25,41 @@ unsafe impl Send for Pulse {} impl Pulse { pub fn init(config : &Sink) -> Self { + let main_loop = Arc::new(PulseMainLoop::new()); + let context = if main_loop.is_valid() { + let api = main_loop.get_api(); + if !api.is_null() { + let plugin_name = CString::new("Swaystatus Pulse Plugin").expect("Pulse context name couldn't be set"); + unsafe { pa_context_new(api, plugin_name.as_ptr()) } + } + else { + std::ptr::null_mut() + } + } + else { + std::ptr::null_mut() + }; + //TODO:Use the sink parameter. Pulse { - //TODO: Initialize main_loop on the pulse-side. - main_loop : Arc::new(PulseMainLoop {}), + main_loop, + context, + sink_name : None, marker :PhantomData } } pub fn get_wake_up(&self) -> PulseWakeUp { PulseWakeUp { main_loop : Arc::downgrade(&self.main_loop) } } + pub fn is_valid(&self) -> bool { + self.main_loop.is_valid() && !self.context.is_null() + } +} + +impl Drop for Pulse { + fn drop(&mut self) { + //TODO! Clean up the context. + } } /// Helper to wake up the Pulseaudio main loop. @@ -65,16 +96,51 @@ impl std::fmt::Display for PulseWakeUpError { } struct PulseMainLoop { - //TODO + main_loop : *mut PaMainloop, } impl PulseMainLoop { //this is intentionally all private. Nobody outside this module should call anything on this. fn awaken(&self) { - //TODO! + if !self.main_loop.is_null() { + unsafe { pa_mainloop_wakeup(self.main_loop); } + } + } + fn new() -> Self { + unsafe { + let pointer = pa_mainloop_new(); + Self { main_loop : pointer } + } + } + fn is_valid(&self) -> bool { + !self.main_loop.is_null() + } + fn get_api(&self) -> *mut PaMainloopApi { + assert!(self.is_valid()); + unsafe { pa_mainloop_get_api(self.main_loop) } } } impl Drop for PulseMainLoop { fn drop(&mut self) { - //TODO: if this gets dropped, free the pulse main loop. + if !self.main_loop.is_null() { + unsafe { pa_mainloop_free(self.main_loop); } + } + self.main_loop = std::ptr::null_mut(); } } + +#[repr(C)] struct PaMainloop { _private: [u8; 0] } +#[repr(C)] struct PaContext { _private: [u8; 0] } + +///While we could in theory wrap the whole API, there's no need for it. We can treat it as an +///opaque type, because we never call any functions on it. +#[repr(C)] struct PaMainloopApi { _private: [u8; 0] } + +#[link(name = "pulse")] +extern { + fn pa_mainloop_new() -> *mut PaMainloop; + fn pa_mainloop_wakeup(_ : *mut PaMainloop); + fn pa_mainloop_free(_ : *mut PaMainloop); + + fn pa_mainloop_get_api(_ : *mut PaMainloop) -> *mut PaMainloopApi; + fn pa_context_new(_ : *mut PaMainloopApi, name :*const c_char) -> *mut PaContext; +} @@ -5,8 +5,28 @@ separator = ", " Plugin = "ClockPlugin" [Element.Config] -Format = "%+" +Format = "%R" [Element.Config.RefreshRate] Synchronization = "UtcSynchronized" -PerThirtyMinutes = 1800 +PerThirtyMinutes = 1800 + +[Element.General] +BeforeText = "" +AfterText = "" + +[[Element]] +Plugin = "PulseVolume" +[Element.Config.Sink] +Sink = "Default" + +[Element.Config.Volume] +Format = "Numeric" +label = "" + +[Element.Config.Balance] +Format = "Off" + +[Element.General] +BeforeText = "" +AfterText = "" |
