Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
382 views
in Technique[技术] by (71.8m points)

rust - Borrowed value in closure does not live long enough

I'm trying to play some audio on my Pi, but I have reached a dead end with the borrowed value does not live long enough, which does not make sense to me, because I create the variables in main and afterwards enter an endless loop. Shouldn't welcome & goodbye live main throughout the program execution?

Full error:

error[E0597]: `welcome` does not live long enough
  --> src/main.rs:37:65
   |
37 |                 let source = rodio::Decoder::new(BufReader::new(&welcome)).unwrap();
   |                                                  ---------------^^^^^^^^-
   |                                                  |              |
   |                                                  |              borrowed value does not live long enough
   |                                                  argument requires that `welcome` is borrowed for `'static`
...
54 | }
   | - `welcome` dropped here while still borrowed

Line 54 is the closing bracket of 'main'.

What would be the Rust way for such a thing? The program basically checks if it should change state and play some audio files if it does change.

fn main() {
    // Audio setup
    let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap();

    let welcome = File::open("audio/welcome.mp3").unwrap();
    let goodbye = File::open("audio/bye.mp3").unwrap();

    loop {
        sonar_state.state_tick();
        let state = sonar_state.get_state();

        match state {
            StatusState::OnTrigger => {
                // TODO make this a function where we pass in the file
                let source = rodio::Decoder::new(BufReader::new(&welcome)).unwrap();
                stream_handle.play_raw(source.convert_samples());
                thread::sleep(Duration::from_millis(1000));
            }
            StatusState::OnTriggerEnd => {
                // Nothing
            }
            StatusState::OffTrigger => {
                let source = rodio::Decoder::new(BufReader::new(&goodbye)).unwrap();
                stream_handle.play_raw(source.convert_samples());
                thread::sleep(Duration::from_millis(1000));
            }
            StatusState::OffTriggerEnd => {
                // Nothing
            }
        }
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As far as I can tell from rodio docs, the issue is that play_raw() sends the stream to a dedicated thread, so you can't send it a reference to a local variable - as far as Rust knows, the thread could outlive the local object. In Rust parlance, play_raw requires a Send + 'static source.

The other issue is that you cannot have multiple decoders reading the same File. Although it may seem ok for multiple handles to "read" from the same source, it's actually not because File is stateful, it contains a pointer to how much of the file has been read. This is why methods like File::read take &mut self.

The solution is to open the file in each loop iteration. For example (untested):

fn main() {
    let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap();

    loop {
        sonar_state.state_tick();
        match sonar_state.get_state() {
            StatusState::OnTrigger => {
                let welcome = File::open("audio/welcome.mp3").unwrap();
                let source = rodio::Decoder::new(BufReader::new(welcome)).unwrap();
                stream_handle.play_raw(source.convert_samples());
                thread::sleep(Duration::from_millis(1000));
            }
            // ...
            StatusState::OffTrigger => {
                let goodbye = File::open("audio/bye.mp3").unwrap();
                let source = rodio::Decoder::new(BufReader::new(goodbye)).unwrap();
                stream_handle.play_raw(source.convert_samples());
                thread::sleep(Duration::from_millis(1000));
            }
            // ...
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...