[WASAPI] fix stream types and frequencies enumeration
[xbmc.git] / xbmc / playlists / PlayList.cpp
blobf64d82b8eafa566ce146d3e6a65d95134c67da4a
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 "PlayList.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "PlayListFactory.h"
14 #include "ServiceBroker.h"
15 #include "filesystem/File.h"
16 #include "interfaces/AnnouncementManager.h"
17 #include "music/MusicFileItemClassify.h"
18 #include "music/tags/MusicInfoTag.h"
19 #include "utils/Random.h"
20 #include "utils/StringUtils.h"
21 #include "utils/URIUtils.h"
22 #include "utils/Variant.h"
23 #include "utils/log.h"
25 #include <algorithm>
26 #include <cassert>
27 #include <iostream>
28 #include <sstream>
29 #include <string>
30 #include <utility>
31 #include <vector>
33 using namespace MUSIC_INFO;
34 using namespace XFILE;
36 namespace KODI::PLAYLIST
39 CPlayList::CPlayList(Id id /* = PLAYLIST::TYPE_NONE */) : m_id(id)
41 m_iPlayableItems = -1;
42 m_bShuffled = false;
43 m_bWasPlayed = false;
46 void CPlayList::AnnounceRemove(int pos)
48 if (m_id == Id::TYPE_NONE)
49 return;
51 CVariant data;
52 data["playlistid"] = static_cast<int>(m_id);
53 data["position"] = pos;
54 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Playlist, "OnRemove", data);
57 void CPlayList::AnnounceClear()
59 if (m_id == Id::TYPE_NONE)
60 return;
62 CVariant data;
63 data["playlistid"] = static_cast<int>(m_id);
64 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Playlist, "OnClear", data);
67 void CPlayList::AnnounceAdd(const std::shared_ptr<CFileItem>& item, int pos)
69 if (m_id == Id::TYPE_NONE)
70 return;
72 CVariant data;
73 data["playlistid"] = static_cast<int>(m_id);
74 data["position"] = pos;
75 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Playlist, "OnAdd", item, data);
78 void CPlayList::Add(const std::shared_ptr<CFileItem>& item, int iPosition, int iOrder)
80 int iOldSize = size();
81 if (iPosition < 0 || iPosition >= iOldSize)
82 iPosition = iOldSize;
83 if (iOrder < 0 || iOrder >= iOldSize)
84 item->m_iprogramCount = iOldSize;
85 else
86 item->m_iprogramCount = iOrder;
88 // increment the playable counter
89 item->ClearProperty("unplayable");
90 if (m_iPlayableItems < 0)
91 m_iPlayableItems = 1;
92 else
93 m_iPlayableItems++;
95 // set 'IsPlayable' property - needed for properly handling plugin:// URLs
96 item->SetProperty("IsPlayable", true);
98 //CLog::Log(LOGDEBUG,"{} item:({:02}/{:02})[{}]", __FUNCTION__, iPosition, item->m_iprogramCount, item->GetPath());
99 if (iPosition == iOldSize)
100 m_vecItems.push_back(item);
101 else
103 ivecItems it = m_vecItems.begin() + iPosition;
104 m_vecItems.insert(it, 1, item);
105 // correct any duplicate order values
106 if (iOrder < iOldSize)
107 IncrementOrder(iPosition + 1, iOrder);
109 AnnounceAdd(item, iPosition);
112 void CPlayList::Add(const std::shared_ptr<CFileItem>& item)
114 Add(item, -1, -1);
117 void CPlayList::Add(const CPlayList& playlist)
119 for (int i = 0; i < playlist.size(); i++)
120 Add(playlist[i], -1, -1);
123 void CPlayList::Add(const CFileItemList& items)
125 for (int i = 0; i < items.Size(); i++)
126 Add(items[i]);
129 void CPlayList::Insert(const CPlayList& playlist, int iPosition /* = -1 */)
131 // out of bounds so just add to the end
132 int iSize = size();
133 if (iPosition < 0 || iPosition >= iSize)
135 Add(playlist);
136 return;
138 for (int i = 0; i < playlist.size(); i++)
140 int iPos = iPosition + i;
141 Add(playlist[i], iPos, iPos);
145 void CPlayList::Insert(const CFileItemList& items, int iPosition /* = -1 */)
147 // out of bounds so just add to the end
148 int iSize = size();
149 if (iPosition < 0 || iPosition >= iSize)
151 Add(items);
152 return;
154 for (int i = 0; i < items.Size(); i++)
156 Add(items[i], iPosition + i, iPosition + i);
160 void CPlayList::Insert(const std::shared_ptr<CFileItem>& item, int iPosition /* = -1 */)
162 // out of bounds so just add to the end
163 int iSize = size();
164 if (iPosition < 0 || iPosition >= iSize)
166 Add(item);
167 return;
169 Add(item, iPosition, iPosition);
172 void CPlayList::DecrementOrder(int iOrder)
174 if (iOrder < 0) return;
176 // it was the last item so do nothing
177 if (iOrder == size()) return;
179 // fix all items with an order greater than the removed iOrder
180 ivecItems it;
181 it = m_vecItems.begin();
182 while (it != m_vecItems.end())
184 CFileItemPtr item = *it;
185 if (item->m_iprogramCount > iOrder)
187 //CLog::Log(LOGDEBUG,"{} fixing item at order {}", __FUNCTION__, item->m_iprogramCount);
188 item->m_iprogramCount--;
190 ++it;
194 void CPlayList::IncrementOrder(int iPosition, int iOrder)
196 if (iOrder < 0) return;
198 // fix all items with an order equal or greater to the added iOrder at iPos
199 ivecItems it;
200 it = m_vecItems.begin() + iPosition;
201 while (it != m_vecItems.end())
203 CFileItemPtr item = *it;
204 if (item->m_iprogramCount >= iOrder)
206 //CLog::Log(LOGDEBUG,"{} fixing item at order {}", __FUNCTION__, item->m_iprogramCount);
207 item->m_iprogramCount++;
209 ++it;
213 void CPlayList::Clear()
215 bool announce = false;
216 if (!m_vecItems.empty())
218 m_vecItems.erase(m_vecItems.begin(), m_vecItems.end());
219 announce = true;
221 m_strPlayListName = "";
222 m_iPlayableItems = -1;
223 m_bWasPlayed = false;
225 if (announce)
226 AnnounceClear();
229 int CPlayList::size() const
231 return (int)m_vecItems.size();
234 const std::shared_ptr<CFileItem> CPlayList::operator[](int iItem) const
236 if (iItem < 0 || iItem >= size())
238 assert(false);
239 CLog::Log(LOGERROR, "Error trying to retrieve an item that's out of range");
240 return CFileItemPtr();
242 return m_vecItems[iItem];
245 std::shared_ptr<CFileItem> CPlayList::operator[](int iItem)
247 if (iItem < 0 || iItem >= size())
249 assert(false);
250 CLog::Log(LOGERROR, "Error trying to retrieve an item that's out of range");
251 return CFileItemPtr();
253 return m_vecItems[iItem];
256 void CPlayList::Shuffle(int iPosition)
258 if (size() == 0)
259 // nothing to shuffle, just set the flag for later
260 m_bShuffled = true;
261 else
263 if (iPosition >= size())
264 return;
265 if (iPosition < 0)
266 iPosition = 0;
267 CLog::Log(LOGDEBUG, "{} shuffling at pos:{}", __FUNCTION__, iPosition);
269 ivecItems it = m_vecItems.begin() + iPosition;
270 KODI::UTILS::RandomShuffle(it, m_vecItems.end());
272 // the list is now shuffled!
273 m_bShuffled = true;
277 struct SSortPlayListItem
279 static bool PlaylistSort(const CFileItemPtr &left, const CFileItemPtr &right)
281 return (left->m_iprogramCount < right->m_iprogramCount);
285 void CPlayList::UnShuffle()
287 std::sort(m_vecItems.begin(), m_vecItems.end(), SSortPlayListItem::PlaylistSort);
288 // the list is now unshuffled!
289 m_bShuffled = false;
292 const std::string& CPlayList::GetName() const
294 return m_strPlayListName;
297 void CPlayList::Remove(const std::string& strFileName)
299 int iOrder = -1;
300 int position = 0;
301 ivecItems it;
302 it = m_vecItems.begin();
303 while (it != m_vecItems.end() )
305 CFileItemPtr item = *it;
306 if (item->GetPath() == strFileName)
308 iOrder = item->m_iprogramCount;
309 it = m_vecItems.erase(it);
310 AnnounceRemove(position);
311 //CLog::Log(LOGDEBUG,"PLAYLIST, removing item at order {}", iPos);
313 else
315 ++position;
316 ++it;
319 DecrementOrder(iOrder);
322 int CPlayList::FindOrder(int iOrder) const
324 for (int i = 0; i < size(); i++)
326 if (m_vecItems[i]->m_iprogramCount == iOrder)
327 return i;
329 return -1;
332 // remove item from playlist by position
333 void CPlayList::Remove(int position)
335 int iOrder = -1;
336 if (position >= 0 && position < (int)m_vecItems.size())
338 iOrder = m_vecItems[position]->m_iprogramCount;
339 m_vecItems.erase(m_vecItems.begin() + position);
341 DecrementOrder(iOrder);
343 AnnounceRemove(position);
346 int CPlayList::RemoveDVDItems()
348 std::vector <std::string> vecFilenames;
350 // Collect playlist items from DVD share
351 ivecItems it;
352 it = m_vecItems.begin();
353 while (it != m_vecItems.end() )
355 CFileItemPtr item = *it;
356 if (MUSIC::IsCDDA(*item) || item->IsOnDVD())
358 vecFilenames.push_back( item->GetPath() );
360 ++it;
363 // Delete them from playlist
364 int nFileCount = vecFilenames.size();
365 if ( nFileCount )
367 std::vector <std::string>::iterator it;
368 it = vecFilenames.begin();
369 while (it != vecFilenames.end() )
371 std::string& strFilename = *it;
372 Remove( strFilename );
373 ++it;
375 vecFilenames.erase( vecFilenames.begin(), vecFilenames.end() );
377 return nFileCount;
380 bool CPlayList::Swap(int position1, int position2)
382 if (
383 (position1 < 0) ||
384 (position2 < 0) ||
385 (position1 >= size()) ||
386 (position2 >= size())
389 return false;
392 if (!IsShuffled())
394 // swap the ordinals before swapping the items!
395 //CLog::Log(LOGDEBUG,"PLAYLIST swapping items at orders ({}, {})",m_vecItems[position1]->m_iprogramCount,m_vecItems[position2]->m_iprogramCount);
396 std::swap(m_vecItems[position1]->m_iprogramCount, m_vecItems[position2]->m_iprogramCount);
399 // swap the items
400 std::swap(m_vecItems[position1], m_vecItems[position2]);
401 return true;
404 void CPlayList::SetUnPlayable(int iItem)
406 if (iItem < 0 || iItem >= size())
408 CLog::Log(LOGWARNING, "Attempt to set unplayable index {}", iItem);
409 return;
412 CFileItemPtr item = m_vecItems[iItem];
413 if (!item->GetProperty("unplayable").asBoolean())
415 item->SetProperty("unplayable", true);
416 m_iPlayableItems--;
421 bool CPlayList::Load(const std::string& strFileName)
423 Clear();
424 m_strBasePath = URIUtils::GetDirectory(strFileName);
426 CFileStream file;
427 if (!file.Open(strFileName))
428 return false;
430 if (file.GetLength() > 1024*1024)
432 CLog::Log(LOGWARNING, "{} - File is larger than 1 MB, most likely not a playlist",
433 __FUNCTION__);
434 return false;
437 return LoadData(file);
440 bool CPlayList::LoadData(std::istream &stream)
442 // try to read as a string
443 std::ostringstream ostr;
444 ostr << stream.rdbuf();
445 return LoadData(ostr.str());
448 bool CPlayList::LoadData(const std::string& strData)
450 return false;
454 bool CPlayList::Expand(int position)
456 CFileItemPtr item = m_vecItems[position];
457 std::unique_ptr<CPlayList> playlist (CPlayListFactory::Create(*item.get()));
458 if (playlist == nullptr)
459 return false;
461 std::string path = item->GetDynPath();
463 if (!playlist->Load(path))
464 return false;
466 // remove any item that points back to itself
467 for (int i = 0;i<playlist->size();i++)
469 if (StringUtils::EqualsNoCase((*playlist)[i]->GetPath(), path))
471 playlist->Remove(i);
472 i--;
476 // @todo
477 // never change original path (id) of a file item
478 for (int i = 0;i<playlist->size();i++)
480 (*playlist)[i]->SetDynPath((*playlist)[i]->GetPath());
481 (*playlist)[i]->SetPath(item->GetDynPath());
482 (*playlist)[i]->SetStartOffset(item->GetStartOffset());
485 if (playlist->size() <= 0)
486 return false;
488 Remove(position);
489 Insert(*playlist, position);
490 return true;
493 void CPlayList::UpdateItem(const CFileItem *item)
495 if (!item) return;
497 for (ivecItems it = m_vecItems.begin(); it != m_vecItems.end(); ++it)
499 CFileItemPtr playlistItem = *it;
500 if (playlistItem->IsSamePath(item))
502 std::string temp = playlistItem->GetPath(); // save path, it may have been altered
503 *playlistItem = *item;
504 playlistItem->SetPath(temp);
505 break;
510 const std::string& CPlayList::ResolveURL(const std::shared_ptr<CFileItem>& item) const
512 if (MUSIC::IsMusicDb(*item) && item->HasMusicInfoTag())
513 return item->GetMusicInfoTag()->GetURL();
514 else
515 return item->GetDynPath();
518 } // namespace KODI::PLAYLIST