Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pvr.vuplus/addon.xml.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon
id="pvr.vuplus"
version="22.3.0"
version="22.4.0"
name="Enigma2 Client"
provider-name="Joerg Dembski and Ross Nicholson">
<requires>@ADDON_DEPENDS@
Expand Down
3 changes: 3 additions & 0 deletions pvr.vuplus/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
v22.4.0
- Support multi-stream recordings

v22.3.0
- Add expert setting to toggle using OpenWebIf internal MovieList on/off

Expand Down
96 changes: 73 additions & 23 deletions src/Enigma2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ Enigma2::Enigma2(const kodi::addon::IInstanceInfo& instance)

Enigma2::~Enigma2()
{
{
std::lock_guard<std::recursive_mutex> lock(m_mutexMultiRecordings);
if (m_multistreamRecordingReaders.size() != 0)
{
std::map<int64_t, RecordingReader*>::iterator itr = m_multistreamRecordingReaders.begin();
while (itr != m_multistreamRecordingReaders.end())
{
CloseRecordedStream(itr->first);
itr = m_multistreamRecordingReaders.begin();
}
}
}

if (connectionManager)
connectionManager->Stop();
delete connectionManager;
Expand Down Expand Up @@ -88,6 +101,7 @@ PVR_ERROR Enigma2::GetCapabilities(kodi::addon::PVRCapabilities& capabilities)
capabilities.SetSupportsAsyncEPGTransfer(false);
capabilities.SetSupportsRecordingSize(m_settings->SupportsRecordingSizes());
capabilities.SetSupportsProviders(true);
capabilities.SetSupportsMultipleRecordedStreams(true);

return PVR_ERROR_NO_ERROR;
}
Expand Down Expand Up @@ -774,13 +788,14 @@ PVR_ERROR Enigma2::GetRecordingEdl(const kodi::addon::PVRRecording& recording, s

bool Enigma2::OpenRecordedStream(const kodi::addon::PVRRecording& recinfo, int64_t& streamId)
{
if (m_recordingReader)
SafeDelete(m_recordingReader);
std::lock_guard<std::recursive_mutex> lock(m_mutexMultiRecordings);

if (m_multistreamRecordingReaders[streamId])
m_multistreamRecordingReaders.erase(streamId);

if (!IsConnected())
return false;

std::lock_guard<std::mutex> lock(m_mutex);
std::time_t now = std::time(nullptr), start = 0, end = 0;
std::string channelName = recinfo.GetChannelName();
auto timer = m_timers.GetTimer([&](const Timer &timer)
Expand All @@ -793,8 +808,10 @@ bool Enigma2::OpenRecordedStream(const kodi::addon::PVRRecording& recinfo, int64
end = timer->GetRealEndTime();
}

m_recordingReader = new RecordingReader(m_recordings.GetRecordingURL(recinfo), start, end, recinfo.GetDuration());
return m_recordingReader->Start();
m_multistreamRecordingReaders.emplace(++m_streamCount, new RecordingReader(m_recordings.GetRecordingURL(recinfo), start, end, recinfo.GetDuration()));
streamId = m_streamCount;

return m_multistreamRecordingReaders[streamId]->Start();
}

bool Enigma2::HasRecordingStreamProgramNumber(const kodi::addon::PVRRecording& recording)
Expand Down Expand Up @@ -1086,17 +1103,8 @@ PVR_ERROR Enigma2::GetStreamTimes(kodi::addon::PVRStreamTimes& times)

return PVR_ERROR_NO_ERROR;
}
else if (m_recordingReader)
{
times.SetStartTime(0);
times.SetPTSStart(0);
times.SetPTSBegin(0);
times.SetPTSEnd(static_cast<int64_t>(m_recordingReader->CurrentDuration()) * STREAM_TIME_BASE);

return PVR_ERROR_NO_ERROR;
}

return PVR_ERROR_NOT_IMPLEMENTED;
return PVR_ERROR_INVALID_PARAMETERS;
}

void Enigma2::PauseStream(bool paused)
Expand All @@ -1119,30 +1127,72 @@ void Enigma2::PauseStream(bool paused)

void Enigma2::CloseRecordedStream(int64_t streamId)
{
if (m_recordingReader)
SafeDelete(m_recordingReader);
std::lock_guard<std::recursive_mutex> lock(m_mutexMultiRecordings);

if (m_multistreamRecordingReaders[streamId])
m_multistreamRecordingReaders.erase(streamId);
}

int Enigma2::ReadRecordedStream(int64_t streamId, unsigned char* buffer, unsigned int size)
{
if (!m_recordingReader)
std::lock_guard<std::recursive_mutex> lock(m_mutexMultiRecordings);

if (!m_multistreamRecordingReaders[streamId])
return 0;

return m_recordingReader->ReadData(buffer, size);
return m_multistreamRecordingReaders[streamId]->ReadData(buffer, size);
}

int64_t Enigma2::SeekRecordedStream(int64_t streamId, int64_t position, int whence)
{
if (!m_recordingReader)
std::lock_guard<std::recursive_mutex> lock(m_mutexMultiRecordings);

if (!m_multistreamRecordingReaders[streamId])
return 0;

return m_recordingReader->Seek(position, whence);
return m_multistreamRecordingReaders[streamId]->Seek(position, whence);
}

int64_t Enigma2::LengthRecordedStream(int64_t streamId)
{
if (!m_recordingReader)
std::lock_guard<std::recursive_mutex> lock(m_mutexMultiRecordings);

if (!m_multistreamRecordingReaders[streamId])
return -1;

return m_recordingReader->Length();
return m_multistreamRecordingReaders[streamId]->Length();
}

PVR_ERROR Enigma2::PauseRecordedStream(int64_t streamId, bool bPaused)
{
if (!IsConnected())
return PVR_ERROR_SERVER_ERROR;

m_recordedStreamPaused = bPaused;

return PVR_ERROR_NO_ERROR;
}

PVR_ERROR Enigma2::IsRecordedStreamRealTime(int64_t streamId, bool& isRealTime)
{
isRealTime = false;

return PVR_ERROR_NO_ERROR;
}

PVR_ERROR Enigma2::GetRecordedStreamTimes(int64_t streamId, kodi::addon::PVRStreamTimes& stimes)
{
std::lock_guard<std::recursive_mutex> lock(m_mutexMultiRecordings);

if (m_multistreamRecordingReaders[streamId])
{
stimes.SetStartTime(0);
stimes.SetPTSStart(0);
stimes.SetPTSBegin(0);
stimes.SetPTSEnd(static_cast<int64_t>(m_multistreamRecordingReaders[streamId]->CurrentDuration()) * STREAM_TIME_BASE);

return PVR_ERROR_NO_ERROR;
}

return PVR_ERROR_UNKNOWN;
}
11 changes: 10 additions & 1 deletion src/Enigma2.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "enigma2/utilities/SignalStatus.h"

#include <atomic>
#include <map>
#include <mutex>
#include <thread>

Expand Down Expand Up @@ -128,6 +129,9 @@ class ATTR_DLL_LOCAL Enigma2 : public enigma2::IConnectionListener
int ReadRecordedStream(int64_t streamId, unsigned char* buffer, unsigned int size) override;
int64_t SeekRecordedStream(int64_t streamId, int64_t position, int whence) override;
int64_t LengthRecordedStream(int64_t streamId) override;
PVR_ERROR PauseRecordedStream(int64_t streamId, bool paused) override;
PVR_ERROR IsRecordedStreamRealTime(int64_t streamId, bool& isRealTime) override;
PVR_ERROR GetRecordedStreamTimes(int64_t streamId, kodi::addon::PVRStreamTimes& times) override;

protected:
void Process();
Expand Down Expand Up @@ -165,11 +169,16 @@ class ATTR_DLL_LOCAL Enigma2 : public enigma2::IConnectionListener

enigma2::IStreamReader* m_activeStreamReader = nullptr;
enigma2::IStreamReader* m_timeshiftInternalStreamReader = nullptr;
enigma2::RecordingReader* m_recordingReader = nullptr;
//enigma2::RecordingReader* m_recordingReader = nullptr;

std::map<int64_t, enigma2::RecordingReader*> m_multistreamRecordingReaders;
mutable std::recursive_mutex m_mutexMultiRecordings;
int64_t m_streamCount = -1;

std::atomic<bool> m_running = {false};
std::thread m_thread;
mutable std::mutex m_mutex;

std::atomic<bool> m_paused = {false};
std::atomic<bool> m_recordedStreamPaused = {false};
};