2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "ApplicationPlayerCallback.h"
12 #include "GUIUserMessages.h"
13 #include "PlayListPlayer.h"
14 #include "ServiceBroker.h"
16 #include "application/ApplicationComponents.h"
17 #include "application/ApplicationPlayer.h"
18 #include "application/ApplicationStackHelper.h"
19 #include "guilib/GUIComponent.h"
20 #include "guilib/GUIMessage.h"
21 #include "guilib/GUIWindowManager.h"
22 #include "guilib/StereoscopicsManager.h"
23 #include "interfaces/AnnouncementManager.h"
24 #include "interfaces/python/XBPython.h"
25 #include "music/MusicFileItemClassify.h"
26 #include "network/NetworkFileItemClassify.h"
27 #include "profiles/ProfileManager.h"
28 #include "settings/AdvancedSettings.h"
29 #include "settings/MediaSettings.h"
30 #include "settings/SettingsComponent.h"
31 #include "utils/JobManager.h"
32 #include "utils/SaveFileStateJob.h"
33 #include "utils/URIUtils.h"
34 #include "utils/log.h"
35 #include "video/VideoDatabase.h"
36 #include "video/VideoFileItemClassify.h"
37 #include "video/VideoInfoTag.h"
43 CApplicationPlayerCallback::CApplicationPlayerCallback()
47 void CApplicationPlayerCallback::OnPlayBackEnded()
49 CLog::LogF(LOGDEBUG
, "CApplicationPlayerCallback::OnPlayBackEnded");
51 CGUIMessage
msg(GUI_MSG_PLAYBACK_ENDED
, 0, 0);
52 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
55 void CApplicationPlayerCallback::OnPlayBackStarted(const CFileItem
& file
)
57 CLog::LogF(LOGDEBUG
, "CApplication::OnPlayBackStarted");
58 std::shared_ptr
<CFileItem
> itemCurrentFile
;
60 // check if VideoPlayer should set file item stream details from its current streams
61 const bool isBlu_dvd_image_or_stream
= URIUtils::IsBluray(file
.GetPath()) ||
62 VIDEO::IsDVDFile(file
) || file
.IsDiscImage() ||
63 NETWORK::IsInternetStream(file
);
65 const bool hasNoStreamDetails
=
66 (!file
.HasVideoInfoTag() || !file
.GetVideoInfoTag()->HasStreamDetails());
68 if (file
.GetProperty("get_stream_details_from_player").asBoolean() ||
69 (hasNoStreamDetails
&& isBlu_dvd_image_or_stream
))
71 auto& components
= CServiceBroker::GetAppComponents();
72 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
73 appPlayer
->SetUpdateStreamDetails();
76 auto& components
= CServiceBroker::GetAppComponents();
77 const auto stackHelper
= components
.GetComponent
<CApplicationStackHelper
>();
79 if (stackHelper
->IsPlayingISOStack() || stackHelper
->IsPlayingRegularStack())
80 itemCurrentFile
= std::make_shared
<CFileItem
>(*stackHelper
->GetRegisteredStack(file
));
82 itemCurrentFile
= std::make_shared
<CFileItem
>(file
);
84 /* When playing video pause any low priority jobs, they will be unpaused when playback stops.
85 * This should speed up player startup for files on internet filesystems (eg. webdav) and
86 * increase performance on low powered systems (Atom/ARM).
88 if (VIDEO::IsVideo(file
) || file
.IsGame())
90 CServiceBroker::GetJobManager()->PauseJobs();
93 stackHelper
->OnPlayBackStarted(file
);
95 CGUIMessage
msg(GUI_MSG_PLAYBACK_STARTED
, 0, 0, 0, 0, itemCurrentFile
);
96 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
99 void CApplicationPlayerCallback::OnPlayerCloseFile(const CFileItem
& file
,
100 const CBookmark
& bookmarkParam
)
102 auto& components
= CServiceBroker::GetAppComponents();
103 const auto stackHelper
= components
.GetComponent
<CApplicationStackHelper
>();
105 std::unique_lock
<CCriticalSection
> lock(stackHelper
->m_critSection
);
107 CFileItem
fileItem(file
);
108 CBookmark bookmark
= bookmarkParam
;
109 CBookmark resumeBookmark
;
110 bool playCountUpdate
= false;
111 float percent
= 0.0f
;
113 // Make sure we don't reset existing bookmark etc. on eg. player start failure
114 if (bookmark
.timeInSeconds
== 0.0)
117 if (stackHelper
->GetRegisteredStack(fileItem
) != nullptr &&
118 stackHelper
->GetRegisteredStackTotalTimeMs(fileItem
) > 0)
120 // regular stack case: we have to save the bookmark on the stack
121 fileItem
= *stackHelper
->GetRegisteredStack(file
);
122 // the bookmark coming from the player is only relative to the current part, thus needs to be corrected with these attributes (start time will be 0 for non-stackparts)
123 bookmark
.timeInSeconds
+= stackHelper
->GetRegisteredStackPartStartTimeMs(file
) / 1000.0;
124 if (stackHelper
->GetRegisteredStackTotalTimeMs(file
) > 0)
125 bookmark
.totalTimeInSeconds
= stackHelper
->GetRegisteredStackTotalTimeMs(file
) / 1000.0;
126 bookmark
.partNumber
= stackHelper
->GetRegisteredStackPartNumber(file
);
129 percent
= bookmark
.timeInSeconds
/ bookmark
.totalTimeInSeconds
* 100;
131 const std::shared_ptr
<CAdvancedSettings
> advancedSettings
=
132 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings();
134 if ((MUSIC::IsAudio(fileItem
) && advancedSettings
->m_audioPlayCountMinimumPercent
> 0 &&
135 percent
>= advancedSettings
->m_audioPlayCountMinimumPercent
) ||
136 (VIDEO::IsVideo(fileItem
) && advancedSettings
->m_videoPlayCountMinimumPercent
> 0 &&
137 percent
>= advancedSettings
->m_videoPlayCountMinimumPercent
))
139 playCountUpdate
= true;
142 if (advancedSettings
->m_videoIgnorePercentAtEnd
> 0 &&
143 bookmark
.totalTimeInSeconds
- bookmark
.timeInSeconds
<
144 0.01 * static_cast<double>(advancedSettings
->m_videoIgnorePercentAtEnd
) *
145 bookmark
.totalTimeInSeconds
)
147 resumeBookmark
.timeInSeconds
= -1.0;
149 else if (bookmark
.timeInSeconds
> advancedSettings
->m_videoIgnoreSecondsAtStart
)
151 resumeBookmark
= bookmark
;
152 if (stackHelper
->GetRegisteredStack(file
) != nullptr)
154 // also update video info tag with total time
155 fileItem
.GetVideoInfoTag()->m_streamDetails
.SetVideoDuration(
156 0, resumeBookmark
.totalTimeInSeconds
);
161 resumeBookmark
.timeInSeconds
= 0.0;
164 if (CServiceBroker::GetSettingsComponent()
165 ->GetProfileManager()
166 ->GetCurrentProfile()
167 .canWriteDatabases())
169 CSaveFileState::DoWork(fileItem
, resumeBookmark
, playCountUpdate
);
173 void CApplicationPlayerCallback::OnPlayBackPaused()
176 CServiceBroker::GetXBPython().OnPlayBackPaused();
179 CGUIMessage
msg(GUI_MSG_PLAYBACK_PAUSED
, 0, 0);
180 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
183 void CApplicationPlayerCallback::OnPlayBackResumed()
186 CServiceBroker::GetXBPython().OnPlayBackResumed();
189 CGUIMessage
msg(GUI_MSG_PLAYBACK_RESUMED
, 0, 0);
190 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
193 void CApplicationPlayerCallback::OnPlayBackStopped()
195 CLog::LogF(LOGDEBUG
, "CApplication::OnPlayBackStopped");
197 CGUIMessage
msg(GUI_MSG_PLAYBACK_STOPPED
, 0, 0);
198 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
201 void CApplicationPlayerCallback::OnPlayBackError()
203 //@todo Playlists can be continued by calling OnPlaybackEnded instead
205 CGUIMessage
msg(GUI_MSG_PLAYBACK_ERROR
, 0, 0);
206 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
210 void CApplicationPlayerCallback::OnQueueNextItem()
212 CLog::LogF(LOGDEBUG
, "CApplication::OnQueueNextItem");
214 // informs python script currently running that we are requesting the next track
215 // (does nothing if python is not loaded)
217 CServiceBroker::GetXBPython().OnQueueNextItem(); // currently unimplemented
220 CGUIMessage
msg(GUI_MSG_QUEUE_NEXT_ITEM
, 0, 0);
221 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
224 void CApplicationPlayerCallback::OnPlayBackSeek(int64_t iTime
, int64_t seekOffset
)
227 CServiceBroker::GetXBPython().OnPlayBackSeek(static_cast<int>(iTime
),
228 static_cast<int>(seekOffset
));
231 CGUIMessage
msg(GUI_MSG_PLAYBACK_SEEKED
, 0, 0, iTime
, seekOffset
);
232 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
235 void CApplicationPlayerCallback::OnPlayBackSeekChapter(int iChapter
)
238 CServiceBroker::GetXBPython().OnPlayBackSeekChapter(iChapter
);
242 void CApplicationPlayerCallback::OnPlayBackSpeedChanged(int iSpeed
)
245 CServiceBroker::GetXBPython().OnPlayBackSpeedChanged(iSpeed
);
248 CGUIMessage
msg(GUI_MSG_PLAYBACK_SPEED_CHANGED
, 0, 0, iSpeed
);
249 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
252 void CApplicationPlayerCallback::OnAVChange()
254 CLog::LogF(LOGDEBUG
, "CApplication::OnAVChange");
256 CServiceBroker::GetGUI()->GetStereoscopicsManager().OnStreamChange();
258 CGUIMessage
msg(GUI_MSG_PLAYBACK_AVCHANGE
, 0, 0);
259 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
262 void CApplicationPlayerCallback::OnAVStarted(const CFileItem
& file
)
264 CLog::LogF(LOGDEBUG
, "CApplication::OnAVStarted");
266 CGUIMessage
msg(GUI_MSG_PLAYBACK_AVSTARTED
, 0, 0);
267 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
270 void CApplicationPlayerCallback::RequestVideoSettings(const CFileItem
& fileItem
)
275 CLog::Log(LOGDEBUG
, "Loading settings for {}", CURL::GetRedacted(fileItem
.GetPath()));
277 // Load stored settings if they exist, otherwise use default
279 if (!dbs
.GetVideoSettings(fileItem
, vs
))
280 vs
= CMediaSettings::GetInstance().GetDefaultVideoSettings();
282 auto& components
= CServiceBroker::GetAppComponents();
283 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
284 appPlayer
->SetVideoSettings(vs
);
290 void CApplicationPlayerCallback::StoreVideoSettings(const CFileItem
& fileItem
,
291 const CVideoSettings
& vs
)
296 if (vs
!= CMediaSettings::GetInstance().GetDefaultVideoSettings())
298 dbs
.SetVideoSettings(fileItem
, vs
);
302 dbs
.EraseVideoSettings(fileItem
);