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