elgato_streamdeck/
asynchronous.rs1use std::iter::zip;
5use std::sync::Arc;
6use std::time::Duration;
7
8use hidapi::{HidApi, HidResult};
9use image::DynamicImage;
10use tokio::sync::Mutex;
11use tokio::task::block_in_place;
12use tokio::time::sleep;
13
14use crate::{DeviceState, DeviceStateUpdate, Kind, list_devices, StreamDeck, StreamDeckError, StreamDeckInput};
15use crate::images::{convert_image_async, ImageRect};
16
17pub fn refresh_device_list_async(hidapi: &mut HidApi) -> HidResult<()> {
19 block_in_place(move || hidapi.refresh_devices())
20}
21
22pub fn list_devices_async(hidapi: &HidApi) -> Vec<(Kind, String)> {
27 block_in_place(move || list_devices(&hidapi))
28}
29
30#[derive(Clone)]
33pub struct AsyncStreamDeck {
34 kind: Kind,
35 device: Arc<Mutex<StreamDeck>>,
36}
37
38impl AsyncStreamDeck {
40 pub fn connect(hidapi: &HidApi, kind: Kind, serial: &str) -> Result<AsyncStreamDeck, StreamDeckError> {
42 let device = block_in_place(move || StreamDeck::connect(hidapi, kind, serial))?;
43
44 Ok(AsyncStreamDeck {
45 kind,
46 device: Arc::new(Mutex::new(device)),
47 })
48 }
49}
50
51impl AsyncStreamDeck {
53 pub fn kind(&self) -> Kind {
55 self.kind
56 }
57
58 pub async fn manufacturer(&self) -> Result<String, StreamDeckError> {
60 let device = self.device.lock().await;
61 Ok(block_in_place(move || device.manufacturer())?)
62 }
63
64 pub async fn product(&self) -> Result<String, StreamDeckError> {
66 let device = self.device.lock().await;
67 Ok(block_in_place(move || device.product())?)
68 }
69
70 pub async fn serial_number(&self) -> Result<String, StreamDeckError> {
72 let device = self.device.lock().await;
73 Ok(block_in_place(move || device.serial_number())?)
74 }
75
76 pub async fn firmware_version(&self) -> Result<String, StreamDeckError> {
78 let device = self.device.lock().await;
79 Ok(block_in_place(move || device.firmware_version())?)
80 }
81
82 pub async fn read_input(&self, poll_rate: f32) -> Result<StreamDeckInput, StreamDeckError> {
85 loop {
86 let device = self.device.lock().await;
87 let data = block_in_place(move || device.read_input(None))?;
88
89 if !data.is_empty() {
90 return Ok(data);
91 }
92
93 sleep(Duration::from_secs_f32(1.0 / poll_rate)).await;
94 }
95 }
96
97 pub async fn reset(&self) -> Result<(), StreamDeckError> {
99 let device = self.device.lock().await;
100 Ok(block_in_place(move || device.reset())?)
101 }
102
103 pub async fn set_brightness(&self, percent: u8) -> Result<(), StreamDeckError> {
105 let device = self.device.lock().await;
106 Ok(block_in_place(move || device.set_brightness(percent))?)
107 }
108
109 pub async fn write_image(&self, key: u8, image_data: &[u8]) -> Result<(), StreamDeckError> {
112 let device = self.device.lock().await;
113 Ok(block_in_place(move || device.write_image(key, image_data))?)
114 }
115
116 pub async fn write_lcd(&self, x: u16, y: u16, rect: &ImageRect) -> Result<(), StreamDeckError> {
119 let device = self.device.lock().await;
120 Ok(block_in_place(move || device.write_lcd(x, y, rect))?)
121 }
122
123 pub async fn write_lcd_fill(&self, image_data: &[u8]) -> Result<(), StreamDeckError> {
132 let device = self.device.lock().await;
133 Ok(block_in_place(move || device.write_lcd_fill(image_data))?)
134 }
135
136 pub async fn clear_button_image(&self, key: u8) -> Result<(), StreamDeckError> {
139 let device = self.device.lock().await;
140 Ok(block_in_place(move || device.clear_button_image(key))?)
141 }
142
143 pub async fn clear_all_button_images(&self) -> Result<(), StreamDeckError> {
146 let device = self.device.lock().await;
147 Ok(block_in_place(move || device.clear_all_button_images())?)
148 }
149
150 pub async fn set_button_image(&self, key: u8, image: DynamicImage) -> Result<(), StreamDeckError> {
153 let image = convert_image_async(self.kind, image)?;
154
155 let device = self.device.lock().await;
156 Ok(block_in_place(move || device.write_image(key, &image))?)
157 }
158
159 pub async fn set_logo_image(&self, image: DynamicImage) -> Result<(), StreamDeckError> {
161 let device = self.device.lock().await;
162 Ok(block_in_place(move || device.set_logo_image(image))?)
163 }
164
165 pub async fn set_touchpoint_color(&self, point: u8, red: u8, green: u8, blue: u8) -> Result<(), StreamDeckError> {
167 let device = self.device.lock().await;
168 Ok(block_in_place(move || device.set_touchpoint_color(point, red, green, blue))?)
169 }
170
171 pub async fn sleep(&self) -> Result<(), StreamDeckError> {
173 let device = self.device.lock().await;
174 Ok(block_in_place(move || device.sleep())?)
175 }
176
177 pub async fn keep_alive(&self) -> Result<(), StreamDeckError> {
179 let device = self.device.lock().await;
180 Ok(block_in_place(move || device.keep_alive())?)
181 }
182
183 pub async fn shutdown(&self) -> Result<(), StreamDeckError> {
185 let device = self.device.lock().await;
186 Ok(block_in_place(move || device.shutdown())?)
187 }
188
189 pub async fn flush(&self) -> Result<(), StreamDeckError> {
191 let device = self.device.lock().await;
192 Ok(block_in_place(move || device.flush())?)
193 }
194
195 pub fn get_reader(&self) -> Arc<AsyncDeviceStateReader> {
197 Arc::new(AsyncDeviceStateReader {
198 device: self.clone(),
199 states: Mutex::new(DeviceState {
200 buttons: vec![false; self.kind.key_count() as usize + self.kind.touchpoint_count() as usize],
201 encoders: vec![false; self.kind.encoder_count() as usize],
202 }),
203 })
204 }
205}
206
207pub struct AsyncDeviceStateReader {
209 device: AsyncStreamDeck,
210 states: Mutex<DeviceState>,
211}
212
213impl AsyncDeviceStateReader {
214 pub async fn read(&self, poll_rate: f32) -> Result<Vec<DeviceStateUpdate>, StreamDeckError> {
216 let input = self.device.read_input(poll_rate).await?;
217 let mut my_states = self.states.lock().await;
218
219 let mut updates = vec![];
220
221 match input {
222 StreamDeckInput::ButtonStateChange(buttons) => {
223 for (index, (their, mine)) in zip(buttons.iter(), my_states.buttons.iter()).enumerate() {
224 match self.device.kind {
225 Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
226 if *their {
227 updates.push(DeviceStateUpdate::ButtonDown(index as u8));
228 updates.push(DeviceStateUpdate::ButtonUp(index as u8));
229 }
230 }
231 _ => {
232 if *their != *mine {
233 if index < self.device.kind.key_count() as usize {
234 if *their {
235 updates.push(DeviceStateUpdate::ButtonDown(index as u8));
236 } else {
237 updates.push(DeviceStateUpdate::ButtonUp(index as u8));
238 }
239 } else {
240 if *their {
241 updates.push(DeviceStateUpdate::TouchPointDown(index as u8 - self.device.kind.key_count()));
242 } else {
243 updates.push(DeviceStateUpdate::TouchPointUp(index as u8 - self.device.kind.key_count()));
244 }
245 }
246 }
247 }
248 }
249 }
250
251 my_states.buttons = buttons;
252 }
253
254 StreamDeckInput::EncoderStateChange(encoders) => {
255 for (index, (their, mine)) in zip(encoders.iter(), my_states.encoders.iter()).enumerate() {
256 if *their != *mine {
257 if *their {
258 updates.push(DeviceStateUpdate::EncoderDown(index as u8));
259 } else {
260 updates.push(DeviceStateUpdate::EncoderUp(index as u8));
261 }
262 }
263 }
264
265 my_states.encoders = encoders;
266 }
267
268 StreamDeckInput::EncoderTwist(twist) => {
269 for (index, change) in twist.iter().enumerate() {
270 if *change != 0 {
271 updates.push(DeviceStateUpdate::EncoderTwist(index as u8, *change));
272 }
273 }
274 }
275
276 StreamDeckInput::TouchScreenPress(x, y) => {
277 updates.push(DeviceStateUpdate::TouchScreenPress(x, y));
278 }
279
280 StreamDeckInput::TouchScreenLongPress(x, y) => {
281 updates.push(DeviceStateUpdate::TouchScreenLongPress(x, y));
282 }
283
284 StreamDeckInput::TouchScreenSwipe(s, e) => {
285 updates.push(DeviceStateUpdate::TouchScreenSwipe(s, e));
286 }
287
288 _ => {}
289 }
290
291 drop(my_states);
292
293 Ok(updates)
294 }
295}