Skip to content

Loading…

tvheadend add-on: some fixes and bump to 1.6.5 #124

Merged
merged 7 commits into from
View
2 addons/pvr.hts/addon/addon.xml.in
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon
id="pvr.hts"
- version="1.6.4"
+ version="1.6.5"
name="Tvheadend HTSP Client"
provider-name="Lars Op den Kamp, Team XBMC">
<requires>
View
12 addons/pvr.hts/addon/changelog.txt
@@ -0,0 +1,12 @@
+1.6.5
+
+- fixed channel and channel group update triggers
+- ensure that the first demux is an I-frame
+- add CHTSPConnection::CheckConnection() that waits for a connection to be restored when it was dropped
+- cleaner CHTSPConnection::Connect()
+- removed unneeded member in CHTSPDemux
+- better handling of disconnect and reconnects
+
+1.6.4
+
+- initial release
View
122 addons/pvr.hts/src/HTSPConnection.cpp
@@ -35,7 +35,7 @@ using namespace std;
using namespace ADDON;
using namespace PLATFORM;
-CHTSPConnection::CHTSPConnection() :
+CHTSPConnection::CHTSPConnection(CHTSPConnectionCallback* callback) :
m_socket(new CTcpConnection(g_strHostname, g_iPortHTSP)),
m_challenge(NULL),
m_iChallengeLength(0),
@@ -48,7 +48,8 @@ CHTSPConnection::CHTSPConnection() :
m_bIsConnected(false),
m_bTimeshiftSupport(false),
m_bTimeshiftSeekSupport(false),
- m_iQueueSize(1000)
+ m_iQueueSize(1000),
+ m_callback(callback)
{
}
@@ -62,38 +63,46 @@ CHTSPConnection::~CHTSPConnection()
m_queue.clear();
}
-bool CHTSPConnection::Connect()
+bool CHTSPConnection::OpenSocket(void)
{
+ CLockObject lock(m_mutex);
+ if (m_socket && m_socket->IsOpen())
+ return true;
+
+ if (!m_socket)
{
- CLockObject lock(m_mutex);
+ XBMC->Log(LOG_ERROR, "%s - failed to connect to the backend (couldn't create a socket)", __FUNCTION__);
+ return false;
+ }
- if (m_bIsConnected)
- return true;
+ XBMC->Log(LOG_DEBUG, "%s - connecting to '%s', port '%d'", __FUNCTION__, m_strHostname.c_str(), m_iPortnumber);
- if (!m_socket)
- {
- XBMC->Log(LOG_ERROR, "%s - failed to connect to the backend (couldn't create a socket)", __FUNCTION__);
- return false;
- }
+ CTimeout timeout(m_iConnectTimeout);
+ while (!m_socket->IsOpen() && timeout.TimeLeft() > 0)
+ {
+ if (!m_socket->Open(timeout.TimeLeft()))
+ CEvent::Sleep(100);
+ }
- XBMC->Log(LOG_DEBUG, "%s - connecting to '%s', port '%d'", __FUNCTION__, m_strHostname.c_str(), m_iPortnumber);
+ if (!m_socket->IsOpen())
+ {
+ XBMC->Log(LOG_ERROR, "%s - failed to connect to the backend (%s)", __FUNCTION__, m_socket->GetError().c_str());
+ return false;
+ }
- CTimeout timeout(m_iConnectTimeout);
- while (!m_socket->IsOpen() && timeout.TimeLeft() > 0)
- {
- if (!m_socket->Open(timeout.TimeLeft()))
- CEvent::Sleep(100);
- }
+ m_bIsConnected = true;
+ XBMC->Log(LOG_DEBUG, "%s - connected to '%s', port '%d'", __FUNCTION__, m_strHostname.c_str(), m_iPortnumber);
+ return true;
+}
- if (!m_socket->IsOpen())
- {
- XBMC->Log(LOG_ERROR, "%s - failed to connect to the backend (%s)", __FUNCTION__, m_socket->GetError().c_str());
- return false;
- }
+bool CHTSPConnection::Connect(void)
+{
+ CLockObject lock(m_mutex);
+ if (m_bIsConnected)
+ return true;
- m_bIsConnected = true;
- XBMC->Log(LOG_DEBUG, "%s - connected to '%s', port '%d'", __FUNCTION__, m_strHostname.c_str(), m_iPortnumber);
- }
+ if (!OpenSocket())
+ return false;
if (!SendGreeting())
{
@@ -116,11 +125,16 @@ bool CHTSPConnection::Connect()
return false;
}
- return true;
+ m_bIsConnected = true;
+ m_connectEvent.Broadcast();
+
+ return CreateThread(true);
}
void CHTSPConnection::Close()
{
+ StopThread();
+
CLockObject lock(m_mutex);
m_bIsConnected = false;
@@ -133,6 +147,8 @@ void CHTSPConnection::Close()
m_challenge = NULL;
m_iChallengeLength = 0;
}
+
+ m_connectEvent.Broadcast();
}
htsmsg_t* CHTSPConnection::ReadMessage(int iInitialTimeout /* = 10000 */, int iDatapacketTimeout /* = 10000 */)
@@ -149,7 +165,7 @@ htsmsg_t* CHTSPConnection::ReadMessage(int iInitialTimeout /* = 10000 */, int iD
{
CLockObject lock(m_mutex);
- if (!IsConnected())
+ if (!m_socket || !m_socket->IsOpen())
{
XBMC->Log(LOG_ERROR, "%s - not connected", __FUNCTION__);
return NULL;
@@ -188,7 +204,7 @@ bool CHTSPConnection::TransmitMessage(htsmsg_t* m)
void* buf;
size_t len;
- if (!IsConnected())
+ if (!m_socket || !m_socket->IsOpen())
{
XBMC->Log(LOG_ERROR, "%s - not connected", __FUNCTION__);
return NULL;
@@ -369,6 +385,15 @@ bool CHTSPConnection::Auth(void)
return ReadSuccess(m, false, "get reply from authentication with server");
}
+bool CHTSPConnection::CheckConnection(uint32_t iTimeout)
+{
+ CLockObject lock(m_mutex);
+ if (IsConnected())
+ return true;
+
+ return m_connectEvent.Wait(m_mutex, m_bIsConnected, iTimeout);
+}
+
bool CHTSPConnection::IsConnected(void)
{
CLockObject lock(m_mutex);
@@ -384,3 +409,42 @@ bool CHTSPConnection::CanSeekLiveStream(void)
{
return m_bTimeshiftSeekSupport;
}
+
+void* CHTSPConnection::Process(void)
+{
+ bool bWarningDisplayed(false);
+ while (!IsStopped())
+ {
+ if (!m_socket || !m_socket->IsOpen())
+ {
+ if (!bWarningDisplayed)
+ {
+ bWarningDisplayed = true;
+ XBMC->Log(LOG_ERROR, "connection dropped, trying to restore");
+ if (m_callback)
+ m_callback->OnConnectionDropped();
+ }
+
+ if(m_challenge)
+ {
+ free(m_challenge);
+ m_challenge = NULL;
+ m_iChallengeLength = 0;
+ }
+
+ if (Connect())
+ {
+ bWarningDisplayed = false;
+ XBMC->Log(LOG_DEBUG, "connection restored");
+ if (m_callback)
+ m_callback->OnConnectionRestored();
+ }
+ }
+ else
+ {
+ Sleep(250);
+ }
+ }
+
+ return NULL;
+}
View
21 addons/pvr.hts/src/HTSPConnection.h
@@ -22,7 +22,7 @@
*/
#include "HTSPTypes.h"
-#include "platform/threads/mutex.h"
+#include "platform/threads/threads.h"
extern "C" {
#include "libhts/net.h"
@@ -34,15 +34,26 @@ namespace PLATFORM
class CTcpConnection;
}
-class CHTSPConnection
+class CHTSPConnectionCallback
{
public:
- CHTSPConnection();
+ CHTSPConnectionCallback(void) {}
+ virtual ~CHTSPConnectionCallback(void) {}
+
+ virtual void OnConnectionDropped(void) {}
+ virtual void OnConnectionRestored(void) {}
+};
+
+class CHTSPConnection : private PLATFORM::CThread
+{
+public:
+ CHTSPConnection(CHTSPConnectionCallback* callback);
~CHTSPConnection();
bool Connect(void);
void Close();
bool IsConnected(void);
+ bool CheckConnection(uint32_t iTimeout);
int GetProtocol() const { return m_iProtocol; }
const char *GetServerName() const { return m_strServerName.c_str(); }
const char *GetVersion() const { return m_strVersion.c_str(); }
@@ -56,6 +67,8 @@ class CHTSPConnection
bool CanSeekLiveStream(void);
private:
+ bool OpenSocket(void);
+ void* Process(void);
bool SendGreeting(void);
bool Auth(void);
@@ -77,4 +90,6 @@ class CHTSPConnection
std::deque<htsmsg_t*> m_queue;
const unsigned int m_iQueueSize;
+ CHTSPConnectionCallback* m_callback;
+ PLATFORM::CCondition<bool> m_connectEvent;
};
View
116 addons/pvr.hts/src/HTSPData.cpp
@@ -42,7 +42,7 @@ using namespace PLATFORM;
CHTSPData::CHTSPData()
{
- m_session = new CHTSPConnection();
+ m_session = NULL;
m_bDisconnectWarningDisplayed = false;
m_bIsStarted = false;
m_recordingId = 0;
@@ -57,6 +57,9 @@ CHTSPData::~CHTSPData()
bool CHTSPData::Open()
{
+ if (!m_session)
+ m_session = new CHTSPConnection(this);
+
CLockObject lock(m_mutex);
if(!m_session->Connect())
{
@@ -86,31 +89,6 @@ void CHTSPData::Close()
StopThread();
}
-bool CHTSPData::CheckConnection(void)
-{
- bool bReturn(true);
-
- if (!m_session->IsConnected() && m_bCreated && !IsStopped())
- {
- if (!m_bDisconnectWarningDisplayed)
- {
- m_bDisconnectWarningDisplayed = true;
- CStdString strNotification(XBMC->GetLocalizedString(30500));
- XBMC->QueueNotification(QUEUE_ERROR, strNotification, m_session->GetServerName());
- }
-
- if ((bReturn = m_session->Connect() && SendEnableAsync()))
- {
- m_bDisconnectWarningDisplayed = false;
- /* notify the user that the connection has been restored */
- CStdString strNotification(XBMC->GetLocalizedString(30501));
- XBMC->QueueNotification(QUEUE_INFO, strNotification, m_session->GetServerName());
- }
- }
-
- return bReturn;
-}
-
void CHTSPData::ReadResult(htsmsg_t *m, CHTSResult &result)
{
if (!m_session || !m_session->IsConnected())
@@ -659,14 +637,8 @@ void *CHTSPData::Process()
htsmsg_t* msg;
while (!IsStopped())
{
- if (!bInitialised && !m_session->IsConnected())
- break;
-
- if (!CheckConnection())
- {
- Sleep(1000);
+ if (!m_session->CheckConnection(1000))
continue;
- }
/* if there's anything in the buffer, read it */
msg = m_session->ReadMessage(5);
@@ -876,7 +848,7 @@ void CHTSPData::ParseChannelRemove(htsmsg_t* msg)
void CHTSPData::ParseChannelUpdate(htsmsg_t* msg)
{
- bool bChanged(false);
+ bool bChannelChanged(false), bTagsChanged(false);
uint32_t iChannelId, iEventId = 0, iChannelNumber = 0, iCaid = 0;
const char *strName, *strIconPath;
if(htsmsg_get_u32(msg, "channelId", &iChannelId))
@@ -894,44 +866,63 @@ void CHTSPData::ParseChannelUpdate(htsmsg_t* msg)
if((strName = htsmsg_get_str(msg, "channelName")))
{
- bChanged = (channel.name != strName);
- channel.name = strName;
+ if (channel.name != strName)
+ {
+ bChannelChanged = true;
+ channel.name = strName;
+ }
}
if((strIconPath = htsmsg_get_str(msg, "channelIcon")))
{
- bChanged = (channel.icon != strIconPath);
- channel.icon = strIconPath;
+ if (channel.icon != strIconPath)
+ {
+ bChannelChanged = true;
+ channel.icon = strIconPath;
+ }
}
if(htsmsg_get_u32(msg, "channelNumber", &iChannelNumber) == 0)
{
int iNewChannelNumber = (iChannelNumber == 0) ? iChannelId + 1000 : iChannelNumber;
- bChanged = (channel.num != iNewChannelNumber);
- channel.num = iNewChannelNumber;
+ if (channel.num != iNewChannelNumber)
+ {
+ bChannelChanged = true;
+ channel.num = iNewChannelNumber;
+ }
}
htsmsg_t *tags;
if((tags = htsmsg_get_list(msg, "tags")))
{
- bChanged = true;
- channel.tags.clear();
-
+ std::vector<int> newTags;
htsmsg_field_t *f;
HTSMSG_FOREACH(f, tags)
{
if(f->hmf_type != HMF_S64)
continue;
- channel.tags.push_back((int)f->hmf_s64);
+ newTags.push_back((int)f->hmf_s64);
+ }
+
+ for (std::vector<int>::const_iterator it = newTags.begin(); it != newTags.end(); it++)
+ {
+ if (std::find(channel.tags.begin(), channel.tags.end(), *it) == channel.tags.end())
+ bTagsChanged = true;
+ }
+ for (std::vector<int>::const_iterator it = channel.tags.begin(); it != channel.tags.end(); it++)
+ {
+ if (std::find(newTags.begin(), newTags.end(), *it) == newTags.end())
+ bTagsChanged = true;
}
+ if (bTagsChanged)
+ channel.tags = newTags;
}
htsmsg_t *services;
-
+ bool bIsRadio(false);
if((services = htsmsg_get_list(msg, "services")))
{
- bChanged = true;
htsmsg_field_t *f;
HTSMSG_FOREACH(f, services)
{
@@ -941,22 +932,33 @@ void CHTSPData::ParseChannelUpdate(htsmsg_t* msg)
htsmsg_t *service = &f->hmf_msg;
const char *service_type = htsmsg_get_str(service, "type");
if(service_type != NULL)
- {
- channel.radio = !strcmp(service_type, "Radio");
- }
+ bIsRadio = !strcmp(service_type, "Radio");
if(!htsmsg_get_u32(service, "caid", &iCaid))
- channel.caid = (int) iCaid;
+ {
+ if ((channel.caid != (int)iCaid))
+ {
+ bChannelChanged = true;
+ channel.caid = (int) iCaid;
+ }
+ }
}
}
+ if (channel.radio != bIsRadio)
+ {
+ bChannelChanged = true;
+ channel.radio = bIsRadio;
+ }
#if HTSP_DEBUGGING
XBMC->Log(LOG_DEBUG, "%s - id:%u, name:'%s', icon:'%s', event:%u",
__FUNCTION__, iChannelId, strName ? strName : "(null)", strIconPath ? strIconPath : "(null)", iEventId);
#endif
- if (bChanged)
+ if (bChannelChanged)
PVR->TriggerChannelUpdate();
+ if (bTagsChanged)
+ PVR->TriggerChannelGroupsUpdate();
}
void CHTSPData::ParseDVREntryDelete(htsmsg_t* msg)
@@ -1332,3 +1334,15 @@ long long CHTSPData::LengthRecordedStream(void)
}
return size;
}
+
+void CHTSPData::OnConnectionDropped(void)
+{
+ CStdString strNotification(XBMC->GetLocalizedString(30500));
+ XBMC->QueueNotification(QUEUE_ERROR, strNotification, GetServerName());
+}
+
+void CHTSPData::OnConnectionRestored(void)
+{
+ CStdString strNotification(XBMC->GetLocalizedString(30501));
+ XBMC->QueueNotification(QUEUE_INFO, strNotification, GetServerName());
+}
View
5 addons/pvr.hts/src/HTSPData.h
@@ -42,7 +42,7 @@ class CHTSResult
PVR_ERROR status;
};
-class CHTSPData : public PLATFORM::CThread
+class CHTSPData : public PLATFORM::CThread, CHTSPConnectionCallback
{
public:
CHTSPData();
@@ -50,7 +50,6 @@ class CHTSPData : public PLATFORM::CThread
bool Open();
void Close();
- bool CheckConnection(void);
bool IsConnected(void) const { return m_session->IsConnected(); }
/*!
@@ -88,6 +87,8 @@ class CHTSPData : public PLATFORM::CThread
long long PositionRecordedStream(void);
long long LengthRecordedStream(void);
+ void OnConnectionDropped(void);
+ void OnConnectionRestored(void);
protected:
virtual void *Process(void);
View
44 addons/pvr.hts/src/HTSPDemux.cpp
@@ -27,13 +27,13 @@
using namespace ADDON;
CHTSPDemux::CHTSPDemux() :
+ m_session(NULL),
m_bIsRadio(false),
m_subs(0),
m_channel(0),
m_tag(0),
- m_StatusCount(0)
+ m_bHasIFrame(false)
{
- m_session = new CHTSPConnection();
for (unsigned int i = 0; i < PVR_STREAM_MAX_STREAMS; i++)
m_Streams.stream[i].iCodecType = AVMEDIA_TYPE_UNKNOWN;
m_Streams.iStreamCount = 0;
@@ -48,6 +48,9 @@ CHTSPDemux::~CHTSPDemux()
bool CHTSPDemux::Open(const PVR_CHANNEL &channelinfo)
{
+ if (!m_session)
+ m_session = new CHTSPConnection(this);
+
m_channel = channelinfo.iUniqueId;
m_bIsRadio = channelinfo.bIsRadio;
return Connect();
@@ -58,28 +61,16 @@ bool CHTSPDemux::Connect(void)
if(!m_session->Connect())
return false;
- if(!SendSubscribe(m_subs, m_channel)) {
+ if(!SendSubscribe(m_subs, m_channel))
+ {
Close();
return false;
}
m_Streams.iStreamCount = 0;
- m_StatusCount = 0;
return true;
}
-// Note: no attempt to warn user about this (the HTSPData link will do
-// that most of the time anyway)
-bool CHTSPDemux::CheckConnection()
-{
- bool bReturn = m_session->IsConnected();
-
- if (!bReturn)
- bReturn = Connect();
-
- return bReturn;
-}
-
void CHTSPDemux::Close()
{
if (m_session->IsConnected())
@@ -134,8 +125,8 @@ void CHTSPDemux::Abort()
DemuxPacket* CHTSPDemux::Read()
{
- if (!CheckConnection())
- return NULL;
+ if (!m_session->CheckConnection(1000))
+ return PVR->AllocateDemuxPacket(0);
htsmsg_t *msg = m_session->ReadMessage(1000, 1000);
if (!msg)
@@ -188,7 +179,7 @@ DemuxPacket* CHTSPDemux::Read()
DemuxPacket *CHTSPDemux::ParseMuxPacket(htsmsg_t *msg)
{
DemuxPacket* pkt = NULL;
- uint32_t index, duration;
+ uint32_t index, duration, frametype;
const void* bin;
size_t binlen;
int64_t ts;
@@ -200,6 +191,10 @@ DemuxPacket *CHTSPDemux::ParseMuxPacket(htsmsg_t *msg)
return PVR->AllocateDemuxPacket(0);
}
+ if (!m_bHasIFrame && (htsmsg_get_u32(msg, "frametype" , &frametype) || (char)frametype != 'I'))
+ return PVR->AllocateDemuxPacket(0);
+ m_bHasIFrame = true;
+
pkt = PVR->AllocateDemuxPacket(binlen);
memcpy(pkt->pData, bin, binlen);
@@ -245,7 +240,6 @@ bool CHTSPDemux::SwitchChannel(const PVR_CHANNEL &channelinfo)
m_channel = channelinfo.iChannelNumber;
m_subs = m_subs+1;
m_Streams.iStreamCount = 0;
- m_StatusCount = 0;
return true;
}
@@ -502,6 +496,8 @@ void CHTSPDemux::ParseSubscriptionStart(htsmsg_t *m)
if (!m_StreamIndex.empty())
m_Streams.iStreamCount++;
+ m_bHasIFrame = false;
+
if (ParseSourceInfo(m))
{
XBMC->Log(LOG_DEBUG, "%s - subscription started on adapter %s, mux %s, network %s, provider %s, service %s"
@@ -533,6 +529,8 @@ void CHTSPDemux::ParseSubscriptionStop (htsmsg_t *m)
m_SourceInfo.si_network = "";
m_SourceInfo.si_provider = "";
m_SourceInfo.si_service = "";
+
+ m_bHasIFrame = false;
}
void CHTSPDemux::ParseSubscriptionStatus(htsmsg_t *m)
@@ -543,7 +541,6 @@ void CHTSPDemux::ParseSubscriptionStatus(htsmsg_t *m)
m_Status = "";
else
{
- m_StatusCount++;
m_Status = status;
XBMC->Log(LOG_DEBUG, "%s - %s", __FUNCTION__, status);
XBMC->QueueNotification(QUEUE_INFO, status);
@@ -673,3 +670,8 @@ bool CHTSPDemux::ParseSourceInfo(htsmsg_t* msg)
return true;
}
+
+void CHTSPDemux::OnConnectionRestored(void)
+{
+ SendSubscribe(m_subs, m_channel);
+}
View
6 addons/pvr.hts/src/HTSPDemux.h
@@ -24,7 +24,7 @@
#include "client.h"
#include "HTSPConnection.h"
-class CHTSPDemux
+class CHTSPDemux : CHTSPConnectionCallback
{
public:
CHTSPDemux();
@@ -40,6 +40,7 @@ class CHTSPDemux
bool GetSignalStatus(PVR_SIGNAL_STATUS &qualityinfo);
bool SeekTime(int time, bool backward, double *startpts);
void SetSpeed(int speed);
+ void OnConnectionRestored(void);
protected:
void ParseSubscriptionStart (htsmsg_t *m);
@@ -52,7 +53,6 @@ class CHTSPDemux
DemuxPacket *ParseMuxPacket(htsmsg_t *m);
bool Connect(void);
- bool CheckConnection(void);
private:
bool ParseQueueStatus(htsmsg_t* msg);
@@ -65,7 +65,6 @@ class CHTSPDemux
unsigned m_subs;
int m_channel;
int m_tag;
- int m_StatusCount;
std::string m_Status;
PVR_STREAM_PROPERTIES m_Streams;
SChannels m_channels;
@@ -73,4 +72,5 @@ class CHTSPDemux
SQuality m_Quality;
SSourceInfo m_SourceInfo;
std::map<int, unsigned int> m_StreamIndex;
+ bool m_bHasIFrame;
};
Something went wrong with that request. Please try again.