DelayQueue
首先看这两个的定义
class DelayQueueEntry {
{
...
DelayQueueEntry* fNext;//后一个对象
DelayQueueEntry* fPrev;//前一个对象
}
class DelayQueue: public DelayQueueEntry
{ ...
virtual ~DelayQueue();
void addEntry(DelayQueueEntry* newEntry); // returns a token for the entry 增加事件节点
void removeEntry(DelayQueueEntry* entry); // but doesn't delete it//将某个任务从队列从移除,但是不销毁该对象
}
可以看到DelayQueue继承自DelayQueueEntry,从DelayQueueEntry的成员可以看出,DelayQueueEntry相当于双链表的一个节点。
#首节点
双链表的首节点为DelayQueue fDelayQueue(
见BasicTaskScheduler0的成员),不管是客户端还是服务器都会调用env->taskScheduler().doEventLoop();也就是调用BasicTaskScheduler0::doEventLoop函数。
#添加
void DelayQueue::addEntry(DelayQueueEntry* newEntry) {
...
// Add "newEntry" to the queue, just before "cur":
newEntry->fNext = cur;
newEntry->fPrev = cur->fPrev;
cur->fPrev = newEntry->fPrev->fNext = newEntry;
}
这个函数提供了双链表插入的功能,实际上是往cur指向的新节点前插入一个新节点newEntry。cur->fPrev = newEntry->fPrev->fNext = newEntry相当于cur->fPrev->fNext = newEntry;cur->fPrev = newEntry。
#删除
void DelayQueue::removeEntry(DelayQueueEntry* entry) {
if (entry == NULL || entry->fNext == NULL) return;
...
entry->fPrev->fNext = entry->fNext;
entry->fNext->fPrev = entry->fPrev;
entry->fNext = entry->fPrev = NULL;
// in case we should try to remove it again
}
可以看出这个removeEntry函数实现了从双链表删除entry指向的节点。
延迟队列的意义:
假如我们要描述一个事件发生的时间,可以有两种方法:一种方法直接描述事件发生的绝对时间;另一种方法则是可以描述和另一事件发生的相对时间。而LIVE555中采用的就是后者。在LIVE555中,首先将所有的事件点以发生时间的先后进行排序,然后每个事件对应的时间都是相对于前一事件发生的时间差。比如B事件中存储的时间就是A事件触发后,再去触发B事件所需要的时间。这样,我们每次去查询这个队列中是否有事件被触发的时候,就只需要查询整个队列中的第一个事件就可以了。
然后就是LIVE555中的实现方法了。整个延时队列是用DelayQueue这个类实现的,而它的基类DelayQueueEntry就是用来描述每个事件节点的。在DelayQueueEntry中的主要成员有以下几个:fDelayTimeRemaining表示的就是与前一事件之间的时间差;fNext和fPrev就是指向时间轴上的下一个事件和前一个事件的指针;ftoken表示当前节点的标识;handleTimeout就是事件超时后的处理方法。
而DelayQueue类里描述的则是具体的实现方法。首先是一些对这个队列进行的基本操作:addEntry实现的是在队列中增加事件节点;removeEntry实现的是在队列中删除某事件节点;updateEntry实现的则是更新某事件的触发时间;而findEntryByToken则是根据节点的标识查找相应的事件。在此类中最常用的方法应该是synchronize,它实现的就是将整个事件队列和当前系统时间进行同步,检测有无事件已经被触发,如果触发并调用handleAlarm方法对相应事件进行处理。而属性fLastSyncTime表示的就是上次同步的系统时间,其实一般情况下,方法synchronize的实现方法其实就是简单地把队列上第一个事件节点存储的时间差减去当前系统时间和上次同步时间的差。
streamState
struct streamState 中保存了 MediaSubsession (即track)和类 StreamState的对应。为何不把 StreamToken保存在 MediaSubsession中呢?看起来在 struct streamState中是一个 MediaSubsession对应一个 streamToken呀?因为 MediaSubsession 代表一个 track的静态数据,它是可以被其它 rtp会话重用的。比如不同的用户可能会连接到同一个媒体的同一个 track。所以 streamToken 与 MediaSubsession 独立存在,只是被 RTSPClientSession 给对应了起来。
SteamState
类 StreamState 代表一个真正流动起来的数据流。这个数据流是从源流到 Sink。客户端与服务端的一个 rtp会话中,有两个数据流,服务端是从 XXXFileSouce流到 RTPSink,而客户端则是从 RTPSource流到 XXXFileSink。建立数据流的过程就是把 Source与 Sink 连接起来。
OutPacketBuffer
/*
If one of the buffers is overflow, this is treated as an error. For the video stream,
the error handler will drop some data till next key frame arrives
*/
// A data structure that a sink may use for an output packet:
class OutPacketBuffer {
public:
OutPacketBuffer(unsigned preferredPacketSize, unsigned maxPacketSize);
~OutPacketBuffer();
static unsigned maxSize;
unsigned char* curPtr() const {return &fBuf[fPacketStart + fCurOffset];}
unsigned totalBytesAvailable() const {
return fLimit - (fPacketStart + fCurOffset);
}
unsigned totalBufferSize() const { return fLimit; }
unsigned char* packet() const {return &fBuf[fPacketStart];}
unsigned curPacketSize() const {return fCurOffset;}
void increment(unsigned numBytes) {fCurOffset += numBytes;}
//从尾部加数据
void enqueue(unsigned char const* from, unsigned numBytes);
void enqueueWord(u_int32_t word);
//从中间加数据
void insert(unsigned char const* from, unsigned numBytes, unsigned toPosition);
void insertWord(u_int32_t word, unsigned toPosition);
//从中间读取数据
void extract(unsigned char* to, unsigned numBytes, unsigned fromPosition);
u_int32_t extractWord(unsigned fromPosition);
void skipBytes(unsigned numBytes);
Boolean isPreferredSize() const {return fCurOffset >= fPreferred;}
Boolean wouldOverflow(unsigned numBytes) const {
return (fCurOffset+numBytes) > fMax;
}
unsigned numOverflowBytes(unsigned numBytes) const { return (fCurOffset+numBytes) - fMax; }
Boolean isTooBigForAPacket(unsigned numBytes) const { return numBytes > fMax; }
void setOverflowData(unsigned overflowDataOffset,unsigned overflowDataSize,struct timeval const& presentationTime,unsigned durationInMicroseconds);
unsigned overflowDataSize() const {return fOverflowDataSize;}
struct timeval overflowPresentationTime() const {return fOverflowPresentationTime;}
unsigned overflowDurationInMicroseconds() const {return fOverflowDurationInMicroseconds;}
Boolean haveOverflowData() const {return fOverflowDataSize > 0;}
void useOverflowData();
void adjustPacketStart(unsigned numBytes);
void resetPacketStart();
void resetOffset() { fCurOffset = 0; }
void resetOverflowData() { fOverflowDataOffset = fOverflowDataSize = 0; }
private:
//fPacketStart为起始位置。
//fCurOffset结束的位置
//fLimit为最大字节
unsigned fPacketStart, fCurOffset, fPreferred, fMax, fLimit;
unsigned char* fBuf;
unsigned fOverflowDataOffset, fOverflowDataSize;
struct timeval fOverflowPresentationTime;
unsigned fOverflowDurationInMicroseconds;
};
unsigned OutPacketBuffer::maxSize = 200000; // by default
//BUF最大为。
OutPacketBuffer::OutPacketBuffer(unsigned preferredPacketSize, unsigned maxPacketSize) : fPreferred(preferredPacketSize), fMax(maxPacketSize),
fOverflowDataSize(0) {
unsigned maxNumPackets = (maxSize + (maxPacketSize-1))/maxPacketSize; //包个数
fLimit = maxNumPackets*maxPacketSize; //包个数*每个包大小。
fBuf = new unsigned char[fLimit]; resetPacketStart(); resetOffset(); resetOverflowData();
}
OutPacketBuffer::~OutPacketBuffer() { delete[] fBuf;}
//---fPacketStart----fCurOffset(curPtr)----fLimit
void OutPacketBuffer::enqueue(unsigned char const* from, unsigned numBytes) {
if (numBytes > totalBytesAvailable()) { //totalBytesAvailable为fLimit - (fPacketStart + fCurOffset);
#ifdef DEBUG
fprintf(stderr, "OutPacketBuffer::enqueue() warning: %d > %d\n", numBytes, totalBytesAvailable());
#endif
numBytes = totalBytesAvailable();
}
if (curPtr() != from) memmove(curPtr(), from, numBytes);
increment(numBytes); //increment(unsigned numBytes) {fCurOffset += numBytes;}
}
void OutPacketBuffer::enqueueWord(u_int32_t word) {u_int32_t nWord = htonl(word);enqueue((unsigned char*)&nWord, 4);}
//---fPacketStart--(toPosition)--fCurOffset(curPtr)----fLimit
void OutPacketBuffer::insert(unsigned char const* from, unsigned numBytes,
unsigned toPosition) {
//从from位置,最多写numBytes个字节到toPosition。
unsigned realToPosition = fPacketStart + toPosition;
if (realToPosition + numBytes > fLimit) {
if (realToPosition > fLimit) return; // we can't do this
numBytes = fLimit - realToPosition;
}
memmove(&fBuf[realToPosition], from, numBytes);
if (toPosition + numBytes > fCurOffset) { fCurOffset = toPosition + numBytes; }
}
void OutPacketBuffer::insertWord(u_int32_t word, unsigned toPosition) {//插入一个字节
u_int32_t nWord = htonl(word); insert((unsigned char*)&nWord, 4, toPosition);
}
void OutPacketBuffer::extract(unsigned char* to, unsigned numBytes,
unsigned fromPosition) {
//从fromPosition位置,最多读取numBytes个字节到to。
unsigned realFromPosition = fPacketStart + fromPosition;
if (realFromPosition + numBytes > fLimit) { // sanity check
if (realFromPosition > fLimit) return; // we can't do this
numBytes = fLimit - realFromPosition;
}
memmove(to, &fBuf[realFromPosition], numBytes);
}
u_int32_t OutPacketBuffer::extractWord(unsigned fromPosition) { u_int32_t nWord; extract((unsigned char*)&nWord, 4, fromPosition); return ntohl(nWord); }
void OutPacketBuffer::skipBytes(unsigned numBytes) {
if (numBytes > totalBytesAvailable()) {
numBytes = totalBytesAvailable();
}
increment(numBytes);
}
void OutPacketBuffer::setOverflowData(unsigned overflowDataOffset,
unsigned overflowDataSize,
struct timeval const& presentationTime,
unsigned durationInMicroseconds) {
fOverflowDataOffset = overflowDataOffset;
fOverflowDataSize = overflowDataSize;
fOverflowPresentationTime = presentationTime;
fOverflowDurationInMicroseconds = durationInMicroseconds;
}
void OutPacketBuffer::useOverflowData() {
enqueue(&fBuf[fPacketStart + fOverflowDataOffset], fOverflowDataSize);
fCurOffset -= fOverflowDataSize; // undoes increment performed by "enqueue"
resetOverflowData(); //fOverflowDataOffset = fOverflowDataSize = 0;
}
void OutPacketBuffer::adjustPacketStart(unsigned numBytes) {
fPacketStart += numBytes;
if (fOverflowDataOffset >= numBytes) {
fOverflowDataOffset -= numBytes;
} else {
fOverflowDataOffset = 0;
fOverflowDataSize = 0; // an error otherwise
}
}
void OutPacketBuffer::resetPacketStart() { if (fOverflowDataSize > 0) { fOverflowDataOffset += fPacketStart; } fPacketStart = 0;}