TAO_AV_Callback for RTCP protocol. More...
#include <RTCP.h>
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_ |
TAO_AV_Callback for RTCP protocol.
Definition at line 139 of file RTCP.h.
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] |
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 | ) |
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; }
int TAO_AV_RTCP_Callback::avg_rtcp_size_ [protected] |
ACE_Hash_Map_Manager<ACE_UINT32, RTCP_Channel_In*, ACE_Null_Mutex> TAO_AV_RTCP_Callback::inputs_ [protected] |
int TAO_AV_RTCP_Callback::is_initial_timeout_ [protected] |
RTCP_Channel_Out TAO_AV_RTCP_Callback::output_ [protected] |
int TAO_AV_RTCP_Callback::packet_size_ [protected] |
int TAO_AV_RTCP_Callback::sdes_count_ [protected] |
int TAO_AV_RTCP_Callback::timeout_ [protected] |
int TAO_AV_RTCP_Callback::timestamp_offset_ [protected] |