Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AudioBuffer "acquire the content" - should we implement this? #68

Closed
orottier opened this issue Dec 16, 2021 · 5 comments
Closed

AudioBuffer "acquire the content" - should we implement this? #68

orottier opened this issue Dec 16, 2021 · 5 comments

Comments

@orottier
Copy link
Owner

orottier commented Dec 16, 2021

see full discussion at #67

Do we follow the spec literally? Or can we use the rust "ownership" semantics to achieve the goal of the spec?

@b-ma
Copy link
Collaborator

b-ma commented Dec 18, 2021

could you confirm this snippet represents well our case here?

use std::sync::Arc;
use std::{thread, time};

#[derive(Clone)]
struct Channel {
    data: Arc<Vec<f32>>
}

impl Channel {
    fn from(data: Vec<f32>) -> Self {
        Self {
            data: Arc::new(data),
        }
    }

    fn as_slice(&self) -> &[f32] {
        &self.data[..]
    }

    fn as_mut_slice(&mut self) -> &mut [f32] {
        &mut Arc::make_mut(&mut self.data)[..]
    }
}

fn main() {
    let data = vec![1., 2., 3.];
    let mut channel = Channel::from(data);
    let clone = channel.clone();

    thread::spawn(move || {
        loop {
            println!("+ read clone in thread");
            println!("{:?}", clone.data.as_slice());

            thread::sleep(time::Duration::from_millis((1000.) as u64));
        }
    });

    thread::sleep(time::Duration::from_millis((1500.) as u64));

    // mutate channel
    let slice = channel.as_mut_slice();
    slice[0] = 0.;

    println!("> channel mutated");
    println!("{:?}", channel.data);

    thread::sleep(time::Duration::from_millis((5000.) as u64));
}

output (which seems to be exactly what we would expect when using copy_to_channel):

+ read clone in thread
[1.0, 2.0, 3.0]
+ read clone in thread
[1.0, 2.0, 3.0]
> channel mutated
[0.0, 2.0, 3.0]
+ read clone in thread
[1.0, 2.0, 3.0]
+ read clone in thread
[1.0, 2.0, 3.0]

@orottier
Copy link
Owner Author

Yes, Arc is a safe way to share data, while at the same time protecting for unwanted mutation. Rust is way more powerful (and more complex..) than JS in this case!
A friendly example for this can also be found here, sample principles uphold: https://doc.rust-lang.org/std/borrow/enum.Cow.html

@b-ma
Copy link
Collaborator

b-ma commented Dec 18, 2021

Ok thanks ! So, my own opinion on the question would be that the very important idea behind the spec (beyond any algorithm description or language/implementation quirks) is that:

This operation returns immutable channel data to the invoker.

So, I would really agree that the question is basically answered here: the "content is de facto acquired" due to the fact that nobody can change and mess up the underlying data without going first through Arc::make_mut, which itself guarantees that existing clones won't be impacted. From what I (finally) understand, the thing does exactly what we expect it to do, so I don't see why we would bother implementing anything special, i.e.: AudioBuffer::clone() actually does acquire the content (...in some kind of Rust lazy way)

@orottier
Copy link
Owner Author

Agreed!

@b-ma
Copy link
Collaborator

b-ma commented Dec 25, 2021

See also: https://www.w3.org/TR/webaudio/#audio-buffer-copying (which basically says that "acquire the content" should be implemented in a lazy way)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants