aboutsummaryrefslogtreecommitdiff
path: root/pulse/src
diff options
context:
space:
mode:
Diffstat (limited to 'pulse/src')
-rw-r--r--pulse/src/communication.rs6
-rw-r--r--pulse/src/runnable/mod.rs8
-rw-r--r--pulse/src/runnable/pulse.rs100
3 files changed, 65 insertions, 49 deletions
diff --git a/pulse/src/communication.rs b/pulse/src/communication.rs
index cfb800e..918d6c9 100644
--- a/pulse/src/communication.rs
+++ b/pulse/src/communication.rs
@@ -9,11 +9,11 @@ pub enum MessagesFromMain {
pub struct SenderForMain {
sender : Sender<MessagesFromMain>,
- pulse_waker : PulseWakeUp
+ pulse_waker : Option<PulseWakeUp>
}
impl<'p> SenderForMain {
- pub fn new(sender : Sender<MessagesFromMain>, pulse_waker : PulseWakeUp) -> Self {
+ pub fn new(sender : Sender<MessagesFromMain>, pulse_waker : Option<PulseWakeUp>) -> Self {
SenderForMain{
sender,
pulse_waker
@@ -24,7 +24,7 @@ impl<'p> SenderForMain {
if let Ok(_) = self.sender.send(message) {
//The cool thing about pulse using poll() is that poll() also wakes up if started after
//the actual wake up call. So no need to worry about races, this is inherently sane!
- self.pulse_waker.wake_up()?;
+ self.pulse_waker.as_ref().ok_or(PluginCommunicationError {})?.wake_up()?;
Ok(())
}
else {
diff --git a/pulse/src/runnable/mod.rs b/pulse/src/runnable/mod.rs
index 612bca9..149e994 100644
--- a/pulse/src/runnable/mod.rs
+++ b/pulse/src/runnable/mod.rs
@@ -4,13 +4,13 @@ use swaystatus_plugin::*;
use crate::communication::*;
pub mod pulse;
-use pulse::Pulse;
+use pulse::{Pulse,MainLoopCreationError};
pub struct PulseVolumeRunnable<'p> {
config : &'p PulseVolumeConfig,
to_main : Box<dyn MsgModuleToMain + 'p>,
from_main : Receiver<MessagesFromMain>,
- pulse : Pulse
+ pulse : Result<Pulse,MainLoopCreationError>
}
impl<'p : 's, 's> PulseVolumeRunnable<'p> {
@@ -20,9 +20,9 @@ impl<'p : 's, 's> PulseVolumeRunnable<'p> {
config,
to_main,
from_main : r,
- pulse: Pulse::init(&config.sink),
+ pulse: Pulse::create()
};
- let sender = SenderForMain::new(s, result.pulse.get_wake_up());
+ let sender = SenderForMain::new(s, result.pulse.as_ref().map_or(None,|x| Some(x.get_wake_up())));
(result, sender)
}
}
diff --git a/pulse/src/runnable/pulse.rs b/pulse/src/runnable/pulse.rs
index 1df1768..7687c86 100644
--- a/pulse/src/runnable/pulse.rs
+++ b/pulse/src/runnable/pulse.rs
@@ -6,7 +6,6 @@ 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 {
@@ -23,56 +22,67 @@ pub(super) struct Pulse {
unsafe impl Send for Pulse {}
impl Pulse {
- pub fn init(config : &Sink) -> Self {
- let main_loop = Arc::new(PulseMainLoop::new());
- //TODO:Use the sink parameter.
- Pulse {
+ pub fn create() -> Result<Self,MainLoopCreationError> {
+ let main_loop = Arc::new(PulseMainLoop::new()?);
+ Ok(Pulse {
main_loop,
_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()
- }
- pub fn create_context<'c>(&'c self) -> PulseContext<'c> {
- let context = if self.main_loop.is_valid() {
- let api = self.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()) }
+ pub fn create_context<'c>(&'c self) -> Result<PulseContext<'c>, PulseContextCreationError> {
+ let api = self.main_loop.get_api();
+ if api.is_null() {
+ Err(PulseContextCreationError::FailedToGetPulseApi)
+ }
+ else {
+ let plugin_name = CString::new("Swaystatus Pulse Plugin").expect("Pulse context name couldn't be set");
+ let context = unsafe { pa_context_new(api, plugin_name.as_ptr()) };
+ if context.is_null() {
+ Err(PulseContextCreationError::ContextNewFailed)
}
else {
- std::ptr::null_mut()
+ Ok(PulseContext { context, _marker : PhantomData })
}
}
- else {
- std::ptr::null_mut()
- };
- PulseContext { context, _marker : PhantomData }
}
}
pub struct PulseContext<'c> {
- context : *mut PaContext,
+ context : *mut PaContext, //Can actually never be null, the nullptr case is handled by create, which returns an Err instead of a PulseContext then.
_marker : PhantomData<&'c PulseMainLoop>
}
-impl<'c> PulseContext<'c> {
- pub fn is_valid(&self) -> bool {
- !self.context.is_null()
+impl<'c> Drop for PulseContext<'c> {
+ fn drop(&mut self) {
+ unsafe {pa_context_unref(self.context)}
}
}
-impl<'c> Drop for PulseContext<'c> {
- fn drop(&mut self) {
- if !self.context.is_null() {
- unsafe {pa_context_unref(self.context)}
+#[derive(Debug)]
+pub enum PulseContextCreationError {
+ SettingNameFailed,
+ FailedToGetPulseApi,
+ ContextNewFailed
+}
+impl std::fmt::Display for PulseContextCreationError {
+ fn fmt(&self, f : &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ PulseContextCreationError::SettingNameFailed => {
+ write!(f, "Pulse Context creation failed, error converting context name to C chars")
+ }
+ PulseContextCreationError::FailedToGetPulseApi => {
+ write!(f, "Pulse Context creation failed, Pulse Main Loop didn't return a valid API")
+ }
+ PulseContextCreationError::ContextNewFailed => {
+ write!(f, "Pulse Context creation failed, Pulse API didn't return a valid context")
+ }
}
}
}
+impl std::error::Error for PulseContextCreationError {}
/// Helper to wake up the Pulseaudio main loop.
/// This implements Send and Sync, because it's explicitly meant to allow cross-thread
@@ -113,36 +123,42 @@ struct PulseMainLoop {
impl PulseMainLoop {
//this is intentionally all private. Nobody outside this module should call anything on this.
fn awaken(&self) {
- if !self.main_loop.is_null() {
- unsafe { pa_mainloop_wakeup(self.main_loop); }
- }
+ unsafe { pa_mainloop_wakeup(self.main_loop); }
}
- fn new() -> Self {
+ fn new() -> Result<Self,MainLoopCreationError> {
unsafe {
let pointer = pa_mainloop_new();
- Self { main_loop : pointer }
+ if pointer.is_null() {
+ Err(MainLoopCreationError{})
+ }
+ else {
+ Ok(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) {
- if !self.main_loop.is_null() {
- unsafe {
- pa_mainloop_quit(self.main_loop, 0);
- pa_mainloop_free(self.main_loop);
- }
+ unsafe {
+ pa_mainloop_quit(self.main_loop, 0);
+ pa_mainloop_free(self.main_loop);
}
self.main_loop = std::ptr::null_mut();
}
}
+#[derive(Debug)]
+pub struct MainLoopCreationError {}
+impl std::fmt::Display for MainLoopCreationError {
+ fn fmt(&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "Failed to create Pulse Main loop, PulseAudio returned a null pointer.")
+ }
+}
+impl std::error::Error for MainLoopCreationError {}
+
#[repr(C)] struct PaMainloop { _private: [u8; 0] }
#[repr(C)] struct PaContext { _private: [u8; 0] }