www.pudn.com > SoundDone.rar > FifoStream.cs


//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 
//  PURPOSE. 
// 
//  This material may not be duplicated in whole or in part, except for  
//  personal use, without the express written consent of the author.  
// 
//  Email:  ianier@hotmail.com 
// 
//  Copyright (C) 1999-2003 Ianier Munoz. All Rights Reserved. 
 
using System; 
using System.IO; 
using System.Collections; 
 
namespace WaveLib 
{ 
	public class FifoStream : Stream 
	{ 
		///  
		/// 数据块大小 
		///  
		private const int BlockSize = 65536; 
		///  
		/// 缓冲区中的数据块数 
		///  
		private const int MaxBlocksInCache = (3 * 1024 * 1024) / BlockSize; 
 
		///  
		/// 大小 
		///  
		private int m_Size; 
		///  
		/// 当前读位置(录制、数据块内) 
		///  
		private int m_RPos; 
		///  
		/// 当前写位置(播放、数据块内) 
		///  
		private int m_WPos; 
		///  
		/// 当前可使用的数据块 
		///  
		private Stack m_UsedBlocks = new Stack(); 
		///  
		/// 当前已使用的数据块 
		///  
		private ArrayList m_Blocks = new ArrayList();  
 
		///  
		/// 分配数据块 
		///  
		/// 数据块 
		private byte[] AllocBlock() 
		{ 
			byte[] Result = null; 
			Result = m_UsedBlocks.Count > 0 ? (byte[])m_UsedBlocks.Pop() : new byte[BlockSize]; 
			return Result; 
		} 
		///  
		/// 清空数据块 
		///  
		/// 数据块 
		private void FreeBlock(byte[] block) 
		{ 
			if (m_UsedBlocks.Count < MaxBlocksInCache) 
				m_UsedBlocks.Push(block); 
		} 
		///  
		/// 获取已使用的数据块 
		///  
		/// 数据块 
		private byte[] GetWBlock() 
		{ 
			byte[] Result = null; 
			if (m_WPos < BlockSize && m_Blocks.Count > 0) 
				Result = (byte[])m_Blocks[m_Blocks.Count - 1]; 
			else 
			{ 
				Result = AllocBlock(); 
				m_Blocks.Add(Result); 
				m_WPos = 0; 
			} 
			return Result; 
		} 
 
		// Stream members 
		public override bool CanRead 
		{ 
			get { return true; } 
		} 
		public override bool CanSeek 
		{ 
			get { return false; } 
		} 
		public override bool CanWrite 
		{ 
			get { return true; } 
		} 
		public override long Length 
		{ 
			get  
			{  
				lock(this) 
					return m_Size; 
			} 
		} 
		///  
		/// 不可用 
		///  
		public override long Position 
		{ 
			get { throw new InvalidOperationException(); } 
			set { throw new InvalidOperationException(); } 
		} 
		///  
		/// 关闭 
		///  
		public override void Close() 
		{ 
			Flush(); 
		} 
		///  
		/// 涮新 
		///  
		public override void Flush() 
		{ 
			lock(this) 
			{ 
				foreach (byte[] block in m_Blocks) 
					FreeBlock(block); 
 
				m_Blocks.Clear(); 
				m_RPos = 0; 
				m_WPos = 0; 
				m_Size = 0; 
			} 
		} 
		///  
		/// 不可用 
		///  
		///  
		public override void SetLength(long len) 
		{ 
			throw new InvalidOperationException(); 
		} 
		///  
		/// 不可用 
		///  
		///  
		///  
		///  
		public override long Seek(long pos, SeekOrigin o) 
		{ 
			throw new InvalidOperationException(); 
		} 
		///  
		/// 将 ofs 作为起始点,从流中读取 count 个字节 
		///  
		///  
		///  
		///  
		///  
		public override int Read(byte[] buf, int ofs, int count) 
		{ 
			lock(this) 
			{ 
				int Result = Peek(buf, ofs, count); 
				Advance(Result); 
				return Result; 
			} 
		} 
		///  
		/// 将 ofs 作为起始点,向流中写入 count 个字节 
		///  
		///  
		///  
		///  
		public override void Write(byte[] buf, int ofs, int count) 
		{ 
			lock(this) 
			{ 
				int Left = count; 
 
				while (Left > 0) 
				{ 
					int ToWrite = Math.Min(BlockSize - m_WPos, Left); 
					Array.Copy(buf, ofs + count - Left, GetWBlock(), m_WPos, ToWrite); 
 
					m_WPos += ToWrite; 
					Left -= ToWrite; 
				} 
				m_Size += count; 
			} 
		} 
 
		///  
		/// extra stuff 
		/// 释放已读的数据块缓冲区 
		///  
		///  
		///  
		public int Advance(int count) 
		{ 
			lock(this) 
			{ 
				int SizeLeft = count; 
				while (SizeLeft > 0 && m_Size > 0) 
				{ 
					if (m_RPos == BlockSize) 
					{ 
						m_RPos = 0; 
						FreeBlock((byte[])m_Blocks[0]); 
						m_Blocks.RemoveAt(0); 
					} 
					int ToFeed= m_Blocks.Count == 1 ? Math.Min(m_WPos - m_RPos, SizeLeft) : Math.Min(BlockSize - m_RPos, SizeLeft); 
 
 
					m_RPos += ToFeed; 
					SizeLeft -= ToFeed; 
					m_Size -= ToFeed; 
				} 
				return count - SizeLeft; 
			} 
		} 
		///  
		/// 将 ofs 作为起始点,从流中读取 count 个字节,但不提升流当前位置 
		///  
		/// 存储数据块 
		///  
		///  
		///  
		public int Peek(byte[] buf, int ofs, int count) 
		{ 
			lock(this) 
			{ 
				//要读取的字符数 
				int SizeLeft = count; 
				//临时存储 m_RPos 
				int TempBlockPos = m_RPos; 
				//临时存储 m_Size 
				int TempSize = m_Size; 
				//当前所在数据块 
				int CurrentBlock = 0; 
 
				//从数据块中读出数据 
				while (SizeLeft > 0 && TempSize > 0) 
				{ 
					if (TempBlockPos == BlockSize) 
					{ 
						TempBlockPos = 0; 
						CurrentBlock++; 
					} 
 
					//当前数据块可读到的最大位置 
					int Upper= CurrentBlock < m_Blocks.Count - 1 ? BlockSize : m_WPos; 
					//当前能读的数据字节数 
					int ToFeed = Math.Min(Upper - TempBlockPos, SizeLeft); 
					Array.Copy((byte[])m_Blocks[CurrentBlock], TempBlockPos, buf, ofs + count - SizeLeft, ToFeed); 
 
					SizeLeft -= ToFeed; 
					TempBlockPos += ToFeed; 
					TempSize -= ToFeed; 
				} 
				return count - SizeLeft; 
			} 
		} 
	} 
}