Skip to content

Commit fb332bc

Browse files
committed
Polish
1 parent a8cf785 commit fb332bc

File tree

2 files changed

+64
-31
lines changed

2 files changed

+64
-31
lines changed

docs/src/contrib/controller.md

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,14 @@ impl ControlledProcessorTrait for VolumeProcessor {
6262
channels: &mut ProcessorChannels<Self::Command, Self::Notification>,
6363
) -> jack::Control {
6464
// Handle incoming commands
65-
while let Ok(cmd) = channels.commands.pop() {
66-
match cmd {
67-
Command::SetVolume(v) => {
68-
self.volume = v;
69-
let _ = channels.notifications.push(Notification::VolumeChanged(v));
70-
}
71-
Command::Mute => self.muted = true,
72-
Command::Unmute => self.muted = false,
65+
channels.drain_commands(|cmd| match cmd {
66+
Command::SetVolume(v) => {
67+
self.volume = v;
68+
channels.try_notify(Notification::VolumeChanged(v));
7369
}
74-
}
70+
Command::Mute => self.muted = true,
71+
Command::Unmute => self.muted = false,
72+
});
7573

7674
// Process audio
7775
let input = self.input.as_slice(scope);
@@ -113,15 +111,13 @@ let (processor_instance, handle) = processor.instance(16, 16);
113111
let active_client = client.activate_async((), processor_instance).unwrap();
114112

115113
// Now you can control the processor from any thread
116-
handle.commands.push(Command::SetVolume(0.5)).unwrap();
114+
handle.send_command(Command::SetVolume(0.5)).unwrap();
117115

118116
// And receive notifications
119-
while let Ok(notification) = handle.notifications.pop() {
120-
match notification {
121-
Notification::ClippingDetected => println!("Clipping detected!"),
122-
Notification::VolumeChanged(v) => println!("Volume changed to {}", v),
123-
}
124-
}
117+
handle.drain_notifications(|notification| match notification {
118+
Notification::ClippingDetected => println!("Clipping detected!"),
119+
Notification::VolumeChanged(v) => println!("Volume changed to {}", v),
120+
});
125121
```
126122

127123
## Channel Capacities

src/contrib/controller.rs

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,53 @@ use crate::{
88

99
/// Communication channels available to a processor in the real-time audio thread.
1010
pub struct ProcessorChannels<Command, Notification> {
11-
/// Send notifications from the processor to the controller.
12-
pub notifications: Producer<Notification>,
13-
/// Receive commands from the controller.
14-
pub commands: Consumer<Command>,
11+
notifications: Producer<Notification>,
12+
commands: Consumer<Command>,
13+
}
14+
15+
impl<Command, Notification> ProcessorChannels<Command, Notification> {
16+
/// Drain and process all pending commands.
17+
pub fn drain_commands(&mut self, mut f: impl FnMut(Command)) {
18+
while let Ok(cmd) = self.commands.pop() {
19+
f(cmd);
20+
}
21+
}
22+
23+
/// Try to send a notification, ignoring if the buffer is full.
24+
///
25+
/// Returns `true` if the notification was sent, `false` if the buffer was full.
26+
pub fn try_notify(&mut self, notification: Notification) -> bool {
27+
self.notifications.push(notification).is_ok()
28+
}
1529
}
1630

1731
/// Handle for controlling a processor from outside the real-time audio thread.
18-
pub struct ProcessorHandle<Command, Notification> {
19-
/// Receive notifications from the processor.
20-
pub notifications: Consumer<Notification>,
21-
/// Send commands to the processor.
22-
pub commands: Producer<Command>,
32+
pub struct Controller<Command, Notification> {
33+
notifications: Consumer<Notification>,
34+
commands: Producer<Command>,
35+
}
36+
37+
impl<Command, Notification> Controller<Command, Notification> {
38+
/// Try to send a command to the processor.
39+
///
40+
/// Returns `Ok(())` if the command was sent, or `Err(command)` if the buffer was full.
41+
pub fn send_command(&mut self, command: Command) -> Result<(), Command> {
42+
self.commands.push(command).map_err(|e| e.into_inner())
43+
}
44+
45+
/// Try to receive a notification from the processor.
46+
///
47+
/// Returns `Some(notification)` if one was available, or `None` if the buffer was empty.
48+
pub fn recv_notification(&mut self) -> Option<Notification> {
49+
self.notifications.pop().ok()
50+
}
51+
52+
/// Drain and process all pending notifications.
53+
pub fn drain_notifications(&mut self, mut f: impl FnMut(Notification)) {
54+
while let Ok(notification) = self.notifications.pop() {
55+
f(notification);
56+
}
57+
}
2358
}
2459

2560
/// A JACK processor that can be controlled via lock-free channels.
@@ -63,18 +98,19 @@ pub trait ControlledProcessorTrait: Send + Sized {
6398
) -> Control;
6499

65100
/// Create a processor instance and its control handle with the given channel capacities.
101+
#[must_use = "the processor instance must be used with Client::activate"]
66102
fn instance(
67103
self,
68104
notification_channel_size: usize,
69105
command_channel_size: usize,
70106
) -> (
71107
ControlledProcessorInstance<Self>,
72-
ProcessorHandle<Self::Command, Self::Notification>,
108+
Controller<Self::Command, Self::Notification>,
73109
) {
74110
let (notifications, notifications_other) =
75111
RingBuffer::<Self::Notification>::new(notification_channel_size);
76112
let (commands_other, commands) = RingBuffer::<Self::Command>::new(command_channel_size);
77-
let handle = ProcessorHandle {
113+
let controller = Controller {
78114
notifications: notifications_other,
79115
commands: commands_other,
80116
};
@@ -85,15 +121,16 @@ pub trait ControlledProcessorTrait: Send + Sized {
85121
commands,
86122
},
87123
};
88-
(processor, handle)
124+
(processor, controller)
89125
}
90126
}
91127

92128
/// A [`ProcessHandler`] wrapper that provides channel-based communication.
93129
///
94130
/// Created via [`ControlledProcessorTrait::instance`].
95131
pub struct ControlledProcessorInstance<T: ControlledProcessorTrait> {
96-
inner: T,
132+
/// The inner processor implementation.
133+
pub inner: T,
97134
channels: ProcessorChannels<T::Command, T::Notification>,
98135
}
99136

@@ -111,8 +148,8 @@ impl<T: ControlledProcessorTrait> ProcessHandler for ControlledProcessorInstance
111148
fn sync(
112149
&mut self,
113150
client: &Client,
114-
state: crate::TransportState,
115-
pos: &crate::TransportPosition,
151+
state: TransportState,
152+
pos: &TransportPosition,
116153
) -> bool {
117154
self.inner.sync(client, state, pos, &mut self.channels)
118155
}

0 commit comments

Comments
 (0)