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

Infinite media source support #67

Open
fragsalat opened this issue Nov 10, 2023 · 0 comments
Open

Infinite media source support #67

fragsalat opened this issue Nov 10, 2023 · 0 comments

Comments

@fragsalat
Copy link

Hey there,

first of all thanks for the great work. This library is core of so many playback libraries!
To my issue, I want to play a radio stream using Kira. The stream is remote and has no content-length as it is infinite. The issue I recognize is that Kira's SymphoniaDecoder::new function tries to determine sample_rate and num_frames at decoder creation and unfortunately it isn't able to determine the num_frames. I guess this is from Kira targeting game development whose would always have files on disk. Could you maybe consider to also allow playing remote files as well? I really like this library and would like to prevent using rodio for streaming and kira for local files (rodio doesn't support seeking or chaning positions).

Here is my example

use std::io::{Read, Seek, SeekFrom};
use std::thread::sleep;
use std::time::Duration;

use kira::manager::{backend::DefaultBackend, AudioManager, AudioManagerSettings};
use kira::sound::streaming::{StreamingSoundData, StreamingSoundSettings};
use reqwest::{Client, Url};
use stream_download::http::HttpStream;
use stream_download::source::SourceStream;
use stream_download::storage::memory::MemoryStorageProvider;
use stream_download::{Settings, StreamDownload};
use symphonia::core::io::MediaSource;

struct RemoteSource {
    reader: StreamDownload<MemoryStorageProvider>,
    content_length: Option<u64>,
}

impl RemoteSource {
    pub async fn from_url(url: String) -> Result<Self, String> {
        let parsed_url = url.parse::<Url>().map_err(|error| format!("Invalid url: {}", error))?;
        let stream = HttpStream::<Client>::create(parsed_url)
            .await
            .map_err(|error| format!("Failed to create stream: {}", error))?;

        let content_length = stream.content_length();
        let reader = StreamDownload::from_stream(stream, MemoryStorageProvider::default(), Settings::default())
            .await
            .map_err(|error| format!("Failed to create download: {}", error))?;

        Ok(RemoteSource { reader, content_length })
    }
}

impl Read for RemoteSource {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.reader.read(buf)
    }
}

impl Seek for RemoteSource {
    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
        self.reader.seek(pos)
    }
}

impl MediaSource for RemoteSource {
    fn is_seekable(&self) -> bool {
        self.content_length.is_some()
    }

    fn byte_len(&self) -> Option<u64> {
        self.content_length
    }
}

const FILE: &'static str = "H:\\Data\\projects\\mupibox-rs\\admin_interface\\.storage\\audio\\0b7678f1-4121-4d38-be75-c26f86e2e30d-IsItReal.mp3";

#[tokio::main]
async fn main() {
    let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default()).expect("manager to load");

    let url = "https://streamtdy.ir-media-tec.com/live/mp3-128/web/play.mp3".to_string();

    let sound = StreamingSoundData::from_media_source(
        RemoteSource::from_url(url).await.expect("source to be loaded"),
        StreamingSoundSettings::default(),
    )
    .expect("stream sound data to be created");

    let mut handle = manager.play(sound).expect("failed to play");

    sleep(Duration::from_secs(5));
}

With these dependencies

[dependencies]
kira = "0.8.5"
symphonia = "0.5.3"
reqwest = { version = "0.11.22", features = ["blocking"] }
stream-download = "0.3.0"
tokio = { version = "1.33.0", features = ["full"] }
rangemap = "1.4.0"

If not I can understand that as well :)

Have a nice day and best regards
fragsalat

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

Successfully merging a pull request may close this issue.

1 participant