Skip to main content

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