Peercast收聽電台的原始碼流程分析

來源:互聯網
上載者:User

以收聽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);
   }

  }
 }
}

根據info中的資訊尋找和播放頻道


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();

 return 0;

}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.