Skip to content

Commit

Permalink
handling of conflicting subscriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
Glenn-1990 committed Jul 28, 2015
1 parent 78a6bd6 commit f55c1f9
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 37 deletions.
1 change: 1 addition & 0 deletions pvr.hts/addon.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<c-pluff version="0.1"/>
<import addon="xbmc.pvr" version="2.1.0"/>
<import addon="xbmc.codec" version="1.0.1"/>
<import addon="kodi.guilib" version="5.8.0"/>
</requires>
<extension
point="xbmc.pvrclient"
Expand Down
54 changes: 54 additions & 0 deletions pvr.hts/resources/language/resource.language.en_gb/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,57 @@ msgstr ""
msgctxt "#30402"
msgid "Unused subscription close delay"
msgstr ""

#empty strings from id 30403 to 30449

#. Subscription states representation

msgctxt "#30450"
msgid "No free adapter available"
msgstr ""

msgctxt "#30451"
msgid "Livestream aborted, adapter stolen by other subscription"
msgstr ""

msgctxt "#30452"
msgid "Scrambled channel"
msgstr ""

msgctxt "#30453"
msgid "No signal"
msgstr ""

msgctxt "#30454"
msgid "Subscription error"
msgstr ""

msgctxt "#30455"
msgid "Failed to hijack an adapter"
msgstr ""

msgctxt "#30456"
msgid "User limit reached"
msgstr ""

#. Subscription conflict dialog

msgctxt "#30457"
msgid "Do you want to increase the priority to hijack an adapter?"
msgstr ""

msgctxt "#30458"
msgid "WARNING: this can abort an active recording or livestream"
msgstr ""

msgctxt "#30459"
msgid "Ignore"
msgstr ""

msgctxt "#30460"
msgid "Increase priority"
msgstr ""

msgctxt "#30461"
msgid "Subscription conflict"
msgstr ""
151 changes: 134 additions & 17 deletions src/HTSPDemuxer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "platform/threads/atomics.h"
#include "platform/util/timeutils.h"
#include "platform/sockets/tcp.h"
#include <thread>

extern "C" {
#include "libhts/htsmsg_binary.h"
Expand All @@ -40,6 +41,24 @@ using namespace std;
using namespace ADDON;
using namespace PLATFORM;

bool bDialogForceStart = false;

void DialogLivestreamAborted( void )
{
bDialogForceStart = GUI->Dialog_YesNo_ShowAndGetInput(
XBMC->GetLocalizedString(30461),XBMC->GetLocalizedString(30451),
XBMC->GetLocalizedString(30457),XBMC->GetLocalizedString(30458),
XBMC->GetLocalizedString(30459),XBMC->GetLocalizedString(30460));
}

void DialogLivestreamNostart( void )
{
bDialogForceStart = GUI->Dialog_YesNo_ShowAndGetInput(
XBMC->GetLocalizedString(30461),XBMC->GetLocalizedString(30450),
XBMC->GetLocalizedString(30457),XBMC->GetLocalizedString(30458),
XBMC->GetLocalizedString(30459),XBMC->GetLocalizedString(30460));
}

CHTSPDemuxer::CHTSPDemuxer ( CHTSPConnection &conn )
: m_conn(conn), m_pktBuffer((size_t)-1),
m_seekTime(INVALID_SEEKTIME)
Expand All @@ -54,7 +73,7 @@ CHTSPDemuxer::~CHTSPDemuxer ( void )
void CHTSPDemuxer::Connected ( void )
{
/* Re-subscribe */
if (m_subscription.active)
if (m_subscription.IsActive())
{
tvhdebug("demux re-starting stream");
SendSubscribe(true);
Expand All @@ -69,7 +88,7 @@ void CHTSPDemuxer::Connected ( void )
void CHTSPDemuxer::Close0 ( void )
{
/* Send unsubscribe */
if (m_subscription.active)
if (m_subscription.IsActive())
SendUnsubscribe();

/* Clear */
Expand All @@ -85,7 +104,7 @@ void CHTSPDemuxer::Abort0 ( void )
}


bool CHTSPDemuxer::Open ( uint32_t channelId, enum eSubscriptionWeight weight )
bool CHTSPDemuxer::Open ( uint32_t channelId, int weight )
{
CLockObject lock(m_conn.Mutex());
tvhdebug("demux open");
Expand All @@ -102,12 +121,12 @@ bool CHTSPDemuxer::Open ( uint32_t channelId, enum eSubscriptionWeight weight )
SendSubscribe();

/* Send unsubscribe if subscribing failed */
if (!m_subscription.active)
if (!m_subscription.IsActive())
SendUnsubscribe();
else
m_lastUse = time(NULL);

return m_subscription.active;
return (m_subscription.IsActive());
}

void CHTSPDemuxer::Close ( void )
Expand Down Expand Up @@ -164,7 +183,7 @@ bool CHTSPDemuxer::Seek
htsmsg_t *m;

CLockObject lock(m_conn.Mutex());
if (!m_subscription.active)
if (!m_subscription.IsActive())
return false;

tvhdebug("demux seek %d", time);
Expand Down Expand Up @@ -202,15 +221,15 @@ bool CHTSPDemuxer::Seek
void CHTSPDemuxer::Speed ( int speed )
{
CLockObject lock(m_conn.Mutex());
if (!m_subscription.active)
if (!m_subscription.IsActive())
return;
m_subscription.speed = speed;
SendSpeed();
}

void CHTSPDemuxer::Weight ( enum eSubscriptionWeight weight )
void CHTSPDemuxer::Weight ( int weight )
{
if (!m_subscription.active || m_subscription.weight == weight)
if (!m_subscription.IsActive() || m_subscription.weight == weight)
return;
m_subscription.weight = weight;
SendWeight();
Expand Down Expand Up @@ -280,7 +299,9 @@ void CHTSPDemuxer::SendSubscribe ( bool force )

htsmsg_destroy(m);

m_subscription.active = true;
m_subscription.state = SUBSCRIPTION_STARTING;
time(&m_subscription.start); // set start time

tvhdebug("demux successfully subscribed to %d", m_subscription.channelId);
}

Expand All @@ -293,7 +314,7 @@ void CHTSPDemuxer::SendUnsubscribe ( void )
htsmsg_add_u32(m, "subscriptionId", m_subscription.subscriptionId);

/* Mark subscription as inactive immediately in case this command fails */
m_subscription.active = false;
m_subscription.state = SUBSCRIPTION_STOPPED;

/* Send and Wait */
tvhdebug("demux unsubscribe from %d", m_subscription.channelId);
Expand Down Expand Up @@ -339,6 +360,8 @@ void CHTSPDemuxer::SendWeight ( void )
m = m_conn.SendAndWait("subscriptionChangeWeight", m);
if (m)
htsmsg_destroy(m);

m_subscription.sendWeightAsync = false;
}

/* **************************************************************************
Expand Down Expand Up @@ -386,7 +409,7 @@ void CHTSPDemuxer::ParseMuxPacket ( htsmsg_t *m )
int iStreamId;

/* Ignore packets while switching channels */
if (!m_subscription.active)
if (!m_subscription.IsActive())
{
tvhdebug("Ignored mux packet due to channel switch");
return;
Expand Down Expand Up @@ -630,18 +653,112 @@ void CHTSPDemuxer::ParseSubscriptionSpeed ( htsmsg_t *m )

void CHTSPDemuxer::ParseSubscriptionStatus ( htsmsg_t *m )
{
const char *status;
const char *status, *error;
status = htsmsg_get_str(m, "status");
error = htsmsg_get_str(m, "subscriptionError");

// not for preTuning subscriptions
if (m_subscription.weight != SUBSCRIPTION_WEIGHT_DEFAULT)
// not for preTuning subscriptions, tag them as unknown
if (m_subscription.weight < SUBSCRIPTION_WEIGHT_DEFAULT)
{
m_subscription.state = SUBSCRIPTION_UNKNOWN;
return;
}

// this field is absent when everything is fine
if (status != NULL)
{
tvhinfo("Bad subscription status: %s", status);
XBMC->QueueNotification(QUEUE_INFO, status);

/* 'subscriptionError' was added in htsp v20 */
/* Use 'status' for older tvheadend backends */
if (m_conn.GetProtocol() >= 20)
{
if (error != NULL)
{
if (!strcmp("badSignal", error))
m_subscription.state = SUBSCRIPTION_NOSIGNAL;
else if (!strcmp("scrambled", error))
m_subscription.state = SUBSCRIPTION_SCRAMBLED;
else if (!strcmp("userLimit", error))
m_subscription.state = SUBSCRIPTION_USERLIMIT;
else if (!strcmp("noFreeAdapter", error))
{
/* No free adapter, AKA subscription conflict */
OnSubscriptionConflict();
}
else
m_subscription.state = SUBSCRIPTION_UNKNOWN;

/* Show an OSD message */
m_subscription.ShowError();
}
else
m_subscription.state = SUBSCRIPTION_RUNNING;
}
else
{
// this field is absent when everything is fine
if (status != NULL)
{
XBMC->QueueNotification(QUEUE_INFO, status);
m_subscription.state = SUBSCRIPTION_UNKNOWN;
}
else
m_subscription.state = SUBSCRIPTION_RUNNING;
}
}

void CHTSPDemuxer::OnSubscriptionConflict ( void )
{
if (m_subscription.state == SUBSCRIPTION_RUNNING)
{
/* Conflict case 1: */
/* Subscription was running before, but the adapter got stolen by another subscription */
/* Ask user if he wants to continue watching by hijacking an adapter back (increase weight) */
std::thread job(DialogLivestreamAborted);
job.detach();
m_subscription.state = SUBSCRIPTION_NOFREEADAPTER_ABORT;
}
else if (m_subscription.state == SUBSCRIPTION_STARTING ||
m_subscription.state == SUBSCRIPTION_NOFREEADAPTER_NOSTART_WAITING)
{
/* Conflict case 2: */
/* No free adapter found to start this channel from the beginning on */
/* Ask user if he wants to hijack an adapter after 'DIALOG_NOSTART_DELAY's of idling */
/* This time of idling is needed to prevent the dialog from popping up when zapping */
if ((time(NULL) - m_subscription.start) > DIALOG_NOSTART_DELAY)
{
std::thread job(DialogLivestreamNostart);
job.detach();
m_subscription.state = SUBSCRIPTION_NOFREEADAPTER_NOSTART;
}
else
m_subscription.state = SUBSCRIPTION_NOFREEADAPTER_NOSTART_WAITING;
}
else if (m_subscription.state == SUBSCRIPTION_NOFREEADAPTER_NOSTART ||
m_subscription.state == SUBSCRIPTION_NOFREEADAPTER_ABORT )
{
if (bDialogForceStart)
{
/* User has chosen to steal an adapter (increase weight) */
bDialogForceStart = false;
m_subscription.state = SUBSCRIPTION_FORCERUNNING;
}
}
else if (m_subscription.state == SUBSCRIPTION_FORCERUNNING)
{
/* Steal an adapter by increasing the subscription weight */
/* We do this in steps of 25 till we are running */
if (m_subscription.weight <= SUBSCRIPTION_WEIGHT_MAX)
{
m_subscription.weight += SUBSCRIPTION_WEIGHT_STEPSIZE;

/* Let the tvh thread send the weight async */
/* We can't do this here as we are in a htsp RX call */
/* And we don't want to block RX by sending a message here */
m_subscription.sendWeightAsync = true;
}
else
m_subscription.state = SUBSCRIPTION_FORCERUNNING_FAILED;
}
}

Expand Down
Loading

0 comments on commit f55c1f9

Please sign in to comment.