wvsyncstream.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2002 Net Integration Technologies, Inc.
00004  *
00005  * WvSyncStream throttles its input to the specified bitrate.
00006  * It only becomes readable at periodic intervals.
00007  */
00008 #include "wvsyncstream.h"
00009 #include "wvtimeutils.h"
00010 
00011 WvSyncStream::WvSyncStream(WvStream *_cloned, size_t _bps,
00012     size_t _avgchunk, size_t _maxchunk) :
00013     WvStreamClone(_cloned)
00014 {
00015     init(_bps, _avgchunk, _maxchunk);
00016 }
00017 
00018 
00019 WvSyncStream::WvSyncStream(WvStream *_cloned, bool _owner, int _srate,
00020     int _bits, int _msec) : WvStreamClone(_cloned)
00021 {
00022     size_t _bps = _srate * _bits / 8;
00023     size_t _avgchunk = _bps * _msec / 1000;
00024     init(_bps, _avgchunk, _avgchunk * 5); // arbitrary choice
00025     disassociate_on_close = ! _owner;
00026 }
00027 
00028 
00029 WvSyncStream::~WvSyncStream()
00030 {
00031     close();
00032 }
00033 
00034 
00035 void WvSyncStream::init(size_t _bps, size_t _avgchunk, size_t _maxchunk)
00036 {
00037     bps = _bps;
00038     avgchunk = _avgchunk;
00039     maxchunk = _maxchunk;
00040     // allow +/- 50% tolerance
00041     // FIXME: this is a purely arbitrary number
00042     int tol = avgchunk / 2;
00043     lowater = avgchunk - tol;
00044     hiwater = avgchunk + tol;
00045     waiting = false;
00046     resettimer();
00047 
00048     force_select(true, false, false);
00049 }
00050 
00051 
00052 size_t WvSyncStream::uread(void *buf, size_t count)
00053 {
00054     poll();
00055     if (count > availchunk)
00056         count = availchunk;
00057     if (availchunk == 0)
00058         return 0; // try again later
00059 
00060     size_t len = WvStreamClone::uread(buf, count);
00061     availchunk -= len;
00062     usedchunk += len;
00063     return len;
00064 }
00065 
00066 
00067 bool WvSyncStream::pre_select(SelectInfo &si)
00068 {
00069     if (waiting)
00070     {
00071         poll();
00072         if (availchunk < lowater)
00073         {
00074             time_t timeout = (hiwater - availchunk) * 1000 / bps + 1;
00075             if (timeout > 0)
00076             {
00077                 if (timeout < si.msec_timeout || si.msec_timeout < 0)
00078                     si.msec_timeout = timeout;
00079                 return false;
00080             }
00081         }
00082         waiting = false;
00083         return true; // we know we had data
00084     }
00085     return WvStreamClone::pre_select(si);
00086 }
00087 
00088 
00089 bool WvSyncStream::post_select(SelectInfo &si)
00090 {
00091     bool havedata = WvStreamClone::post_select(si);
00092     if (havedata && si.wants.readable)
00093     {
00094         poll();
00095         if (availchunk < lowater)
00096         {
00097             // not enough data to care about right now
00098             waiting = true;
00099             return false;
00100         }
00101     }
00102     return havedata;
00103 }
00104 
00105 
00106 void WvSyncStream::poll()
00107 {
00108     // we advance the reference time periodically size to avoid
00109     // overflows during some integer calculations
00110     const int WINDOW = 10;
00111 
00112     // how long has it been since we started
00113     struct timeval now;
00114     gettimeofday(& now, NULL);
00115     time_t msec = msecdiff(now, reference);
00116     if (msec > WINDOW * 1000 * 2)
00117     {
00118         // avoid overflow by adjusting reference time
00119         reference.tv_sec += WINDOW;
00120         msec -= WINDOW * 1000;
00121         size_t consume = WINDOW * bps;
00122         if (usedchunk >= consume)
00123             usedchunk -= consume;
00124         else
00125             usedchunk = 0; // got very far behind reading?
00126     }
00127     else if (msec < 0)
00128     {
00129         // reference clock is confused!
00130         resettimer();
00131         return;
00132     }
00133     
00134     // how much can we read?
00135     size_t totalchunk = bps * msec / 1000;
00136     availchunk = totalchunk - usedchunk;
00137     if (availchunk > maxchunk)
00138     {
00139         // resynchronize after a long delay
00140         availchunk = maxchunk;
00141         usedchunk = totalchunk - availchunk;
00142     }
00143 }
00144 
00145 
00146 void WvSyncStream::resettimer()
00147 {
00148     // make full chunk available immediately
00149     gettimeofday(& reference, NULL);
00150     reference.tv_sec -= 1;
00151     availchunk = hiwater;
00152     usedchunk = bps - availchunk;
00153 }

Generated on Sun Sep 24 20:10:52 2006 for WvStreams by  doxygen 1.4.7