Public Member Functions | Protected Attributes

TAO_AV_RTCP_Callback Class Reference

TAO_AV_Callback for RTCP protocol. More...

#include <RTCP.h>

Inheritance diagram for TAO_AV_RTCP_Callback:
Inheritance graph
[legend]
Collaboration diagram for TAO_AV_RTCP_Callback:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 TAO_AV_RTCP_Callback (void)
 RTCP callback.
virtual ~TAO_AV_RTCP_Callback (void)
 virtual destructor.
virtual int handle_start (void)
 Called during Streamctrl->start.
virtual int handle_stop (void)
 Called during Streamctrl->stop.
virtual int handle_timeout (void *arg)
 Called during timeout for Flow Producers.
virtual int receive_frame (ACE_Message_Block *frame, TAO_AV_frame_info *frame_info=0, const ACE_Addr &peer_address=ACE_Addr::sap_any)
 Called when a frame arrives for a FlowConsumer.
int send_frame (ACE_Message_Block *frame)
virtual int receive_control_frame (ACE_Message_Block *frame, const ACE_Addr &peer_address=ACE_Addr::sap_any)
virtual int handle_destroy (void)
virtual void get_timeout (ACE_Time_Value *&tv, void *&arg)
int send_report (int bye)
void schedule (int ms)
TAO_AV_RTP_State * state (void)
void ts_offset (ACE_UINT32 offset)

Protected Attributes

ACE_Hash_Map_Manager
< ACE_UINT32, RTCP_Channel_In
*, ACE_Null_Mutex
inputs_
RTCP_Channel_Out output_
int timeout_
int timestamp_offset_
int sdes_count_
int is_initial_timeout_
int avg_rtcp_size_
int packet_size_

Detailed Description

TAO_AV_Callback for RTCP protocol.

Definition at line 139 of file RTCP.h.


Constructor & Destructor Documentation

TAO_AV_RTCP_Callback::TAO_AV_RTCP_Callback ( void   ) 

RTCP callback.

Definition at line 498 of file RTCP.cpp.

  :is_initial_timeout_(1),
   packet_size_(0)
{
  char cname[256];
  char host[256];
  ACE_OS::hostname(host, sizeof(host));

  // TODO: determine username auto-magically?
  ACE_OS::sprintf(cname, "username@%s", host);

  this->output_.cname(cname);
}

TAO_AV_RTCP_Callback::~TAO_AV_RTCP_Callback ( void   )  [virtual]

virtual destructor.

Definition at line 512 of file RTCP.cpp.

{
}


Member Function Documentation

void TAO_AV_RTCP_Callback::get_timeout ( ACE_Time_Value *&  tv,
void *&  arg 
) [virtual]

Called to get the timeout. If tv is 0 then the framework stop calling this.

Reimplemented from TAO_AV_Callback.

Definition at line 728 of file RTCP.cpp.

{
  int senders = 0;
  int members = 1;  // count self as member

  // TODO: this should be 5% of the session bw
  double rtcp_bw = 1000;
  double interval;

  ACE_Hash_Map_Iterator<ACE_UINT32, RTCP_Channel_In*, ACE_Null_Mutex> iter (this->inputs_);
  iter = this->inputs_.begin();

  if (this->output_.active ())
    senders++;

  // determine the number of senders and members of this session
  while (iter != this->inputs_.end ())
    {
      if ((*iter).int_id_->active ())
        {
          if ((*iter).int_id_->sender ())
            senders++;
          members++;
        }
      iter++;
    }

  // Here we do the RTCP timeout calculation.
  interval = TAO_AV_RTCP::rtcp_interval (members,                  // members
                                         senders,                  // senders
                                         rtcp_bw,                  // rtcp_bw
                                         this->output_.active (),  // we_sent
                                         this->packet_size_,       // packet_size
                                         &this->avg_rtcp_size_,    // avg_rtcp_size
                                         this->is_initial_timeout_);  // initial)

  this->is_initial_timeout_ = 0;

  ACE_NEW (tv,
           ACE_Time_Value);

  tv->sec ((int)interval);
  tv->usec ((int)((interval - (int)interval) * 1000000));
}

int TAO_AV_RTCP_Callback::handle_destroy ( void   )  [virtual]

Called during Streamctrl->destroy i.e tear_down of the stream @coryan:Call it handle_destroy or handle_close.

Reimplemented from TAO_AV_Callback.

Definition at line 775 of file RTCP.cpp.

{
  return 0;
}

int TAO_AV_RTCP_Callback::handle_start ( void   )  [virtual]

Called during Streamctrl->start.

Reimplemented from TAO_AV_Callback.

Definition at line 523 of file RTCP.cpp.

{
  return 0;
}

int TAO_AV_RTCP_Callback::handle_stop ( void   )  [virtual]

Called during Streamctrl->stop.

Reimplemented from TAO_AV_Callback.

Definition at line 529 of file RTCP.cpp.

{
  return this->send_report(1);
}

int TAO_AV_RTCP_Callback::handle_timeout ( void *  arg  )  [virtual]

Called during timeout for Flow Producers.

Reimplemented from TAO_AV_Callback.

Definition at line 535 of file RTCP.cpp.

{
  return this->send_report(0);
}

int TAO_AV_RTCP_Callback::receive_control_frame ( ACE_Message_Block data,
const ACE_Addr peer_address = ACE_Addr::sap_any 
) [virtual]

Copyright (c) 1994-1995 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 University of California, Berkeley and the Network Research Group at Lawrence Berkeley 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.

Reimplemented from TAO_AV_Callback.

Definition at line 51 of file RTCP.cpp.

{
  int length = static_cast<int> (data->length ());
  int more = length;
  char *buf_ptr = data->rd_ptr ();
  char first_rtcp_packet = 1;
  RTCP_Channel_In *c;

  // This code performs the RTCP Header validity checks detailed in RFC 1889
  // Appendix A.2

  while (more > 0)
    {
      // the second byte of the control packet is the type
      switch ((unsigned char)buf_ptr[length - more + 1])
      {
        case RTCP_PT_SR:
          {
            RTCP_SR_Packet sr(&buf_ptr[length-more],
                              &more);

            if (!sr.is_valid(first_rtcp_packet))
              ACE_DEBUG ((LM_DEBUG,
                          "TAO_AV_RTCP_Callback::receive_control_frame - "
                          "warning invalid rtcp packet\n"));

            if (this->inputs_.find (sr.ssrc (), c) == -1)
              {
                ACE_NEW_RETURN (c,
                                RTCP_Channel_In (sr.ssrc (),
                                                 &peer_address),
                                -1);
                this->inputs_.bind (sr.ssrc (), c);
              }
            c->updateStatistics (&sr);

            if (TAO_debug_level > 0)
              sr.dump ();
            break;
          }
        case RTCP_PT_RR:
          {
            RTCP_RR_Packet rr(&buf_ptr[length-more],
                              &more);

            if (!rr.is_valid(first_rtcp_packet))
              ACE_DEBUG ((LM_DEBUG,
                          "TAO_AV_RTCP_Callback::receive_control_frame - "
                          "warning invalid rtcp packet\n"));

            if (this->inputs_.find (rr.ssrc (), c) == -1)
              {
                ACE_NEW_RETURN (c,
                                RTCP_Channel_In (rr.ssrc (),
                                                 &peer_address),
                                -1);
                this->inputs_.bind (rr.ssrc (), c);
              }

            c->updateStatistics (&rr);

            if (TAO_debug_level > 0)
              rr.dump ();
            break;
          }
        case RTCP_PT_SDES:
          {
            RTCP_SDES_Packet sdes (&buf_ptr[length-more],
                                   &more);

            if (!sdes.is_valid(first_rtcp_packet))
              ACE_DEBUG ((LM_DEBUG,
                          "TAO_AV_RTCP_Callback::receive_control_frame - "
                          "warning invalid rtcp packet\n"));

            if (TAO_debug_level > 0)
              sdes.dump ();
            break;
          }
        case RTCP_PT_BYE:
          {
            RTCP_BYE_Packet bye (&buf_ptr[length-more],
                                 &more);

            if (!bye.is_valid(first_rtcp_packet))
              ACE_DEBUG ((LM_DEBUG,
                          "TAO_AV_RTCP_Callback::receive_control_frame - "
                          "warning invalid rtcp packet\n"));

            // Inform the listener that a source(s) has left the session
            ACE_UINT32 *ssrc_list;
            unsigned char length;

            bye.ssrc_list(&ssrc_list, length);

            for (int i=0; i<length; i++)
              {
                RTCP_Channel_In *c = 0;

                // remove the channel from the list
                this->inputs_.unbind(ssrc_list[i], c);

                if (c != 0)
                  delete c;
              }

            if (TAO_debug_level > 0)
              bye.dump ();

            break;
          }
        case RTCP_PT_APP:
          // If we receive one of these, ignore it.
          ACE_DEBUG ((LM_DEBUG,
                      "TAO_AV_RTCP_Callback::receive_control_frame - "
                      "APP packet - ignore\n"));
          more -= (4 + (ACE_UINT16)buf_ptr[length - more + 2]);
          break;
        default:
          ACE_DEBUG ((LM_DEBUG,
                      "TAO_AV_RTCP_Callback::receive_control_frame - "
                      "UNKNOWN packet type %u; ignore the rest\n",
                      (int)buf_ptr[length - more + 1]));
          more = 0;
      }

      first_rtcp_packet = 0;

    }

    if (more != 0)
      ACE_DEBUG ((LM_DEBUG,
                  "TAO_AV_RTCP_Callback::receive_control_frame - "
                  "Error in overall packet length\n"));
    return 0;
}

int TAO_AV_RTCP_Callback::receive_frame ( ACE_Message_Block frame,
TAO_AV_frame_info frame_info = 0,
const ACE_Addr peer_address = ACE_Addr::sap_any 
) [virtual]

Called when a frame arrives for a FlowConsumer.

Reimplemented from TAO_AV_Callback.

Definition at line 781 of file RTCP.cpp.

{
  RTCP_Channel_In *c;

  RTP_Packet packet (frame->rd_ptr(), static_cast<int> (frame->length()));

  if (this->inputs_.find (packet.ssrc(), c) < 0)
    {
      ACE_NEW_RETURN (c,
                      RTCP_Channel_In (packet.ssrc(),
                                       &peer_address),
                      -1);

      this->inputs_.bind (packet.ssrc(), c);
    }

  c->recv_rtp_packet (frame, &peer_address);
  return 0;
}

void TAO_AV_RTCP_Callback::schedule ( int  ms  ) 

Definition at line 517 of file RTCP.cpp.

{
  this->timeout_ = ms;
}

int TAO_AV_RTCP_Callback::send_frame ( ACE_Message_Block frame  ) 

Definition at line 804 of file RTCP.cpp.

{
  RTP_Packet packet (frame->rd_ptr(), static_cast<int> (frame->length()));
  this->output_.updateStatistics (&packet);

  return 0;
}

int TAO_AV_RTCP_Callback::send_report ( int  bye  ) 

Definition at line 541 of file RTCP.cpp.

{
  // get the RTCP control object in order to get the ssrc
  TAO_AV_RTCP_Object *rtcp_prot_obj = dynamic_cast<TAO_AV_RTCP_Object*> (this->protocol_object_);
  ACE_UINT32 my_ssrc = rtcp_prot_obj->ssrc ();

  RTCP_Packet *cp;
  RTCP_SDES_Packet sdes;
  ACE_CString value = "";
  ACE_CString note = "";
  unsigned char sdes_type = 0;
  RTCP_BYE_Packet *bye_packet = 0;  // only used for bye
  ACE_UINT32 ssrc_list[1];          // only used for bye

  // get an iterator for the incoming channels.
  ACE_Hash_Map_Iterator<ACE_UINT32, RTCP_Channel_In*, ACE_Null_Mutex> iter (this->inputs_);
  iter = this->inputs_.begin();

  // first send an SR/RR
  RR_Block *blocks = 0;
  RR_Block *b_iter = 0;
  RR_Block *b_ptr = 0;

  while (iter != this->inputs_.end() )
    {
      if (!b_iter)
      {
        b_ptr = (*iter).int_id_->getRRBlock ();
        if (b_ptr)
          {
            blocks = b_ptr;
            b_iter = b_ptr;
          }
      }
      else
      {
        b_ptr = (*iter).int_id_->getRRBlock ();
        if (b_ptr)
          {
            b_iter->next_ = b_ptr;
          }
      }

      iter++;
    }

  if (b_iter)
    b_iter->next_ = 0;

  if (this->output_.active ())
    {
      // get the NTP timestamp
      ACE_Time_Value unix_now = ACE_OS::gettimeofday ();
      TAO_AV_RTCP::ntp64 ntp_now = ntp64time (unix_now);
      ACE_UINT32 rtp_ts = ACE_Utils::truncate_cast<ACE_UINT32> (
                            unix_now.sec () * 8000 + unix_now.usec () / 125 +
                            this->timestamp_offset_);
      ACE_NEW_RETURN(cp,
                     RTCP_SR_Packet (my_ssrc,
                                     ntp_now.upper,
                                     ntp_now.lower,
                                     rtp_ts,
                                     this->output_.packets_sent (),
                                     this->output_.octets_sent (),
                                     blocks),
                     -1);
    }
  else
    {
      ACE_NEW_RETURN(cp,
                     RTCP_RR_Packet (my_ssrc,
                                     blocks),
                     -1);
    }

  /*
   * We always send a cname plus one other sdes
   * There's a schedule for what we send sequenced by sdes_seq_:
   *   - send 'email' every 0th & 4th packet
   *   - send 'note' every 2nd packet
   *   - send 'tool' every 6th packet
   *   - send 'name' in all the odd slots
   * (if 'note' is not the empty string, we switch the roles
   *  of name & note)
   */

  // TODO: need capability to change these settings
  switch (this->sdes_count_%8)
  {
    case 0:
    case 4:
      value = "tao-users@wustl.edu";
      sdes_type = RTCP_SDES_EMAIL;
      break;
    case 2:
      if (note.length () > 0)
        {
          value = "Joe User";
          sdes_type = RTCP_SDES_NAME;
        }
      else
        {
          value = "An important note...";
          sdes_type = RTCP_SDES_NOTE;
        }
      break;
    case 6:
      value = "TAO A/V Service";
      sdes_type = RTCP_SDES_TOOL;
      break;
    case 1:
    case 3:
    case 5:
    case 7:
      if (note.length () == 0)
        {
          value = "Joe User";
          sdes_type = RTCP_SDES_NAME;
        }
      else
        {
          value = "An important note...";
          sdes_type = RTCP_SDES_NOTE;
        }
      break;
  }

  ++this->sdes_count_;

  sdes.add_item (my_ssrc,
                 RTCP_SDES_CNAME,
                 static_cast<unsigned char> (ACE_OS::strlen(this->output_.cname())),
                 this->output_.cname());
  if (bye)
    {
      ssrc_list[0] = rtcp_prot_obj->ssrc ();

      ACE_NEW_RETURN (bye_packet,
                      RTCP_BYE_Packet(ssrc_list,
                                      sizeof(ssrc_list)/sizeof(ssrc_list[0]),
                                      "Got bored."),
                      -1);
    }
  else
    {
      unsigned char length = (unsigned char)(value.length() & 0xFF);
      sdes.add_item (my_ssrc, sdes_type, length, value.c_str ());
    }

  // create the message block
  char *cp_ptr;
  char *sdes_ptr;
  char *bye_ptr = 0;
  ACE_UINT16 cp_length;
  ACE_UINT16 sdes_length;
  ACE_UINT16 bye_length = 0;
  cp->get_packet_data (&cp_ptr, cp_length);
  sdes.get_packet_data (&sdes_ptr, sdes_length);
  if (bye_packet)
    bye_packet->get_packet_data(&bye_ptr, bye_length);

  ACE_Message_Block mb (cp_length + sdes_length + bye_length);

  ACE_OS::memcpy (mb.wr_ptr (), cp_ptr, cp_length);
  mb.wr_ptr (cp_length);
  ACE_OS::memcpy (mb.wr_ptr (), sdes_ptr, sdes_length);
  mb.wr_ptr (sdes_length);
  if (bye_length)
    {
      ACE_OS::memcpy (mb.wr_ptr (), bye_ptr, bye_length);
      mb.wr_ptr (bye_length);
    }

  // send the report
  this->protocol_object_->send_frame (&mb);

  this->packet_size_ = cp_length + sdes_length + bye_length;

  delete cp;
  if (bye_packet)
    delete bye_packet;

  return 0;
}

TAO_AV_RTP_State* TAO_AV_RTCP_Callback::state ( void   ) 
void TAO_AV_RTCP_Callback::ts_offset ( ACE_UINT32  offset  ) 

Definition at line 813 of file RTCP.cpp.

{
  this->timestamp_offset_ = offset;
}


Member Data Documentation

Definition at line 188 of file RTCP.h.

Definition at line 181 of file RTCP.h.

Definition at line 187 of file RTCP.h.

Definition at line 182 of file RTCP.h.

Definition at line 189 of file RTCP.h.

Definition at line 185 of file RTCP.h.

Definition at line 183 of file RTCP.h.

Definition at line 184 of file RTCP.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines