From b07a8159ccaa0e194e044385cd1c2ac4d5b42b84 Mon Sep 17 00:00:00 2001 From: Kai Sommerfeld Date: Sun, 10 Feb 2019 13:49:32 +0100 Subject: [PATCH] [PVR] Fix deadlock while obtaining recordings from PVR client. --- xbmc/pvr/epg/EpgContainer.cpp | 34 +++++++++++++++++++++++++++ xbmc/pvr/epg/EpgContainer.h | 7 ++++++ xbmc/pvr/recordings/PVRRecording.cpp | 19 --------------- xbmc/pvr/recordings/PVRRecording.h | 5 ---- xbmc/pvr/recordings/PVRRecordings.cpp | 20 +++++++--------- xbmc/pvr/recordings/PVRRecordings.h | 20 ++++++++++++++++ 6 files changed, 69 insertions(+), 36 deletions(-) diff --git a/xbmc/pvr/epg/EpgContainer.cpp b/xbmc/pvr/epg/EpgContainer.cpp index 0e13688a0f705..608c57947d2a0 100644 --- a/xbmc/pvr/epg/EpgContainer.cpp +++ b/xbmc/pvr/epg/EpgContainer.cpp @@ -221,6 +221,8 @@ void CPVREpgContainer::Start(bool bAsync) { CheckPlayingEvents(); + CServiceBroker::GetPVRManager().Recordings()->Events().Subscribe(this, &CPVREpgContainer::OnPVRRecordingsEvent); + Create(); SetPriority(-1); @@ -237,6 +239,9 @@ void CPVREpgContainer::Start(bool bAsync) void CPVREpgContainer::Stop(void) { + if (m_bStarted) + CServiceBroker::GetPVRManager().Recordings()->Events().Unsubscribe(this); + StopThread(); m_database->Close(); @@ -245,6 +250,35 @@ void CPVREpgContainer::Stop(void) m_bStarted = false; } +void CPVREpgContainer::OnPVRRecordingsEvent(const PVRRecordingsEvent& event) +{ + switch (event.id) + { + case PVRRecordingsEvent::RecordingUpdated: + case PVRRecordingsEvent::RecordingRemoved: + { + if (event.recording->BroadcastUid() == EPG_TAG_INVALID_UID ) + break; + + const std::shared_ptr channel + = CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(event.recording->ChannelUid(), + event.recording->ClientID()); + const std::shared_ptr epgTag = GetTagById(channel, event.recording->BroadcastUid()); + if (!epgTag) + break;; + + if (event.id == PVRRecordingsEvent::RecordingUpdated) + epgTag->SetRecording(event.recording); + else if (event.id == PVRRecordingsEvent::RecordingRemoved) + epgTag->ClearRecording(); + + break; + } + default: + break; + } +} + void CPVREpgContainer::Notify(const Observable &obs, const ObservableMessage msg) { if (msg == ObservableMessageEpgItemUpdate) diff --git a/xbmc/pvr/epg/EpgContainer.h b/xbmc/pvr/epg/EpgContainer.h index cd43345ab8150..6b4a5561c14b3 100644 --- a/xbmc/pvr/epg/EpgContainer.h +++ b/xbmc/pvr/epg/EpgContainer.h @@ -22,6 +22,7 @@ class CFileItemList; namespace PVR { + struct PVRRecordingsEvent; class CEpgUpdateRequest; class CEpgTagStateChange; @@ -76,6 +77,12 @@ namespace PVR */ bool DeleteEpg(const CPVREpgPtr &epg, bool bDeleteFromDatabase = false); + /*! + * @brief Process an event. + * @param event The event. + */ + void OnPVRRecordingsEvent(const PVRRecordingsEvent& event); + /*! * @brief Process a notification from an observable. * @param obs The observable that sent the update. diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp index b50f68e0d7670..bb3569bcb314b 100644 --- a/xbmc/pvr/recordings/PVRRecording.cpp +++ b/xbmc/pvr/recordings/PVRRecording.cpp @@ -22,7 +22,6 @@ #include "pvr/PVRManager.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/Epg.h" -#include "pvr/epg/EpgContainer.h" #include "pvr/recordings/PVRRecordingsPath.h" #include "pvr/timers/PVRTimers.h" @@ -220,24 +219,9 @@ bool CPVRRecording::Delete(void) if (!client || client->DeleteRecording(*this) != PVR_ERROR_NO_ERROR) return false; - OnDelete(); return true; } -void CPVRRecording::OnDelete(void) -{ - if (m_iEpgEventId != EPG_TAG_INVALID_UID) - { - const CPVRChannelPtr channel(Channel()); - if (channel) - { - const CPVREpgInfoTagPtr epgTag(CServiceBroker::GetPVRManager().EpgContainer().GetTagById(channel, m_iEpgEventId)); - if (epgTag) - epgTag->ClearRecording(); - } - } -} - bool CPVRRecording::Undelete(void) { const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId); @@ -410,9 +394,6 @@ void CPVRRecording::Update(const CPVRRecording &tag) m_strShowTitle = strEpisode; } - if (m_bIsDeleted) - OnDelete(); - UpdatePath(); } diff --git a/xbmc/pvr/recordings/PVRRecording.h b/xbmc/pvr/recordings/PVRRecording.h index 72e57eda8e8de..6bd4995a9814b 100644 --- a/xbmc/pvr/recordings/PVRRecording.h +++ b/xbmc/pvr/recordings/PVRRecording.h @@ -94,11 +94,6 @@ namespace PVR */ bool Delete(void); - /*! - * @brief Called when this recording has been deleted - */ - void OnDelete(void); - /*! * @brief Undelete this recording on the client (if supported). * @return True if it was undeleted successfully, false otherwise. diff --git a/xbmc/pvr/recordings/PVRRecordings.cpp b/xbmc/pvr/recordings/PVRRecordings.cpp index 492f5412ed5b1..6d8fdd768a057 100644 --- a/xbmc/pvr/recordings/PVRRecordings.cpp +++ b/xbmc/pvr/recordings/PVRRecordings.cpp @@ -24,7 +24,6 @@ #include "pvr/PVRManager.h" #include "pvr/addons/PVRClients.h" -#include "pvr/epg/EpgContainer.h" #include "pvr/epg/EpgInfoTag.h" #include "pvr/recordings/PVRRecordingsPath.h" @@ -209,7 +208,12 @@ bool CPVRRecordings::DeleteRecording(const CFileItem &item) } CPVRRecordingPtr tag = item.GetPVRRecordingInfoTag(); - return tag->Delete(); + if (tag->Delete()) + { + m_events.Publish(PVRRecordingsEvent(PVRRecordingsEvent::RecordingRemoved, tag)); + return true; + } + return false; } bool CPVRRecordings::Undelete(const CFileItem &item) @@ -395,22 +399,14 @@ void CPVRRecordings::UpdateFromClient(const CPVRRecordingPtr &tag) { newTag = CPVRRecordingPtr(new CPVRRecording); newTag->Update(*tag); - if (newTag->BroadcastUid() != EPG_TAG_INVALID_UID) - { - const CPVRChannelPtr channel(newTag->Channel()); - if (channel) - { - const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(channel, newTag->BroadcastUid()); - if (epgTag) - epgTag->SetRecording(newTag); - } - } newTag->m_iRecordingId = ++m_iLastId; m_recordings.insert(std::make_pair(CPVRRecordingUid(newTag->m_iClientId, newTag->m_strRecordingId), newTag)); if (newTag->IsRadio()) ++m_iRadioRecordings; else ++m_iTVRecordings; + + m_events.Publish(PVRRecordingsEvent(PVRRecordingsEvent::RecordingUpdated, newTag)); } } diff --git a/xbmc/pvr/recordings/PVRRecordings.h b/xbmc/pvr/recordings/PVRRecordings.h index 4672fb0d40d3d..55e860f6e104d 100644 --- a/xbmc/pvr/recordings/PVRRecordings.h +++ b/xbmc/pvr/recordings/PVRRecordings.h @@ -12,6 +12,7 @@ #include #include "FileItem.h" +#include "utils/EventStream.h" #include "video/VideoDatabase.h" #include "pvr/PVRTypes.h" @@ -21,11 +22,28 @@ namespace PVR { class CPVRRecordingsPath; + struct PVRRecordingsEvent + { + static const int RecordingUpdated = 0; + static const int RecordingRemoved = 1; + + PVRRecordingsEvent(int _id, const std::shared_ptr& _recording) + : id(_id), recording(_recording) {} + + int id; + std::shared_ptr recording; + }; + class CPVRRecordings { public: virtual ~CPVRRecordings(void); + /*! + * @brief Query the events available for CEventStream + */ + CEventStream& Events() { return m_events; } + /** * @brief (re)load the recordings from the clients. * @return the number of recordings loaded. @@ -98,6 +116,8 @@ namespace PVR unsigned int m_iTVRecordings = 0; unsigned int m_iRadioRecordings = 0; + CEventSource m_events; + void UpdateFromClients(void); std::string TrimSlashes(const std::string &strOrig) const; bool IsDirectoryMember(const std::string &strDirectory, const std::string &strEntryDirectory, bool bGrouped) const;