 
   精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
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();