您的位置:首页 > 其它

Peercast播放模块分析

2006-05-02 16:17 543 查看
这里以YP上的JOKV-FM(TEST)为例
当点击YP上的一个频道时,其访问地址为peercast://pls/25838B9F1EAE27079B793C9FBA0E4156?

tip=222.148.187.176:7144
peercast://指的是peercast协议,由于peercast注册了此协议,所以在IE中输入这个地址时会自动启动

peercast并把这个地址传送给peercast
25838B9F1EAE27079B793C9FBA0E4156指的是广播端的ChanID,每广播一个电台peercast会根据相应算法生

成一个ID,这个ID可以唯一标识一个频道。
tip=222.148.187.176:7144表示广播主机的地址和端口号。这样的话本地的peercast会先去和这个主机建

立连接,然后根据这个主机去找8个转播相同频道的主机,选择其中最好的一个作为传输者。
建立连接后,生成播放列表play.pls如下
[playlist]

NumberOfEntries=1
File1=http://localhost:7144/stream/25838B9F1EAE27079B793C9FBA0E4156.ogg
Title1=JOKV-FM(TEST)
Length1=-1
Version=2

然后调用播放器(例如winamp)去播放这个列表,这时winamp访问的url地址为

http://localhost:7144/stream/74F7ECF0508E50E62FD3BEB0624921E4.ogg。即winamp通过http方式从

peercast获得媒体数据并播放,访问主机为本机localhost,端口为7144。
winamp发送的HTTP请求类似如下:
GET /stream/74F7ECF0508E50E62FD3BEB0624921E4.ogg HTTP/1.1
Host: localhost:7144

Peercast有一个servent监听7144端口,并处理发来的HTTP请求。
void Servent::handshakeHTTP(HTTP &http, bool isHTTP)
{
 char *in = http.cmdLine;

 if (http.isRequest("GET /"))
 {
  char *fn = in+4;
     if (strncmp(fn,"/stream/",8)==0)
   triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
 }
}

下面主要分析Peercast如何把数据送往播放器

// 触发频道,调用processStream传送媒体数据给播放器
void Servent::triggerChannel(char *str, ChanInfo::PROTOCOL proto,bool relay) 
{
 outputProtocol = proto;
 processStream(false,info);
}

// outputProtocol为HTTP协议,调用sendRawChannel发送数据
void Servent::processStream(bool doneHandshake,ChanInfo &chanInfo)
{
 if (outputProtocol == ChanInfo::SP_HTTP)
 {
  sendRawChannel(true,true);
 }
}

// 发送频道数据给播放器
void Servent::sendRawChannel(bool sendHead, bool sendData)
{
 try
 {

  sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);

  Channel *ch = chanMgr->findChannelByID(chanID);
  if (!ch)
   throw StreamException("Channel not found");

  setStatus(S_CONNECTED);

  //这里进行最重要的数据传输,请特别注意
  LOG_DEBUG("Starting Raw stream of %s at %d",ch->info.name.cstr(),streamPos);

  if (sendHead)
  {
   ch->headPack.writeRaw(*sock);
   streamPos = ch->headPack.pos + ch->headPack.len;
   LOG_DEBUG("Sent %d bytes header ",ch->headPack.len);
  }

  if (sendData)
  {

   unsigned int streamIndex = ch->streamIndex;
   unsigned int connectTime = sys->getTime();
   unsigned int lastWriteTime = connectTime;

   while ((thread.active) && sock->active())
   {
    ch = chanMgr->findChannelByID(chanID);

    if (ch)
    {

     if (streamIndex != ch->streamIndex)
     {
      streamIndex = ch->streamIndex;
      streamPos = ch->headPack.pos;
      LOG_DEBUG("sendRaw got new stream index");
     }

     ChanPacket rawPack;
     if (ch->rawData.findPacket(streamPos,rawPack))
     {
      if (syncPos != rawPack.sync)
       LOG_ERROR("Send skip: %

d",rawPack.sync-syncPos);
      syncPos = rawPack.sync+1;

      if ((rawPack.type == ChanPacket::T_DATA) ||

(rawPack.type == ChanPacket::T_HEAD))
      {
       rawPack.writeRaw(*sock);
       lastWriteTime = sys->getTime();
      }

      if (rawPack.pos < streamPos)
       LOG_DEBUG("raw: skip back %

d",rawPack.pos-streamPos);
      streamPos = rawPack.pos+rawPack.len;
     }
    }

    if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
     throw TimeoutException();
    
    sys->sleepIdle();
   }
  }
 }catch(StreamException &e)
 {
  LOG_ERROR("Stream channel: %s",e.msg);
 }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  stream header 算法 file url ie