aboutsummaryrefslogtreecommitdiff
path: root/pulse
diff options
context:
space:
mode:
authorAndreas Grois <andi@grois.info>2021-05-02 19:37:40 +0200
committerAndreas Grois <andi@grois.info>2021-05-02 19:37:40 +0200
commit2664e8443069fb25cd31afdef1e55bc18f052bfe (patch)
treeeb5525c8f2ffe7f496728586bf95b1be4ace69da /pulse
parente1f0525e4e1dcf674aa7489042a06b7c7d671a2a (diff)
Create a pulse context. Seems to be working.
Diffstat (limited to 'pulse')
-rw-r--r--pulse/Cargo.toml1
-rw-r--r--pulse/src/runnable/pulse.rs78
2 files changed, 73 insertions, 6 deletions
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;
+}