feat: 支持设置音量。
This commit is contained in:
parent
9109518822
commit
2c5ac11579
123
src-tauri/Cargo.lock
generated
123
src-tauri/Cargo.lock
generated
@ -109,6 +109,26 @@ version = "0.21.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bindgen"
|
||||||
|
version = "0.64.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cexpr",
|
||||||
|
"clang-sys",
|
||||||
|
"lazy_static",
|
||||||
|
"lazycell",
|
||||||
|
"peeking_take_while",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"rustc-hash",
|
||||||
|
"shlex",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@ -231,6 +251,15 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cexpr"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||||
|
dependencies = [
|
||||||
|
"nom 7.1.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfb"
|
name = "cfb"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
@ -280,6 +309,17 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clang-sys"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cmake"
|
name = "cmake"
|
||||||
version = "0.1.50"
|
version = "0.1.50"
|
||||||
@ -414,6 +454,26 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coreaudio-rs"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb17e2d1795b1996419648915df94bc7103c28f7b48062d7acf4652fc371b2ff"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"core-foundation-sys 0.6.2",
|
||||||
|
"coreaudio-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coreaudio-sys"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f034b2258e6c4ade2f73bf87b21047567fb913ee9550837c2316d139b0262b24"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@ -734,7 +794,7 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24ce75530893d834dcfe3bb67ce0e7dec489484e7cb4423ca31618af4bab24fe"
|
checksum = "24ce75530893d834dcfe3bb67ce0e7dec489484e7cb4423ca31618af4bab24fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nom",
|
"nom 3.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1674,10 +1734,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "lazycell"
|
||||||
version = "0.2.142"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.143"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libudev-sys"
|
name = "libudev-sys"
|
||||||
@ -1831,7 +1907,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8eb961d01a3bb07969cfa276be2ab88c31d0fefa77a872696832732d6e9ec094"
|
checksum = "8eb961d01a3bb07969cfa276be2ab88c31d0fefa77a872696832732d6e9ec094"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mccs",
|
"mccs",
|
||||||
"nom",
|
"nom 3.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1841,7 +1917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "3cdaa8fe19a1a1918becc1b8cbbbdc1058bc71411dff4de0a6ec6b5269f49d38"
|
checksum = "3cdaa8fe19a1a1918becc1b8cbbbdc1058bc71411dff4de0a6ec6b5269f49d38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mccs",
|
"mccs",
|
||||||
"nom",
|
"nom 3.2.1",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
@ -1884,6 +1960,12 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@ -1955,6 +2037,16 @@ dependencies = [
|
|||||||
"memchr 1.0.2",
|
"memchr 1.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr 2.5.0",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
@ -2202,6 +2294,12 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "peeking_take_while"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
@ -2623,6 +2721,12 @@ dependencies = [
|
|||||||
"uninitialized",
|
"uninitialized",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -2863,6 +2967,12 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@ -3330,6 +3440,7 @@ dependencies = [
|
|||||||
"color_space",
|
"color_space",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
|
"coreaudio-rs",
|
||||||
"ddc-hi",
|
"ddc-hi",
|
||||||
"display-info",
|
"display-info",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
@ -36,6 +36,7 @@ tokio-stream = "0.1.14"
|
|||||||
mdns-sd = "0.7.2"
|
mdns-sd = "0.7.2"
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
ddc-hi = "0.4.1"
|
ddc-hi = "0.4.1"
|
||||||
|
coreaudio-rs = "0.11.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# this feature is used for production builds or when `devPath` points to the filesystem
|
# this feature is used for production builds or when `devPath` points to the filesystem
|
||||||
|
@ -5,8 +5,9 @@ mod ambient_light;
|
|||||||
mod display;
|
mod display;
|
||||||
mod led_color;
|
mod led_color;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
pub mod screenshot;
|
mod screenshot;
|
||||||
mod screenshot_manager;
|
mod screenshot_manager;
|
||||||
|
mod volume;
|
||||||
|
|
||||||
use ambient_light::{Border, ColorCalibration, LedStripConfig, LedStripConfigGroup};
|
use ambient_light::{Border, ColorCalibration, LedStripConfig, LedStripConfigGroup};
|
||||||
use display::{DisplayManager, DisplayState};
|
use display::{DisplayManager, DisplayState};
|
||||||
@ -18,6 +19,7 @@ use screenshot_manager::ScreenshotManager;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
use tauri::{http::ResponseBuilder, regex, Manager};
|
use tauri::{http::ResponseBuilder, regex, Manager};
|
||||||
|
use volume::VolumeManager;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "DisplayInfo")]
|
#[serde(remote = "DisplayInfo")]
|
||||||
@ -223,6 +225,8 @@ async fn main() {
|
|||||||
|
|
||||||
let _mqtt = MqttRpc::global().await;
|
let _mqtt = MqttRpc::global().await;
|
||||||
|
|
||||||
|
let _volume = VolumeManager::global().await;
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
greet,
|
greet,
|
||||||
|
@ -45,6 +45,8 @@ impl Board {
|
|||||||
let display_setting_request_sender = board_message_channels
|
let display_setting_request_sender = board_message_channels
|
||||||
.display_setting_request_sender
|
.display_setting_request_sender
|
||||||
.clone();
|
.clone();
|
||||||
|
let volume_setting_request_sender =
|
||||||
|
board_message_channels.volume_setting_request_sender.clone();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match socket.try_recv(&mut buf) {
|
match socket.try_recv(&mut buf) {
|
||||||
@ -60,6 +62,8 @@ impl Board {
|
|||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
error!("send display setting request to channel failed: {:?}", err);
|
error!("send display setting request to channel failed: {:?}", err);
|
||||||
}
|
}
|
||||||
|
} else if buf[0] == 4 {
|
||||||
|
let result = volume_setting_request_sender.send(buf[1] as f32 / 100.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
|
@ -6,6 +6,7 @@ use super::DisplaySettingRequest;
|
|||||||
|
|
||||||
pub struct BoardMessageChannels {
|
pub struct BoardMessageChannels {
|
||||||
pub display_setting_request_sender: Arc<broadcast::Sender<DisplaySettingRequest>>,
|
pub display_setting_request_sender: Arc<broadcast::Sender<DisplaySettingRequest>>,
|
||||||
|
pub volume_setting_request_sender: Arc<broadcast::Sender<f32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoardMessageChannels {
|
impl BoardMessageChannels {
|
||||||
@ -19,8 +20,12 @@ impl BoardMessageChannels {
|
|||||||
let (display_setting_request_sender, _) = broadcast::channel(16);
|
let (display_setting_request_sender, _) = broadcast::channel(16);
|
||||||
let display_setting_request_sender = Arc::new(display_setting_request_sender);
|
let display_setting_request_sender = Arc::new(display_setting_request_sender);
|
||||||
|
|
||||||
|
let (volume_setting_request_sender, _) = broadcast::channel(16);
|
||||||
|
let volume_setting_request_sender = Arc::new(volume_setting_request_sender);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
display_setting_request_sender,
|
display_setting_request_sender,
|
||||||
|
volume_setting_request_sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,9 +3,9 @@ use std::{collections::HashMap, sync::Arc, time::Duration};
|
|||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use mdns_sd::{ServiceDaemon, ServiceEvent};
|
use mdns_sd::{ServiceDaemon, ServiceEvent};
|
||||||
use paris::{error, info, warn};
|
use paris::{error, info, warn};
|
||||||
use tokio::sync::{watch, OnceCell, RwLock, broadcast};
|
use tokio::sync::{watch, OnceCell, RwLock};
|
||||||
|
|
||||||
use super::{Board, BoardInfo, DisplaySettingRequest};
|
use super::{Board, BoardInfo};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UdpRpc {
|
pub struct UdpRpc {
|
||||||
|
101
src-tauri/src/volume/manager.rs
Normal file
101
src-tauri/src/volume/manager.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
use std::{
|
||||||
|
mem,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
|
use coreaudio::{
|
||||||
|
audio_unit::macos_helpers::get_default_device_id,
|
||||||
|
sys::{
|
||||||
|
kAudioHardwareServiceDeviceProperty_VirtualMasterVolume, kAudioObjectPropertyScopeOutput,
|
||||||
|
AudioObjectHasProperty, AudioObjectPropertyAddress, AudioObjectSetPropertyData,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use paris::error;
|
||||||
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
|
use crate::rpc::BoardMessageChannels;
|
||||||
|
|
||||||
|
pub struct VolumeManager {
|
||||||
|
current_volume: Arc<RwLock<f32>>,
|
||||||
|
handler: Option<tokio::task::JoinHandle<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VolumeManager {
|
||||||
|
pub async fn global() -> &'static Self {
|
||||||
|
static VOLUME_MANAGER: OnceCell<VolumeManager> = OnceCell::const_new();
|
||||||
|
|
||||||
|
VOLUME_MANAGER
|
||||||
|
.get_or_init(|| async { Self::create() })
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create() -> Self {
|
||||||
|
let mut instance = Self {
|
||||||
|
current_volume: Arc::new(RwLock::new(0.0)),
|
||||||
|
handler: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
instance.subscribe_volume_setting_request();
|
||||||
|
|
||||||
|
instance
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subscribe_volume_setting_request(&mut self) {
|
||||||
|
let handler = tokio::spawn(async {
|
||||||
|
let channels = BoardMessageChannels::global().await;
|
||||||
|
let mut request_rx = channels.volume_setting_request_sender.subscribe();
|
||||||
|
|
||||||
|
while let Ok(volume) = request_rx.recv().await {
|
||||||
|
if let Err(err) = Self::set_volume(volume) {
|
||||||
|
error!("failed to set volume: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.handler = Some(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_volume(volume: f32) -> anyhow::Result<()> {
|
||||||
|
log::debug!("set volume: {}", volume);
|
||||||
|
|
||||||
|
let device_id = get_default_device_id(false);
|
||||||
|
|
||||||
|
if device_id.is_none() {
|
||||||
|
anyhow::bail!("default audio output device is not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let device_id = device_id.unwrap();
|
||||||
|
|
||||||
|
let address = AudioObjectPropertyAddress {
|
||||||
|
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
|
||||||
|
mScope: kAudioObjectPropertyScopeOutput,
|
||||||
|
mElement: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
log::debug!("device id: {}", device_id);
|
||||||
|
log::debug!("address: {:?}", address);
|
||||||
|
|
||||||
|
if 0 == unsafe { AudioObjectHasProperty(device_id, &address) } {
|
||||||
|
anyhow::bail!("Can not get audio property");
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = mem::size_of::<f32>() as u32;
|
||||||
|
|
||||||
|
let result = unsafe {
|
||||||
|
AudioObjectSetPropertyData(
|
||||||
|
device_id,
|
||||||
|
&address,
|
||||||
|
0,
|
||||||
|
std::ptr::null(),
|
||||||
|
size,
|
||||||
|
&volume as *const f32 as *const std::ffi::c_void,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if result != 0 {
|
||||||
|
anyhow::bail!("Can not set audio property");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
3
src-tauri/src/volume/mod.rs
Normal file
3
src-tauri/src/volume/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mod manager;
|
||||||
|
|
||||||
|
pub use manager::*;
|
Loading…
Reference in New Issue
Block a user