标题不写中文,因为搜索的时候都会用英文搜索的。中文是使用环境,这个稍微浏览了一下还挺多内容的,有3个类,希望一篇能解决。
继承图:
这个继承图,有3个类,我们这篇应该会把这个3个类分析完,希望不要太长。
协作图:
这个调度有关的也需要UsageEnvironment,不过这个是下一篇分析,这里就分析上面3个类。
class UsageEnvironment {
public:
Boolean reclaim();
// returns True iff we were actually able to delete our object
// task scheduler:
TaskScheduler& taskScheduler() const {return fScheduler;}
// result message handling:
typedef char const* MsgString;
virtual MsgString getResultMsg() const = 0;
virtual void setResultMsg(MsgString msg) = 0;
virtual void setResultMsg(MsgString msg1, MsgString msg2) = 0;
virtual void setResultMsg(MsgString msg1, MsgString msg2, MsgString msg3) = 0;
virtual void setResultErrMsg(MsgString msg, int err = 0) = 0;
// like setResultMsg(), except that an 'errno' message is appended. (If "err == 0", the "getErrno()" code is used instead.)
virtual void appendToResultMsg(MsgString msg) = 0;
virtual void reportBackgroundError() = 0;
// used to report a (previously set) error message within
// a background event
virtual void internalError(); // used to 'handle' a 'should not occur'-type error condition within the library.
// 'errno'
virtual int getErrno() const = 0;
// 'console' output:
virtual UsageEnvironment& operator<<(char const* str) = 0;
virtual UsageEnvironment& operator<<(int i) = 0;
virtual UsageEnvironment& operator<<(unsigned u) = 0;
virtual UsageEnvironment& operator<<(double d) = 0;
virtual UsageEnvironment& operator<<(void* p) = 0;
// a pointer to additional, optional, client-specific state
void* liveMediaPriv;
void* groupsockPriv;
protected:
UsageEnvironment(TaskScheduler& scheduler); // abstract base class
virtual ~UsageEnvironment(); // we are deleted only by reclaim()
private:
TaskScheduler& fScheduler;
};
UsageEnvironment 类持有 TaskScheduler 的引用,并提供文本的输出操作,用于输出信息,其它还提供了获取 errno 的操作,在发生内部错误时的处理程序 internalError(),以及销毁自身的操作。
class BasicUsageEnvironment0: public UsageEnvironment {
public:
// redefined virtual functions:
virtual MsgString getResultMsg() const;
virtual void setResultMsg(MsgString msg);
virtual void setResultMsg(MsgString msg1,
MsgString msg2);
virtual void setResultMsg(MsgString msg1,
MsgString msg2,
MsgString msg3);
virtual void setResultErrMsg(MsgString msg, int err = 0);
virtual void appendToResultMsg(MsgString msg);
virtual void reportBackgroundError();
protected:
BasicUsageEnvironment0(TaskScheduler& taskScheduler);
virtual ~BasicUsageEnvironment0();
private:
void reset();
char fResultMsgBuffer[RESULT_MSG_BUFFER_MAX];
unsigned fCurBufferSize;
unsigned fBufferMaxSize;
};
class BasicUsageEnvironment: public BasicUsageEnvironment0 {
public:
static BasicUsageEnvironment* createNew(TaskScheduler& taskScheduler);
// redefined virtual functions:
virtual int getErrno() const;
virtual UsageEnvironment& operator<<(char const* str);
virtual UsageEnvironment& operator<<(int i);
virtual UsageEnvironment& operator<<(unsigned u);
virtual UsageEnvironment& operator<<(double d);
virtual UsageEnvironment& operator<<(void* p);
protected:
BasicUsageEnvironment(TaskScheduler& taskScheduler);
// called only by "createNew()" (or subclass constructors)
virtual ~BasicUsageEnvironment();
};
3个类的定义就在这里了,接下来了解一下实现。
不知道为什么这么喜欢把构造函数私有化,然后又一个创建函数,留一个创建函数让我们直接创建一个对象,其实创建对象也是直接new一个对象。
BasicUsageEnvironment*
BasicUsageEnvironment::createNew(TaskScheduler& taskScheduler) {
return new BasicUsageEnvironment(taskScheduler);
}
参数是TaskScheduler类的引用,这个类明天再分析。
BasicUsageEnvironment::BasicUsageEnvironment(TaskScheduler& taskScheduler)
: BasicUsageEnvironment0(taskScheduler) {
#if defined(__WIN32__) || defined(_WIN32)
if (!initializeWinsockIfNecessary()) {
setResultErrMsg("Failed to initialize 'winsock': ");
reportBackgroundError();
internalError();
}
#endif
}
调用BasicUsageEnvironment0类的构造函数,还有win下还要初始化Winsock,这个win下就不清楚了,我们看linux下的,linux下好像没啥。
#define RESULT_MSG_BUFFER_MAX 1000
BasicUsageEnvironment0::BasicUsageEnvironment0(TaskScheduler& taskScheduler)
: UsageEnvironment(taskScheduler),
fBufferMaxSize(RESULT_MSG_BUFFER_MAX) {
reset();
}
void BasicUsageEnvironment0::reset() {
fCurBufferSize = 0;
fResultMsgBuffer[fCurBufferSize] = '\0'; //把buffer值初始化为‘\0’
}
这个也简单,调用UsageEnvironment的构造函数,
fBufferMaxSize:设置输出Buffer的最大值1000
fCurBufferSize : 当前buffer的大小
fResultMsgBuffer: 输出缓冲区
UsageEnvironment::UsageEnvironment(TaskScheduler& scheduler)
: liveMediaPriv(NULL), groupsockPriv(NULL), fScheduler(scheduler) {
}
构造函数就是初始化了几个变量
liveMediaPriv:
groupsockPriv:
fScheduler:
这个浏览了一遍,感觉确实没什么好讲的,也不知道live555为什么这么封装。所以下面改变策略,直接分析一个.cpp文件。
//返回错误
int BasicUsageEnvironment::getErrno() const {
#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_WCE)
return WSAGetLastError();
#else
return errno; //linux下直接返回这个错误
#endif
}
//<< 操作符重写
UsageEnvironment& BasicUsageEnvironment::operator<<(char const* str) {
if (str == NULL) str = "(NULL)"; // sanity check
fprintf(stderr, "%s", str);
return *this;
}
//<< 操作符重写
UsageEnvironment& BasicUsageEnvironment::operator<<(int i) {
fprintf(stderr, "%d", i);
return *this;
}
//<< 操作符重写
UsageEnvironment& BasicUsageEnvironment::operator<<(unsigned u) {
fprintf(stderr, "%u", u);
return *this;
}
//<< 操作符重写
UsageEnvironment& BasicUsageEnvironment::operator<<(double d) {
fprintf(stderr, "%f", d);
return *this;
}
//<< 操作符重写
UsageEnvironment& BasicUsageEnvironment::operator<<(void* p) {
fprintf(stderr, "%p", p);
return *this;
}
没什么好分析的,就是用了fprintf函数,相标准错误打印。
// Implementation of virtual functions:
//这个用的比较多,就放在开头
//这个函数就是往fResultMsgBuffer这个缓冲区中追加内容
void BasicUsageEnvironment0::appendToResultMsg(MsgString msg) {
char* curPtr = &fResultMsgBuffer[fCurBufferSize];
unsigned spaceAvailable = fBufferMaxSize - fCurBufferSize;
unsigned msgLength = strlen(msg);
// Copy only enough of "msg" as will fit:
if (msgLength > spaceAvailable-1) {
msgLength = spaceAvailable-1;
}
memmove(curPtr, (char*)msg, msgLength);
fCurBufferSize += msgLength;
fResultMsgBuffer[fCurBufferSize] = '\0';
}
//直接返回缓冲区内容
char const* BasicUsageEnvironment0::getResultMsg() const {
return fResultMsgBuffer;
}
//清空缓冲区,msg直接写入缓冲区
void BasicUsageEnvironment0::setResultMsg(MsgString msg) {
reset();
appendToResultMsg(msg);
}
//写两段信息
void BasicUsageEnvironment0::setResultMsg(MsgString msg1, MsgString msg2) {
setResultMsg(msg1);
appendToResultMsg(msg2);
}
//写三段信息
void BasicUsageEnvironment0::setResultMsg(MsgString msg1, MsgString msg2,
MsgString msg3) {
setResultMsg(msg1, msg2);
appendToResultMsg(msg3);
}
//写一段错误信息,还有一个错误码
void BasicUsageEnvironment0::setResultErrMsg(MsgString msg, int err) {
setResultMsg(msg);
if (err == 0) err = getErrno();
#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_WCE)
#ifndef _UNICODE
char errMsg[RESULT_MSG_BUFFER_MAX] = "\0";
if (0 != FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, errMsg, sizeof(errMsg)/sizeof(errMsg[0]), NULL)) {
// Remove all trailing '\r', '\n' and '.'
for (char* p = errMsg + strlen(errMsg); p != errMsg && (*p == '\r' || *p == '\n' || *p == '.' || *p == '\0'); --p) {
*p = '\0';
}
} else
snprintf(errMsg, sizeof(errMsg)/sizeof(errMsg[0]), "error %d", err);
appendToResultMsg(errMsg);
#endif
#else
appendToResultMsg(strerror(err));
#endif
}
//往标准错误打印信息
void BasicUsageEnvironment0::reportBackgroundError() {
fputs(getResultMsg(), stderr);
}
看着这部分代码确实有点难受。
//如果没有关联liveMediaPriv 和 groupsockPriv 就删除自己对象
Boolean UsageEnvironment::reclaim() {
// We delete ourselves only if we have no remainining state:
if (liveMediaPriv == NULL && groupsockPriv == NULL) {
delete this;
return True;
}
return False;
}
// By default, we handle 'should not occur'-type library errors by calling abort(). Subclasses can redefine this, if desired.
// (If your runtime library doesn't define the "abort()" function, then define your own (e.g., that does nothing).)
void UsageEnvironment::internalError() {
abort(); //错误的处理方式
}
想不到这个竟然比哈希表更是软柿子,简单点分析的快一点也好,明天就分析下一个重点内容TaskScheduler,这个分析完,live555的基础已经分析了,接下来就要开始实际的代码了。