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 }