sl4f_lib/audio/
commands.rs1use 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_recording::{AudioRecordingControlMarker, AudioRecordingControlProxy};
14use fuchsia_component::client::connect_to_protocol;
15use futures::lock::Mutex;
16use log::info;
17use serde_json::{to_value, Value};
18
19#[async_trait(?Send)]
20impl Facade for AudioFacade {
21 async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
22 match method.parse()? {
23 AudioMethod::PutInputAudio => self.put_input_audio(args).await,
24 AudioMethod::StartInputInjection => self.start_input_injection(args).await,
25 AudioMethod::StopInputInjection => self.stop_input_injection().await,
26 AudioMethod::StartOutputSave => self.start_output_save().await,
27 AudioMethod::StopOutputSave => self.stop_output_save().await,
28 AudioMethod::GetOutputAudio => self.get_output_audio().await,
29 AudioMethod::PlaySound => self.play_sine_wave().await,
30 }
31 }
32}
33
34#[derive(Debug)]
35pub struct AudioFacade {
36 audio_proxy: AudioRecordingControlProxy,
37 player_proxy: PlayerProxy,
38 sound_buffer_id: Mutex<u32>,
39}
40
41impl AudioFacade {
42 pub fn new() -> Result<AudioFacade, Error> {
43 info!("Launching audio_recording component");
44 let audio_proxy = connect_to_protocol::<AudioRecordingControlMarker>()?;
45 let player_proxy = connect_to_protocol::<PlayerMarker>()?;
46 let sound_buffer_id = Mutex::new(0u32);
47
48 Ok(AudioFacade { audio_proxy, player_proxy, sound_buffer_id })
49 }
50
51 pub async fn put_input_audio(&self, args: Value) -> Result<Value, Error> {
52 let data = args.get("data").ok_or_else(|| format_err!("PutInputAudio failed, no data"))?;
53 let data =
54 data.as_str().ok_or_else(|| format_err!("PutInputAudio failed, data not string"))?;
55
56 let wave_data_vec = BASE64_STANDARD.decode(data)?;
57 let max_buffer_bytes = 8192;
58 let wave_data_iter: Vec<&[u8]> = wave_data_vec.chunks(max_buffer_bytes).collect();
59
60 let mut byte_cnt = 0;
61 let sample_index =
62 args["index"].as_u64().ok_or_else(|| format_err!("index not a number"))?;
63 let sample_index = sample_index.try_into()?;
64
65 let _ = self
66 .audio_proxy
67 .clear_input_audio(sample_index)
68 .await
69 .context("Error calling put_input_audio")?;
70
71 for chunk in wave_data_iter {
72 byte_cnt += self
73 .audio_proxy
74 .put_input_audio(sample_index, &chunk)
75 .await
76 .context("Error calling put_input_audio")?;
77 }
78 Ok(to_value(byte_cnt)?)
79 }
80
81 pub async fn start_input_injection(&self, args: Value) -> Result<Value, Error> {
82 let sample_index =
83 args["index"].as_u64().ok_or_else(|| format_err!("index not a number"))?;
84 let sample_index = sample_index.try_into()?;
85 let status = self
86 .audio_proxy
87 .start_input_injection(sample_index)
88 .await
89 .context("Error calling put_input_audio")?;
90 match status {
91 Ok(_) => return Ok(to_value(true)?),
92 Err(_) => return Ok(to_value(false)?),
93 }
94 }
95
96 pub async fn stop_input_injection(&self) -> Result<Value, Error> {
97 let status = self
98 .audio_proxy
99 .stop_input_injection()
100 .await
101 .context("Error calling stop_input_injection")?;
102 match status {
103 Ok(_) => return Ok(to_value(true)?),
104 Err(_) => return Ok(to_value(false)?),
105 }
106 }
107
108 pub async fn start_output_save(&self) -> Result<Value, Error> {
109 let status = self
110 .audio_proxy
111 .start_output_save()
112 .await
113 .context("Error calling start_output_save")?;
114 match status {
115 Ok(_) => return Ok(to_value(true)?),
116 Err(_) => return Ok(to_value(false)?),
117 }
118 }
119
120 pub async fn stop_output_save(&self) -> Result<Value, Error> {
121 let status =
122 self.audio_proxy.stop_output_save().await.context("Error calling stop_output_save")?;
123 match status {
124 Ok(_) => return Ok(to_value(true)?),
125 Err(_) => return Ok(to_value(false)?),
126 }
127 }
128
129 pub async fn get_output_audio(&self) -> Result<Value, Error> {
130 let result =
131 self.audio_proxy.get_output_audio().await.context("Error calling get_output_audio")?;
132 let buffer_size = result.get_size()?;
133 let mut buffer = vec![0; buffer_size.try_into().unwrap()];
134 result.read(&mut buffer, 0)?;
135 Ok(to_value(BASE64_STANDARD.encode(&buffer))?)
136 }
137
138 pub async fn play_sine_wave(&self) -> Result<Value, Error> {
140 let mut id = self.sound_buffer_id.lock().await;
141 *(id) += 1;
142 const FREQUENCY: f32 = 399.0;
143 const VOLUME: f32 = 0.1;
144 const DURATION: std::time::Duration = std::time::Duration::from_secs(1);
145 const FRAMES_PER_SECOND: u32 = 44100;
146
147 let (buffer, stream_type) =
148 self.sound_in_buffer(FREQUENCY, VOLUME, FRAMES_PER_SECOND, DURATION)?;
149
150 match self.player_proxy.add_sound_buffer(*id, buffer, &stream_type) {
151 Ok(()) => (),
152 Err(e) => return Err(format_err!("Cannot add sound to buffer: {}", e)),
153 };
154 self.player_proxy
155 .play_sound2(*id, AudioRenderUsage2::Media)
156 .await?
157 .map_err(|err| format_err!("PlaySound2 failed: {:?}", err))?;
158 Ok(to_value(true)?)
159 }
160
161 fn sound_in_buffer(
162 &self,
163 frequency: f32,
164 volume: f32,
165 frames_per_second: u32,
166 duration: std::time::Duration,
167 ) -> Result<(fidl_fuchsia_mem::Buffer, AudioStreamType), Error> {
168 let frame_count = (frames_per_second as f32 * duration.as_secs_f32()) as usize;
169
170 let amplitude = volume * (std::i16::MAX as f32);
171 let frames_per_period = (frames_per_second as f32) / (frequency as f32);
172 let mut samples = std::vec::Vec::with_capacity(frame_count);
173 for i in 0..frame_count {
174 let sample_f = f32::sin((i as f32) / frames_per_period * 2.0 * std::f32::consts::PI);
175 samples.push((sample_f * amplitude) as i16);
176 }
177
178 let bytes =
180 unsafe { std::slice::from_raw_parts(samples.as_ptr() as *const _, samples.len() * 2) };
181 let vmo = zx::Vmo::create((frame_count * 2) as u64).context("Creating VMO")?;
182 vmo.write(&bytes, 0).context("Writing to VMO")?;
183
184 Ok((
185 fidl_fuchsia_mem::Buffer { vmo: vmo, size: (frame_count * 2) as u64 },
186 AudioStreamType {
187 sample_format: AudioSampleFormat::Signed16,
188 channels: 1,
189 frames_per_second: frames_per_second,
190 },
191 ))
192 }
193}