Logo Search packages:      
Sourcecode: vat version File versions  Download package

session-vat.cc

/*
 * Copyright (c) 1995 The Regents of the University of California.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the Network Research
 *    Group at Lawrence Berkeley National Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
static const char rcsid[] =
    "@(#) $Header: session-vat.cc,v 1.9 96/04/04 03:46:39 van Exp $ (LBL)";

#include "config.h"
#include <math.h>
#include "session.h"
#include "source.h"
#include "rtp.h"
#include "ntp-time.h"

/*
 * A class for backward compat with the old vat protocol
 * (vat-3.x and earlier).  Vat now uses RTPv2.
 */
class VatSessionManager : public AudioSessionManager {
    public:
      virtual void send_bye();
      virtual void send_report();
    protected:
      virtual void transmit(pktbuf* pb);
      virtual void recv(CtrlHandler*);
      virtual void recv(DataHandler*);
};

static class VatSessionMatcher : public Matcher {
    public:
      VatSessionMatcher() : Matcher("session") {}
      TclObject* match(const char* id) {
            if (strcmp(id, "audio/vat") == 0)
                  return (new VatSessionManager);
            else
                  return (0);
      }
} vat_matcher;

/*
 * this table maps vat format codes to RTP format codes.  Invalid
 * codes are signaled by -1.  The table includes the 2 'must be zero'
 * bits in the vat hdr to merge their check with the fmt code check.
 */
static const signed char rtp_format[128] = {
      RTP_PT_PCMU, RTP_PT_CELP, -1,              RTP_PT_GSM,      //  0 - 3
      -1,        -1,      -1,        -1,        //  4 - 7
      -1,        -1,      -1,        -1,        //  8 - 11
      -1,        -1,      -1,        -1,        // 12 - 15
      -1,        -1,      -1,        -1,        // 16 - 19
      -1,        -1,      -1,        -1,        // 20 - 23
      -1,        -1,      -1,        -1,        // 24 - 27
      RTP_PT_LPC,  RTP_PT_LPC,  RTP_PT_DVI,  -1,            // 28 - 31

      // remaining codes are not valid vat formats 
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 48
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //112
};

static timeval tzero;

void VatSessionManager::transmit(pktbuf* pb)
{
      mh_.msg_iov = pb->iov;
      Network* net = dh_.net();
      /*
       * Smash the packet for RTPv1 compat.
       * (put the contents back because it gets looped back above)
       */
      rtphdr rhs = *(rtphdr*)pb->iov[0].iov_base; // save
      pb->iov[0].iov_base = (caddr_t)pb->iov[0].iov_base + 4;
      pb->iov[0].iov_len -= 4;
      u_char* bp = (u_char*)pb->iov[0].iov_base;
      bp[0] = 0;
      int flags = ((u_char*)&rhs)[1];
      int fmt = flags & 0x7f;
      if (fmt == RTP_PT_LPC)
            fmt = 28;
      else if (fmt == RTP_PT_DVI)
            /*XXX*/
            fmt = 30;
      bp[1] = (flags & 0x80) | fmt;
      bp[2] = confid_ >> 8;
      bp[3] = confid_;
      *(u_int32_t*)&bp[4] = rhs.rh_ts;
      net->sendmsg(mh_);
      pb->iov[0].iov_len += 4;
      pb->iov[0].iov_base = (caddr_t)pb->iov[0].iov_base - 4;
      *(rtphdr*)pb->iov[0].iov_base = rhs;
}

/*
 * Send a vat report packet.
 */
void VatSessionManager::send_report()
{
      SourceManager& sm = SourceManager::instance();
      Source& s = *sm.localsrc();
      s.lts_ctrl(unixtime());

      u_char* bp = pktbuf_;
      bp[0] = 0;
      bp[1] = 1;
      bp[2] = confid_ >> 8;
      bp[3] = confid_;
      const char* name = s.sdes(RTCP_SDES_NAME);
      int n = strlen(name) + 1;
      memcpy(&bp[4], name, n);
      ch_.send(pktbuf_, n + 4);

      /* update the avg control msg size with our msg */
      rtcp_avg_size_ += RTCP_SIZE_GAIN * (double(n + 32) - rtcp_avg_size_);

      /*
       * compute the time to the next report.  The bandwidth
       * limit for rtcp traffic was set on startup from the
       * session bandwidth.  It is the inverse of bandwidth
       * (ie., ms/byte) to avoid a divide below.
       */
      int nsrc = sm.nsources();
      double rint = rtcp_avg_size_ * double(nsrc) * rtcp_inv_bw_;
      if (rint < RTCP_MIN_RPT_TIME * 1000.)
            rint = RTCP_MIN_RPT_TIME * 1000.;
      rt_.msched(int(fmod(double(random()), rint) + rint * .5 + .5));
      sm.CheckActiveSources(rint);
}

/*
 * Send a vat bye message.
 */
void VatSessionManager::send_bye()
{
      u_int8_t* bp = pktbuf_;
      bp[0] = 0;
      bp[1] = 2;
      bp[2] = confid_ >> 8;
      bp[3] = confid_;
      ch_.send(pktbuf_, 4);
}

void VatSessionManager::recv(DataHandler* dh)
{
      u_int32_t addr;
      u_char* bp = &pktbuf_[4];
      int cc = dh->recv(bp, 2 * RTP_MTU - 4, addr);
      if (cc <= 8) {
            ++nrunt_;
            return;
      }
      int flags = ntohs(*(u_int16_t*)bp);
      if ((flags & 0xc000) != 0 || ntohs(*(u_int16_t*)(bp + 2)) != confid_) {
            ++badversion_;
            return;
      }
      int fmt = rtp_format[flags & 0x7f];
      if (fmt < 0) {
            ++badfmt_;
            return;
      }

      u_int32_t ts = *(u_int32_t*)(bp + 4);
      SourceManager& sm = SourceManager::instance();
      Source* s = sm.lookup(addr, addr, addr);
      timeval now = unixtime();

      /* skip over vat header */
      cc -= 8;
      bp += 8;
      rtphdr* rh = (rtphdr*)(bp - 12);

      s->np(1);
      s->nb(cc + sizeof(*rh));
      if (s->checkseq(ntohl(ts) / FRAMESIZE))
            /* this is a dup */
            return;

      int cnt = (flags >> 8) & 0x3f;
      if (cnt > 0) {
            if (cc <= cnt * 4) {
                  ++badoptions_; /*XXX*/
                  return;
            }
            s->ismixer(1);
            rh = (rtphdr*)((char*)rh + (cnt << 2));
            while (--cnt >= 0) {
                  u_int32_t csrc = *(u_int32_t*)bp;
                  bp += 4;
                  cc -= 4;
                  Source* cs = sm.lookup(csrc, addr, addr);
                  cs->lts_data(now);
                  cs->sts_data(ts);
                  cs->action();
            }
      } else {
            s->lts_data(now);
            s->sts_data(ts);
            /*
             * because of bugs in the vat-2/3 'mixer' code, we
             * occasionally get packets from a 'mixer' that's not
             * really active.  suppress marking a mixer active
             * unless we got a name from it.
             */
            if (s->ismixer() == 0 || s->sdes(0))
                  s->action();
      }

      /* fill in stuff decoders want */
      flags = (flags & 0x80) | fmt;
      rh->rh_flags = ntohs(flags);
      rh->rh_ts = ts;
      if (flags & RTP_M)
            s->nf(1);

      /*
       * This is a data packet.  If the source needs activation,
       * or the packet format has changed, deal with this.
       * Then, hand the packet off to the packet handler.
       * XXX might want to be careful about flip-flopping
       * here when format changes due to misordered packets
       * (easy solution -- keep rtp seqno of last fmt change).
       */
      PacketHandler* h = s->handler();
      if (h == 0)
            h = s->activate(fmt);
      else if (s->format() != fmt)
            h = s->change_format(fmt);

      int hlen = h->hdrlen();
      cc -= hlen;
      if (cc < 0) {
            s->runt(1);
            return;
      }
      if (!s->mute())
            h->recv(rh, bp + hlen, cc);
}

void VatSessionManager::recv(CtrlHandler* ch)
{
      /*
       * handle in incoming vat session packet
       */
      u_int8_t* bp = pktbuf_;
      u_int32_t addr;
      int cc = ch->recv(bp, 2 * RTP_MTU, addr);
      if (cc <= 0)
            return;
      if (cc < 4) {
            ++nrunt_;
            return;
      }
      if ((bp[0] & 0xc0) != 0 || ntohs(*(u_int16_t*)(bp + 2)) != confid_) {
            ++badversion_;
            return;
      }
      rtcp_avg_size_ += RTCP_SIZE_GAIN * (double(cc + 28) - rtcp_avg_size_);

      SourceManager& sm = SourceManager::instance();
      Source* s = sm.lookup(addr, addr, addr);

      u_int8_t* ep = &bp[cc];
      *ep = 0;
      int i;
      timeval now = unixtime();
      switch (bp[1]) {

      case 1: /* ID */
            s->sdes(RTCP_SDES_NAME, (char*)&bp[4]);
            if (s->lts_done().tv_sec &&
                int(now.tv_sec - s->lts_done().tv_sec) > 2) {
                  /*
                   * the site said it was done but then came back -
                   * reactivate it.  (the 2 second delay is to
                   * account for possible packet reordering.)
                   */
                  s->lts_done(tzero);
                  s->lost(0);
            }
            break;

       case 2: /* BYE */
            s->lts_done(now);
            break;

      case 3: /* IDLIST */
            i = bp[4];
            bp += 8;
            while (--i >= 0 && bp < ep) {
                  u_int32_t id = *(u_int32_t*)bp;
                  bp += 4;
                  /* 
                   * Due to a bug in vat-3, mixers are
                   * identified with id 0.  We conveniently
                   * use this fact to filter out mixer
                   * names, since the rest of vat assumes
                   * that a mixer usually won't send their
                   * name and uses this as a hint to
                   * not display them in the UI.  (In RTP,
                   * if a mixer does send it's name, then
                   * we go ahead and display it.)
                   */
                  if (id != 0) {
                        s = sm.lookup(id, addr, addr);
                        s->sdes(RTCP_SDES_NAME, (char*)bp);
                        s->lts_ctrl(now);
                  }
                  int n = strlen((char*)bp);
                  n += 4 - (n & 3);
                  bp += n;
            }
            break;
      }
      s->lts_ctrl(now);
}

Generated by  Doxygen 1.6.0   Back to index