MythTV master
filetransfer.cpp
Go to the documentation of this file.
1#include <QFileInfo>
2#include <QMutexLocker>
3#include <utility>
4
9
10#include "filetransfer.h"
11
13 MythSocketManager *parent,
14 bool usereadahead, std::chrono::milliseconds timeout) :
15 SocketHandler(remote, parent, ""),
16 m_pginfo(new ProgramInfo(filename)),
17 m_rbuffer(MythMediaBuffer::Create(filename, false, usereadahead, timeout))
18{
20}
21
23 MythSocketManager *parent, bool write) :
24 SocketHandler(remote, parent, ""),
25 m_pginfo(new ProgramInfo(filename)),
26 m_rbuffer(MythMediaBuffer::Create(filename, write)),
27 m_writemode(write)
28{
30
31 if (write)
32 {
33 remote->SetReadyReadCallbackEnabled(false);
35 }
36}
37
39{
40 Stop();
41
42 if (m_rbuffer)
43 {
44 delete m_rbuffer;
45 m_rbuffer = nullptr;
46 }
47
48 if (m_pginfo)
49 {
51 delete m_pginfo;
52 }
53}
54
56{
57 return m_rbuffer && m_rbuffer->IsOpen();
58}
59
60bool FileTransfer::ReOpen(const QString& newFilename)
61{
62 if (!m_writemode)
63 return false;
64
65 if (m_rbuffer)
66 return m_rbuffer->ReOpen(newFilename);
67
68 return false;
69}
70
72{
74 {
75 m_readthreadlive = false;
76 LOG(VB_FILE, LOG_INFO, "calling StopReads()");
78 QMutexLocker locker(&m_lock);
79 m_readsLocked = true;
80 }
81
82 if (m_writemode)
84
85 if (m_pginfo)
87}
88
90{
91 LOG(VB_FILE, LOG_INFO, "calling StopReads()");
93 QMutexLocker locker(&m_lock);
94 m_readsLocked = true;
95
96 if (m_pginfo)
98}
99
101{
102 LOG(VB_FILE, LOG_INFO, "calling StartReads()");
104 {
105 QMutexLocker locker(&m_lock);
106 m_readsLocked = false;
107 }
108 m_readsUnlockedCond.wakeAll();
109
110 if (m_pginfo)
112}
113
115{
117 return -1;
118
119 int tot = 0;
120 int ret = 0;
121
122 QMutexLocker locker(&m_lock);
123 while (m_readsLocked)
124 m_readsUnlockedCond.wait(&m_lock, 100 /*ms*/);
125
126 m_requestBuffer.resize(std::max((size_t)std::max(size,0) + 128, m_requestBuffer.size()));
127 char *buf = (m_requestBuffer).data();
128 while (tot < size && !m_rbuffer->GetStopReads() && m_readthreadlive)
129 {
130 int request = size - tot;
131
132 ret = m_rbuffer->Read(buf, request);
133
134 if (m_rbuffer->GetStopReads() || ret <= 0)
135 break;
136
137 if (GetSocket()->Write(buf, (uint)ret) != ret)
138 {
139 tot = -1;
140 break;
141 }
142
143 tot += ret;
144 if (ret < request)
145 break; // we hit eof
146 }
147
148 if (m_pginfo)
150
151 return (ret < 0) ? -1 : tot;
152}
153
155{
156 if (!m_writemode || !m_rbuffer)
157 return -1;
158
159 int tot = 0;
160 int ret = 0;
161
162 QMutexLocker locker(&m_lock);
163
164 m_requestBuffer.resize(std::max((size_t)std::max(size,0) + 128, m_requestBuffer.size()));
165 char *buf = (m_requestBuffer).data();
166 int attempts = 0;
167
168 while (tot < size)
169 {
170 int request = size - tot;
171 int received = GetSocket()->Read(buf, (uint)request, 200ms);
172
173 if (received != request)
174 {
175 LOG(VB_FILE, LOG_DEBUG,
176 QString("WriteBlock(): Read failed. Requested %1 got %2")
177 .arg(request).arg(received));
178 if (received < 0)
179 {
180 // An error occurred, abort immediately
181 break;
182 }
183 if (received == 0)
184 {
185 attempts++;
186 if (attempts > 3)
187 {
188 LOG(VB_FILE, LOG_ERR,
189 "WriteBlock(): Read tried too many times, aborting "
190 "(client or network too slow?)");
191 break;
192 }
193 continue;
194 }
195 }
196 attempts = 0;
197 ret = m_rbuffer->Write(buf, received);
198 if (ret <= 0)
199 {
200 LOG(VB_FILE, LOG_DEBUG,
201 QString("WriteBlock(): Write failed. Requested %1 got %2")
202 .arg(received).arg(ret));
203 break;
204 }
205
206 tot += received;
207 }
208
209 if (m_pginfo)
211
212 return (ret < 0) ? -1 : tot;
213}
214
215long long FileTransfer::Seek(long long curpos, long long pos, int whence)
216{
217 if (m_pginfo)
219
220 if (!m_rbuffer)
221 return -1;
222 if (!m_readthreadlive)
223 return -1;
224
225 m_ateof = false;
226
227 Pause();
228
229 if (whence == SEEK_CUR)
230 {
231 long long desired = curpos + pos;
232 long long realpos = m_rbuffer->GetReadPosition();
233
234 pos = desired - realpos;
235 }
236
237 long long ret = m_rbuffer->Seek(pos, whence);
238
239 Unpause();
240
241 if (m_pginfo)
243
244 return ret;
245}
246
248{
249 if (m_pginfo)
251
252 return m_rbuffer->GetRealFileSize();
253}
254
256{
257 if (!m_rbuffer)
258 return {};
259
260 return m_rbuffer->GetFilename();
261}
262
264{
265 if (m_pginfo)
267
268 m_rbuffer->SetOldFile(fast);
269}
270
271/* vim: set expandtab tabstop=4 shiftwidth=4: */
bool m_readsLocked
Definition: filetransfer.h:48
int WriteBlock(int size)
FileTransfer(QString &filename, MythSocket *remote, MythSocketManager *parent, bool usereadahead, std::chrono::milliseconds timeout)
void Pause(void)
void Stop(void)
~FileTransfer() override
long long Seek(long long curpos, long long pos, int whence)
QString GetFileName(void)
MythMediaBuffer * m_rbuffer
Definition: filetransfer.h:52
bool ReOpen(const QString &newFilename="")
QWaitCondition m_readsUnlockedCond
Definition: filetransfer.h:49
bool isOpen(void)
std::vector< char > m_requestBuffer
Definition: filetransfer.h:55
uint64_t GetFileSize(void)
void SetTimeout(bool fast)
void Unpause(void)
volatile bool m_readthreadlive
Definition: filetransfer.h:47
int RequestBlock(int size)
ProgramInfo * m_pginfo
Definition: filetransfer.h:51
bool m_writemode
Definition: filetransfer.h:59
QMutex m_lock
Definition: filetransfer.h:57
long long GetRealFileSize(void) const
bool WriterSetBlocking(bool Lock=true)
Calls ThreadedFileWriter::SetBlocking(bool)
void SetOldFile(bool Old)
Tell RingBuffer if this is an old file or not.
virtual bool ReOpen(const QString &="")
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
int Read(void *Buffer, int Count)
This is the public method for reading from a file, it calls the appropriate read method if the file i...
virtual bool IsOpen(void) const =0
long long Seek(long long Position, int Whence, bool HasLock=false)
bool GetStopReads(void) const
int Write(const void *Buffer, uint Count)
Writes buffer to ThreadedFileWriter::Write(const void*,uint)
virtual long long GetReadPosition(void) const =0
QString GetFilename(void) const
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
int Read(char *data, int size, std::chrono::milliseconds max_wait)
Definition: mythsocket.cpp:527
void SetReadyReadCallbackEnabled(bool enabled)
Definition: mythsocket.h:48
int Write(const char *data, int size)
Definition: mythsocket.cpp:514
Holds information on recordings and videos.
Definition: programinfo.h:68
void UpdateInUseMark(bool force=false)
void MarkAsInUse(bool inuse, const QString &usedFor="")
Tracks a recording's in use status, to prevent deletion and to allow the storage scheduler to perform...
MythSocket * GetSocket(void) const
Definition: sockethandler.h:29
unsigned int uint
Definition: freesurround.h:24
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
def write(text, progress=True)
Definition: mythburn.py:307
const QString kFileTransferInUseID
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:89