summaryrefslogtreecommitdiff
path: root/src/audio/rodio.rs
blob: 3dffa5e1d63ac53b282c91add7b97edf5f870f24 (plain)
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use std::num::NonZeroUsize;

use rodio::{Decoder, OutputStream, Sink};
use stream_download::{
    http::{reqwest::Client, HttpStream},
    source::SourceStream,
    storage::{
        bounded::BoundedStorageProvider, memory::MemoryStorageProvider, temp::TempStorageProvider,
    },
    Settings, StreamDownload,
};

pub struct Rodio {}

impl Rodio {
    pub async fn play(&self, url: &str) {
        let reader = StreamDownload::new_http(
            url.parse().unwrap(),
            TempStorageProvider::new(),
            Settings::default(),
        )
        .await
        .unwrap();

        let _res = tokio::task::spawn_blocking(move || {
            let (_stream, handle) = OutputStream::try_default().unwrap();
            let sink = Sink::try_new(&handle).unwrap();
            sink.append(Decoder::new(reader).unwrap());
            sink.sleep_until_end();
        })
        .await;

        let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
        let sink = rodio::Sink::try_new(&handle).unwrap();
        let stream = HttpStream::<Client>::create(url.parse().unwrap())
            .await
            .unwrap();

        println!("content type={:?}", stream.content_type());
        let bitrate: u64 = stream.header("Icy-Br").unwrap().parse().unwrap();
        println!("bitrate={bitrate}");

        // buffer 5 seconds of audio
        // bitrate (in kilobits) / bits per byte * bytes per kilobyte * 5 seconds
        let prefetch_bytes = bitrate / 8 * 1024 * 5;
        println!("prefetch bytes={prefetch_bytes}");

        let reader = StreamDownload::from_stream(
            stream,
            // use bounded storage to keep the underlying size from growing indefinitely
            BoundedStorageProvider::new(
                MemoryStorageProvider,
                // be liberal with the buffer size, you need to make sure it holds enough space to
                // prevent any out-of-bounds reads
                NonZeroUsize::new(512 * 1024).unwrap(),
            ),
            Settings::default().prefetch_bytes(prefetch_bytes),
        )
        .await
        .unwrap();
        sink.append(rodio::Decoder::new(reader).unwrap());

        let handle = tokio::task::spawn_blocking(move || {
            sink.sleep_until_end();
        });
        handle.await.unwrap()
    }
}