mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +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]]
|
[[package]]
|
||||||
name = "vorbis"
|
name = "vorbis"
|
||||||
version = "0.0.11"
|
version = "0.0.11"
|
||||||
source = "git+https://github.com/plietar/vorbis-rs#b28d0d14f623b0204b29cba435b3cf9be249290a"
|
source = "git+https://github.com/plietar/vorbis-rs#78058c3341832969030f49cbc4b8bc9deb376776"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use byteorder::{ByteOrder, BigEndian};
|
use byteorder::{ByteOrder, BigEndian};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::collections::BitSet;
|
use std::collections::{BitSet, HashMap};
|
||||||
use std::io::{self, SeekFrom};
|
use std::io::{self, SeekFrom};
|
||||||
use std::slice::bytes::copy_memory;
|
use std::slice::bytes::copy_memory;
|
||||||
use std::sync::{Arc, Condvar, Mutex};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
|
@ -35,31 +35,7 @@ struct AudioFileData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'s> AudioFile <'s> {
|
impl <'s> AudioFile <'s> {
|
||||||
pub fn new(session: &Session, file_id: FileId) -> AudioFile {
|
fn new(session: &Session, shared: Arc<AudioFileShared>) -> 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(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let shared_ = shared.clone();
|
let shared_ = shared.clone();
|
||||||
let (seek_tx, seek_rx) = mpsc::channel();
|
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(
|
vorbis::Decoder::new(
|
||||||
Subfile::new(
|
Subfile::new(
|
||||||
AudioDecrypt::new(key,
|
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();
|
decoder.as_mut().unwrap().time_seek(position as f64 / 1000f64).unwrap();
|
||||||
|
|
||||||
let mut h = self.state.0.lock().unwrap();
|
let mut h = self.state.0.lock().unwrap();
|
||||||
|
|
|
@ -13,6 +13,7 @@ use mercury::{MercuryManager, MercuryRequest, MercuryResponse};
|
||||||
use metadata::{MetadataManager, MetadataRef, MetadataTrait};
|
use metadata::{MetadataManager, MetadataRef, MetadataTrait};
|
||||||
use stream::{StreamManager, StreamEvent};
|
use stream::{StreamManager, StreamEvent};
|
||||||
use audio_key::{AudioKeyManager, AudioKey};
|
use audio_key::{AudioKeyManager, AudioKey};
|
||||||
|
use audio_file::{AudioFileManager, AudioFile};
|
||||||
use connection::PacketHandler;
|
use connection::PacketHandler;
|
||||||
|
|
||||||
use util;
|
use util;
|
||||||
|
@ -30,6 +31,7 @@ pub struct Session {
|
||||||
metadata: Mutex<MetadataManager>,
|
metadata: Mutex<MetadataManager>,
|
||||||
stream: Mutex<StreamManager>,
|
stream: Mutex<StreamManager>,
|
||||||
audio_key: Mutex<AudioKeyManager>,
|
audio_key: Mutex<AudioKeyManager>,
|
||||||
|
audio_file: Mutex<AudioFileManager>,
|
||||||
rx_connection: Mutex<CipherConnection>,
|
rx_connection: Mutex<CipherConnection>,
|
||||||
tx_connection: Mutex<CipherConnection>,
|
tx_connection: Mutex<CipherConnection>,
|
||||||
}
|
}
|
||||||
|
@ -118,6 +120,7 @@ impl Session {
|
||||||
metadata: Mutex::new(MetadataManager::new()),
|
metadata: Mutex::new(MetadataManager::new()),
|
||||||
stream: Mutex::new(StreamManager::new()),
|
stream: Mutex::new(StreamManager::new()),
|
||||||
audio_key: Mutex::new(AudioKeyManager::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)
|
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> {
|
pub fn stream(&self, file: FileId, offset: u32, size: u32) -> mpsc::Receiver<StreamEvent> {
|
||||||
self.stream.lock().unwrap().request(self, file, offset, size)
|
self.stream.lock().unwrap().request(self, file, offset, size)
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,16 +87,20 @@ impl PacketHandler for StreamManager {
|
||||||
ChannelMode::Header => {
|
ChannelMode::Header => {
|
||||||
let mut length = 0;
|
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();
|
length = packet.read_u16::<BigEndian>().unwrap();
|
||||||
if length > 0 {
|
if length > 0 {
|
||||||
let header_id = packet.read_u8().unwrap();
|
let header_id = packet.read_u8().unwrap();
|
||||||
channel.callback.send(StreamEvent::Header(
|
channel.callback
|
||||||
header_id,
|
.send(StreamEvent::Header(
|
||||||
data.clone()
|
header_id,
|
||||||
.offset(packet.position() as usize)
|
data.clone()
|
||||||
.limit(length as usize - 1)
|
.offset(packet.position() as usize)
|
||||||
)).unwrap();
|
.limit(length as usize - 1)
|
||||||
|
))
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
close = true;
|
||||||
|
});
|
||||||
|
|
||||||
packet.seek(SeekFrom::Current(length as i64 - 1)).unwrap();
|
packet.seek(SeekFrom::Current(length as i64 - 1)).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -109,8 +113,11 @@ impl PacketHandler for StreamManager {
|
||||||
|
|
||||||
ChannelMode::Data => {
|
ChannelMode::Data => {
|
||||||
if packet.position() < data.len() as u64 {
|
if packet.position() < data.len() as u64 {
|
||||||
channel.callback.send(StreamEvent::Data(
|
channel.callback
|
||||||
data.clone().offset(packet.position() as usize))).unwrap();
|
.send(StreamEvent::Data(data.clone().offset(packet.position() as usize)))
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
close = true;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
close = true;
|
close = true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue