소스 검색

Keep audio files cached in ram.

Paul Lietar 9 년 전
부모
커밋
9ae452e22d
5개의 변경된 파일77개의 추가작업 그리고 37개의 파일을 삭제
  1. 1 1
      Cargo.lock
  2. 52 26
      src/audio_file.rs
  3. 1 1
      src/player.rs
  4. 7 0
      src/session.rs
  5. 16 9
      src/stream.rs

+ 1 - 1
Cargo.lock

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

+ 52 - 26
src/audio_file.rs

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

+ 1 - 1
src/player.rs

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

+ 7 - 0
src/session.rs

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

+ 16 - 9
src/stream.rs

@@ -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(
-                                    header_id,
-                                    data.clone()
-                                        .offset(packet.position() as usize)
-                                        .limit(length as usize - 1)
-                                )).unwrap();
+                            channel.callback
+                                .send(StreamEvent::Header(
+                                        header_id,
+                                        data.clone()
+                                            .offset(packet.position() as usize)
+                                            .limit(length as usize - 1)
+                                            ))
+                                .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;
                     }