CLog::Log(LOGNOTICE, "stop player");
m_pPlayer->ClosePlayer();
+ CAnnouncementManager::Deinitialize();
+
StopPVRManager();
StopServices();
//Sleep(5000);
should the playerState be required, it is fetched from the database.
See the note in CGUIWindowVideoBase::ShowResumeMenu.
*/
- if (item.HasVideoInfoTag() && item.GetVideoInfoTag()->m_resumePoint.IsSet())
- options.starttime = item.GetVideoInfoTag()->m_resumePoint.timeInSeconds;
+ if (item.IsResumePointSet())
+ options.starttime = item.GetCurrentResumeTime();
}
else if (item.HasVideoInfoTag())
{
return type;
}
+bool CFileItem::IsResumePointSet() const
+{
+ return (HasVideoInfoTag() && GetVideoInfoTag()->m_resumePoint.IsSet()) ||
+ (HasPVRRecordingInfoTag() && GetPVRRecordingInfoTag()->GetLastPlayedPosition() > 0);
+}
+
+double CFileItem::GetCurrentResumeTime() const
+{
+ if (HasPVRRecordingInfoTag())
+ {
+ // This will retrieve 'fresh' resume information from the PVR server
+ int rc = GetPVRRecordingInfoTag()->GetLastPlayedPosition();
+ if (rc > 0)
+ return rc;
+ // Fall through to default value
+ }
+ if (HasVideoInfoTag() && GetVideoInfoTag()->m_resumePoint.IsSet())
+ {
+ return GetVideoInfoTag()->m_resumePoint.timeInSeconds;
+ }
+ // Resume from start when resume points are invalid or the PVR server returns an error
+ return 0;
+}
return m_pvrTimerInfoTag;
}
+ /*!
+ \brief Test if this item has a valid resume point set.
+ \return True if this item has a resume point and it is set, false otherwise.
+ */
+ bool IsResumePointSet() const;
+
+ /*!
+ \brief Return the current resume time.
+ \return The time in seconds from the start to resume playing from.
+ */
+ double GetCurrentResumeTime() const;
+
inline bool HasPictureInfoTag() const
{
return m_pictureInfoTag != NULL;
#define m_announcers XBMC_GLOBAL_USE(ANNOUNCEMENT::CAnnouncementManager::Globals).m_announcers
#define m_critSection XBMC_GLOBAL_USE(ANNOUNCEMENT::CAnnouncementManager::Globals).m_critSection
+void CAnnouncementManager::Deinitialize()
+{
+ CSingleLock lock (m_critSection);
+ m_announcers.clear();
+}
+
void CAnnouncementManager::AddAnnouncer(IAnnouncer *listener)
{
if (!listener)
std::vector<IAnnouncer *> m_announcers;
};
+ static void Deinitialize();
+
static void AddAnnouncer(IAnnouncer *listener);
static void RemoveAnnouncer(IAnnouncer *listener);
static void Announce(AnnouncementFlag flag, const char *sender, const char *message);
#define AIRPLAY_STATUS_NOT_IMPLEMENTED 501
#define AIRPLAY_STATUS_NO_RESPONSE_NEEDED 1000
+CCriticalSection CAirPlayServer::ServerInstanceLock;
CAirPlayServer *CAirPlayServer::ServerInstance = NULL;
int CAirPlayServer::m_isPlaying = 0;
void CAirPlayServer::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
{
+ CSingleLock lock(ServerInstanceLock);
+
if ( (flag & Player) && strcmp(sender, "xbmc") == 0 && ServerInstance)
{
if (strcmp(message, "OnStop") == 0)
{
StopServer(true);
+ CSingleLock lock(ServerInstanceLock);
+
ServerInstance = new CAirPlayServer(port, nonlocal);
if (ServerInstance->Initialize())
{
bool CAirPlayServer::SetCredentials(bool usePassword, const CStdString& password)
{
+ CSingleLock lock(ServerInstanceLock);
bool ret = false;
if (ServerInstance)
void CAirPlayServer::StopServer(bool bWait)
{
+ CSingleLock lock(ServerInstanceLock);
if (ServerInstance)
{
ServerInstance->StopThread(bWait);
void CAirPlayServer::backupVolume()
{
- if (ServerInstance->m_origVolume == -1)
+ CSingleLock lock(ServerInstanceLock);
+
+ if (ServerInstance && ServerInstance->m_origVolume == -1)
ServerInstance->m_origVolume = (int)g_application.GetVolume();
}
void CAirPlayServer::restoreVolume()
{
- if (ServerInstance->m_origVolume != -1 && CSettings::Get().GetBool("services.airplayvolumecontrol"))
+ CSingleLock lock(ServerInstanceLock);
+
+ if (ServerInstance && ServerInstance->m_origVolume != -1 && CSettings::Get().GetBool("services.airplayvolumecontrol"))
{
g_application.SetVolume((float)ServerInstance->m_origVolume);
ServerInstance->m_origVolume = -1;
CStdString m_password;
int m_origVolume;
+ static CCriticalSection ServerInstanceLock;
static CAirPlayServer *ServerInstance;
};
// this isn't pretty but needed to properly hide the addons node from clients
if (StringUtils::StartsWith(items.GetPath(), "library")) {
for (int i=0; i<items.Size(); i++) {
- if (StringUtils::StartsWith(items[i]->GetPath(), "addons"))
+ if (StringUtils::StartsWith(items[i]->GetPath(), "addons") ||
+ StringUtils::EndsWith(items[i]->GetPath(), "/addons.xml/"))
items.Remove(i);
}
}
// First try to find the resume position on the back-end, if that fails use video database
int positionInSeconds = item.GetPVRRecordingInfoTag()->GetLastPlayedPosition();
- // If the back-end does report a saved position then make sure there is a corresponding resume bookmark
- if (positionInSeconds > 0)
- {
- CBookmark bookmark;
- bookmark.timeInSeconds = positionInSeconds;
- bookmark.totalTimeInSeconds = (double)item.GetPVRRecordingInfoTag()->GetDuration();
- CVideoDatabase db;
- if (db.Open())
- {
- CStdString itemPath(item.GetPVRRecordingInfoTag()->m_strFileNameAndPath);
- db.AddBookMarkToFile(itemPath, bookmark, CBookmark::RESUME);
- db.Close();
- }
- }
- else if (positionInSeconds < 0)
+ // If the back-end does report a saved position it will be picked up by FileItem
+ if (positionInSeconds < 0)
{
CVideoDatabase db;
if (db.Open())