精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
2007年05月14日 上午 11:42
以收听JOKV-FM(TEST)为例,在YP上点击Play,则其URL地址为
peercast://pls/25838B9F1EAE27079B793C9FBA0E4156?tip=222.148.187.176:7144
case WM_COPYDATA:
{
COPYDATASTRUCT *pc = (COPYDATASTRUCT *)lParam;
LOG_DEBUG("URL request: %s",pc->lpData);
if (pc->dwData == WM_PLAYCHANNEL)
{
ChanInfo info;
servMgr->procConnectArgs((char *)pc->lpData,info);
chanMgr->findAndPlayChannel(info,false);
}
//sys->callLocalURL((const char *)pc->lpData,servMgr->serverHost.port);
}
break;
// 解析连接参数,str表示相应的频道URL,例65051E037A7A2A3433090065051E037A?tip=211.132.83.9:7144
// 从URL中解析频道的相关信息以初始化info
void ServMgr::procConnectArgs(char *str,ChanInfo &info)
{
char arg[512];
char curr[256];
//使args等于?后面的字符串,即tip=211.132.83.9:7144
char *args = strstr(str,"?");
if (args)
*args++=0;
info.initNameID(str);
if (args)
{
//nextCGIarg分解字符串,把"tip"保存到curr中,"211.132.83.9"保存到arg中
while (args=nextCGIarg(args,curr,arg))
{
LOG_DEBUG("cmd: %s, arg: %s",curr,arg);
if (strcmp(curr,"sip")==0)
// sip - add network connection to client with channel
{
Host h;
h.fromStrName(arg,DEFAULT_PORT);
if (addOutgoing(h,servMgr->networkID,true))
LOG_NETWORK("Added connection: %s",arg);
}else if (strcmp(curr,"pip")==0)
// pip - add private network connection to client with channel
{
Host h;
h.fromStrName(arg,DEFAULT_PORT);
if (addOutgoing(h,info.id,true))
LOG_NETWORK("Added private connection: %s",arg);
}else if (strcmp(curr,"ip")==0)
// ip - add hit
{
Host h;
h.fromStrName(arg,DEFAULT_PORT);
ChanHit hit;
hit.init();
hit.host = h;
hit.rhost[0] = h;
hit.rhost[1].init();
hit.chanID = info.id;
hit.recv = true;
chanMgr->addHit(hit);
}else if (strcmp(curr,"tip")==0)
// tip - add tracker hit
{
Host h;
h.fromStrName(arg,DEFAULT_PORT);
chanMgr->addHit(h,info.id,true);
}
}
}
}
void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
{
ChanFindInfo *cfi = new ChanFindInfo;
cfi->info = info;
cfi->keep = keep;
cfi->func = findAndPlayChannelProc;
sys->startThread(cfi);
}
THREAD_PROC findAndPlayChannelProc(ThreadInfo *th)
{
ChanFindInfo *cfi = (ChanFindInfo *)th;
ChanInfo info;
info = cfi->info;
Channel *ch = chanMgr->findChannelByNameID(info);
chanMgr->currFindAndPlayChannel = info.id;
if (!ch)
ch = chanMgr->findAndRelay(info);
if (ch)
{
// check that a different channel hasn`t be selected already.
if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
chanMgr->playChannel(ch->info);
if (cfi->keep)
ch->stayConnected = cfi->keep;
}
delete cfi;
return 0;
}
// 寻找和转播相应频道
Channel *ChanMgr::findAndRelay(ChanInfo &info)
{
char idStr[64];
info.id.toStr(idStr);
LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
Channel *c = NULL;
c = findChannelByNameID(info);
//如果当前没有转播该频道,则新创建一个频道
if (!c)
{
c = chanMgr->createChannel(info,NULL);
if (c)
{
c->setStatus(Channel::S_SEARCHING);
c->startGet();
}
}
for(int i=0; i<600; i++) // search for 1 minute.
{
c = findChannelByNameID(info);
if (!c)
{
peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
return NULL;
}
if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
break;
sys->sleep(100);
}
return c;
}
创建频道
Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
{
lock.on();
Channel *nc=NULL;
nc = new Channel();
//将新建的频道加入频道列表
nc->next = channel;
channel = nc;
nc->info = info;
nc->info.lastPlayStart = 0;
nc->info.lastPlayEnd = 0;
nc->info.status = ChanInfo::S_UNKNOWN;
if (mount)
nc->mount.set(mount);
nc->setStatus(Channel::S_WAIT);
nc->type = Channel::T_ALLOCATED;
nc->info.createdTime = sys->getTime();
LOG_CHANNEL("New channel created");
lock.off();
return nc;
开始获取数据,即新创建一个Source并调用startStream进行实际传输
void Channel::startGet()
{
srcType = SRC_PEERCAST;
type = T_RELAY;
info.srcProtocol = ChanInfo::SP_PCP;
sourceData = new PeercastSource();
startStream();
}
启动传输线程
void Channel::startStream()
{
thread.data = this;
thread.func = stream;
if (!sys->startThread(&thread))
reset();
}
进行实际的流传输,调用ChannelSource::stream函数
THREAD_PROC Channel::stream(ThreadInfo *thread)
{
// thread->lock();
Channel *ch = (Channel *)thread->data;
while (thread->active && !peercastInst->isQuitting)
{
LOG_CHANNEL("Channel started");
ChanHitList *chl = chanMgr->findHitList(ch->info);
if (!chl)
chanMgr->addHitList(ch->info);
ch->sourceData->stream(ch);
LOG_CHANNEL("Channel stopped");
if (!ch->stayConnected)
{
break;
}else
{
if (!ch->info.lastPlayEnd)
ch->info.lastPlayEnd = sys->getTime();
unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
LOG_DEBUG("Channel sleeping for %d seconds",diff);
for(unsigned int i=0; i<diff; i++)
{
if (!thread->active || peercastInst->isQuitting)
break;
sys->sleep(1000);
}
}
}
ch->endThread();