00001
00002
00003
00004
00005
00006
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);
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
00041
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;
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;
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
00098 waiting = true;
00099 return false;
00100 }
00101 }
00102 return havedata;
00103 }
00104
00105
00106 void WvSyncStream::poll()
00107 {
00108
00109
00110 const int WINDOW = 10;
00111
00112
00113 struct timeval now;
00114 gettimeofday(& now, NULL);
00115 time_t msec = msecdiff(now, reference);
00116 if (msec > WINDOW * 1000 * 2)
00117 {
00118
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;
00126 }
00127 else if (msec < 0)
00128 {
00129
00130 resettimer();
00131 return;
00132 }
00133
00134
00135 size_t totalchunk = bps * msec / 1000;
00136 availchunk = totalchunk - usedchunk;
00137 if (availchunk > maxchunk)
00138 {
00139
00140 availchunk = maxchunk;
00141 usedchunk = totalchunk - availchunk;
00142 }
00143 }
00144
00145
00146 void WvSyncStream::resettimer()
00147 {
00148
00149 gettimeofday(& reference, NULL);
00150 reference.tv_sec -= 1;
00151 availchunk = hiwater;
00152 usedchunk = bps - availchunk;
00153 }