fuchsia_audio_dai/
discover.rs

1// Copyright 2021 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 anyhow::Error;
6use fidl_fuchsia_io as fio;
7use std::path::Path;
8
9use crate::DigitalAudioInterface;
10
11const DAI_DEVICE_DIR: &str = "/dev/class/dai";
12
13/// Finds any DAI devices, connects to any that are available and provides
14pub async fn find_devices() -> Result<Vec<DigitalAudioInterface>, Error> {
15    // Connect to the component's environment.
16    let directory_proxy =
17        fuchsia_fs::directory::open_in_namespace(DAI_DEVICE_DIR, fio::Flags::empty())?;
18    find_devices_internal(directory_proxy).await
19}
20
21async fn find_devices_internal(
22    directory_proxy: fio::DirectoryProxy,
23) -> Result<Vec<DigitalAudioInterface>, Error> {
24    let files = fuchsia_fs::directory::readdir(&directory_proxy).await?;
25
26    let paths: Vec<_> =
27        files.iter().map(|file| Path::new(DAI_DEVICE_DIR).join(&file.name)).collect();
28    let devices = paths.iter().map(|path| DigitalAudioInterface::new(&path)).collect();
29
30    Ok(devices)
31}
32
33#[cfg(test)]
34mod tests {
35    use fuchsia_component_test::{
36        Capability, ChildOptions, LocalComponentHandles, RealmBuilder, Route,
37    };
38    use futures::channel::mpsc;
39    use futures::{SinkExt, StreamExt};
40    use realmbuilder_mock_helpers::mock_dev;
41
42    use super::*;
43    use crate::test::mock_dai_dev_with_io_devices;
44
45    #[fuchsia::test]
46    async fn test_env_dir_is_not_found() {
47        let _ = find_devices().await.expect_err("find devices okay");
48    }
49
50    async fn mock_client(
51        handles: LocalComponentHandles,
52        mut sender: mpsc::Sender<()>,
53    ) -> Result<(), Error> {
54        let proxy = handles.clone_from_namespace("dev/class/dai")?;
55        let devices = find_devices_internal(proxy).await.expect("should find devices");
56        assert_eq!(devices.len(), 2);
57        let _ = sender.send(()).await.unwrap();
58        Ok(())
59    }
60
61    #[fuchsia::test]
62    async fn devices_found_from_env() {
63        let (device_sender, mut device_receiver) = mpsc::channel(0);
64        let builder = RealmBuilder::new().await.expect("Failed to create test realm builder");
65
66        // Add a mock that provides the dev/ directory with one input and output device.
67        let mock_dev = builder
68            .add_local_child(
69                "mock-dev",
70                move |handles: LocalComponentHandles| {
71                    Box::pin(mock_dev(
72                        handles,
73                        mock_dai_dev_with_io_devices("input1".to_string(), "output1".to_string()),
74                    ))
75                },
76                ChildOptions::new().eager(),
77            )
78            .await
79            .expect("Failed adding mock /dev provider to topology");
80
81        // Add a mock that represents a client trying to discover DAI devices.
82        let mock_client = builder
83            .add_local_child(
84                "mock-client",
85                move |handles: LocalComponentHandles| {
86                    let s = device_sender.clone();
87                    Box::pin(mock_client(handles, s.clone()))
88                },
89                ChildOptions::new().eager(),
90            )
91            .await
92            .expect("Failed adding mock client to topology");
93
94        // Give client access to dev/
95        builder
96            .add_route(
97                Route::new()
98                    .capability(
99                        Capability::directory("dev-dai")
100                            .path(DAI_DEVICE_DIR)
101                            .rights(fio::R_STAR_DIR),
102                    )
103                    .from(&mock_dev)
104                    .to(&mock_client),
105            )
106            .await
107            .expect("Failed adding route for dai device directory");
108
109        let _test_topology = builder.build().await.unwrap();
110
111        let _ = device_receiver.next().await.expect("should receive devices");
112    }
113}