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/json-rpc/JSONUtils.h"
25 #include "interfaces/python/XBPython.h"
26 #include "profiles/ProfileManager.h"
27 #include "settings/AdvancedSettings.h"
28 #include "settings/MediaSettings.h"
29 #include "settings/SettingsComponent.h"
30 #include "utils/JobManager.h"
31 #include "utils/SaveFileStateJob.h"
32 #include "utils/URIUtils.h"
33 #include "utils/log.h"
34 #include "video/VideoDatabase.h"
35 #include "video/VideoInfoTag.h"
39 CApplicationPlayerCallback::CApplicationPlayerCallback()
43 void CApplicationPlayerCallback::OnPlayBackEnded()
45 CLog::LogF(LOGDEBUG
, "CApplicationPlayerCallback::OnPlayBackEnded");
47 CGUIMessage
msg(GUI_MSG_PLAYBACK_ENDED
, 0, 0);
48 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
51 void CApplicationPlayerCallback::OnPlayBackStarted(const CFileItem
& file
)
53 CLog::LogF(LOGDEBUG
, "CApplication::OnPlayBackStarted");
54 std::shared_ptr
<CFileItem
> itemCurrentFile
;
56 // check if VideoPlayer should set file item stream details from its current streams
57 const bool isBlu_dvd_image_or_stream
= (URIUtils::IsBluray(file
.GetPath()) || file
.IsDVDFile() ||
58 file
.IsDiscImage() || file
.IsInternetStream());
60 const bool hasNoStreamDetails
=
61 (!file
.HasVideoInfoTag() || !file
.GetVideoInfoTag()->HasStreamDetails());
63 if (file
.GetProperty("get_stream_details_from_player").asBoolean() ||
64 (hasNoStreamDetails
&& isBlu_dvd_image_or_stream
))
66 auto& components
= CServiceBroker::GetAppComponents();
67 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
68 appPlayer
->SetUpdateStreamDetails();
71 auto& components
= CServiceBroker::GetAppComponents();
72 const auto stackHelper
= components
.GetComponent
<CApplicationStackHelper
>();
74 if (stackHelper
->IsPlayingISOStack() || stackHelper
->IsPlayingRegularStack())
75 itemCurrentFile
= std::make_shared
<CFileItem
>(*stackHelper
->GetRegisteredStack(file
));
77 itemCurrentFile
= std::make_shared
<CFileItem
>(file
);
79 /* When playing video pause any low priority jobs, they will be unpaused when playback stops.
80 * This should speed up player startup for files on internet filesystems (eg. webdav) and
81 * increase performance on low powered systems (Atom/ARM).
83 if (file
.IsVideo() || file
.IsGame())
85 CServiceBroker::GetJobManager()->PauseJobs();
88 stackHelper
->OnPlayBackStarted(file
);
90 CGUIMessage
msg(GUI_MSG_PLAYBACK_STARTED
, 0, 0, 0, 0, itemCurrentFile
);
91 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
94 void CApplicationPlayerCallback::OnPlayerCloseFile(const CFileItem
& file
,
95 const CBookmark
& bookmarkParam
)
97 auto& components
= CServiceBroker::GetAppComponents();
98 const auto stackHelper
= components
.GetComponent
<CApplicationStackHelper
>();
100 std::unique_lock
<CCriticalSection
> lock(stackHelper
->m_critSection
);
102 CFileItem
fileItem(file
);
103 CBookmark bookmark
= bookmarkParam
;
104 CBookmark resumeBookmark
;
105 bool playCountUpdate
= false;
106 float percent
= 0.0f
;
108 // Make sure we don't reset existing bookmark etc. on eg. player start failure
109 if (bookmark
.timeInSeconds
== 0.0)
112 if (stackHelper
->GetRegisteredStack(fileItem
) != nullptr &&
113 stackHelper
->GetRegisteredStackTotalTimeMs(fileItem
) > 0)
115 // regular stack case: we have to save the bookmark on the stack
116 fileItem
= *stackHelper
->GetRegisteredStack(file
);
117 // 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)
118 bookmark
.timeInSeconds
+= stackHelper
->GetRegisteredStackPartStartTimeMs(file
) / 1000.0;
119 if (stackHelper
->GetRegisteredStackTotalTimeMs(file
) > 0)
120 bookmark
.totalTimeInSeconds
= stackHelper
->GetRegisteredStackTotalTimeMs(file
) / 1000.0;
121 bookmark
.partNumber
= stackHelper
->GetRegisteredStackPartNumber(file
);
124 percent
= bookmark
.timeInSeconds
/ bookmark
.totalTimeInSeconds
* 100;
126 const std::shared_ptr
<CAdvancedSettings
> advancedSettings
=
127 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings();
129 if ((fileItem
.IsAudio() && advancedSettings
->m_audioPlayCountMinimumPercent
> 0 &&
130 percent
>= advancedSettings
->m_audioPlayCountMinimumPercent
) ||
131 (fileItem
.IsVideo() && advancedSettings
->m_videoPlayCountMinimumPercent
> 0 &&
132 percent
>= advancedSettings
->m_videoPlayCountMinimumPercent
))
134 playCountUpdate
= true;
137 if (advancedSettings
->m_videoIgnorePercentAtEnd
> 0 &&
138 bookmark
.totalTimeInSeconds
- bookmark
.timeInSeconds
<
139 0.01 * static_cast<double>(advancedSettings
->m_videoIgnorePercentAtEnd
) *
140 bookmark
.totalTimeInSeconds
)
142 resumeBookmark
.timeInSeconds
= -1.0;
144 else if (bookmark
.timeInSeconds
> advancedSettings
->m_videoIgnoreSecondsAtStart
)
146 resumeBookmark
= bookmark
;
147 if (stackHelper
->GetRegisteredStack(file
) != nullptr)
149 // also update video info tag with total time
150 fileItem
.GetVideoInfoTag()->m_streamDetails
.SetVideoDuration(
151 0, resumeBookmark
.totalTimeInSeconds
);
156 resumeBookmark
.timeInSeconds
= 0.0;
159 if (CServiceBroker::GetSettingsComponent()
160 ->GetProfileManager()
161 ->GetCurrentProfile()
162 .canWriteDatabases())
164 CSaveFileState::DoWork(fileItem
, resumeBookmark
, playCountUpdate
);
168 void CApplicationPlayerCallback::OnPlayBackPaused()
171 CServiceBroker::GetXBPython().OnPlayBackPaused();
174 CGUIMessage
msg(GUI_MSG_PLAYBACK_PAUSED
, 0, 0);
175 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
178 void CApplicationPlayerCallback::OnPlayBackResumed()
181 CServiceBroker::GetXBPython().OnPlayBackResumed();
184 CGUIMessage
msg(GUI_MSG_PLAYBACK_RESUMED
, 0, 0);
185 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
188 void CApplicationPlayerCallback::OnPlayBackStopped()
190 CLog::LogF(LOGDEBUG
, "CApplication::OnPlayBackStopped");
192 CGUIMessage
msg(GUI_MSG_PLAYBACK_STOPPED
, 0, 0);
193 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
196 void CApplicationPlayerCallback::OnPlayBackError()
198 //@todo Playlists can be continued by calling OnPlaybackEnded instead
200 CGUIMessage
msg(GUI_MSG_PLAYBACK_ERROR
, 0, 0);
201 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
205 void CApplicationPlayerCallback::OnQueueNextItem()
207 CLog::LogF(LOGDEBUG
, "CApplication::OnQueueNextItem");
209 // informs python script currently running that we are requesting the next track
210 // (does nothing if python is not loaded)
212 CServiceBroker::GetXBPython().OnQueueNextItem(); // currently unimplemented
215 CGUIMessage
msg(GUI_MSG_QUEUE_NEXT_ITEM
, 0, 0);
216 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
219 void CApplicationPlayerCallback::OnPlayBackSeek(int64_t iTime
, int64_t seekOffset
)
222 CServiceBroker::GetXBPython().OnPlayBackSeek(static_cast<int>(iTime
),
223 static_cast<int>(seekOffset
));
226 CGUIMessage
msg(GUI_MSG_PLAYBACK_SEEKED
, 0, 0, iTime
, seekOffset
);
227 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
230 void CApplicationPlayerCallback::OnPlayBackSeekChapter(int iChapter
)
233 CServiceBroker::GetXBPython().OnPlayBackSeekChapter(iChapter
);
237 void CApplicationPlayerCallback::OnPlayBackSpeedChanged(int iSpeed
)
240 CServiceBroker::GetXBPython().OnPlayBackSpeedChanged(iSpeed
);
243 CGUIMessage
msg(GUI_MSG_PLAYBACK_SPEED_CHANGED
, 0, 0, iSpeed
);
244 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
247 void CApplicationPlayerCallback::OnAVChange()
249 CLog::LogF(LOGDEBUG
, "CApplication::OnAVChange");
251 CServiceBroker::GetGUI()->GetStereoscopicsManager().OnStreamChange();
253 CGUIMessage
msg(GUI_MSG_PLAYBACK_AVCHANGE
, 0, 0);
254 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
257 void CApplicationPlayerCallback::OnAVStarted(const CFileItem
& file
)
259 CLog::LogF(LOGDEBUG
, "CApplication::OnAVStarted");
261 CGUIMessage
msg(GUI_MSG_PLAYBACK_AVSTARTED
, 0, 0);
262 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
265 void CApplicationPlayerCallback::RequestVideoSettings(const CFileItem
& fileItem
)
270 CLog::Log(LOGDEBUG
, "Loading settings for {}", CURL::GetRedacted(fileItem
.GetPath()));
272 // Load stored settings if they exist, otherwise use default
274 if (!dbs
.GetVideoSettings(fileItem
, vs
))
275 vs
= CMediaSettings::GetInstance().GetDefaultVideoSettings();
277 auto& components
= CServiceBroker::GetAppComponents();
278 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
279 appPlayer
->SetVideoSettings(vs
);
285 void CApplicationPlayerCallback::StoreVideoSettings(const CFileItem
& fileItem
,
286 const CVideoSettings
& vs
)
291 if (vs
!= CMediaSettings::GetInstance().GetDefaultVideoSettings())
293 dbs
.SetVideoSettings(fileItem
, vs
);
297 dbs
.EraseVideoSettings(fileItem
);