bt_vcs/
debug.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use bt_common::debug_command::CommandRunner;
6use bt_common::debug_command::CommandSet;
7use bt_common::gen_commandset;
8
9use parking_lot::Mutex;
10
11use crate::*;
12
13gen_commandset! {
14    VcsCmd {
15        Connect = ("connect", [], [], "Connect to VCS"),
16        Info = ("info", [], [], "Info about the current status"),
17        Up = ("up", [], [], "Volume up"),
18        Down = ("down", [], [], "Volume down"),
19        Update = ("update", [], [], "Update"),
20        Mute = ("mute", [], [], "Mute"),
21        Unmute = ("unmute", [], [], "Unmute"),
22        Set = ("set", [], ["level"], "Set the level"),
23    }
24}
25
26pub struct VcsDebug<T: bt_gatt::GattTypes> {
27    peer_client: T::Client,
28    client: Mutex<Option<Arc<VolumeControlClient<T>>>>,
29}
30
31impl<T: bt_gatt::GattTypes> VcsDebug<T> {
32    pub fn new(client: T::Client) -> Self {
33        Self { peer_client: client, client: Mutex::new(None) }
34    }
35
36    async fn connect(&self) -> Option<Arc<VolumeControlClient<T>>> {
37        let client_result = VolumeControlClient::connect(&self.peer_client).await;
38        let Ok(client) = client_result else {
39            eprintln!("Could not connect to VCS: {:?}", client_result.err());
40            return None;
41        };
42        if client.is_none() {
43            eprintln!("Found no clients or had an error connecting.");
44            return None;
45        }
46        Some(Arc::new(client.unwrap()))
47    }
48
49    fn try_client(&self) -> Option<Arc<VolumeControlClient<T>>> {
50        let lock = self.client.lock();
51        let Some(vcs_client) = lock.as_ref() else {
52            eprintln!("Client not connected, connect first");
53            return None;
54        };
55        Some(vcs_client.clone())
56    }
57}
58
59impl<T: bt_gatt::GattTypes> CommandRunner for VcsDebug<T> {
60    type Set = VcsCmd;
61
62    fn run(
63        &self,
64        cmd: Self::Set,
65        args: Vec<String>,
66    ) -> impl futures::Future<Output = Result<(), impl std::error::Error>> {
67        async move {
68            match cmd {
69                // TODO(fxbug.dev/438282674): Add a way to register for vol state changes.
70                VcsCmd::Connect => {
71                    let lock = self.client.lock();
72                    if lock.is_some() {
73                        eprintln!("Already connected to VCS");
74                        return Ok(());
75                    }
76                    drop(lock);
77                    let Some(vcs_client) = self.connect().await else {
78                        eprintln!("Could not connect to VCS");
79                        return Ok(());
80                    };
81                    *self.client.lock() = Some(vcs_client);
82                    println!("Connected to VCS");
83                }
84                VcsCmd::Info => {
85                    let Some(client) = self.try_client() else {
86                        return Ok(());
87                    };
88                    println!("{}", client);
89                }
90                VcsCmd::Up => {
91                    let Some(client) = self.try_client() else {
92                        return Ok(());
93                    };
94                    client.volume_up(false).await?;
95                }
96                VcsCmd::Down => {
97                    let Some(client) = self.try_client() else {
98                        return Ok(());
99                    };
100                    client.volume_down(false).await?;
101                }
102                VcsCmd::Update => {
103                    let Some(client) = self.try_client() else {
104                        return Ok(());
105                    };
106                    client.update().await?;
107                    println!("{}", client);
108                }
109                VcsCmd::Mute => {
110                    let Some(client) = self.try_client() else {
111                        return Ok(());
112                    };
113                    client.mute().await?;
114                }
115                VcsCmd::Unmute => {
116                    let Some(client) = self.try_client() else {
117                        return Ok(());
118                    };
119                    client.unmute().await?;
120                }
121                VcsCmd::Set => {
122                    let Some(client) = self.try_client() else {
123                        return Ok(());
124                    };
125                    if args.len() != 1 {
126                        eprintln!("Expecting one arg: level to set (0-255)");
127                        return Ok(());
128                    }
129                    let Ok(level) = args[0].parse::<u8>() else {
130                        eprintln!("Couldn't parse level");
131                        return Ok(());
132                    };
133                    client.set_absolute_volume(level).await?;
134                }
135            }
136
137            Ok::<(), Error>(())
138        }
139    }
140}