| 40 | #[async_trait(?Send)] |
| 41 | impl AudioOps for WebAudioOps { |
| 42 | async fn play_tone(&mut self, tone: Tone) -> io::Result<()> { |
| 43 | if tone.frequency_hz == 0 { |
| 44 | return Err(io::Error::new( |
| 45 | io::ErrorKind::InvalidInput, |
| 46 | "Tone frequency must be positive", |
| 47 | )); |
| 48 | } |
| 49 | |
| 50 | // Oscillators are one-shot nodes in the Web Audio API, so we must create one per tone. |
| 51 | let oscillator = self.context.create_oscillator().map_err(js_value_to_io_error)?; |
| 52 | oscillator.frequency().set_value(tone.frequency_hz as f32); |
| 53 | oscillator.set_type(match tone.waveform { |
| 54 | Waveform::Square => OscillatorType::Square, |
| 55 | }); |
| 56 | oscillator |
| 57 | .connect_with_audio_node(&self.context.destination()) |
| 58 | .map_err(js_value_to_io_error)?; |
| 59 | oscillator.start().map_err(js_value_to_io_error)?; |
| 60 | |
| 61 | let ms = i32::try_from(tone.duration.as_millis()) |
| 62 | .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Tone duration too long"))?; |
| 63 | do_sleep(ms, ()).await; |
| 64 | |
| 65 | oscillator.stop().map_err(js_value_to_io_error)?; |
| 66 | Ok(()) |
| 67 | } |
| 68 | } |