rtp.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1997 Regents of the University of California.
00004  * All rights reserved.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *  This product includes software developed by the MASH Research
00017  *  Group at the University of California Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group may be
00019  *    used to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  * 
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  */
00034 
00035 #ifndef lint
00036 static const char rcsid[] =
00037     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/apps/rtp.cc,v 1.27 2005/08/22 05:08:32 tomh Exp $";
00038 #endif
00039 
00040 
00041 #include <stdlib.h>
00042 
00043 #include "config.h"
00044 #include "agent.h"
00045 #include "random.h"
00046 #include "rtp.h"
00047 
00048 int hdr_rtp::offset_;
00049 
00050 class RTPHeaderClass : public PacketHeaderClass {
00051 public: 
00052         RTPHeaderClass() : PacketHeaderClass("PacketHeader/RTP",
00053                          sizeof(hdr_rtp)) {
00054         bind_offset(&hdr_rtp::offset_);
00055     }
00056 } class_rtphdr;
00057 
00058 static class RTPAgentClass : public TclClass {
00059 public:
00060     RTPAgentClass() : TclClass("Agent/RTP") {}
00061     TclObject* create(int, const char*const*) {
00062         return (new RTPAgent());
00063     }
00064 } class_rtp_agent;
00065 
00066 RTPAgent::RTPAgent() : Agent(PT_RTP), session_(0), lastpkttime_(-1e6), 
00067     running_(0), rtp_timer_(this)
00068 {
00069     bind("seqno_", &seqno_);
00070     bind_time("interval_", &interval_);
00071     bind("packetSize_", &size_);
00072     bind("maxpkts_", &maxpkts_);
00073     bind("random_", &random_);
00074 }
00075 
00076 void RTPAgent::start()
00077 {
00078         running_ = 1;
00079         sendpkt();
00080         rtp_timer_.resched(interval_);
00081 }
00082 
00083 void RTPAgent::stop()
00084 {
00085         rtp_timer_.force_cancel();
00086         finish();
00087 }
00088 
00089 void RTPAgent::sendmsg(int nbytes, const char* /*flags*/)
00090 {
00091         Packet *p;
00092         int n;
00093 
00094     assert (size_ > 0);
00095 
00096         if (++seqno_ < maxpkts_) {
00097         n = nbytes / size_;
00098 
00099                 if (nbytes == -1) {
00100                         start();
00101                         return;
00102                 }
00103                 while (n-- > 0) {
00104                         p = allocpkt();
00105                         hdr_rtp* rh = hdr_rtp::access(p);
00106                         rh->seqno() = seqno_;
00107                         target_->recv(p);
00108                 }
00109                 n = nbytes % size_;
00110                 if (n > 0) {
00111                         p = allocpkt();
00112                         hdr_rtp* rh = hdr_rtp::access(p);
00113                         rh->seqno() = seqno_;
00114                         target_->recv(p);
00115                 }
00116                 idle();
00117         } else {
00118                 finish();
00119                 // xxx: should we deschedule the timer here? */
00120         };
00121 }
00122 
00123 void RTPAgent::timeout(int) 
00124 {
00125     if (running_) {
00126         sendpkt();
00127         if (session_)
00128             session_->localsrc_update(size_);
00129         double t = interval_;
00130         if (random_)
00131             /* add some zero-mean white noise */
00132             t += interval_ * Random::uniform(-0.5, 0.5);
00133         rtp_timer_.resched(t);
00134     }
00135 }
00136 
00137 /*
00138  * finish() is called when we must stop (either by request or because
00139  * we're out of packets to send.
00140  */
00141 void RTPAgent::finish()
00142 {
00143         running_ = 0;
00144         Tcl::instance().evalf("%s done", this->name());
00145 }
00146 
00147 void RTPAgent::advanceby(int delta)
00148 {
00149         maxpkts_ += delta;
00150         if (seqno_ < maxpkts_ && !running_)
00151                 start();
00152 }               
00153 
00154 
00155 void RTPAgent::recv(Packet* p, Handler*)
00156 {
00157     if (session_)
00158         session_->recv(p, 0);
00159     else
00160         Packet::free(p);
00161 }
00162 
00163 int RTPAgent::command(int argc, const char*const* argv)
00164 {
00165     if (argc == 2) {
00166         if (strcmp(argv[1], "rate-change") == 0) {
00167             rate_change();
00168             return (TCL_OK);
00169         } else if (strcmp(argv[1], "start") == 0) {
00170                         start();
00171                         return (TCL_OK);
00172                 } else if (strcmp(argv[1], "stop") == 0) {
00173                         stop();
00174                         return (TCL_OK);
00175                 }
00176     } else if (argc == 3) {
00177         if (strcmp(argv[1], "session") == 0) {
00178             session_ = (RTPSession*)TclObject::lookup(argv[2]);
00179             return (TCL_OK);
00180         } else if (strcmp(argv[1], "advance") == 0) {
00181                         int newseq = atoi(argv[2]);
00182                         advanceby(newseq - seqno_);
00183                         return (TCL_OK); 
00184                 } else if (strcmp(argv[1], "advanceby") == 0) {
00185                         advanceby(atoi(argv[2]));
00186                         return (TCL_OK);
00187                 }       
00188     }
00189     return (Agent::command(argc, argv));
00190 }
00191 
00192 /* 
00193  * We modify the rate in this way to get a faster reaction to the a rate
00194  * change since a rate change from a very low rate to a very fast rate may 
00195  * take an undesireably long time if we have to wait for timeout at the old
00196  * rate before we can send at the new (faster) rate.
00197  */
00198 void RTPAgent::rate_change()
00199 {
00200     rtp_timer_.force_cancel();
00201     
00202     double t = lastpkttime_ + interval_;
00203     
00204     double now = Scheduler::instance().clock();
00205     if ( t > now)
00206         rtp_timer_.resched(t - now);
00207     else {
00208         sendpkt();
00209         rtp_timer_.resched(interval_);
00210     }
00211 }
00212 
00213 void RTPAgent::sendpkt()
00214 {
00215     Packet* p = allocpkt();
00216     lastpkttime_ = Scheduler::instance().clock();
00217     makepkt(p);
00218     target_->recv(p, (Handler*)0);
00219 }
00220 
00221 void RTPAgent::makepkt(Packet* p)
00222 {
00223     hdr_rtp *rh = hdr_rtp::access(p);
00224     /* Fill in srcid_ and seqno */
00225     rh->seqno() = seqno_++;
00226     rh->srcid() = session_ ? session_->srcid() : 0;
00227 }
00228 
00229 void RTPTimer::expire(Event* /*e*/) {
00230         a_->timeout(0);
00231 }
00232 

Generated on Tue Mar 6 16:47:50 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6