Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

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

1 Answer

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));
            }
            // ...
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...