#include <lib/base/filepush.h>
#include <lib/base/eerror.h>
+#include <lib/base/nconfig.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <sys/vfs.h>
+#if 0
+#include <dirent.h>
+#else
+#include <sys/types.h>
+#endif
#define PVR_COMMIT 1
+#define MAJORSD_ 8
+#define MAJORMMCBLK 179
+#define LIMIT_FILESIZE_NOHDD 2*1024*1024*1024LL // 2GBytes
+
//FILE *f = fopen("/log.ts", "wb");
+static bool g_is_diskfull = false;
eFilePushThread::eFilePushThread(int io_prio_class, int io_prio_level, int blocksize)
:prio_class(io_prio_class), prio(io_prio_level), m_messagepump(eApp, 0)
flush();
enablePVRCommit(0);
CONNECT(m_messagepump.recv_msg, eFilePushThread::recvEvent);
+ m_is_timeshift = false;
+ m_hdd_connected = true;
}
static void signal_handler(int x)
{
setIoPrio(prio_class, prio);
- off_t dest_pos = 0, source_pos = 0;
+ off_t dest_pos = 0;
size_t bytes_read = 0;
off_t current_span_offset = 0;
size_t written_since_last_sync = 0;
+#if 0
+ DIR *tsdir_info;
+ struct dirent *tsdir_entry;
+ tsdir_info = opendir("/sys/block");
+ if (tsdir_info != NULL) {
+ m_hdd_connected = false;
+ while (tsdir_entry = readdir(tsdir_info)) {
+ if (strncmp(tsdir_entry->d_name, "sd", 2) == 0) {
+ eDebug("HDD found: %s", tsdir_entry->d_name);
+ m_hdd_connected = true;
+ break;
+ }
+ }
+ }
+#else
+ if (m_tspath.empty())
+ defaultTSPath(m_is_timeshift);
+
+ struct stat tspath_st;
+ if (stat(m_tspath.c_str(), &tspath_st) == 0) {
+ if (major(tspath_st.st_dev) == MAJORSD_) {
+ eDebug("%s location on HDD!", m_tspath.c_str());
+ m_hdd_connected = true;
+ } else if (major(tspath_st.st_dev) == MAJORMMCBLK) {
+ eDebug("%s location on eMMC!", m_tspath.c_str());
+ m_hdd_connected = false;
+ } else {
+ eDebug("%s location on other device", m_tspath.c_str());
+ }
+ } else {
+ eDebug("stat failed!");
+ }
+#endif
+
eDebug("FILEPUSH THREAD START");
/* we set the signal to not restart syscalls, so we can detect our signal. */
sigaction(SIGUSR1, &act, 0);
hasStarted();
-
- source_pos = m_raw_source.lseek(0, SEEK_CUR);
-
+
/* m_stop must be evaluated after each syscall. */
while (!m_stop)
{
// eDebug("wrote %d bytes", w);
if (w <= 0)
{
- if (errno == EINTR || errno == EAGAIN || errno == EBUSY)
+ if (w < 0 && (errno == EINTR || errno == EAGAIN || errno == EBUSY))
continue;
eDebug("eFilePushThread WRITE ERROR");
sendEvent(evtWriteError);
+
+ struct statfs fs;
+ if (statfs(m_tspath.c_str(), &fs) < 0) {
+ eDebug("statfs failed!");
+ }
+ if ((off_t)fs.f_bavail < 1) {
+ eDebug("not enough diskspace!");
+ g_is_diskfull = true;
+ }
break;
// ... we would stop the thread
}
continue;
}
+ if (!m_hdd_connected) {
+ struct stat limit_filesize;
+ if (fstat(m_fd_dest, &limit_filesize) == 0) {
+ if (limit_filesize.st_size > LIMIT_FILESIZE_NOHDD) {
+ eDebug("eFilePushThread %lld > %lld LIMIT FILESIZE", limit_filesize.st_size, LIMIT_FILESIZE_NOHDD);
+ sendEvent(evtWriteError);
+
+ g_is_diskfull = true;
+ break;
+ }
+ }
+ }
+
/* now fill our buffer. */
if (m_sg && !current_span_remaining)
{
- m_sg->getNextSourceSpan(source_pos, bytes_read, current_span_offset, current_span_remaining);
+ m_sg->getNextSourceSpan(m_current_position, bytes_read, current_span_offset, current_span_remaining);
ASSERT(!(current_span_remaining % m_blocksize));
-
- if (source_pos != current_span_offset)
- source_pos = m_raw_source.lseek(current_span_offset, SEEK_SET);
+ m_current_position = current_span_offset;
bytes_read = 0;
}
-
+
size_t maxread = sizeof(m_buffer);
/* if we have a source span, don't read past the end */
m_buf_start = 0;
m_filter_end = 0;
m_buf_end = 0;
-
+
if (maxread)
- m_buf_end = m_raw_source.read(m_buffer, maxread);
+ m_buf_end = m_source->read(m_current_position, m_buffer, maxread);
if (m_buf_end < 0)
{
/* a read might be mis-aligned in case of a short read. */
int d = m_buf_end % m_blocksize;
if (d)
- {
- m_raw_source.lseek(-d, SEEK_CUR);
m_buf_end -= d;
- }
if (m_buf_end == 0)
{
sleep(1);
continue;
}
-#if 0
- eDebug("FILEPUSH: end-of-file! (currently unhandled)");
- if (!m_raw_source.lseek(0, SEEK_SET))
- {
- eDebug("(looping)");
- continue;
- }
-#endif
break;
} else
{
- source_pos += m_buf_end;
+ m_current_position += m_buf_end;
bytes_read += m_buf_end;
if (m_sg)
current_span_remaining -= m_buf_end;
}
// printf("FILEPUSH: read %d bytes\n", m_buf_end);
+
+ if (g_is_diskfull) {
+ sendEvent(evtUser+3);
+ g_is_diskfull = false;
+ }
}
fdatasync(m_fd_dest);
eDebug("FILEPUSH THREAD STOP");
}
-void eFilePushThread::start(int fd_source, int fd_dest)
+void eFilePushThread::start(int fd, int fd_dest)
{
- m_raw_source.setfd(fd_source);
- m_fd_dest = fd_dest;
- resume();
+ eRawFile *f = new eRawFile();
+ ePtr<iTsSource> source = f;
+ f->setfd(fd);
+ start(source, fd_dest);
}
-int eFilePushThread::start(const char *filename, int fd_dest)
+int eFilePushThread::start(const char *file, int fd_dest)
{
- if (m_raw_source.open(filename) < 0)
+ eRawFile *f = new eRawFile();
+ ePtr<iTsSource> source = f;
+ if (f->open(file) < 0)
return -1;
+ start(source, fd_dest);
+ return 0;
+}
+
+void eFilePushThread::start(ePtr<iTsSource> &source, int fd_dest)
+{
+ m_source = source;
m_fd_dest = fd_dest;
+ m_current_position = 0;
resume();
- return 0;
}
void eFilePushThread::stop()
stop();
}
-void eFilePushThread::seek(int whence, off_t where)
-{
- m_raw_source.lseek(where, whence);
-}
-
void eFilePushThread::resume()
{
m_stop = 0;
m_stream_mode = s;
}
+void eFilePushThread::setTimeshift(bool s)
+{
+ m_is_timeshift = s;
+}
+
+void eFilePushThread::setTSPath(const std::string s)
+{
+ m_tspath = s;
+}
+
void eFilePushThread::setScatterGather(iFilePushScatterGather *sg)
{
m_sg = sg;
m_event(evt);
}
+void eFilePushThread::defaultTSPath(bool s)
+{
+ std::string tspath;
+
+ if (s) {
+ if (ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1)
+ eDebug("could not query ts path from config");
+ } else {
+ if (ePythonConfigQuery::getConfigValue("config.usage.instantrec_path", tspath) == -1) {
+ eDebug("could not query ts path from config");
+ } else {
+ if (tspath == "<default>") {
+ if (ePythonConfigQuery::getConfigValue("config.usage.default_path", tspath) == -1)
+ eDebug("could not query ts path from config");
+ } else if (tspath == "<current>") {
+ if (ePythonConfigQuery::getConfigValue("config.movielist.last_videodir", tspath) == -1)
+ eDebug("could not query ts path from config");
+ } else if (tspath == "<timer>") {
+ if (ePythonConfigQuery::getConfigValue("config.movielist.last_timer_videodir", tspath) == -1)
+ eDebug("could not query ts path from config");
+ }
+ }
+ }
+
+ if (!tspath.empty())
+ tspath.append("/");
+
+ m_tspath = tspath;
+}
+
int eFilePushThread::filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining)
{
return len;