[Test] Added tests for CUtil::SplitParams
[xbmc.git] / xbmc / application / ApplicationPlayerCallback.cpp
blobed36a27e185a2abbdfc96ead2d842d7d37c64272
1 /*
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.
7 */
9 #include "ApplicationPlayerCallback.h"
11 #include "FileItem.h"
12 #include "GUIUserMessages.h"
13 #include "PlayListPlayer.h"
14 #include "ServiceBroker.h"
15 #include "URL.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"
37 #include <memory>
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));
76 else
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)
110 return;
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);
154 else
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()
170 #ifdef HAS_PYTHON
171 CServiceBroker::GetXBPython().OnPlayBackPaused();
172 #endif
174 CGUIMessage msg(GUI_MSG_PLAYBACK_PAUSED, 0, 0);
175 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
178 void CApplicationPlayerCallback::OnPlayBackResumed()
180 #ifdef HAS_PYTHON
181 CServiceBroker::GetXBPython().OnPlayBackResumed();
182 #endif
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
199 // open error dialog
200 CGUIMessage msg(GUI_MSG_PLAYBACK_ERROR, 0, 0);
201 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
202 OnPlayBackStopped();
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)
211 #ifdef HAS_PYTHON
212 CServiceBroker::GetXBPython().OnQueueNextItem(); // currently unimplemented
213 #endif
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)
221 #ifdef HAS_PYTHON
222 CServiceBroker::GetXBPython().OnPlayBackSeek(static_cast<int>(iTime),
223 static_cast<int>(seekOffset));
224 #endif
226 CGUIMessage msg(GUI_MSG_PLAYBACK_SEEKED, 0, 0, iTime, seekOffset);
227 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
230 void CApplicationPlayerCallback::OnPlayBackSeekChapter(int iChapter)
232 #ifdef HAS_PYTHON
233 CServiceBroker::GetXBPython().OnPlayBackSeekChapter(iChapter);
234 #endif
237 void CApplicationPlayerCallback::OnPlayBackSpeedChanged(int iSpeed)
239 #ifdef HAS_PYTHON
240 CServiceBroker::GetXBPython().OnPlayBackSpeedChanged(iSpeed);
241 #endif
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)
267 CVideoDatabase dbs;
268 if (dbs.Open())
270 CLog::Log(LOGDEBUG, "Loading settings for {}", CURL::GetRedacted(fileItem.GetPath()));
272 // Load stored settings if they exist, otherwise use default
273 CVideoSettings vs;
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);
281 dbs.Close();
285 void CApplicationPlayerCallback::StoreVideoSettings(const CFileItem& fileItem,
286 const CVideoSettings& vs)
288 CVideoDatabase dbs;
289 if (dbs.Open())
291 if (vs != CMediaSettings::GetInstance().GetDefaultVideoSettings())
293 dbs.SetVideoSettings(fileItem, vs);
295 else
297 dbs.EraseVideoSettings(fileItem);
299 dbs.Close();