sl4f_lib/audio/
commands.rs

1// Copyright 2019 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 crate::audio::types::AudioMethod;
6use crate::server::Facade;
7use anyhow::{Context, Error};
8use async_trait::async_trait;
9use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
10use base64::engine::Engine as _;
11use fidl_fuchsia_media::{AudioRenderUsage2, AudioSampleFormat, AudioStreamType};
12use fidl_fuchsia_media_sounds::{PlayerMarker, PlayerProxy};
13use fidl_fuchsia_test_audio::{CaptureMarker, CaptureProxy, InjectionMarker, InjectionProxy};
14use fuchsia_async as fasync;
15use fuchsia_component::client::connect_to_protocol;
16use futures::lock::Mutex;
17use futures::{AsyncReadExt, AsyncWriteExt};
18use log::{error, info};
19use serde_json::{to_value, Value};
20
21#[async_trait(?Send)]
22impl Facade for AudioFacade {
23    async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
24        match method.parse()? {
25            AudioMethod::PutInputAudio => self.put_input_audio(args).await,
26            AudioMethod::StartInputInjection => self.start_input_injection(args).await,
27            AudioMethod::StopInputInjection => self.stop_input_injection().await,
28            AudioMethod::StartOutputSave => self.start_output_save().await,
29            AudioMethod::StopOutputSave => self.stop_output_save().await,
30            AudioMethod::GetOutputAudio => self.get_output_audio().await,
31            AudioMethod::PlaySound => self.play_sine_wave().await,
32        }
33    }
34}
35
36#[derive(Debug)]
37pub struct AudioFacade {
38    injection_proxy: InjectionProxy,
39    capture_proxy: CaptureProxy,
40    player_proxy: PlayerProxy,
41    sound_buffer_id: Mutex<u32>,
42}
43
44impl AudioFacade {
45    pub fn new() -> Result<AudioFacade, Error> {
46        info!("Launching audio_recording component");
47        let injection_proxy = connect_to_protocol::<InjectionMarker>()?;
48        let recording_proxy = connect_to_protocol::<CaptureMarker>()?;
49        let player_proxy = connect_to_protocol::<PlayerMarker>()?;
50        let sound_buffer_id = Mutex::new(0u32);
51
52        Ok(AudioFacade {
53            injection_proxy,
54            capture_proxy: recording_proxy,
55            player_proxy,
56            sound_buffer_id,
57        })
58    }
59
60    pub async fn put_input_audio(&self, args: Value) -> Result<Value, Error> {
61        let data = args.get("data").ok_or_else(|| format_err!("PutInputAudio failed, no data"))?;
62        let data =
63            data.as_str().ok_or_else(|| format_err!("PutInputAudio failed, data not string"))?;
64
65        let wave_data_vec = BASE64_STANDARD.decode(data)?;
66
67        let sample_index =
68            args["index"].as_u64().ok_or_else(|| format_err!("index not a number"))?;
69        let sample_index = sample_index.try_into()?;
70
71        let _ = self
72            .injection_proxy
73            .clear_input_audio(sample_index)
74            .await
75            .context("Error calling clear_input_audio")?;
76
77        let (tx, rx) = zx::Socket::create_stream();
78        tx.half_close().expect("prevent writes on other side");
79        self.injection_proxy.write_input_audio(sample_index, rx)?;
80
81        let mut tx = fasync::Socket::from_socket(tx);
82        if let Err(e) = tx.write_all(&wave_data_vec).await {
83            error!("Failed to write audio data to socket: {:?}", e);
84            return Err(e.into());
85        }
86        std::mem::drop(tx); // close socket to prevent hang
87
88        let byte_count = self
89            .injection_proxy
90            .get_input_audio_size(sample_index)
91            .await
92            .context("Error calling get_input_audio_size")?
93            .map_err(|e| anyhow!("get_input_audio_size failed: {:?}", e))?;
94        if byte_count != wave_data_vec.len() as u64 {
95            bail!("Expected to write {} bytes, found {} bytes", wave_data_vec.len(), byte_count);
96        }
97
98        Ok(to_value(byte_count)?)
99    }
100
101    pub async fn start_input_injection(&self, args: Value) -> Result<Value, Error> {
102        let sample_index =
103            args["index"].as_u64().ok_or_else(|| format_err!("index not a number"))?;
104        let sample_index = sample_index.try_into()?;
105        let status = self
106            .injection_proxy
107            .start_input_injection(sample_index)
108            .await
109            .context("Error calling start_input_injection")?;
110        match status {
111            Ok(_) => return Ok(to_value(true)?),
112            Err(_) => return Ok(to_value(false)?),
113        }
114    }
115
116    pub async fn stop_input_injection(&self) -> Result<Value, Error> {
117        let status = self
118            .injection_proxy
119            .stop_input_injection()
120            .await
121            .context("Error calling stop_input_injection")?;
122        match status {
123            Ok(_) => return Ok(to_value(true)?),
124            Err(_) => return Ok(to_value(false)?),
125        }
126    }
127
128    pub async fn start_output_save(&self) -> Result<Value, Error> {
129        let status = self
130            .capture_proxy
131            .start_output_capture()
132            .await
133            .context("Error calling start_output_save")?;
134        match status {
135            Ok(_) => return Ok(to_value(true)?),
136            Err(_) => return Ok(to_value(false)?),
137        }
138    }
139
140    pub async fn stop_output_save(&self) -> Result<Value, Error> {
141        let status = self
142            .capture_proxy
143            .stop_output_capture()
144            .await
145            .context("Error calling stop_output_save")?;
146        match status {
147            Ok(_) => return Ok(to_value(true)?),
148            Err(_) => return Ok(to_value(false)?),
149        }
150    }
151
152    pub async fn get_output_audio(&self) -> Result<Value, Error> {
153        let mut rx_socket = fasync::Socket::from_socket(
154            match self
155                .capture_proxy
156                .get_output_audio()
157                .await
158                .context("Error calling get_output_audio")?
159            {
160                Ok(socket) => socket,
161                Err(e) => {
162                    bail!("Failure: {:?}", e);
163                }
164            },
165        );
166
167        let mut buffer = Vec::new();
168        rx_socket.read_to_end(&mut buffer).await?;
169        Ok(to_value(BASE64_STANDARD.encode(&buffer))?)
170    }
171
172    // This will play a 1-second 399-Hz sine wave at volume 0.1, to the default audio
173    // output device, using the standard `PlaySound2` client playback API.
174    pub async fn play_sine_wave(&self) -> Result<Value, Error> {
175        let mut id = self.sound_buffer_id.lock().await;
176        *(id) += 1;
177        const FREQUENCY: f32 = 399.0;
178        const VOLUME: f32 = 0.1;
179        const DURATION: std::time::Duration = std::time::Duration::from_secs(1);
180        const FRAMES_PER_SECOND: u32 = 44100;
181
182        let (buffer, stream_type) =
183            self.sound_in_buffer(FREQUENCY, VOLUME, FRAMES_PER_SECOND, DURATION)?;
184
185        match self.player_proxy.add_sound_buffer(*id, buffer, &stream_type) {
186            Ok(()) => (),
187            Err(e) => return Err(format_err!("Cannot add sound to buffer: {}", e)),
188        };
189        self.player_proxy
190            .play_sound2(*id, AudioRenderUsage2::Media)
191            .await?
192            .map_err(|err| format_err!("PlaySound2 failed: {:?}", err))?;
193        Ok(to_value(true)?)
194    }
195
196    fn sound_in_buffer(
197        &self,
198        frequency: f32,
199        volume: f32,
200        frames_per_second: u32,
201        duration: std::time::Duration,
202    ) -> Result<(fidl_fuchsia_mem::Buffer, AudioStreamType), Error> {
203        let frame_count = (frames_per_second as f32 * duration.as_secs_f32()) as usize;
204
205        let amplitude = volume * (std::i16::MAX as f32);
206        let frames_per_period = (frames_per_second as f32) / (frequency as f32);
207        let mut samples = std::vec::Vec::with_capacity(frame_count);
208        for i in 0..frame_count {
209            let sample_f = f32::sin((i as f32) / frames_per_period * 2.0 * std::f32::consts::PI);
210            samples.push((sample_f * amplitude) as i16);
211        }
212
213        // This is safe since `bytes` will cover the same memory range as `samples`.
214        let bytes =
215            unsafe { std::slice::from_raw_parts(samples.as_ptr() as *const _, samples.len() * 2) };
216        let vmo = zx::Vmo::create((frame_count * 2) as u64).context("Creating VMO")?;
217        vmo.write(&bytes, 0).context("Writing to VMO")?;
218
219        Ok((
220            fidl_fuchsia_mem::Buffer { vmo: vmo, size: (frame_count * 2) as u64 },
221            AudioStreamType {
222                sample_format: AudioSampleFormat::Signed16,
223                channels: 1,
224                frames_per_second: frames_per_second,
225            },
226        ))
227    }
228}