Skip to content

Commit

Permalink
Add Rolling File, several fixes for v18 API changes, use more data fr…
Browse files Browse the repository at this point in the history
…om backend when available
  • Loading branch information
emveepee committed Feb 16, 2019
1 parent 78c6633 commit 86c2adf
Show file tree
Hide file tree
Showing 16 changed files with 1,477 additions and 358 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Expand Up @@ -21,11 +21,13 @@ set(NEXTPVR_SOURCES src/client.cpp
src/pvrclient-nextpvr.cpp
src/Socket.cpp
src/uri.cpp
src/BackendRequest.cpp
src/buffers/Buffer.cpp
src/buffers/DummyBuffer.cpp
src/buffers/TimeshiftBuffer.cpp
src/buffers/RecordingBuffer.cpp
src/buffers/CircularBuffer.cpp
src/buffers/RollingFile.cpp
src/buffers/Seeker.cpp)

set(NEXTPVR_HEADERS src/client.h
Expand All @@ -35,11 +37,13 @@ set(NEXTPVR_HEADERS src/client.h
src/pvrclient-nextpvr.h
src/Socket.h
src/uri.h
src/BackendRequest.h
src/buffers/Buffer.h
src/buffers/DummyBuffer.h
src/buffers/TimeshiftBuffer.h
src/buffers/RecordingBuffer.h
src/buffers/CircularBuffer.h
src/buffers/RollingFile.h
src/buffers/Seeker.h)

SET(DEPLIBS ${p8-platform_LIBRARIES}
Expand Down
2 changes: 1 addition & 1 deletion pvr.nextpvr/addon.xml.in
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon
id="pvr.nextpvr"
version="3.3.12"
version="3.3.13"
name="NextPVR PVR Client"
provider-name="Graeme Blackley">
<requires>@ADDON_DEPENDS@</requires>
Expand Down
11 changes: 11 additions & 0 deletions pvr.nextpvr/changelog.txt
@@ -1,3 +1,14 @@
v3.3.13
- Add Extended Timeshift Rolling File based live tv and radio buffer (pause and seekable)
- Use file-system for recording and rolling file playback if available
- Removed GetBackendTime() not part of API, changed RenameRecordings not supported
- Fixes radio playback with timeshift, fixes All Channel recurring recordings, fixes problems passing expired EPG ID's
- Separate and show Failed recordings, added Conflict Timers
- Disable backend updates during media playback. Kodi still will update if configured
- Separate Radio recordings for current stations, don't know type for deleted stations
- Use S##E## and subtitles for improved Kodi skin display
- Improved system wake and added WOL (still needs state machine), get server time difference as global

v3.3.12
- Bugfixes, seek re-init, and jump to last block already buffered.

Expand Down
20 changes: 20 additions & 0 deletions pvr.nextpvr/resources/language/resource.language.en_gb/strings.po
Expand Up @@ -137,3 +137,23 @@ msgstr ""
msgctxt "#30161"
msgid "All"
msgstr ""

msgctxt "#30162"
msgid "Pre-buffer time in seconds"
msgstr ""

msgctxt "#30163"
msgid "Enable Wake On LAN"
msgstr ""

msgctxt "#30164"
msgid "Wait for server after wake in seconds"
msgstr ""

msgctxt "#30165"
msgid "NextPVR server MAC address"
msgstr ""

msgctxt "#30166"
msgid "Failed Recordings"
msgstr ""
7 changes: 6 additions & 1 deletion pvr.nextpvr/resources/settings.xml
Expand Up @@ -9,7 +9,12 @@

<!-- advanced -->
<category label="30041">
<setting id="usetimeshift" type="bool" label="30003" default="false"/>
<setting id="usetimeshift" type="bool" label="30003" default="false" visible="false" />
<setting id="livestreamingmethod" type="enum" label="Live TV Stream" values="Timeshift|Extended Timeshift|Real Time" default="Real Time"/>
<setting id="prebuffer" label="30162" option="int" range="4,1,15" type="slider" visible="eq(-1,1)" default="8" />
<setting id="wolenable" label="30163" type="bool" default="false"/>
<setting id="woltimeout" label="30164" option="int" range="5,5,45" type="slider" visible="eq(-1,true)" default="20" />
<setting id="host_mac" label="30165" type="text" enable="false" default="00:00:00:00:00:00" visible="eq(-2,true)" />
<setting id="guideartwork" type="bool" label="30004" default="false"/>
</category>
</settings>
118 changes: 118 additions & 0 deletions src/BackendRequest.cpp
@@ -0,0 +1,118 @@
/*
* Copyright (C) 2005-2011 Team XBMC
* http://www.xbmc.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/


#include "BackendRequest.h"
#include "Filesystem.h"

#define HTTP_OK 200
#define HTTP_NOTFOUND 404
#define HTTP_BADREQUEST 400

using namespace ADDON;

namespace NextPVR
{
Request *m_backEnd;
int Request::DoRequest(const char *resource, std::string &response)
{
P8PLATFORM::CLockObject lock(m_mutexRequest);
m_start = time(nullptr);
// build request string, adding SID if requred
char strURL[1024];

if (strstr(resource, "method=session") == NULL)
snprintf(strURL,sizeof(strURL),"http://%s:%d%s&sid=%s", g_szHostname.c_str(), g_iPort, resource, m_sid);
else
snprintf(strURL,sizeof(strURL),"http://%s:%d%s", g_szHostname.c_str(), g_iPort, resource);

// ask XBMC to read the URL for us
int resultCode = HTTP_NOTFOUND;
void* fileHandle = XBMC->OpenFile(strURL, READ_NO_CACHE);
if (fileHandle)
{
char buffer[1024];
while (XBMC->ReadFileString(fileHandle, buffer, 1024))
{
response.append(buffer);
}
XBMC->CloseFile(fileHandle);
resultCode = HTTP_OK;
if ((response.empty() || strstr(response.c_str(), "<rsp stat=\"ok\">") == NULL) && strstr(resource, "method=channel.stream.info") == NULL )
{
XBMC->Log(LOG_ERROR, "DoRequest failed, response=%s", response.c_str());
resultCode = HTTP_BADREQUEST;
}
}
XBMC->Log(LOG_DEBUG, "DoRequest return %s %d %d %d", resource, resultCode,response.length(),time(nullptr) -m_start);

return resultCode;
}
int Request::FileCopy(const char *resource,std::string fileName)
{
P8PLATFORM::CLockObject lock(m_mutexRequest);
int written = 0;
m_start = time(nullptr);

char strURL[1024];
char separator = (strchr(resource,'?') == nullptr) ? '?' : '&';
snprintf(strURL,sizeof(strURL),"http://%s:%d%s%csid=%s", g_szHostname.c_str(), g_iPort, resource, separator, m_sid);

// ask XBMC to read the URL for us
int resultCode = HTTP_NOTFOUND;
void* inputFile = XBMC->OpenFile(strURL, READ_NO_CACHE);
int datalen;
if (inputFile)
{
void* outputFile = XBMC->OpenFileForWrite(fileName.c_str(), true);
if (outputFile)
{
char buffer[1024];
while (datalen=XBMC->ReadFile(inputFile, buffer, sizeof(buffer)))
{
XBMC->WriteFile(outputFile, buffer, datalen);
written += datalen;
}
XBMC->CloseFile(inputFile);
XBMC->CloseFile(outputFile);
resultCode = HTTP_OK;
}
}
if (written == 0)
{
resultCode = HTTP_BADREQUEST;
}
XBMC->Log(LOG_DEBUG, "FileCopy (%s - %s) %d %d %d", resource, fileName.c_str(), resultCode,written,time(nullptr) -m_start);

return resultCode;
}
bool Request::PingBackend()
{
char strURL[1024];
snprintf(strURL,sizeof(strURL),"http://%s:%d%s|connection-timeout=2", g_szHostname.c_str(), g_iPort, "/service?method=recording.lastupdated");
void* fileHandle = XBMC->OpenFile(strURL, READ_NO_CACHE);
if (fileHandle)
{
XBMC->CloseFile(fileHandle);
return true;
}
return false;
}
}
49 changes: 49 additions & 0 deletions src/BackendRequest.h
@@ -0,0 +1,49 @@
#pragma once
/*
* Copyright (C) 2005-2011 Team XBMC
* http://www.xbmc.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include <ctime>
#include <stdio.h>
#include <stdlib.h>

#include "client.h"
#include "p8-platform/threads/mutex.h"

using namespace ADDON;

namespace NextPVR
{
class Request
{
public:
int DoRequest(const char *resource, std::string &response);
int FileCopy(const char *resource, std::string fileName);
void setSID(char *newsid) {strcpy(m_sid,newsid);};
bool PingBackend();
const char *getSID() {return m_sid;};
Request(void){};
virtual ~Request() {};
private:
P8PLATFORM::CMutex m_mutexRequest;
time_t m_start;
char m_sid[64];
};
extern Request *m_backEnd;
}
12 changes: 10 additions & 2 deletions src/buffers/Buffer.cpp
Expand Up @@ -20,6 +20,7 @@
*/

#include "Buffer.h"
#include "Filesystem.h"
#include <sstream>

using namespace timeshift;
Expand All @@ -35,8 +36,15 @@ bool Buffer::Open(const std::string inputUrl)
// Append the read timeout parameter
XBMC->Log(LOG_DEBUG, "Buffer::Open() called! [ %s ]", inputUrl.c_str());
std::stringstream ss;
ss << inputUrl << "|connection-timeout=" << m_readTimeout;
m_inputHandle = XBMC->OpenFile(ss.str().c_str(), 0x08 ); /*READ_NO_CACHE*/
if (inputUrl.rfind("http", 0) == 0)
{
ss << inputUrl << "|connection-timeout=" << m_readTimeout;
}
else
{
ss << inputUrl;
}
m_inputHandle = XBMC->OpenFile(ss.str().c_str(), READ_NO_CACHE );
}
// Remember the start time and open the input
m_startTime = time(nullptr);
Expand Down
34 changes: 32 additions & 2 deletions src/buffers/RecordingBuffer.cpp
Expand Up @@ -29,7 +29,6 @@ PVR_ERROR RecordingBuffer::GetStreamTimes(PVR_STREAM_TIMES *stimes)
stimes->ptsStart = 0;
stimes->ptsBegin = 0;
stimes->ptsEnd = ((int64_t ) Duration() ) * DVD_TIME_BASE;
XBMC->Log(LOG_DEBUG, "RecordingBuffer::GetStreamTimes called!");
return PVR_ERROR_NO_ERROR;
}

Expand Down Expand Up @@ -67,7 +66,38 @@ bool RecordingBuffer::Open(const std::string inputUrl,const PVR_RECORDING &recor
{
m_isRecording = false;
}

if (recording.strDirectory)
{
char strDirectory [PVR_ADDON_URL_STRING_LENGTH];
strcpy(strDirectory,recording.strDirectory);
int i = 0;
int j = 0;
for(; i <= strlen(recording.strDirectory); i++, j++)
{
if (recording.strDirectory[i] == '\\')
{
if (i==0 && recording.strDirectory[1] == '\\')
{
strcpy(strDirectory,"smb://");
i = 1;
j = 5;
}
else
{
strDirectory[j] = '/';
}
}
else
{
strDirectory[j] = recording.strDirectory[i];
}
}
if ( XBMC->FileExists(strDirectory,false))
{
XBMC->Log(LOG_DEBUG, "Native playback %s", strDirectory);
return Buffer::Open(std::string(strDirectory));
}
}
return Buffer::Open(inputUrl);
}

Expand Down
19 changes: 9 additions & 10 deletions src/buffers/RecordingBuffer.h
Expand Up @@ -34,7 +34,6 @@ namespace timeshift {
private:
int m_Duration;
bool m_isRecording;
time_t m_startTime;

public:
RecordingBuffer() : Buffer() { m_Duration = 0; XBMC->Log(LOG_NOTICE, "RecordingBuffer created!"); }
Expand All @@ -44,6 +43,7 @@ namespace timeshift {

virtual int64_t Seek(int64_t position, int whence) override
{
XBMC->Log(LOG_DEBUG, "Seek: %s:%d %lld %lld %lld", __FUNCTION__, __LINE__,position, XBMC->GetFilePosition(m_inputHandle), XBMC->GetFileLength(m_inputHandle) );
return XBMC->SeekFile(m_inputHandle, position, whence);
}

Expand All @@ -57,22 +57,21 @@ namespace timeshift {
return true;
}

virtual int64_t Position() const override
{
return XBMC->GetFilePosition(m_inputHandle);
}
PVR_ERROR GetStreamTimes(PVR_STREAM_TIMES *) override;

virtual int64_t Length() const override
{
return XBMC->GetFileLength(m_inputHandle);
}
virtual int64_t Position() const override
{
return XBMC->GetFilePosition(m_inputHandle);
}

PVR_ERROR GetStreamTimes(PVR_STREAM_TIMES *) override;

void SetDuration(int duration) { m_Duration = duration; XBMC->Log(LOG_ERROR, "XXXXX Duration set to %d XXXXX", m_Duration); }
virtual int Duration(void);
int GetDuration(void) { return m_Duration; XBMC->Log(LOG_ERROR, "XXXXX Duration set to %d XXXXX", m_Duration); }
int Duration(void);
bool Open(const std::string inputUrl,const PVR_RECORDING &recording);
void SetDuration(int duration) { m_Duration = duration; XBMC->Log(LOG_ERROR, "XXXXX Duration set to %d XXXXX", m_Duration); }

bool Open(const std::string inputUrl,const PVR_RECORDING &recording);
};
}

0 comments on commit 86c2adf

Please sign in to comment.