mirror of
https://github.com/librespot-org/librespot.git
synced 2024-11-08 16:45:43 +00:00
Keep audio files cached in ram.
This commit is contained in:
parent
28a7db26be
commit
9ae452e22d
5 changed files with 77 additions and 37 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -203,7 +203,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "vorbis"
|
||||
version = "0.0.11"
|
||||
source = "git+https://github.com/plietar/vorbis-rs#b28d0d14f623b0204b29cba435b3cf9be249290a"
|
||||
source = "git+https://github.com/plietar/vorbis-rs#78058c3341832969030f49cbc4b8bc9deb376776"
|
||||
dependencies = [
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use byteorder::{ByteOrder, BigEndian};
|
||||
use std::cmp::min;
|
||||
use std::collections::BitSet;
|
||||
use std::collections::{BitSet, HashMap};
|
||||
use std::io::{self, SeekFrom};
|
||||
use std::slice::bytes::copy_memory;
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
|
@ -35,31 +35,7 @@ struct AudioFileData {
|
|||
}
|
||||
|
||||
impl <'s> AudioFile <'s> {
|
||||
pub fn new(session: &Session, file_id: FileId) -> AudioFile {
|
||||
let mut it = session.stream(file_id, 0, 1).into_iter()
|
||||
.filter_map(|event| {
|
||||
match event {
|
||||
StreamEvent::Header(id, ref data) if id == 0x3 => {
|
||||
Some(BigEndian::read_u32(data) as usize * 4)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
});
|
||||
|
||||
let size = it.next().unwrap();
|
||||
|
||||
let bufsize = size + (CHUNK_SIZE - size % CHUNK_SIZE);
|
||||
|
||||
let shared = Arc::new(AudioFileShared {
|
||||
file_id: file_id,
|
||||
size: size,
|
||||
data: Mutex::new(AudioFileData {
|
||||
buffer: vec![0u8; bufsize],
|
||||
bitmap: BitSet::with_capacity(bufsize / CHUNK_SIZE as usize)
|
||||
}),
|
||||
cond: Condvar::new(),
|
||||
});
|
||||
|
||||
fn new(session: &Session, shared: Arc<AudioFileShared>) -> AudioFile {
|
||||
let shared_ = shared.clone();
|
||||
let (seek_tx, seek_rx) = mpsc::channel();
|
||||
|
||||
|
@ -164,4 +140,54 @@ impl <'s> io::Seek for AudioFile <'s> {
|
|||
}
|
||||
}
|
||||
|
||||
impl AudioFileShared {
|
||||
fn new(session: &Session, file_id: FileId) -> Arc<AudioFileShared> {
|
||||
let size = session.stream(file_id, 0, 1).into_iter()
|
||||
.filter_map(|event| {
|
||||
match event {
|
||||
StreamEvent::Header(id, ref data) if id == 0x3 => {
|
||||
Some(BigEndian::read_u32(data) as usize * 4)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}).next().unwrap();
|
||||
|
||||
let bufsize = size + (CHUNK_SIZE - size % CHUNK_SIZE);
|
||||
|
||||
Arc::new(AudioFileShared {
|
||||
file_id: file_id,
|
||||
size: size,
|
||||
data: Mutex::new(AudioFileData {
|
||||
buffer: vec![0u8; bufsize],
|
||||
bitmap: BitSet::with_capacity(bufsize / CHUNK_SIZE as usize)
|
||||
}),
|
||||
cond: Condvar::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AudioFileManager {
|
||||
cache: HashMap<FileId, Arc<AudioFileShared>>
|
||||
}
|
||||
|
||||
impl AudioFileManager {
|
||||
pub fn new() -> AudioFileManager {
|
||||
AudioFileManager {
|
||||
cache: HashMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request<'a> (&mut self, session: &'a Session, file_id: FileId) -> AudioFile<'a> {
|
||||
let shared = self.cache
|
||||
.get(&file_id)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| {
|
||||
println!("Cache miss");
|
||||
let shared = AudioFileShared::new(session, file_id.clone());
|
||||
self.cache.insert(file_id, shared.clone());
|
||||
shared
|
||||
});
|
||||
AudioFile::new(session, shared)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ impl <'s> PlayerInternal<'s> {
|
|||
vorbis::Decoder::new(
|
||||
Subfile::new(
|
||||
AudioDecrypt::new(key,
|
||||
AudioFile::new(self.session, file_id)), 0xa7)).unwrap());
|
||||
self.session.audio_file(file_id)), 0xa7)).unwrap());
|
||||
decoder.as_mut().unwrap().time_seek(position as f64 / 1000f64).unwrap();
|
||||
|
||||
let mut h = self.state.0.lock().unwrap();
|
||||
|
|
|
@ -13,6 +13,7 @@ use mercury::{MercuryManager, MercuryRequest, MercuryResponse};
|
|||
use metadata::{MetadataManager, MetadataRef, MetadataTrait};
|
||||
use stream::{StreamManager, StreamEvent};
|
||||
use audio_key::{AudioKeyManager, AudioKey};
|
||||
use audio_file::{AudioFileManager, AudioFile};
|
||||
use connection::PacketHandler;
|
||||
|
||||
use util;
|
||||
|
@ -30,6 +31,7 @@ pub struct Session {
|
|||
metadata: Mutex<MetadataManager>,
|
||||
stream: Mutex<StreamManager>,
|
||||
audio_key: Mutex<AudioKeyManager>,
|
||||
audio_file: Mutex<AudioFileManager>,
|
||||
rx_connection: Mutex<CipherConnection>,
|
||||
tx_connection: Mutex<CipherConnection>,
|
||||
}
|
||||
|
@ -118,6 +120,7 @@ impl Session {
|
|||
metadata: Mutex::new(MetadataManager::new()),
|
||||
stream: Mutex::new(StreamManager::new()),
|
||||
audio_key: Mutex::new(AudioKeyManager::new()),
|
||||
audio_file: Mutex::new(AudioFileManager::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,6 +174,10 @@ impl Session {
|
|||
self.audio_key.lock().unwrap().request(self, track, file)
|
||||
}
|
||||
|
||||
pub fn audio_file(&self, file: FileId) -> AudioFile {
|
||||
self.audio_file.lock().unwrap().request(self, file)
|
||||
}
|
||||
|
||||
pub fn stream(&self, file: FileId, offset: u32, size: u32) -> mpsc::Receiver<StreamEvent> {
|
||||
self.stream.lock().unwrap().request(self, file, offset, size)
|
||||
}
|
||||
|
|
|
@ -87,16 +87,20 @@ impl PacketHandler for StreamManager {
|
|||
ChannelMode::Header => {
|
||||
let mut length = 0;
|
||||
|
||||
while packet.position() < data.len() as u64 {
|
||||
while packet.position() < data.len() as u64 && !close {
|
||||
length = packet.read_u16::<BigEndian>().unwrap();
|
||||
if length > 0 {
|
||||
let header_id = packet.read_u8().unwrap();
|
||||
channel.callback.send(StreamEvent::Header(
|
||||
channel.callback
|
||||
.send(StreamEvent::Header(
|
||||
header_id,
|
||||
data.clone()
|
||||
.offset(packet.position() as usize)
|
||||
.limit(length as usize - 1)
|
||||
)).unwrap();
|
||||
))
|
||||
.unwrap_or_else(|_| {
|
||||
close = true;
|
||||
});
|
||||
|
||||
packet.seek(SeekFrom::Current(length as i64 - 1)).unwrap();
|
||||
}
|
||||
|
@ -109,8 +113,11 @@ impl PacketHandler for StreamManager {
|
|||
|
||||
ChannelMode::Data => {
|
||||
if packet.position() < data.len() as u64 {
|
||||
channel.callback.send(StreamEvent::Data(
|
||||
data.clone().offset(packet.position() as usize))).unwrap();
|
||||
channel.callback
|
||||
.send(StreamEvent::Data(data.clone().offset(packet.position() as usize)))
|
||||
.unwrap_or_else(|_| {
|
||||
close = true;
|
||||
});
|
||||
} else {
|
||||
close = true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue