00001
00002 #include <cmath>
00003 #include <cstdio>
00004 #include <cstdlib>
00005 #include <cerrno>
00006
00007
00008 #include <sys/types.h>
00009 #include <sys/stat.h>
00010 #include <sys/time.h>
00011 #include <unistd.h>
00012 #include <fcntl.h>
00013 #include <pthread.h>
00014
00015
00016 #include <qsocket.h>
00017 #include <qfile.h>
00018 #include <qapplication.h>
00019 #include <qdatetime.h>
00020 #include <qfileinfo.h>
00021
00022 using namespace std;
00023
00024 #include "exitcodes.h"
00025 #include "RingBuffer.h"
00026 #include "mythcontext.h"
00027 #include "remotefile.h"
00028 #include "remoteencoder.h"
00029 #include "ThreadedFileWriter.h"
00030 #include "livetvchain.h"
00031 #include "DVDRingBuffer.h"
00032 #include "util.h"
00033 #include "compat.h"
00034
00035 #ifndef O_STREAMING
00036 #define O_STREAMING 0
00037 #endif
00038
00039 #ifndef O_LARGEFILE
00040 #define O_LARGEFILE 0
00041 #endif
00042
00043 #ifndef O_BINARY
00044 #define O_BINARY 0
00045 #endif
00046
00047 const uint RingBuffer::kBufferSize = 3 * 1024 * 1024;
00048
00049 #define CHUNK 32768
00050
00051 #define PNG_MIN_SIZE 20
00052 #define NUV_MIN_SIZE 204
00053 #define MPEG_MIN_SIZE 376
00054
00055 #define LOC QString("RingBuf(%1): ").arg(filename)
00056 #define LOC_ERR QString("RingBuf(%1) Error: ").arg(filename)
00057
00058
00059 const uint RingBuffer::kReadTestSize = PNG_MIN_SIZE;
00060
00086 RingBuffer::RingBuffer(const QString &lfilename,
00087 bool write, bool readahead,
00088 uint read_retries)
00089 : filename(QDeepCopy<QString>(lfilename)),
00090 tfw(NULL), fd2(-1),
00091 writemode(false),
00092 readpos(0), writepos(0),
00093 stopreads(false), recorder_num(0),
00094 remoteencoder(NULL), remotefile(NULL),
00095 startreadahead(readahead),readAheadBuffer(NULL),
00096 readaheadrunning(false), readaheadpaused(false),
00097 pausereadthread(false),
00098 rbrpos(0), rbwpos(0),
00099 internalreadpos(0), ateof(false),
00100 readsallowed(false), wantseek(false), setswitchtonext(false),
00101 rawbitrate(4000), playspeed(1.0f),
00102 fill_threshold(65536), fill_min(-1),
00103 readblocksize(CHUNK), wanttoread(0),
00104 numfailures(0), commserror(false),
00105 dvdPriv(NULL), oldfile(false),
00106 livetvchain(NULL), ignoreliveeof(false),
00107 readAdjust(0)
00108 {
00109 pthread_rwlock_init(&rwlock, NULL);
00110
00111 if (write)
00112 {
00113 tfw = new ThreadedFileWriter(
00114 filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644);
00115
00116 if (!tfw->Open())
00117 {
00118 delete tfw;
00119 tfw = NULL;
00120 }
00121 writemode = true;
00122 return;
00123 }
00124
00125 if (read_retries != (uint)-1)
00126 OpenFile(filename, read_retries);
00127 }
00128
00133 bool check_permissions(const QString &filename)
00134 {
00135 QFileInfo fileInfo(filename);
00136 if (fileInfo.exists() && !fileInfo.isReadable())
00137 {
00138 VERBOSE(VB_IMPORTANT, LOC_ERR +
00139 "File exists but is not readable by MythTV!");
00140 return false;
00141 }
00142 return true;
00143 }
00144
00151 void RingBuffer::OpenFile(const QString &lfilename, uint retryCount)
00152 {
00153 VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %1)")
00154 .arg(lfilename).arg(retryCount));
00155
00156 uint openAttempts = retryCount + 1;
00157
00158 filename = lfilename;
00159
00160 if (remotefile)
00161 {
00162 delete remotefile;
00163 }
00164
00165 if (fd2 >= 0)
00166 {
00167 close(fd2);
00168 fd2 = -1;
00169 }
00170
00171 bool is_local = false;
00172 bool is_dvd = false;
00173 (void) is_dvd;
00174
00175 if ((filename.left(1) == "/") ||
00176 (QFile::exists(filename)))
00177 is_local = true;
00178 #ifdef USING_FRONTEND
00179 else if (filename.left(4) == "dvd:")
00180 {
00181 is_dvd = true;
00182 dvdPriv = new DVDRingBufferPriv();
00183 startreadahead = false;
00184
00185 if (filename.left(6) == "dvd://")
00186 filename.remove(0,5);
00187 else
00188 filename.remove(0,4);
00189
00190 if (QFile::exists(filename))
00191 VERBOSE(VB_PLAYBACK, "OpenFile() trying DVD at " + filename);
00192 else
00193 {
00194 filename = "/dev/dvd";
00195 }
00196 }
00197 #endif // USING_FRONTEND
00198
00199 if (is_local)
00200 {
00201 char buf[kReadTestSize];
00202 int timetowait = 500 * openAttempts;
00203 int lasterror = 0;
00204
00205 MythTimer openTimer;
00206 openTimer.start();
00207
00208 while (openTimer.elapsed() < timetowait)
00209 {
00210 lasterror = 0;
00211 fd2 = open(filename.local8Bit(),
00212 O_RDONLY|O_LARGEFILE|O_STREAMING|O_BINARY);
00213
00214 if (fd2 < 0)
00215 {
00216 if (!check_permissions(filename))
00217 break;
00218
00219 lasterror = 1;
00220 usleep(1000);
00221 }
00222 else
00223 {
00224 int ret = read(fd2, buf, kReadTestSize);
00225 if (ret != (int)kReadTestSize)
00226 {
00227 lasterror = 2;
00228 close(fd2);
00229 fd2 = -1;
00230 usleep(1000);
00231 }
00232 else
00233 {
00234 lseek(fd2, 0, SEEK_SET);
00235 #ifdef HAVE_POSIX_FADVISE
00236 posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL);
00237 #endif
00238 openAttempts = 0;
00239 break;
00240 }
00241 }
00242 }
00243
00244 switch (lasterror)
00245 {
00246 case 1:
00247 VERBOSE(VB_IMPORTANT, LOC +
00248 QString("Could not open %1.").arg(filename));
00249 break;
00250 case 2:
00251 VERBOSE(VB_IMPORTANT, LOC +
00252 QString("Invalid file (fd %1) when opening '%2'.")
00253 .arg(fd2).arg(filename));
00254 break;
00255 default:
00256 break;
00257 }
00258
00259
00260 QFileInfo fileInfo(filename);
00261 if (fileInfo.lastModified().secsTo(QDateTime::currentDateTime()) >
00262 30 * 60)
00263 {
00264 oldfile = true;
00265 }
00266 }
00267 #ifdef USING_FRONTEND
00268 else if (is_dvd)
00269 {
00270 dvdPriv->OpenFile(filename);
00271 readblocksize = DVD_BLOCK_SIZE * 62;
00272 }
00273 #endif // USING_FRONTEND
00274 else
00275 {
00276 remotefile = new RemoteFile(filename);
00277 if (!remotefile->isOpen())
00278 {
00279 VERBOSE(VB_IMPORTANT,
00280 QString("RingBuffer::RingBuffer(): Failed to open remote "
00281 "file (%1)").arg(filename));
00282 delete remotefile;
00283 remotefile = NULL;
00284 }
00285 }
00286
00287 setswitchtonext = false;
00288 ateof = false;
00289 commserror = false;
00290 numfailures = 0;
00291
00292 rawbitrate = 4000;
00293 CalcReadAheadThresh();
00294 }
00295
00299 bool RingBuffer::IsOpen(void) const
00300 {
00301 #ifdef USING_FRONTEND
00302 return tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen());
00303 #else // if !USING_FRONTEND
00304 return tfw || (fd2 > -1) || remotefile;
00305 #endif // !USING_FRONTEND
00306 }
00307
00311 RingBuffer::~RingBuffer(void)
00312 {
00313 KillReadAheadThread();
00314
00315 pthread_rwlock_wrlock(&rwlock);
00316
00317 if (remotefile)
00318 {
00319 delete remotefile;
00320 }
00321
00322 if (tfw)
00323 {
00324 delete tfw;
00325 tfw = NULL;
00326 }
00327
00328 if (fd2 >= 0)
00329 {
00330 close(fd2);
00331 fd2 = -1;
00332 }
00333
00334 #ifdef USING_FRONTEND
00335 if (dvdPriv)
00336 {
00337 delete dvdPriv;
00338 }
00339 #endif // USING_FRONTEND
00340
00341 pthread_rwlock_unlock(&rwlock);
00342 pthread_rwlock_destroy(&rwlock);
00343 }
00344
00352 void RingBuffer::Start(void)
00353 {
00354 if (!writemode && !readaheadrunning && startreadahead)
00355 StartupReadAheadThread();
00356 }
00357
00361 void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal)
00362 {
00363 wantseek = true;
00364 pthread_rwlock_wrlock(&rwlock);
00365 wantseek = false;
00366 numfailures = 0;
00367 commserror = false;
00368 setswitchtonext = false;
00369
00370 writepos = 0;
00371 readpos = (toAdjust) ? (readpos - readAdjust) : 0;
00372 readAdjust = 0;
00373
00374 if (full)
00375 ResetReadAhead(readpos);
00376
00377 if (resetInternal)
00378 internalreadpos = readpos;
00379
00380 pthread_rwlock_unlock(&rwlock);
00381 }
00382
00394 int RingBuffer::safe_read(int fd, void *data, uint sz)
00395 {
00396 int ret;
00397 unsigned tot = 0;
00398 unsigned errcnt = 0;
00399 unsigned zerocnt = 0;
00400
00401 if (fd < 0)
00402 {
00403 VERBOSE(VB_IMPORTANT, LOC_ERR +
00404 "Invalid file descriptor in 'safe_read()'");
00405 return 0;
00406 }
00407
00408 if (stopreads)
00409 return 0;
00410
00411 while (tot < sz)
00412 {
00413 ret = read(fd, (char *)data + tot, sz - tot);
00414 if (ret < 0)
00415 {
00416 if (errno == EAGAIN)
00417 continue;
00418
00419 VERBOSE(VB_IMPORTANT,
00420 LOC_ERR + "File I/O problem in 'safe_read()'" + ENO);
00421
00422 errcnt++;
00423 numfailures++;
00424 if (errcnt == 3)
00425 break;
00426 }
00427 else if (ret > 0)
00428 {
00429 tot += ret;
00430 }
00431
00432 if (ret == 0)
00433 {
00434 if (tot > 0)
00435 break;
00436
00437 zerocnt++;
00438
00439
00440
00441 if (zerocnt >= ((oldfile) ? 2 : (livetvchain) ? 6 : 40))
00442 {
00443 break;
00444 }
00445 }
00446 if (stopreads)
00447 break;
00448 if (tot < sz)
00449 usleep(60000);
00450 }
00451 return tot;
00452 }
00453
00462 int RingBuffer::safe_read(RemoteFile *rf, void *data, uint sz)
00463 {
00464 int ret = 0;
00465
00466 ret = rf->Read(data, sz);
00467 if (ret < 0)
00468 {
00469 VERBOSE(VB_IMPORTANT, LOC_ERR +
00470 "RingBuffer::safe_read(RemoteFile* ...): read failed");
00471
00472 rf->Seek(internalreadpos - readAdjust, SEEK_SET);
00473 ret = 0;
00474 numfailures++;
00475 }
00476
00477 return ret;
00478 }
00479
00485 void RingBuffer::UpdateRawBitrate(uint raw_bitrate)
00486 {
00487 QMutexLocker locker(&bitratelock);
00488 rawbitrate = raw_bitrate;
00489 CalcReadAheadThresh();
00490 }
00491
00498 uint RingBuffer::GetBitrate(void) const
00499 {
00500 QMutexLocker locker(&bitratelock);
00501 uint tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
00502 return min(rawbitrate * 3, tmp);
00503 }
00504
00508 uint RingBuffer::GetReadBlockSize(void) const
00509 {
00510 QMutexLocker locker(&bitratelock);
00511 return readblocksize;
00512 }
00513
00518 void RingBuffer::UpdatePlaySpeed(float play_speed)
00519 {
00520 QMutexLocker locker(&bitratelock);
00521 playspeed = play_speed;
00522 CalcReadAheadThresh();
00523 }
00524
00529 void RingBuffer::CalcReadAheadThresh(void)
00530 {
00531 uint estbitrate;
00532
00533 pthread_rwlock_wrlock(&rwlock);
00534 wantseek = false;
00535 readsallowed = false;
00536 readblocksize = CHUNK;
00537
00538
00539 fill_threshold = CHUNK * 2;
00540 fill_min = 1;
00541
00542 #ifdef USING_FRONTEND
00543 if (dvdPriv)
00544 {
00545 const uint KB32 = 32*1024;
00546 const uint KB64 = 64*1024;
00547 const uint KB128 = 128*1024;
00548 const uint KB256 = 256*1024;
00549 const uint KB512 = 512*1024;
00550
00551 estbitrate = (uint) max(abs(rawbitrate * playspeed),
00552 0.5f * rawbitrate);
00553 estbitrate = min(rawbitrate * 3, estbitrate);
00554 readblocksize = (estbitrate > 2500) ? KB64 : KB32;
00555 readblocksize = (estbitrate > 5000) ? KB128 : readblocksize;
00556 readblocksize = (estbitrate > 9000) ? KB256 : readblocksize;
00557 readblocksize = (estbitrate > 18000) ? KB512 : readblocksize;
00558
00559
00560 float secs_min = 0.1;
00561
00562
00563 fill_min = (uint) ((estbitrate * secs_min) * 0.125f);
00564
00565 fill_min = ((fill_min / KB32) + 1) * KB32;
00566 }
00567 #endif // USING_FRONTEND
00568
00569 pthread_rwlock_unlock(&rwlock);
00570
00571 VERBOSE(VB_PLAYBACK, LOC +
00572 QString("CalcReadAheadThresh(%1 KB)\n\t\t\t -> "
00573 "threshhold(%2 KB) min read(%3 KB) blk size(%4 KB)")
00574 .arg(estbitrate).arg(fill_threshold/1024)
00575 .arg(fill_min/1024).arg(readblocksize/1024));
00576 }
00577
00581 int RingBuffer::ReadBufFree(void) const
00582 {
00583 QMutexLocker locker(&readAheadLock);
00584 return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
00585 }
00586
00590 int RingBuffer::ReadBufAvail(void) const
00591 {
00592 QMutexLocker locker(&readAheadLock);
00593 return (rbwpos >= rbrpos) ?
00594 rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
00595 }
00596
00608 void RingBuffer::ResetReadAhead(long long newinternal)
00609 {
00610 readAheadLock.lock();
00611 readblocksize = CHUNK;
00612 rbrpos = 0;
00613 rbwpos = 0;
00614 internalreadpos = newinternal;
00615 ateof = false;
00616 readsallowed = false;
00617 setswitchtonext = false;
00618 readAheadLock.unlock();
00619 }
00620
00626 void RingBuffer::StartupReadAheadThread(void)
00627 {
00628 readaheadrunning = false;
00629
00630 readAheadRunningCondLock.lock();
00631 pthread_create(&reader, NULL, StartReader, this);
00632 readAheadRunningCond.wait(&readAheadRunningCondLock);
00633 readAheadRunningCondLock.unlock();
00634 }
00635
00639 void RingBuffer::KillReadAheadThread(void)
00640 {
00641 if (!readaheadrunning)
00642 return;
00643
00644 readaheadrunning = false;
00645 pthread_join(reader, NULL);
00646 }
00647
00652 void RingBuffer::StopReads(void)
00653 {
00654 stopreads = true;
00655 availWait.wakeAll();
00656 }
00657
00662 void RingBuffer::StartReads(void)
00663 {
00664 stopreads = false;
00665 }
00666
00671 void RingBuffer::Pause(void)
00672 {
00673 pausereadthread = true;
00674 StopReads();
00675 }
00676
00681 void RingBuffer::Unpause(void)
00682 {
00683 StartReads();
00684 pausereadthread = false;
00685 }
00686
00690 void RingBuffer::WaitForPause(void)
00691 {
00692 if (!readaheadrunning)
00693 return;
00694
00695 if (!readaheadpaused)
00696 {
00697 while (!pauseWait.wait(1000))
00698 VERBOSE(VB_IMPORTANT,
00699 LOC + "Waited too long for ringbuffer pause..");
00700 }
00701 }
00702
00706 void *RingBuffer::StartReader(void *type)
00707 {
00708 RingBuffer *rbuffer = (RingBuffer *)type;
00709 rbuffer->ReadAheadThread();
00710 return NULL;
00711 }
00712
00716 void RingBuffer::ReadAheadThread(void)
00717 {
00718 long long totfree = 0;
00719 int ret = -1;
00720 int used = 0;
00721 int loops = 0;
00722
00723 struct timeval lastread, now;
00724 gettimeofday(&lastread, NULL);
00725 const int KB640 = 640*1024;
00726 int readtimeavg = 300;
00727 int readinterval;
00728
00729 pausereadthread = false;
00730
00731 readAheadBuffer = new char[kBufferSize + KB640];
00732
00733 ResetReadAhead(0);
00734 totfree = ReadBufFree();
00735
00736 readaheadrunning = true;
00737 readAheadRunningCondLock.lock();
00738 readAheadRunningCond.wakeAll();
00739 readAheadRunningCondLock.unlock();
00740 while (readaheadrunning)
00741 {
00742 if (pausereadthread || writemode)
00743 {
00744 readaheadpaused = true;
00745 pauseWait.wakeAll();
00746 usleep(5000);
00747 totfree = ReadBufFree();
00748 continue;
00749 }
00750
00751 if (readaheadpaused)
00752 {
00753 totfree = ReadBufFree();
00754 readaheadpaused = false;
00755 }
00756
00757 if (totfree < readblocksize)
00758 {
00759 usleep(50000);
00760 totfree = ReadBufFree();
00761 ++loops;
00762
00763
00764 if (readsallowed && loops < 10)
00765 continue;
00766 }
00767 loops = 0;
00768
00769 pthread_rwlock_rdlock(&rwlock);
00770 if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext)
00771 {
00772
00773 totfree = readblocksize;
00774
00775
00776 gettimeofday(&now, NULL);
00777 readinterval = (now.tv_sec - lastread.tv_sec ) * 1000 +
00778 (now.tv_usec - lastread.tv_usec) / 1000;
00779
00780 readtimeavg = (readtimeavg * 9 + readinterval) / 10;
00781
00782 if (readtimeavg < 200 && readblocksize < KB640)
00783 {
00784 readblocksize += CHUNK;
00785
00786
00787
00788 readtimeavg = 300;
00789 }
00790 else if (readtimeavg > 400 && readblocksize > CHUNK)
00791 {
00792 readblocksize -= CHUNK;
00793
00794
00795
00796 readtimeavg = 300;
00797 }
00798 lastread = now;
00799
00800 if (rbwpos + totfree > kBufferSize)
00801 totfree = kBufferSize - rbwpos;
00802
00803 if (internalreadpos == 0)
00804 totfree = fill_min;
00805
00806 if (remotefile)
00807 {
00808 if (livetvchain && livetvchain->HasNext())
00809 remotefile->SetTimeout(true);
00810
00811 ret = safe_read(remotefile, readAheadBuffer + rbwpos,
00812 totfree);
00813 internalreadpos += ret;
00814 }
00815 #ifdef USING_FRONTEND
00816 else if (dvdPriv)
00817 {
00818 ret = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
00819 internalreadpos += ret;
00820 }
00821 #endif // USING_FRONTEND
00822 else
00823 {
00824 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
00825 internalreadpos += ret;
00826 }
00827
00828 readAheadLock.lock();
00829 if (ret > 0 )
00830 rbwpos = (rbwpos + ret) % kBufferSize;
00831 readAheadLock.unlock();
00832
00833 if (ret == 0 && !stopreads)
00834 {
00835 if (livetvchain)
00836 {
00837 if (!setswitchtonext && !ignoreliveeof &&
00838 livetvchain->HasNext())
00839 {
00840 livetvchain->SwitchToNext(true);
00841 setswitchtonext = true;
00842 }
00843 }
00844 else
00845 ateof = true;
00846 }
00847 }
00848
00849 if (numfailures > 5)
00850 commserror = true;
00851
00852 totfree = ReadBufFree();
00853 used = kBufferSize - totfree;
00854
00855 if (ateof || commserror)
00856 {
00857 readsallowed = true;
00858 totfree = 0;
00859 }
00860
00861 if (!readsallowed && (used >= fill_min || setswitchtonext))
00862 {
00863 readsallowed = true;
00864
00865
00866 }
00867
00868
00869
00870
00871
00872 if (readsallowed && used < fill_min && !ateof && !setswitchtonext)
00873 {
00874 readsallowed = false;
00875
00876
00877 }
00878
00879 if (readsallowed || stopreads)
00880 readsAllowedWait.wakeAll();
00881
00882 availWaitMutex.lock();
00883 if (commserror || ateof || stopreads || setswitchtonext ||
00884 (wanttoread <= used && wanttoread > 0))
00885 {
00886 availWait.wakeAll();
00887 }
00888 availWaitMutex.unlock();
00889
00890 pthread_rwlock_unlock(&rwlock);
00891
00892 if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&
00893 !pausereadthread)
00894 {
00895 usleep(500);
00896 }
00897 }
00898
00899 delete [] readAheadBuffer;
00900 readAheadBuffer = NULL;
00901 rbrpos = 0;
00902 rbwpos = 0;
00903 }
00904
00905 long long RingBuffer::SetAdjustFilesize(void)
00906 {
00907 readAdjust += internalreadpos;
00908 return readAdjust;
00909 }
00910
00911 int RingBuffer::Peek(void *buf, int count)
00912 {
00913
00914 if (!readaheadrunning)
00915 {
00916 int ret = Read(buf, count);
00917 Seek(0, SEEK_SET);
00918 return ret;
00919 }
00920
00921 return ReadFromBuf(buf, count, true);
00922 }
00923
00932 int RingBuffer::ReadFromBuf(void *buf, int count, bool peek)
00933 {
00934 if (commserror)
00935 return 0;
00936
00937 bool readone = false;
00938 int readErr = 0;
00939
00940 if (readaheadpaused && stopreads)
00941 {
00942 readone = true;
00943 Unpause();
00944 }
00945 else
00946 {
00947 while (!readsallowed && !stopreads)
00948 {
00949 if (!readsAllowedWait.wait(1000))
00950 {
00951 VERBOSE(VB_IMPORTANT,
00952 LOC + "Taking too long to be allowed to read..");
00953 readErr++;
00954
00955
00956 if ((readErr > 4 && readErr % 2) && (rbrpos ==0))
00957 {
00958 VERBOSE(VB_IMPORTANT, "restarting readhead thread..");
00959 KillReadAheadThread();
00960 StartupReadAheadThread();
00961 }
00962
00963 if (readErr > 10)
00964 {
00965 VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
00966 "10 seconds to be allowed to read, aborting.");
00967 wanttoread = 0;
00968 stopreads = true;
00969 return 0;
00970 }
00971 }
00972 }
00973 }
00974
00975 int avail = ReadBufAvail();
00976
00977 if (ateof && avail < count)
00978 count = avail;
00979
00980 MythTimer t;
00981 t.start();
00982 while (avail < count && !stopreads)
00983 {
00984 availWaitMutex.lock();
00985 wanttoread = count;
00986 if (!availWait.wait(&availWaitMutex, 250))
00987 {
00988 int elapsed = t.elapsed();
00989 if (
00990 ((elapsed > 1000) && (elapsed < 1250)) ||
00991 ((elapsed > 2000) && (elapsed < 2250)) ||
00992 ((elapsed > 4000) && (elapsed < 4250)) ||
00993 ((elapsed > 8000) && (elapsed < 8250)))
00994 {
00995 VERBOSE(VB_IMPORTANT, LOC + "Waited " +
00996 QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) +
00997 " seconds for data to become available...");
00998 if (livetvchain)
00999 {
01000 VERBOSE(VB_IMPORTANT, "Checking to see if there's a "
01001 "new livetv program to switch to..");
01002 livetvchain->ReloadAll();
01003 }
01004 }
01005
01006 bool quit = livetvchain && (livetvchain->NeedsToSwitch() ||
01007 livetvchain->NeedsToJump() ||
01008 setswitchtonext);
01009
01010 if (elapsed > 16000 || quit)
01011 {
01012 if (!quit)
01013 VERBOSE(VB_IMPORTANT, LOC_ERR + "Waited " +
01014 QString("%1").arg(elapsed/1000) +
01015 " seconds for data, aborting.");
01016 else
01017 VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to "
01018 "impending livetv switch.");
01019
01020 ateof = true;
01021 wanttoread = 0;
01022 stopreads = true;
01023 availWaitMutex.unlock();
01024 return 0;
01025 }
01026 }
01027
01028 wanttoread = 0;
01029 availWaitMutex.unlock();
01030
01031 avail = ReadBufAvail();
01032 if ((ateof || setswitchtonext) && avail < count)
01033 count = avail;
01034
01035 if (commserror)
01036 return 0;
01037 }
01038
01039 if ((ateof || stopreads) && avail < count)
01040 count = avail;
01041
01042 if (rbrpos + count > (int) kBufferSize)
01043 {
01044 int firstsize = kBufferSize - rbrpos;
01045 int secondsize = count - firstsize;
01046
01047 memcpy(buf, readAheadBuffer + rbrpos, firstsize);
01048 memcpy((char *)buf + firstsize, readAheadBuffer, secondsize);
01049 }
01050 else
01051 memcpy(buf, readAheadBuffer + rbrpos, count);
01052
01053 if (!peek)
01054 {
01055 readAheadLock.lock();
01056 rbrpos = (rbrpos + count) % kBufferSize;
01057 readAheadLock.unlock();
01058 }
01059
01060 if (readone)
01061 {
01062 Pause();
01063 WaitForPause();
01064 }
01065
01066 return count;
01067 }
01068
01077 int RingBuffer::Read(void *buf, int count)
01078 {
01079 int ret = -1;
01080 if (writemode)
01081 {
01082 VERBOSE(VB_IMPORTANT, LOC_ERR +
01083 "Attempt to read from a write only file");
01084 return ret;
01085 }
01086
01087 pthread_rwlock_rdlock(&rwlock);
01088
01089 if (!readaheadrunning)
01090 {
01091 if (remotefile)
01092 {
01093 ret = safe_read(remotefile, buf, count);
01094 readpos += ret;
01095 }
01096 #ifdef USING_FRONTEND
01097 else if (dvdPriv)
01098 {
01099 ret = dvdPriv->safe_read(buf, count);
01100 readpos += ret;
01101 }
01102 #endif // USING_FRONTEND
01103 else
01104 {
01105 ret = safe_read(fd2, buf, count);
01106 readpos += ret;
01107 }
01108 }
01109 else
01110 {
01111 ret = ReadFromBuf(buf, count);
01112 readpos += ret;
01113 }
01114
01115 pthread_rwlock_unlock(&rwlock);
01116 return ret;
01117 }
01118
01122 bool RingBuffer::IsIOBound(void) const
01123 {
01124 bool ret = false;
01125 int used, free;
01126 pthread_rwlock_rdlock(&rwlock);
01127
01128 if (!tfw)
01129 {
01130 pthread_rwlock_unlock(&rwlock);
01131 return ret;
01132 }
01133
01134 used = tfw->BufUsed();
01135 free = tfw->BufFree();
01136
01137 ret = (used * 5 > free);
01138
01139 pthread_rwlock_unlock(&rwlock);
01140 return ret;
01141 }
01142
01147 int RingBuffer::Write(const void *buf, uint count)
01148 {
01149 int ret = -1;
01150 if (!writemode)
01151 {
01152 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file.");
01153 return ret;
01154 }
01155
01156 if (!tfw)
01157 return ret;
01158
01159 pthread_rwlock_rdlock(&rwlock);
01160
01161 ret = tfw->Write(buf, count);
01162 writepos += ret;
01163
01164 pthread_rwlock_unlock(&rwlock);
01165 return ret;
01166 }
01167
01171 void RingBuffer::Sync(void)
01172 {
01173 if (tfw)
01174 tfw->Sync();
01175 }
01176
01180 long long RingBuffer::Seek(long long pos, int whence)
01181 {
01182 wantseek = true;
01183 pthread_rwlock_wrlock(&rwlock);
01184 wantseek = false;
01185
01186
01187 if ((whence == SEEK_SET && pos == readpos) ||
01188 (whence == SEEK_CUR && pos == 0))
01189 {
01190 pthread_rwlock_unlock(&rwlock);
01191 return readpos;
01192 }
01193
01194 long long ret = -1;
01195 if (remotefile)
01196 ret = remotefile->Seek(pos, whence, readpos);
01197 #ifdef USING_FRONTEND
01198 else if (dvdPriv)
01199 {
01200 dvdPriv->NormalSeek(pos);
01201 }
01202 #endif // USING_FRONTEND
01203 else
01204 {
01205 if (whence == SEEK_SET)
01206 #ifdef USING_MINGW
01207 ret = lseek64(fd2, pos, whence);
01208 #else
01209 ret = lseek(fd2, pos, whence);
01210 #endif
01211 else
01212 {
01213 long long realseek = readpos + pos;
01214 #ifdef USING_MINGW
01215 ret = lseek64(fd2, realseek, SEEK_SET);
01216 #else
01217 ret = lseek(fd2, realseek, SEEK_SET);
01218 #endif
01219 }
01220 }
01221
01222 if (whence == SEEK_SET)
01223 readpos = ret;
01224 else if (whence == SEEK_CUR)
01225 readpos += pos;
01226
01227 if (readaheadrunning)
01228 ResetReadAhead(readpos);
01229
01230 readAdjust = 0;
01231
01232 pthread_rwlock_unlock(&rwlock);
01233
01234 return ret;
01235 }
01236
01240 long long RingBuffer::WriterSeek(long long pos, int whence)
01241 {
01242 long long ret = -1;
01243
01244 if (tfw)
01245 {
01246 ret = tfw->Seek(pos, whence);
01247 writepos = ret;
01248 }
01249
01250 return ret;
01251 }
01252
01257 void RingBuffer::WriterFlush(void)
01258 {
01259 if (tfw)
01260 {
01261 tfw->Flush();
01262 tfw->Sync();
01263 }
01264 }
01265
01269 void RingBuffer::SetWriteBufferSize(int newSize)
01270 {
01271 tfw->SetWriteBufferSize(newSize);
01272 }
01273
01277 void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize)
01278 {
01279 tfw->SetWriteBufferMinWriteSize(newMinSize);
01280 }
01281
01285 long long RingBuffer::GetReadPosition(void) const
01286 {
01287 #ifdef USING_FRONTEND
01288 if (dvdPriv)
01289 return dvdPriv->GetReadPosition();
01290 #endif // USING_FRONTEND
01291
01292 return readpos;
01293 }
01294
01298 long long RingBuffer::GetWritePosition(void) const
01299 {
01300 return writepos;
01301 }
01302
01307 long long RingBuffer::GetRealFileSize(void) const
01308 {
01309 if (remotefile)
01310 return remotefile->GetFileSize();
01311
01312 struct stat st;
01313 if (stat(filename.ascii(), &st) == 0)
01314 return st.st_size;
01315 return -1;
01316 }
01317
01322 bool RingBuffer::LiveMode(void) const
01323 {
01324 return (livetvchain);
01325 }
01326
01331 void RingBuffer::SetLiveMode(LiveTVChain *chain)
01332 {
01333 livetvchain = chain;
01334 }
01335
01336 bool RingBuffer::InDVDMenuOrStillFrame(void)
01337 {
01338 #ifdef USING_FRONTEND
01339 if (dvdPriv)
01340 return (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
01341 #endif // USING_FRONTEND
01342 return false;
01343 }
01344
01345