Skip to content

Commit

Permalink
Simplify LiveTVChain updates during channel changes.
Browse files Browse the repository at this point in the history
A channel change during Live TV usually involves 4 updates to the
LiveTVChain - starting and stopping the dummy and actual recordings.

On the frontend, each update caused a reload of the tvchain entries
from the database.  This is improved by sending the new contents of
the LiveTVChain as part of the update message from the backend, to
avoid the DB queries.

In addition, the update mechanism on the frontend of using a timer
event to defer the update is removed.  Originally, this was probably
done to allow the DB query to proceed outside the UI thread, but
currently the timer event handler is in the same thread as the message
handler, so this deferral was almost entirely unnecessary.

There is still the minor issue that each update message from the
backend appears to be handled twice by the frontend, though this
doesn't affect correctness.
  • Loading branch information
stichnot committed Jun 7, 2013
1 parent ce9e95c commit 0529d46
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 64 deletions.
135 changes: 104 additions & 31 deletions mythtv/libs/libmythtv/livetvchain.cpp
Expand Up @@ -63,13 +63,10 @@ void LiveTVChain::AppendNewProgram(ProgramInfo *pginfo, QString channum,
{
QMutexLocker lock(&m_lock);

QTime tmptime = pginfo->GetRecordingStartTime().time();

LiveTVChainEntry newent;
newent.chanid = pginfo->GetChanID();
newent.starttime = QDateTime(
pginfo->GetRecordingStartTime().date(),
QTime(tmptime.hour(), tmptime.minute(), tmptime.second()), Qt::UTC);
newent.starttime = pginfo->GetRecordingStartTime();
newent.endtime = pginfo->GetRecordingEndTime();
newent.discontinuity = discont;
newent.hostprefix = m_hostprefix;
newent.cardtype = m_cardtype;
Expand Down Expand Up @@ -189,7 +186,7 @@ void LiveTVChain::DeleteProgram(ProgramInfo *pginfo)
void LiveTVChain::BroadcastUpdate(void)
{
QString message = QString("LIVETV_CHAIN UPDATE %1").arg(m_id);
MythEvent me(message);
MythEvent me(message, entriesToStringList());
gCoreContext->dispatch(me);
}

Expand All @@ -207,38 +204,42 @@ void LiveTVChain::DestroyChain(void)
MythDB::DBError("LiveTVChain::DestroyChain", query);
}

void LiveTVChain::ReloadAll(void)
void LiveTVChain::ReloadAll(const QStringList &data)
{
QMutexLocker lock(&m_lock);

int prev_size = m_chain.size();
m_chain.clear();

MSqlQuery query(MSqlQuery::InitCon());
query.prepare("SELECT chanid, starttime, endtime, discontinuity, "
"chainpos, hostprefix, cardtype, channame, input "
"FROM tvchain "
"WHERE chainid = :CHAINID ORDER BY chainpos;");
query.bindValue(":CHAINID", m_id);

if (query.exec() && query.isActive() && query.size() > 0)
if (data.isEmpty() || !entriesFromStringList(data))
{
while (query.next())
{

LiveTVChainEntry entry;
entry.chanid = query.value(0).toUInt();
entry.starttime = MythDate::as_utc(query.value(1).toDateTime());
entry.endtime = MythDate::as_utc(query.value(2).toDateTime());
entry.discontinuity = query.value(3).toInt();
entry.hostprefix = query.value(5).toString();
entry.cardtype = query.value(6).toString();
entry.channum = query.value(7).toString();
entry.inputname = query.value(8).toString();
m_chain.clear();

m_maxpos = query.value(4).toInt() + 1;
MSqlQuery query(MSqlQuery::InitCon());
query.prepare("SELECT chanid, starttime, endtime, discontinuity, "
"chainpos, hostprefix, cardtype, channame, input "
"FROM tvchain "
"WHERE chainid = :CHAINID ORDER BY chainpos;");
query.bindValue(":CHAINID", m_id);

m_chain.append(entry);
if (query.exec() && query.isActive() && query.size() > 0)
{
while (query.next())
{
LiveTVChainEntry entry;
entry.chanid = query.value(0).toUInt();
entry.starttime =
MythDate::as_utc(query.value(1).toDateTime());
entry.endtime =
MythDate::as_utc(query.value(2).toDateTime());
entry.discontinuity = query.value(3).toInt();
entry.hostprefix = query.value(5).toString();
entry.cardtype = query.value(6).toString();
entry.channum = query.value(7).toString();
entry.inputname = query.value(8).toString();

m_maxpos = query.value(4).toInt() + 1;

m_chain.append(entry);
}
}
}

Expand Down Expand Up @@ -608,3 +609,75 @@ QString LiveTVChain::toString() const
}
return ret;
}

QStringList LiveTVChain::entriesToStringList() const
{
QMutexLocker lock(&m_lock);
QStringList ret;
ret << QString::number(m_maxpos);
for (int i = 0; i < m_chain.size(); i++)
{
ret << QString::number(m_chain[i].chanid);
ret << m_chain[i].starttime.toString(Qt::ISODate);
ret << m_chain[i].endtime.toString(Qt::ISODate);
ret << QString::number(m_chain[i].discontinuity);
ret << m_chain[i].hostprefix;
ret << m_chain[i].cardtype;
ret << m_chain[i].channum;
ret << m_chain[i].inputname;
}
return ret;
}

bool LiveTVChain::entriesFromStringList(const QStringList &items)
{
int numItems = items.size();
QList<LiveTVChainEntry> chain;
int itemIdx = 0;
int maxpos = 0;
bool ok = false;
if (itemIdx < numItems)
maxpos = items[itemIdx++].toInt(&ok);
while (ok && itemIdx < numItems)
{
LiveTVChainEntry entry;
if (ok && itemIdx < numItems)
entry.chanid = items[itemIdx++].toUInt(&ok);
if (ok && itemIdx < numItems)
{
entry.starttime =
QDateTime::fromString(items[itemIdx++], Qt::ISODate);
ok = entry.starttime.isValid();
}
if (ok && itemIdx < numItems)
{
entry.endtime =
QDateTime::fromString(items[itemIdx++], Qt::ISODate);
ok = entry.endtime.isValid();
}
if (ok && itemIdx < numItems)
entry.discontinuity = items[itemIdx++].toInt(&ok);
if (ok && itemIdx < numItems)
entry.hostprefix = items[itemIdx++];
if (ok && itemIdx < numItems)
entry.cardtype = items[itemIdx++];
if (ok && itemIdx < numItems)
entry.channum = items[itemIdx++];
if (ok && itemIdx < numItems)
entry.inputname = items[itemIdx++];
if (ok)
chain.append(entry);
}
if (ok)
{
QMutexLocker lock(&m_lock);
m_maxpos = maxpos;
m_chain = chain;
}
else
{
LOG(VB_PLAYBACK, LOG_INFO,
QString("Failed to deserialize TVChain - ") + items.join("|"));
}
return ok;
}
8 changes: 7 additions & 1 deletion mythtv/libs/libmythtv/livetvchain.h
Expand Up @@ -2,6 +2,7 @@
#define _LIVETVCHAIN_H_

#include <QString>
#include <QStringList>
#include <QDateTime>
#include <QMutex>
#include <QList>
Expand Down Expand Up @@ -42,7 +43,7 @@ class MTV_PUBLIC LiveTVChain
void FinishedRecording(ProgramInfo *pginfo);
void DeleteProgram(ProgramInfo *pginfo);

void ReloadAll();
void ReloadAll(const QStringList &data = QStringList());

// const gets
QString GetID(void) const { return m_id; }
Expand Down Expand Up @@ -84,6 +85,11 @@ class MTV_PUBLIC LiveTVChain

QString toString() const;

// serialize m_maxpos and m_chain to a stringlist
QStringList entriesToStringList() const;
// deserialize m_maxpos and m_chain from a stringlist
bool entriesFromStringList(const QStringList &items);

private:
void BroadcastUpdate();
void GetEntryAt(int at, LiveTVChainEntry &entry) const;
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/playercontext.cpp
Expand Up @@ -481,12 +481,12 @@ void PlayerContext::StopPlaying(void)
player->StopPlaying();
}

void PlayerContext::UpdateTVChain(void)
void PlayerContext::UpdateTVChain(const QStringList &data)
{
QMutexLocker locker(&deletePlayerLock);
if (tvchain && player)
{
tvchain->ReloadAll();
tvchain->ReloadAll(data);
player->CheckTVChain();
}
}
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/playercontext.h
Expand Up @@ -60,7 +60,7 @@ class MTV_PUBLIC PlayerContext
void TeardownPlayer(void);
bool StartPlaying(int maxWait = -1);
void StopPlaying(void);
void UpdateTVChain(void);
void UpdateTVChain(const QStringList &data = QStringList());
bool ReloadTVChain(void);
void CreatePIPWindow(const QRect&, int pos = -1,
QWidget *widget = NULL);
Expand Down
31 changes: 3 additions & 28 deletions mythtv/libs/libmythtv/tv_play.cpp
Expand Up @@ -2806,31 +2806,6 @@ void TV::timerEvent(QTimerEvent *te)
if (handled)
return;

// Check if it matches a tvchainUpdateTimerId
ctx = NULL;
{
QMutexLocker locker(&timerIdLock);
TimerContextMap::iterator it = tvchainUpdateTimerId.find(timer_id);
if (it != tvchainUpdateTimerId.end())
{
KillTimer(timer_id);
ctx = *it;
tvchainUpdateTimerId.erase(it);
}
}

if (ctx)
{
PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
bool still_exists = find_player_index(ctx) >= 0;

if (still_exists)
ctx->UpdateTVChain();

ReturnPlayerLock(mctx);
handled = true;
}

if (handled)
return;

Expand Down Expand Up @@ -9527,10 +9502,10 @@ void TV::customEvent(QEvent *e)
for (uint i = 0; mctx && (i < player.size()); i++)
{
PlayerContext *ctx = GetPlayer(mctx, i);
if (ctx->tvchain && ctx->tvchain->GetID() == id)
if (ctx->tvchain && ctx->tvchain->GetID() == id &&
find_player_index(ctx) >= 0)
{
QMutexLocker locker(&timerIdLock);
tvchainUpdateTimerId[StartTimer(1, __LINE__)] = ctx;
ctx->UpdateTVChain(me->ExtraDataList());
break;
}
}
Expand Down
1 change: 0 additions & 1 deletion mythtv/libs/libmythtv/tv_play.h
Expand Up @@ -976,7 +976,6 @@ class MTV_PUBLIC TV : public QObject, public MenuItemDisplayer
mutable volatile int exitPlayerTimerId;
TimerContextMap stateChangeTimerId;
TimerContextMap signalMonitorTimerId;
TimerContextMap tvchainUpdateTimerId;

// Playback menu state caching
PlayerContext *m_tvmCtx;
Expand Down

0 comments on commit 0529d46

Please sign in to comment.