ardaku / wavy

Asynchronous cross-platform real-time audio recording & playback.
https://docs.rs/crate/wavy/latest
Apache License 2.0
84 stars 4 forks source link

Works only with the pasts::block_on executor #25

Closed Dragoncraft89 closed 3 years ago

Dragoncraft89 commented 3 years ago

Describe the bug Running wavy in another async executor, such as the futures crate, results in an Invalid Instruction. I had a quick look into the pasts crate and what its block_on does, but I haven't figured out why this happens. It looks like undefined behaviour to me.

To Reproduce Here's a modified version of monitor.rs, that I could trigger the bug with:

use fon::{stereo::Stereo32, Audio, Sink};
use futures::prelude::*;
use wavy::{Microphone, MicrophoneStream, Speakers, SpeakersSink};

/// An event handled by the event loop.
enum Event<'a> {
    /// Speaker is ready to play more audio.
    Play(SpeakersSink<'a, Stereo32>),
    /// Microphone has recorded some audio.
    Record(MicrophoneStream<'a, Stereo32>),
}

/// Shared state between tasks on the thread.
struct State {
    /// Temporary buffer for holding real-time audio samples.
    buffer: Audio<Stereo32>,
}

impl State {
    fn event(&mut self, event: Event<'_>) {
        match event {
            Event::Play(mut speakers) => speakers.stream(self.buffer.drain()),
            Event::Record(microphone) => self.buffer.extend(microphone),
        }
    }
}

async fn playback(mut state: State, mut speakers: Speakers, mut microphone: Microphone) {
    loop {
       let event = futures::select! {
            input = microphone.record().fuse() => Event::Record(input),
            output = speakers.play().fuse() => Event::Play(output)
       };

        state.event(event)
    }
}

/// Program start.
fn main() {
    let state = State {
        buffer: Audio::with_silence(48_000, 0),
    };
    let speakers = Speakers::default();
    let microphone = Microphone::default();

    futures::executor::block_on(playback(state, speakers, microphone));
    // This works
    // pasts::block_on(playback(state, speakers, microphone));
}

Expected behavior Not an "invalid instruction" :wink:

I expected it either to work the same as with the pasts crate or give me some form of compile time error.

Desktop (please complete the following information):

AldaronLau commented 3 years ago

@Dragoncraft89 that's pretty weird, I would expect it to work. I'll take a look into it this weekend (or earlier if I have time), and try and get a patch released.

AldaronLau commented 3 years ago

@Dragoncraft89 I was unable to reproduce "Invalid Instruction", it works fine using future's block_on() on my machine (running Fedora Workstation Linux). I had to reduce the amount of unsafe code depended on for the new version 0.9 that I just released, would you mind testing again with wavy 0.9 and see if the undefined behavior is still there?

Dragoncraft89 commented 3 years ago

Can confirm that 0.9 works.

Thx a lot. I'll be closing this then