-
Notifications
You must be signed in to change notification settings - Fork 228
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
[WIP] feat: playing sound from remote source #282
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
fn main() { | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
|
||
let url = "https://github.com/RustAudio/rodio/raw/master/examples/music.flac"; | ||
let request = rodio::SeekableRequest::get(url); | ||
let buffer = rodio::SeekableBufReader::new(request); | ||
let source = rodio::Decoder::new(buffer).unwrap(); | ||
|
||
sink.append(source); | ||
sink.sleep_until_end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
fn main() { | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
|
||
let url = "https://github.com/RustAudio/rodio/raw/master/examples/music.mp3"; | ||
let request = rodio::SeekableRequest::get(url); | ||
let buffer = rodio::SeekableBufReader::new(request); | ||
let source = rodio::Decoder::new(buffer).unwrap(); | ||
|
||
sink.append(source); | ||
sink.sleep_until_end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
fn main() { | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
|
||
let url = "https://github.com/RustAudio/rodio/raw/master/examples/music.ogg"; | ||
let request = rodio::SeekableRequest::get(url); | ||
let buffer = rodio::SeekableBufReader::new(request); | ||
let source = rodio::Decoder::new(buffer).unwrap(); | ||
|
||
sink.append(source); | ||
sink.sleep_until_end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
fn main() { | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
|
||
let url = "https://github.com/RustAudio/rodio/raw/master/examples/music.wav"; | ||
let request = rodio::SeekableRequest::get(url); | ||
let buffer = rodio::SeekableBufReader::new(request); | ||
let source = rodio::Decoder::new(buffer).unwrap(); | ||
|
||
sink.append(source); | ||
sink.sleep_until_end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
extern crate rodio; | ||
|
||
use std::io::BufReader; | ||
use std::{fs::File, io::BufReader}; | ||
|
||
fn main() { | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
|
||
let file = std::fs::File::open("examples/music.flac").unwrap(); | ||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); | ||
let path = "examples/music.flac"; | ||
let file = File::open(path).unwrap(); | ||
let buffer = BufReader::new(file); | ||
let source = rodio::Decoder::new(buffer).unwrap(); | ||
|
||
sink.sleep_until_end(); | ||
sink.append(source); | ||
sink.sleep_until_end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
extern crate rodio; | ||
|
||
use std::io::BufReader; | ||
use std::{fs::File, io::BufReader}; | ||
|
||
fn main() { | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
let device = rodio::default_output_device().unwrap(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rodio uses spaces for indentation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I planed to run
I will fix it later. |
||
let sink = rodio::Sink::new(&device); | ||
|
||
let file = std::fs::File::open("examples/music.mp3").unwrap(); | ||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); | ||
let path = "examples/music.mp3"; | ||
let file = File::open(path).unwrap(); | ||
let buffer = BufReader::new(file); | ||
let source = rodio::Decoder::new(buffer).unwrap(); | ||
|
||
sink.sleep_until_end(); | ||
sink.append(source); | ||
sink.sleep_until_end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
extern crate rodio; | ||
|
||
use std::io::BufReader; | ||
use std::{fs::File, io::BufReader}; | ||
|
||
fn main() { | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
|
||
let file = std::fs::File::open("examples/music.ogg").unwrap(); | ||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); | ||
let path = "examples/music.ogg"; | ||
let file = File::open(path).unwrap(); | ||
let buffer = BufReader::new(file); | ||
let source = rodio::Decoder::new(buffer).unwrap(); | ||
|
||
sink.sleep_until_end(); | ||
sink.append(source); | ||
sink.sleep_until_end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
extern crate rodio; | ||
|
||
use std::io::BufReader; | ||
use std::{fs::File, io::BufReader}; | ||
|
||
fn main() { | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
let device = rodio::default_output_device().unwrap(); | ||
let sink = rodio::Sink::new(&device); | ||
|
||
let file = std::fs::File::open("examples/music.wav").unwrap(); | ||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); | ||
let path = "examples/music.wav"; | ||
let file = File::open(path).unwrap(); | ||
let buffer = BufReader::new(file); | ||
let source = rodio::Decoder::new(buffer).unwrap(); | ||
|
||
sink.sleep_until_end(); | ||
sink.append(source); | ||
sink.sleep_until_end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#[cfg(feature = "http")] | ||
pub mod seekable_bufreader; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use std::io::{BufRead, Error, Read, Seek, SeekFrom}; | ||
|
||
use crate::utils::Cache; | ||
|
||
pub struct SeekableBufReader<B> { | ||
buffer: B, | ||
} | ||
|
||
impl<B: Cache> SeekableBufReader<B> { | ||
pub fn new(buffer: B) -> Self { | ||
SeekableBufReader { | ||
buffer, | ||
} | ||
} | ||
} | ||
|
||
impl<B: Cache> Read for SeekableBufReader<B> { | ||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { | ||
let position = self.buffer.position(); | ||
let cache = self.buffer.slice( | ||
position, | ||
position + buf.len(), | ||
); | ||
let amt = cache.len(); | ||
|
||
buf[..amt].copy_from_slice(cache); | ||
self.consume(amt); | ||
Ok(amt) | ||
} | ||
} | ||
|
||
impl<B: Cache> Seek for SeekableBufReader<B> { | ||
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> { | ||
self.buffer.seek(pos) | ||
} | ||
} | ||
|
||
impl<B: Cache> BufRead for SeekableBufReader<B> { | ||
fn fill_buf(&mut self) -> Result<&[u8], Error> { | ||
Ok(self.buffer.slice( | ||
self.buffer.position(), | ||
self.buffer.available(), | ||
)) | ||
} | ||
|
||
#[allow(unused_must_use)] | ||
fn consume(&mut self, amt: usize) { | ||
self.buffer.seek(SeekFrom::Current(amt as i64)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use std::io::{Read, Seek}; | ||
|
||
pub mod buffer; | ||
pub mod source; | ||
|
||
#[cfg(feature = "http")] | ||
pub trait Cache: Read + Seek { | ||
fn available(&self) -> usize; | ||
|
||
fn position(&self) -> usize; | ||
|
||
fn get(&mut self, index: usize) -> Option<&u8>; | ||
|
||
fn slice(&mut self, from: usize, to: usize) -> &[u8]; | ||
|
||
fn cache_to_index(&mut self, index: usize); | ||
|
||
fn cache_to_end(&mut self); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom}; | ||
|
||
use reqwest::blocking::{get, Response}; | ||
|
||
use crate::utils::Cache; | ||
|
||
pub struct SeekableRequest {} | ||
|
||
impl SeekableRequest { | ||
pub fn get(url: &str) -> SeekableResponse { | ||
SeekableResponse::from(get(url).unwrap()) | ||
} | ||
} | ||
|
||
pub struct SeekableResponse { | ||
inner: Response, | ||
position: usize, | ||
buffer: Vec<u8>, | ||
} | ||
|
||
impl From<Response> for SeekableResponse { | ||
fn from(inner: Response) -> Self { | ||
SeekableResponse { | ||
inner, | ||
position: 0, | ||
buffer: Vec::default(), | ||
} | ||
} | ||
} | ||
|
||
impl Cache for SeekableResponse { | ||
fn available(&self) -> usize { | ||
self.buffer.len() | ||
} | ||
|
||
fn position(&self) -> usize { | ||
self.position | ||
} | ||
|
||
fn get(&mut self, index: usize) -> Option<&u8> { | ||
if self.buffer.len() <= index { | ||
self.cache_to_index(index); | ||
} | ||
self.buffer.get(index) | ||
} | ||
|
||
fn slice(&mut self, from: usize, to: usize) -> &[u8] { | ||
if self.buffer.len() <= to { | ||
self.cache_to_index(to); | ||
} | ||
if self.buffer.len() <= from { | ||
return &[]; | ||
} | ||
if self.buffer.len() <= to { | ||
return &self.buffer[from..]; | ||
} | ||
&self.buffer[from..to] | ||
} | ||
|
||
#[allow(unused_must_use)] | ||
fn cache_to_index(&mut self, index: usize) { | ||
let available = self.buffer.len(); | ||
if index >= available { | ||
self.read(&mut vec![0u8; index - available]); | ||
} | ||
} | ||
|
||
#[allow(unused_must_use)] | ||
fn cache_to_end(&mut self) { | ||
self.read_to_end(&mut Vec::default()); | ||
} | ||
} | ||
|
||
impl Read for SeekableResponse { | ||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { | ||
Ok(self.inner.read(buf).map(|len| { | ||
self.buffer.extend(&buf[..len]); | ||
len | ||
})?) | ||
} | ||
} | ||
|
||
impl Seek for SeekableResponse { | ||
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> { | ||
let (position, offset) = match pos { | ||
SeekFrom::Start(position) => (0, position as i64), | ||
SeekFrom::Current(position) => (self.position, position), | ||
SeekFrom::End(position) => (self.buffer.len(), position), | ||
}; | ||
let position = if offset < 0 { | ||
position.checked_sub(offset.wrapping_neg() as usize) | ||
} else { | ||
position.checked_add(offset as usize) | ||
}; | ||
match position { | ||
Some(position) => { | ||
self.position = position; | ||
Ok(position as u64) | ||
} | ||
None => Err(Error::new( | ||
ErrorKind::InvalidInput, | ||
"invalid seek to a negative or overflowing position", | ||
)), | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#[cfg(feature = "http")] | ||
pub mod http; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is redundant as true is already the default
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact I am not even sure if setting it to
true
have any effect...But at least, it remove a warning.
Since I am setting an example like:
I got a warning: