streamduck_core/
lib.rs

1#![deny(missing_docs)]
2//! Crate responsible for managing streamdeck devices, rendering, managing configuration and pretty much everything
3
4/// Utility code for rendering and conversions
5pub mod util;
6/// Core object and button definitions
7pub mod core;
8/// Font related code
9pub mod font;
10/// Module definition and built-in modules
11pub mod modules;
12/// Everything related to image processing
13pub mod images;
14
15pub mod versions;
16pub mod config;
17pub mod socket;
18pub mod thread;
19
20pub use streamdeck;
21pub use hidapi;
22pub use palette;
23pub use image;
24pub use async_trait::async_trait;
25pub use async_recursion::async_recursion;
26
27use std::sync::Arc;
28use hidapi::HidApi;
29use streamdeck::pids;
30use streamdeck::StreamDeck;
31use crate::config::{Config, UniqueDeviceConfig};
32use crate::core::{SDCore};
33use crate::modules::ModuleManager;
34use thread::ImageCollection;
35use crate::socket::SocketManager;
36use crate::thread::rendering::custom::RenderingManager;
37
38#[macro_use] extern crate async_trait;
39
40/// Attempts to connect to any detected streamdeck
41pub async fn connect_any(module_manager: Arc<ModuleManager>, render_manager: Arc<RenderingManager>, socket_manager: Arc<SocketManager>, config: Arc<Config>, device_config: UniqueDeviceConfig, image_collection: ImageCollection, hid: &HidApi, frame_rate: u32) -> Result<Arc<SDCore>, Error> {
42    Ok(SDCore::new(module_manager, render_manager, socket_manager, config, device_config, image_collection, attempt_connection_to_any(hid)?, frame_rate).await)
43}
44
45fn attempt_connection_to_any(hid: &HidApi) -> Result<StreamDeck, Error> {
46    let mut decks = find_decks(hid);
47
48    if let Some((vid, pid, serial)) = decks.pop() {
49        match StreamDeck::connect_with_hid(&hid, vid, pid, serial) {
50            Ok(streamdeck) => Ok(streamdeck),
51            Err(err) => Err(Error::StreamDeckError(err))
52        }
53    } else {
54        Err(Error::DeviceNotFound)
55    }
56}
57
58/// Attempts to connect to specified device as a streamdeck
59pub async fn connect(module_manager: Arc<ModuleManager>, render_manager: Arc<RenderingManager>, socket_manager: Arc<SocketManager>, config: Arc<Config>, device_config: UniqueDeviceConfig, image_collection: ImageCollection, hid: &HidApi, vid: u16, pid: u16, serial: &str, frame_rate: u32) -> Result<Arc<SDCore>, Error> {
60    Ok(SDCore::new(module_manager, render_manager, socket_manager, config, device_config, image_collection, attempt_connection(hid, vid, pid, serial)?, frame_rate).await)
61}
62
63fn attempt_connection(hid: &HidApi, vid: u16, pid: u16, serial: &str) -> Result<StreamDeck, Error> {
64    match StreamDeck::connect_with_hid(&hid, vid, pid, Some(serial.to_string())) {
65        Ok(streamdeck) => Ok(streamdeck),
66        Err(err) => Err(Error::StreamDeckError(err))
67    }
68}
69
70/// Retrieves a list of found streamdeck devices
71pub fn find_decks(hid: &HidApi) -> Vec<(u16, u16, Option<String>)> {
72    let devices = hid
73        .device_list()
74        .filter(|item| check_if_streamdeck(item.product_id()));
75
76    devices.map(
77        |d| (
78            d.vendor_id(),
79            d.product_id(),
80            d.serial_number().map(|f| f.to_string())
81        ))
82        .filter(|(_, _, s)| {
83            if let Some(s) = s {
84                return s.chars().all(|c| char::is_ascii_alphanumeric(&c));
85            }
86
87            false
88        })
89        .collect()
90}
91
92/// Checks if PID of the device matches streamdeck
93pub fn check_if_streamdeck(product_id: u16) -> bool {
94    match product_id {
95        pids::MINI | pids::ORIGINAL | pids::ORIGINAL_V2 | pids::XL | pids::MK2 => true,
96        _ => false,
97    }
98}
99
100/// Error type for streamdeck connections
101#[derive(Debug)]
102pub enum Error {
103    /// Couldn't find the device while establishing connection to any streamdeck
104    DeviceNotFound,
105    /// Any error of the under laying streamdeck library
106    StreamDeckError(streamdeck::Error)
107}