1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
use crate::errors::{Error, NativeError};
use js_sys::Object;
use log::info;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{AudioBuffer, AudioBufferSourceNode, AudioContext, AudioNode, Element, Event};

pub struct AudioPlayer {
    pub node: AudioBufferSourceNode,
    pub cb: Option<Closure<dyn FnMut() -> ()>>,
}

impl AudioPlayer {
    pub fn start<F>(
        ctx: &AudioContext,
        buffer: &AudioBuffer,
        on_ended: Option<F>,
    ) -> Result<Self, Error>
    where
        F: FnMut() -> () + 'static,
    {
        let node = ctx.create_buffer_source()?;

        node.set_buffer(Some(buffer));
        node.connect_with_audio_node(&ctx.destination())?;

        let cb: Option<Closure<dyn FnMut() -> ()>> = match on_ended {
            Some(f) => {
                let cb = Closure::wrap(Box::new(f) as Box<dyn FnMut() -> ()>);
                node.set_onended(Some(cb.as_ref().unchecked_ref()));
                Some(cb)
            }
            None => None,
        };

        node.start()?;

        Ok(Self { node, cb })
    }
}

impl Drop for AudioPlayer {
    fn drop(&mut self) {
        self.node.stop().unwrap();
        self.node.set_onended(None);
        self.cb.take();
    }
}