Keep audio files cached in ram.

This commit is contained in:
Paul Lietar 2015-07-03 02:23:49 +02:00
parent 28a7db26be
commit 9ae452e22d
5 changed files with 77 additions and 37 deletions

2
Cargo.lock generated
View file

@ -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)",

View file

@ -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)
}
}

View file

@ -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();

View file

@ -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)
} }

View file

@ -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;
} }