MythTV  master
musicplayer.cpp
Go to the documentation of this file.
1 // ANSI C includes
2 #include <cstdlib>
3 
4 // qt
5 #include <QApplication>
6 #include <QWidget>
7 #include <QFile>
8 #include <QList>
9 #include <QDir>
10 
11 // mythtv
12 #include <mythcontext.h>
13 #include <audiooutput.h>
14 #include <mythdb.h>
15 #include <mythdialogbox.h>
16 #include <mythmainwindow.h>
17 #include <musicutils.h>
18 #include <mthreadpool.h>
19 #include <mythuihelper.h>
20 
21 // mythmusic
22 #include "musicdata.h"
23 #include "musicplayer.h"
24 #include "decoder.h"
25 #include "decoderhandler.h"
26 #include "metaio.h"
27 #ifdef HAVE_CDIO
28 #include "cddecoder.h"
29 #endif
30 #include "constants.h"
31 #include "mainvisual.h"
32 #include "miniplayer.h"
33 #include "playlistcontainer.h"
34 
35 MusicPlayer *gPlayer = nullptr;
36 QString gCDdevice = "";
37 
39 
40 QEvent::Type MusicPlayerEvent::TrackChangeEvent = (QEvent::Type) QEvent::registerEventType();
41 QEvent::Type MusicPlayerEvent::VolumeChangeEvent = (QEvent::Type) QEvent::registerEventType();
42 QEvent::Type MusicPlayerEvent::TrackAddedEvent = (QEvent::Type) QEvent::registerEventType();
43 QEvent::Type MusicPlayerEvent::TrackRemovedEvent = (QEvent::Type) QEvent::registerEventType();
44 QEvent::Type MusicPlayerEvent::TrackUnavailableEvent = (QEvent::Type) QEvent::registerEventType();
45 QEvent::Type MusicPlayerEvent::AllTracksRemovedEvent = (QEvent::Type) QEvent::registerEventType();
46 QEvent::Type MusicPlayerEvent::MetadataChangedEvent = (QEvent::Type) QEvent::registerEventType();
47 QEvent::Type MusicPlayerEvent::TrackStatsChangedEvent = (QEvent::Type) QEvent::registerEventType();
48 QEvent::Type MusicPlayerEvent::AlbumArtChangedEvent = (QEvent::Type) QEvent::registerEventType();
49 QEvent::Type MusicPlayerEvent::CDChangedEvent = (QEvent::Type) QEvent::registerEventType();
50 QEvent::Type MusicPlayerEvent::PlaylistChangedEvent = (QEvent::Type) QEvent::registerEventType();
51 QEvent::Type MusicPlayerEvent::PlayedTracksChangedEvent = (QEvent::Type) QEvent::registerEventType();
52 
53 MusicPlayer::MusicPlayer(QObject *parent)
54  :QObject(parent)
55 {
56  setObjectName("MusicPlayer");
57 
58  QString playmode = gCoreContext->GetSetting("PlayMode", "none");
59  if (playmode.toLower() == "random")
61  else if (playmode.toLower() == "intelligent")
63  else if (playmode.toLower() == "album")
65  else if (playmode.toLower() == "artist")
67  else
69 
70  QString repeatmode = gCoreContext->GetSetting("RepeatMode", "all");
71  if (repeatmode.toLower() == "track")
73  else if (repeatmode.toLower() == "all")
75  else
77 
78  loadSettings();
79 
82  connect(gCoreContext, SIGNAL(TVPlaybackStopped()), this, SLOT(StartPlayback()));
83  connect(gCoreContext, SIGNAL(TVPlaybackAborted()), this, SLOT(StartPlayback()));
84 }
85 
87 {
88  if (!hasClient())
89  savePosition();
90 
93 
94  QMap<QString, int>::Iterator i;
95  for (i = m_notificationMap.begin(); i != m_notificationMap.end(); i++)
96  GetNotificationCenter()->UnRegister(this, (*i));
97 
98  m_notificationMap.clear();
99 
100  stop(true);
101 
102  if (m_decoderHandler)
103  {
105  m_decoderHandler->deleteLater();
106  m_decoderHandler = nullptr;
107  }
108 
109  if (m_oneshotMetadata)
110  {
111  delete m_oneshotMetadata;
112  m_oneshotMetadata = nullptr;
113  }
114 
115  while (!m_playedList.empty())
116  {
117  delete m_playedList.back();
118  m_playedList.pop_back();
119  }
120 
122  gCoreContext->SaveSetting("PlayMode", "intelligent");
123  else if (m_shuffleMode == SHUFFLE_RANDOM)
124  gCoreContext->SaveSetting("PlayMode", "random");
125  else if (m_shuffleMode == SHUFFLE_ALBUM)
126  gCoreContext->SaveSetting("PlayMode", "album");
127  else if (m_shuffleMode == SHUFFLE_ARTIST)
128  gCoreContext->SaveSetting("PlayMode", "artist");
129  else
130  gCoreContext->SaveSetting("PlayMode", "none");
131 
132  if (m_repeatMode == REPEAT_TRACK)
133  gCoreContext->SaveSetting("RepeatMode", "track");
134  else if (m_repeatMode == REPEAT_ALL)
135  gCoreContext->SaveSetting("RepeatMode", "all");
136  else
137  gCoreContext->SaveSetting("RepeatMode", "none");
138 
139  gCoreContext->SaveSetting("MusicAutoShowPlayer",
140  (m_autoShowPlayer ? "1" : "0"));
141 }
142 
143 void MusicPlayer::addListener(QObject *listener)
144 {
145  if (listener && m_output)
146  m_output->addListener(listener);
147 
148  if (listener && getDecoder())
149  getDecoder()->addListener(listener);
150 
151  if (listener && m_decoderHandler)
152  m_decoderHandler->addListener(listener);
153 
154  MythObservable::addListener(listener);
155 
157 }
158 
159 void MusicPlayer::removeListener(QObject *listener)
160 {
161  if (listener && m_output)
162  m_output->removeListener(listener);
163 
164  if (listener && getDecoder())
165  getDecoder()->removeListener(listener);
166 
167  if (listener && m_decoderHandler)
168  m_decoderHandler->removeListener(listener);
169 
171 
173 }
174 
176 {
177  if (visual && !m_visualisers.contains(visual))
178  {
179  if (m_output)
180  {
181  m_output->addListener(visual);
182  m_output->addVisual(visual);
183  }
184 
185  m_visualisers.insert(visual);
186  }
187 }
188 
190 {
191  if (visual)
192  {
193  if (m_output)
194  {
195  m_output->removeListener(visual);
196  m_output->removeVisual(visual);
197  }
198 
199  m_visualisers.remove(visual);
200  }
201 }
202 
204 {
205  if (m_playMode == PLAYMODE_RADIO)
206  return m_resumeModeRadio;
208  return m_resumeModeEditor;
209  return m_resumeModePlayback;
210 }
211 
213 {
217 
218  m_lastplayDelay = gCoreContext->GetNumSetting("MusicLastPlayDelay", LASTPLAY_DELAY);
219  m_autoShowPlayer = (gCoreContext->GetNumSetting("MusicAutoShowPlayer", 1) > 0);
220 }
221 
222 // this stops playing the playlist and plays the file pointed to by mdata
224 {
225  if (m_oneshotMetadata)
226  {
227  delete m_oneshotMetadata;
228  m_oneshotMetadata = nullptr;
229  }
230 
232  *m_oneshotMetadata = mdata;
233 
234  play();
235 }
236 
237 void MusicPlayer::stop(bool stopAll)
238 {
239  stopDecoder();
240 
241  if (m_output)
242  {
243  if (m_output->IsPaused())
244  pause();
245  m_output->Reset();
246  }
247 
248  if (m_oneshotMetadata)
249  {
250  delete m_oneshotMetadata;
251  m_oneshotMetadata = nullptr;
252  }
253 
254  m_isPlaying = false;
255 
256  if (stopAll && getDecoder())
257  {
258  getDecoder()->removeListener(this);
259 
260  // remove any listeners from the decoder
261  {
262  QMutexLocker locker(m_lock);
263  // NOLINTNEXTLINE(modernize-loop-convert)
264  for (auto it = m_listeners.begin(); it != m_listeners.end() ; ++it)
265  getDecoder()->removeListener(*it);
266  }
267  }
268 
269  if (stopAll && m_output)
270  {
271  m_output->removeListener(this);
272  delete m_output;
273  m_output = nullptr;
274  }
275 
276  // because we don't actually stop the audio output we have to fake a Stopped
277  // event so any listeners can act on it
279  dispatch(oe);
280 
282 
284 }
285 
287 {
288  if (m_output)
289  {
292  }
293  // wake up threads
294  if (getDecoder())
295  {
296  getDecoder()->lock();
297  getDecoder()->cond()->wakeAll();
298  getDecoder()->unlock();
299  }
300 
302 }
303 
305 {
306  stopDecoder();
307 
309  if (!meta)
310  return;
311 
312  if (meta->Filename() == METADATA_INVALID_FILENAME)
313  {
314  // put an upper limit on the number of consecutive track unavailable errors
315  if (m_errorCount >= 1000)
316  {
317  ShowOkPopup(tr("Got too many track unavailable errors. Maybe the host with the music on is off-line?"));
318  stop(true);
319  m_errorCount = 0;
320  return;
321  }
322 
323  if (m_errorCount < 5)
324  {
325  MythErrorNotification n(tr("Track Unavailable"), tr("MythMusic"), QString("Cannot find file '%1'").arg(meta->Filename(false)));
327  }
328 
329  m_errorCount++;
330 
331  sendTrackUnavailableEvent(meta->ID());
332  next();
333  return;
334  }
335 
336  // Notify others that we are about to play
338 
339  if (!m_output)
340  {
341  if (!openOutputDevice())
342  return;
343  }
344 
345  if (!getDecoderHandler())
347 
348  getDecoderHandler()->start(meta);
349 
351 }
352 
354 {
355  if (getDecoderHandler())
356  getDecoderHandler()->stop();
357 }
358 
360 {
361  QString adevice;
362  QString pdevice;
363 
364  adevice = gCoreContext->GetSetting("MusicAudioDevice", "default");
365  if (adevice == "default" || adevice.isEmpty())
366  adevice = gCoreContext->GetSetting("AudioOutputDevice");
367  else
368  adevice = gCoreContext->GetSetting("MusicAudioDevice");
369 
370  pdevice = gCoreContext->GetBoolSetting("PassThruDeviceOverride", false) ?
371  gCoreContext->GetSetting("PassThruOutputDevice") : "auto";
372 
374  adevice, pdevice, FORMAT_S16, 2, AV_CODEC_ID_NONE, 44100,
375  AUDIOOUTPUT_MUSIC, true, false,
376  gCoreContext->GetNumSetting("MusicDefaultUpmix", 0) + 1);
377 
378  if (!m_output)
379  {
380  LOG(VB_GENERAL, LOG_ERR,
381  QString("MusicPlayer: Cannot open audio output device: %1").arg(adevice));
382 
383  return false;
384  }
385 
386  if (!m_output->GetError().isEmpty())
387  {
388  LOG(VB_GENERAL, LOG_ERR,
389  QString("MusicPlayer: Cannot open audio output device: %1").arg(adevice));
390  LOG(VB_GENERAL, LOG_ERR,
391  QString("Error was: %1").arg(m_output->GetError()));
392 
393  delete m_output;
394  m_output = nullptr;
395 
396  return false;
397  }
398 
399  m_output->setBufferSize(256 * 1024);
400 
401  m_output->addListener(this);
402 
403  // add any visuals to the audio output
404  // NOLINTNEXTLINE(modernize-loop-convert)
405  for (auto it = m_visualisers.begin(); it != m_visualisers.end() ; ++it)
407 
408  // add any listeners to the audio output
409  QMutexLocker locker(m_lock);
410  // NOLINTNEXTLINE(modernize-loop-convert)
411  for (auto it = m_listeners.begin(); it != m_listeners.end() ; ++it)
412  m_output->addListener(*it);
413 
414  return true;
415 }
416 
418 {
419  int currentTrack = m_currentTrack;
420 
421  if (!getCurrentPlaylist())
422  return;
423 
424  if (m_oneshotMetadata)
425  {
426  delete m_oneshotMetadata;
427  m_oneshotMetadata = nullptr;
428  }
429  else
430  currentTrack++;
431 
432  if (currentTrack >= getCurrentPlaylist()->getTrackCount())
433  {
434  if (m_repeatMode == REPEAT_ALL)
435  {
436  // start playing again from first track
437  currentTrack = 0;
438  }
439  else
440  {
441  stop();
442  return;
443  }
444  }
445 
446  changeCurrentTrack(currentTrack);
447 
448  if (getCurrentMetadata())
449  play();
450  else
451  stop();
452 }
453 
455 {
456  int currentTrack = m_currentTrack;
457 
458  if (!getCurrentPlaylist())
459  return;
460 
461  if (m_oneshotMetadata)
462  {
463  delete m_oneshotMetadata;
464  m_oneshotMetadata = nullptr;
465  }
466  else
467  currentTrack--;
468 
469  if (currentTrack >= 0)
470  {
471  changeCurrentTrack(currentTrack);
472 
473  if (getCurrentMetadata())
474  play();
475  else
476  return;//stop();
477  }
478  else
479  {
480  // FIXME take repeat mode into account
481  return; //stop();
482  }
483 }
484 
486 {
487  if (!getCurrentPlaylist())
488  return;
489 
490  if (m_oneshotMetadata)
491  {
492  delete m_oneshotMetadata;
493  m_oneshotMetadata = nullptr;
494  stop(true);
495  return;
496  }
497 
498  if (m_repeatMode == REPEAT_TRACK)
499  {
500  play();
501  return;
502  }
503  if (!m_decoderHandler->next())
504  next();
505 
506  // if we don't already have a gui attached show the miniplayer if configured to do so
508  {
509  MythScreenStack *popupStack =
510  GetMythMainWindow()->GetStack("popup stack");
511 
512  auto *miniplayer = new MiniPlayer(popupStack);
513 
514  if (miniplayer->Create())
515  popupStack->AddScreen(miniplayer);
516  else
517  delete miniplayer;
518  }
519 }
520 
522 {
524  {
525  play();
526 
527  m_wasPlaying = false;
528  }
529 }
530 
532 {
533  if (m_output)
534  {
536 
537  savePosition();
538  stop(true);
539  }
540 }
541 
542 void MusicPlayer::customEvent(QEvent *event)
543 {
544  // handle decoderHandler events
545  if (event->type() == DecoderHandlerEvent::Ready)
546  {
547  m_errorCount = 0;
549  }
550  else if (event->type() == DecoderHandlerEvent::Meta)
551  {
552  auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
553  if (!dhe)
554  return;
555 
556  auto *mdata = new MusicMetadata(*dhe->getMetadata());
557 
559 
560  if (getCurrentMetadata())
561  {
562  mdata->setID(getCurrentMetadata()->ID());
563  mdata->setHostname(gCoreContext->GetMasterHostName());
564  mdata->setTrack(m_playedList.count() + 1);
565  mdata->setBroadcaster(getCurrentMetadata()->Broadcaster());
566  mdata->setChannel(getCurrentMetadata()->Channel());
567 
568  getCurrentMetadata()->setTitle(mdata->Title());
569  getCurrentMetadata()->setArtist(mdata->Artist());
570  getCurrentMetadata()->setAlbum(mdata->Album());
571  getCurrentMetadata()->setTrack(mdata->Track());
572  }
573 
574  m_playedList.append(mdata);
575 
577  {
578  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
579 
580  auto *miniplayer = new MiniPlayer(popupStack);
581 
582  if (miniplayer->Create())
583  popupStack->AddScreen(miniplayer);
584  else
585  delete miniplayer;
586  }
587 
588  // tell any listeners we've added a new track to the played list
590  dispatch(me);
591  }
592  // handle MythEvent events
593  else if (event->type() == MythEvent::MythEventMessage)
594  {
595  auto *me = dynamic_cast<MythEvent*>(event);
596  if (!me)
597  return;
598 
599  if (me->Message().left(13) == "MUSIC_COMMAND")
600  {
601  QStringList list = me->Message().simplified().split(' ');
602 
603  if (list.size() >= 3 && list[1] == gCoreContext->GetHostName())
604  {
605  if (list[2] == "PLAY")
606  play();
607  else if (list[2] == "STOP")
608  stop();
609  else if (list[2] == "PAUSE")
610  pause();
611  else if (list[2] == "SET_VOLUME")
612  {
613  if (list.size() >= 3)
614  {
615  int volume = list[3].toInt();
616  if (volume >= 0 && volume <= 100)
617  setVolume(volume);
618  }
619  }
620  else if (list[2] == "GET_VOLUME")
621  {
622  QString message = QString("MUSIC_CONTROL ANSWER %1 %2")
623  .arg(gCoreContext->GetHostName()).arg(getVolume());
624  MythEvent me2(message);
625  gCoreContext->dispatch(me2);
626  }
627  else if (list[2] == "PLAY_FILE")
628  {
629  int start = me->Message().indexOf("'");
630  int end = me->Message().lastIndexOf("'");
631 
632  if (start != -1 && end != -1 && start != end)
633  {
634  QString filename = me->Message().mid(start + 1, end - start - 1);
635  MusicMetadata mdata;
636  mdata.setFilename(filename);
637  playFile(mdata);
638  }
639  else
640  {
641  LOG(VB_GENERAL, LOG_ERR,
642  QString("MusicPlayer: got invalid MUSIC_COMMAND "
643  "PLAY_FILE - %1").arg(me->Message()));
644  }
645  }
646  else if (list[2] == "PLAY_URL")
647  {
648  if (list.size() == 4)
649  {
650  QString filename = list[3];
651  MusicMetadata mdata;
652  mdata.setFilename(filename);
653  playFile(mdata);
654  }
655  else
656  {
657  LOG(VB_GENERAL, LOG_ERR,
658  QString("MusicPlayer: got invalid MUSIC_COMMAND "
659  "PLAY_URL - %1").arg(me->Message()));
660  }
661  }
662  else if (list[2] == "PLAY_TRACK")
663  {
664  if (list.size() == 4)
665  {
666  int trackID = list[3].toInt();
667  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackID);
668  if (mdata)
669  playFile(*mdata);
670  }
671  else
672  {
673  LOG(VB_GENERAL, LOG_ERR,
674  QString("MusicPlayer: got invalid MUSIC_COMMAND "
675  "PLAY_TRACK - %1").arg(me->Message()));
676  }
677  }
678  else if (list[2] == "GET_METADATA")
679  {
680  QString mdataStr;
682  if (mdata)
683  mdataStr = QString("%1 by %2 from %3").arg(mdata->Title()).arg(mdata->Artist()).arg(mdata->Album());
684  else
685  mdataStr = "Unknown Track2";
686 
687  QString message = QString("MUSIC_CONTROL ANSWER %1 %2")
688  .arg(gCoreContext->GetHostName()).arg(mdataStr);
689  MythEvent me2(message);
690  gCoreContext->dispatch(me2);
691  }
692  else if (list[2] == "GET_STATUS")
693  {
694  QString statusStr = "STOPPED";
695 
696  if (gPlayer->isPlaying())
697  statusStr = "PLAYING";
698  else if (gPlayer->isPaused())
699  statusStr = "PAUSED";
700 
701  QString message = QString("MUSIC_CONTROL ANSWER %1 %2")
702  .arg(gCoreContext->GetHostName()).arg(statusStr);
703  MythEvent me2(message);
704  gCoreContext->dispatch(me2);
705  }
706  }
707  else
708  {
709  LOG(VB_GENERAL, LOG_ERR,
710  QString("MusicPlayer: got unknown/invalid MUSIC_COMMAND "
711  "- %1").arg(me->Message()));
712  }
713  }
714  else if (me->Message().startsWith("MUSIC_SETTINGS_CHANGED"))
715  {
716  loadSettings();
717  }
718  else if (me->Message().startsWith("MUSIC_METADATA_CHANGED"))
719  {
721  {
722  QStringList list = me->Message().simplified().split(' ');
723  if (list.size() == 2)
724  {
725  int songID = list[1].toInt();
726  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(songID);
727 
728  if (mdata)
729  {
730  mdata->reloadMetadata();
731 
732  // tell any listeners the metadata has changed for this track
733  sendMetadataChangedEvent(songID);
734  }
735  }
736  }
737  }
738  else if (me->Message().startsWith("MUSIC_SCANNER_STARTED"))
739  {
740  QStringList list = me->Message().simplified().split(' ');
741  if (list.size() == 2)
742  {
743  QString host = list[1];
744  int id = getNotificationID(host);
745  sendNotification(id,
746  tr("A music file scan has started on %1").arg(host),
747  tr("Music File Scanner"),
748  tr("This may take a while I'll give a shout when finished"));
749  }
750  }
751  else if (me->Message().startsWith("MUSIC_SCANNER_FINISHED"))
752  {
753  QStringList list = me->Message().simplified().split(' ');
754  if (list.size() == 6)
755  {
756  QString host = list[1];
757  int id = getNotificationID(host);
758  int totalTracks = list[2].toInt();
759  int newTracks = list[3].toInt();
760  int totalCoverart = list[4].toInt();
761  int newCoverart = list[5].toInt();
762 
763  QString summary = QString("Total Tracks: %2, new tracks: %3,\nTotal Coverart: %4, New CoverArt %5")
764  .arg(totalTracks).arg(newTracks).arg(totalCoverart).arg(newCoverart);
765  sendNotification(id,
766  tr("A music file scan has finished on %1").arg(host),
767  tr("Music File Scanner"), summary);
768 
770  }
771  }
772  else if (me->Message().startsWith("MUSIC_SCANNER_ERROR"))
773  {
774  QStringList list = me->Message().simplified().split(' ');
775  if (list.size() == 3)
776  {
777  QString host = list[1];
778  QString error = list[2];
779  int id = getNotificationID(host);
780 
781  if (error == "Already_Running")
782  {
783  sendNotification(id, tr(""),
784  tr("Music File Scanner"),
785  tr("Can't run the music file scanner because it is already running on %1").arg(host));
786  }
787  else if (error == "Stalled")
788  {
789  sendNotification(id, tr(""),
790  tr("Music File Scanner"),
791  tr("The music file scanner has been running for more than 60 minutes on %1.\nResetting and trying again")
792  .arg(host));
793  }
794  }
795  }
796  }
797 
798  if (event->type() == OutputEvent::Error)
799  {
800  auto *aoe = dynamic_cast<OutputEvent *>(event);
801 
802  if (!aoe)
803  return;
804 
805  LOG(VB_GENERAL, LOG_ERR, QString("Audio Output Error: %1").arg(*aoe->errorMessage()));
806 
807  MythErrorNotification n(tr("Audio Output Error"), tr("MythMusic"), *aoe->errorMessage());
809 
810  m_errorCount++;
811 
812  if (m_errorCount <= 5)
813  nextAuto();
814  else
815  {
816  m_errorCount = 0;
817  stop(true);
818  }
819  }
820  else if (event->type() == DecoderEvent::Error)
821  {
822  auto *dxe = dynamic_cast<DecoderEvent *>(event);
823 
824  if (!dxe)
825  return;
826 
827  LOG(VB_GENERAL, LOG_ERR, QString("Decoder Error: %2").arg(*dxe->errorMessage()));
828 
829  MythErrorNotification n(tr("Decoder Error"), tr("MythMusic"), *dxe->errorMessage());
831 
832  m_errorCount++;
833 
834  if (m_playMode != PLAYMODE_RADIO && m_errorCount <= 5)
835  nextAuto();
836  else
837  {
838  m_errorCount = 0;
839  stop(true);
840  }
841  }
842  else if (event->type() == DecoderHandlerEvent::Error)
843  {
844  auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
845 
846  if (!dhe)
847  return;
848 
849  LOG(VB_GENERAL, LOG_ERR, QString("Decoder Handler Error - %1").arg(*dhe->getMessage()));
850 
851  MythErrorNotification n(tr("Decoder Handler Error"), tr("MythMusic"), *dhe->getMessage());
853 
854  m_errorCount++;
855 
856  if (m_errorCount <= 5)
857  nextAuto();
858  else
859  {
860  m_errorCount = 0;
861  stop(true);
862  }
863  }
864  else if (event->type() == OutputEvent::Info)
865  {
866  auto *oe = dynamic_cast<OutputEvent*>(event);
867 
868  if (!oe)
869  return;
870 
871  if (m_playMode != PLAYMODE_RADIO)
872  m_currentTime = oe->elapsedSeconds();
873  else
874  m_currentTime = oe->elapsedSeconds() - m_lastTrackStart;
875 
877  {
878  // we update the lastplay and playcount after playing
879  // for m_lastplayDelay seconds or half the total track time
881  (getCurrentMetadata()->Length() / 1000) / 2) ||
883  {
884  updateLastplay();
885  }
886  }
887 
888  // update the current tracks time in the last played list
889  if (m_playMode == PLAYMODE_RADIO)
890  {
891  if (!m_playedList.isEmpty())
892  {
893  m_playedList.last()->setLength(m_currentTime * 1000);
894  // this will update any track lengths displayed on screen
896  }
897  }
898  }
899  else if (event->type() == DecoderEvent::Finished)
900  {
901  if (m_oneshotMetadata)
902  {
903  delete m_oneshotMetadata;
904  m_oneshotMetadata = nullptr;
905  stop(true);
906  }
907  else
908  {
910  m_currentTime != getCurrentMetadata()->Length() / 1000)
911  {
912  LOG(VB_GENERAL, LOG_NOTICE, QString("MusicPlayer: Updating track length was %1s, should be %2s")
913  .arg(getCurrentMetadata()->Length() / 1000).arg(m_currentTime));
914 
917 
918  // this will update any track lengths displayed on screen
920 
921  // this will force the playlist stats to update
923  dispatch(me);
924  }
925 
926  nextAuto();
927  }
928  }
929  else if (event->type() == DecoderEvent::Stopped)
930  {
931  }
932  else if (event->type() == DecoderHandlerEvent::BufferStatus)
933  {
934  auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
935  if (!dhe)
936  return;
937 
939  }
940 
941  QObject::customEvent(event);
942 }
943 
944 void MusicPlayer::getBufferStatus(int *bufferAvailable, int *bufferSize) const
945 {
946  *bufferAvailable = m_bufferAvailable;
947  *bufferSize = m_bufferSize;
948 }
949 
951 {
952  if (m_playMode == mode)
953  return;
954 
955  savePosition();
956 
957  m_playMode = mode;
958 
959  loadPlaylist();
960 }
961 
963 {
964  if (m_playMode == PLAYMODE_RADIO)
965  {
967  {
968  int bookmark = gCoreContext->GetNumSetting("MusicRadioBookmark", 0);
969  if (bookmark < 0 || bookmark >= getCurrentPlaylist()->getTrackCount())
970  bookmark = 0;
971 
972  m_currentTrack = bookmark;
973  }
974  else
975  m_currentTrack = 0;
976 
978  }
979  else
980  {
982  {
983  int bookmark = gCoreContext->GetNumSetting("MusicBookmark", 0);
984  if (bookmark < 0 || bookmark >= getCurrentPlaylist()->getTrackCount())
985  bookmark = 0;
986 
987  m_currentTrack = bookmark;
988  }
989  else
990  m_currentTrack = 0;
991  }
992 }
993 
995 {
997 
998  // create the radio playlist
1002 
1003  for (int x = 0; x < list->count(); x++)
1004  {
1005  MusicMetadata *mdata = list->at(x);
1006  gMusicData->m_all_playlists->getStreamPlaylist()->addTrack(mdata->ID(), false);
1007 
1008  if (mdata->ID() == id)
1009  m_currentTrack = x;
1010  }
1011 
1013 }
1014 
1015 void MusicPlayer::moveTrackUpDown(bool moveUp, int whichTrack)
1016 {
1017  if (!getCurrentPlaylist())
1018  return;
1019 
1020  if (moveUp && whichTrack <= 0)
1021  return;
1022 
1023  if (!moveUp && whichTrack >= getCurrentPlaylist()->getTrackCount() - 1)
1024  return;
1025 
1027 
1028  getCurrentPlaylist()->moveTrackUpDown(moveUp, whichTrack);
1029 
1031 }
1032 
1034 {
1035  changeCurrentTrack(pos);
1036 
1037  if (!getCurrentMetadata())
1038  {
1039  stop();
1040  return false;
1041  }
1042 
1043  play();
1044 
1045  return true;
1046 }
1047 
1049 {
1050  // can't save a bookmark if we don't know what we are playing
1051  if (!getCurrentMetadata())
1052  return;
1053 
1054  if (m_playMode == PLAYMODE_RADIO)
1055  {
1056  gCoreContext->SaveSetting("MusicRadioBookmark", getCurrentMetadata()->ID());
1057  }
1058  else
1059  {
1060  gCoreContext->SaveSetting("MusicBookmark", getCurrentMetadata()->ID());
1061  gCoreContext->SaveSetting("MusicBookmarkPosition", m_currentTime);
1062  }
1063 }
1064 
1066 {
1067  // if we are switching views we don't wont to restore the position
1068  if (!m_allowRestorePos)
1069  return;
1070 
1071  m_currentTrack = 0;
1072  uint id = -1;
1073 
1075  {
1076  if (m_playMode == PLAYMODE_RADIO)
1077  id = gCoreContext->GetNumSetting("MusicRadioBookmark", 0);
1078  else
1079  id = gCoreContext->GetNumSetting("MusicBookmark", 0);
1080  }
1081 
1082  if (getCurrentPlaylist())
1083  {
1084  for (int x = 0; x < getCurrentPlaylist()->getTrackCount(); x++)
1085  {
1086  if (getCurrentPlaylist()->getSongAt(x) &&
1087  getCurrentPlaylist()->getSongAt(x)->ID() == id)
1088  {
1089  m_currentTrack = x;
1090  break;
1091  }
1092  }
1093  }
1094 
1095  if (getCurrentMetadata())
1096  {
1098  play();
1099 
1101  seek(gCoreContext->GetNumSetting("MusicBookmarkPosition", 0));
1102  }
1103 }
1104 
1105 void MusicPlayer::seek(int pos)
1106 {
1107  if (m_output)
1108  {
1109  if (getDecoder() && getDecoder()->isRunning())
1110  getDecoder()->seek(pos);
1111 
1112  m_output->SetTimecode(pos*1000);
1113  }
1114 }
1115 
1117 {
1118  if (m_canShowPlayer)
1119  {
1120  MythScreenStack *popupStack =
1121  GetMythMainWindow()->GetStack("popup stack");
1122 
1123  auto *miniplayer = new MiniPlayer(popupStack);
1124 
1125  if (miniplayer->Create())
1126  popupStack->AddScreen(miniplayer);
1127  else
1128  delete miniplayer;
1129  }
1130 }
1131 
1134 {
1135  if (!getCurrentPlaylist())
1136  return;
1137 
1138  // check to see if we need to save the current tracks volatile metadata (playcount, last played etc)
1140 
1141  m_currentTrack = trackNo;
1142 
1143  // sanity check the current track
1144  if (m_currentTrack < 0 || m_currentTrack >= getCurrentPlaylist()->getTrackCount())
1145  {
1146  LOG(VB_GENERAL, LOG_ERR,
1147  QString("MusicPlayer: asked to set the current track to an invalid track no. %1")
1148  .arg(trackNo));
1149  m_currentTrack = -1;
1150  return;
1151  }
1152 }
1153 
1156 {
1157  if (m_oneshotMetadata)
1158  return m_oneshotMetadata;
1159 
1160  if (!getCurrentPlaylist() || !getCurrentPlaylist()->getSongAt(m_currentTrack))
1161  return nullptr;
1162 
1164 }
1165 
1168 {
1169  if (m_playMode == PLAYMODE_RADIO)
1170  return nullptr;
1171 
1172  if (m_oneshotMetadata)
1173  return getCurrentMetadata();
1174 
1175  if (!getCurrentPlaylist() || !getCurrentPlaylist()->getSongAt(m_currentTrack))
1176  return nullptr;
1177 
1178  if (m_repeatMode == REPEAT_TRACK)
1179  return getCurrentMetadata();
1180 
1181  // if we are not playing the last track then just return the next track
1182  if (m_currentTrack < getCurrentPlaylist()->getTrackCount() - 1)
1184 
1185  // if we are playing the last track then we need to take the
1186  // repeat mode into account
1187  if (m_repeatMode == REPEAT_ALL)
1188  return getCurrentPlaylist()->getSongAt(0);
1189  return nullptr;
1190 }
1191 
1193 {
1194  switch (m_repeatMode)
1195  {
1196  case REPEAT_OFF:
1198  break;
1199  case REPEAT_TRACK:
1201  break;
1202  case REPEAT_ALL:
1203  default:
1205  break;
1206  }
1207 
1208  return m_repeatMode;
1209 }
1210 
1212 {
1213  switch (m_shuffleMode)
1214  {
1215  case SHUFFLE_OFF:
1217  break;
1218  case SHUFFLE_RANDOM:
1220  break;
1221  case SHUFFLE_INTELLIGENT:
1223  break;
1224  case SHUFFLE_ALBUM:
1226  break;
1227  case SHUFFLE_ARTIST:
1228  default:
1230  break;
1231  }
1232 
1234 
1235  return m_shuffleMode;
1236 }
1237 
1239 {
1240  int curTrackID = -1;
1241  if (getCurrentMetadata())
1242  curTrackID = getCurrentMetadata()->ID();
1243 
1244  // only save the mode if we are playing tracks
1245  if (m_playMode != PLAYMODE_RADIO)
1246  m_shuffleMode = mode;
1247 
1248  if (!getCurrentPlaylist())
1249  return;
1250 
1252 
1253  if (curTrackID != -1)
1254  {
1255  for (int x = 0; x < getCurrentPlaylist()->getTrackCount(); x++)
1256  {
1258  if (mdata && mdata->ID() == (MusicMetadata::IdType) curTrackID)
1259  {
1260  m_currentTrack = x;
1261  break;
1262  }
1263  }
1264  }
1265 }
1266 
1268 {
1270  {
1273  }
1274 
1275  m_updatedLastplay = true;
1276 }
1277 
1279 {
1281  {
1282  if (getCurrentMetadata()->hasChanged())
1283  {
1285 
1286  // only write the last played, playcount & rating to the tag if it's enabled by the user
1287  if (GetMythDB()->GetNumSetting("AllowTagWriting", 0) == 1)
1288  {
1289  QStringList strList;
1290  strList << QString("MUSIC_TAG_UPDATE_VOLATILE")
1292  << QString::number(getCurrentMetadata()->ID())
1293  << QString::number(getCurrentMetadata()->Rating())
1294  << QString::number(getCurrentMetadata()->Playcount())
1295  << getCurrentMetadata()->LastPlay().toString(Qt::ISODate);
1296  auto *thread = new SendStringListThread(strList);
1297  MThreadPool::globalInstance()->start(thread, "UpdateVolatile");
1298  }
1299 
1301  }
1302  }
1303 }
1304 
1305 void MusicPlayer::setSpeed(float newspeed)
1306 {
1307  if (m_output)
1308  {
1309  m_playSpeed = newspeed;
1311  }
1312 }
1313 
1315 {
1316  m_playSpeed += 0.05F;
1318 }
1319 
1321 {
1322  m_playSpeed -= 0.05F;
1324 }
1325 
1327 {
1329  dispatch(me);
1330 }
1331 
1333 {
1335  dispatch(me);
1336 }
1337 
1339 {
1341  dispatch(me);
1342 }
1343 
1345 {
1347  dispatch(me);
1348 }
1349 
1351 {
1353  dispatch(me);
1354 }
1355 
1357 {
1359  dispatch(me);
1360 }
1361 
1363 {
1364  if (getOutput())
1365  {
1368  }
1369 }
1370 
1372 {
1373  if (getOutput())
1374  {
1377  }
1378 }
1379 
1380 void MusicPlayer::setVolume(int volume)
1381 {
1382  if (getOutput())
1383  {
1384  getOutput()->SetCurrentVolume(volume);
1386  }
1387 }
1388 
1390 {
1391  if (m_output)
1392  return m_output->GetCurrentVolume();
1393  return 0;
1394 }
1395 
1397 {
1398  if (m_output)
1399  {
1400  m_output->ToggleMute();
1402  }
1403 }
1404 
1406 {
1407  if (m_output)
1408  return m_output->GetMuteState();
1409  return kMuteOff;
1410 }
1411 
1412 void MusicPlayer::toMap(InfoMap &map) const
1413 {
1414  map["volumemute"] = isMuted() ? tr("%1% (Muted)", "Zero Audio Volume").arg(getVolume()) :
1415  QString("%1%").arg(getVolume());
1416  map["volume"] = QString("%1").arg(getVolume());
1417  map["volumepercent"] = QString("%1%").arg(getVolume());
1418  map["mute"] = isMuted() ? tr("Muted") : "";
1419 }
1420 
1421 void MusicPlayer::activePlaylistChanged(int trackID, bool deleted)
1422 {
1423  if (trackID == -1)
1424  {
1425  if (deleted)
1426  {
1428  dispatch(me);
1429  }
1430  else
1431  {
1433  dispatch(me);
1434  }
1435  }
1436  else
1437  {
1438  if (deleted)
1439  {
1441  dispatch(me);
1442  }
1443  else
1444  {
1446  dispatch(me);
1447  }
1448  }
1449 
1450  // if we don't have any tracks to play stop here
1451  if (!getCurrentPlaylist() || getCurrentPlaylist()->getTrackCount() == 0)
1452  {
1453  m_currentTrack = -1;
1454  if (isPlaying())
1455  stop(true);
1456  return;
1457  }
1458 
1459  int trackPos = -1;
1460 
1461  // make sure the current playing track is still valid
1462  if (isPlaying() && getDecoderHandler())
1463  {
1464  for (int x = 0; x < getCurrentPlaylist()->getTrackCount(); x++)
1465  {
1467  {
1468  trackPos = x;
1469  break;
1470  }
1471  }
1472  }
1473 
1474  if (trackPos != m_currentTrack)
1475  m_currentTrack = trackPos;
1476 
1477  if (!getCurrentMetadata())
1478  {
1479  m_currentTrack = -1;
1480  stop(true);
1481  }
1482 }
1483 
1484 void MusicPlayer::playlistChanged(int playlistID)
1485 {
1487  dispatch(me);
1488 }
1489 
1491 {
1494 
1495  // add any listeners to the decoderHandler
1496  {
1497  QMutexLocker locker(m_lock);
1498  // NOLINTNEXTLINE(modernize-loop-convert)
1499  for (auto it = m_listeners.begin(); it != m_listeners.end() ; ++it)
1501  }
1502 }
1503 
1505 {
1506  if (!getDecoder())
1507  return;
1508 
1509  LOG(VB_PLAYBACK, LOG_INFO, QString ("decoder handler is ready, decoding %1")
1510  .arg(getDecoder()->getURL()));
1511 
1512 #ifdef HAVE_CDIO
1513  auto *cddecoder = dynamic_cast<CdDecoder*>(getDecoder());
1514  if (cddecoder)
1515  cddecoder->setDevice(gCDdevice);
1516 #endif
1517 
1518  // Decoder thread can't be running while being initialized
1519  if (getDecoder()->isRunning())
1520  {
1521  getDecoder()->stop();
1522  getDecoder()->wait();
1523  }
1524 
1526  //getDecoder()-> setBlockSize(2 * 1024);
1527  getDecoder()->addListener(this);
1528 
1529  // add any listeners to the decoder
1530  {
1531  QMutexLocker locker(m_lock);
1532  // NOLINTNEXTLINE(modernize-loop-convert)
1533  for (auto it = m_listeners.begin(); it != m_listeners.end() ; ++it)
1534  getDecoder()->addListener(*it);
1535  }
1536 
1537  m_currentTime = 0;
1538  m_lastTrackStart = 0;
1539 
1540  // NOLINTNEXTLINE(modernize-loop-convert)
1541  for (auto it = m_visualisers.begin(); it != m_visualisers.end() ; ++it)
1542  {
1543  //m_output->addVisual((MythTV::Visual*)(*it));
1544  //(*it)->setDecoder(getDecoder());
1545  //m_visual->setOutput(m_output);
1546  }
1547 
1548  if (getDecoder()->initialize())
1549  {
1550  if (m_output)
1552 
1553  getDecoder()->start();
1554 
1556  gCoreContext->GetNumSetting("MusicBookmarkPosition", 0) > 0)
1557  {
1558  seek(gCoreContext->GetNumSetting("MusicBookmarkPosition", 0));
1559  gCoreContext->SaveSetting("MusicBookmarkPosition", 0);
1560  }
1561 
1562  m_isPlaying = true;
1563  m_updatedLastplay = false;
1564  }
1565  else
1566  {
1567  LOG(VB_PLAYBACK, LOG_ERR, QString("Cannot initialise decoder for %1")
1568  .arg(getDecoder()->getURL()));
1569  return;
1570  }
1571 
1572  // tell any listeners we've started playing a new track
1574  dispatch(me);
1575 }
1576 
1577 void MusicPlayer::removeTrack(int trackID)
1578 {
1579  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackID);
1580  if (mdata)
1581  {
1582  int trackPos = getCurrentPlaylist()->getTrackPosition(mdata->ID());
1583  if (m_currentTrack > 0 && m_currentTrack >= trackPos)
1584  m_currentTrack--;
1585 
1586  getCurrentPlaylist()->removeTrack(trackID);
1587  }
1588 }
1589 
1590 void MusicPlayer::addTrack(int trackID, bool updateUI)
1591 {
1592  getCurrentPlaylist()->addTrack(trackID, updateUI);
1593 }
1594 
1596 {
1598  return nullptr;
1599 
1600  if (m_playMode == PLAYMODE_RADIO)
1601  {
1603  }
1605 }
1606 
1608 {
1609  return gMusicData->m_all_streams->getStreams();
1610 }
1611 
1613 {
1614  if (m_notificationMap.find(hostname) == m_notificationMap.end())
1615  m_notificationMap.insert(hostname, GetNotificationCenter()->Register(this));
1616 
1617  return m_notificationMap[hostname];
1618 }
1619 
1620 void MusicPlayer::sendNotification(int notificationID, const QString &title, const QString &author, const QString &desc)
1621 {
1622  QString image = "musicscanner.png";
1623  if (!GetMythUI()->FindThemeFile(image))
1624  LOG(VB_GENERAL, LOG_ERR, "MusicPlayer: sendNotification failed to find the 'musicscanner.png' image");
1625 
1626  DMAP map;
1627  map["asar"] = title;
1628  map["minm"] = author;
1629  map["asal"] = desc;
1630 
1631  auto *n = new MythImageNotification(MythNotification::Info, image, map);
1632 
1633  n->SetId(notificationID);
1634  n->SetParent(this);
1635  n->SetDuration(5);
1636  n->SetFullScreen(false);
1638  delete n;
1639 }
MusicPlayer::addVisual
void addVisual(MainVisual *visual)
Definition: musicplayer.cpp:175
AudioOutput::GetError
QString GetError(void) const
Definition: audiooutput.h:146
OutputListeners::addVisual
void addVisual(MythTV::Visual *v)
Definition: output.cpp:36
MusicPlayer::StopPlayback
void StopPlayback(void)
Definition: musicplayer.cpp:531
DecoderHandlerEvent::Ready
static Type Ready
Definition: decoderhandler.h:47
MusicPlayer::PLAYMODE_TRACKSEDITOR
@ PLAYMODE_TRACKSEDITOR
Definition: musicplayer.h:65
VolumeBase::SetCurrentVolume
virtual void SetCurrentVolume(int value)
Definition: volumebase.cpp:123
DecoderHandlerEvent::BufferStatus
static Type BufferStatus
Definition: decoderhandler.h:49
MusicPlayer::toggleMute
void toggleMute(void)
Definition: musicplayer.cpp:1396
MusicPlayer::openOutputDevice
bool openOutputDevice(void)
Definition: musicplayer.cpp:359
MusicPlayer::SHUFFLE_INTELLIGENT
@ SHUFFLE_INTELLIGENT
Definition: musicplayer.h:166
MusicPlayer::m_bufferAvailable
int m_bufferAvailable
Definition: musicplayer.h:248
MusicPlayer::getDecoder
Decoder * getDecoder(void)
Definition: musicplayer.h:115
MusicPlayer::StartPlayback
void StartPlayback(void)
Definition: musicplayer.cpp:521
playlistcontainer.h
MusicPlayer::getOutput
AudioOutput * getOutput(void)
Definition: musicplayer.h:117
MusicMetadata::Title
QString Title() const
Definition: musicmetadata.h:162
Channel
Definition: channel.h:34
gPlayer
MusicPlayer * gPlayer
Definition: musicplayer.cpp:35
Playlist::getSongAt
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1090
MusicMetadata::Filename
QString Filename(bool find=true)
Definition: musicmetadata.cpp:973
MythEvent::MythEventMessage
static Type MythEventMessage
Definition: mythevent.h:73
MusicPlayer::m_notificationMap
QMap< QString, int > m_notificationMap
Definition: musicplayer.h:243
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:292
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:825
METADATA_INVALID_FILENAME
#define METADATA_INVALID_FILENAME
Definition: musicmetadata.h:73
MusicMetadata::incPlayCount
void incPlayCount()
Definition: musicmetadata.cpp:1205
MusicPlayer::m_bufferSize
int m_bufferSize
Definition: musicplayer.h:249
MusicPlayer::setCurrentTrackPos
bool setCurrentTrackPos(int pos)
Definition: musicplayer.cpp:1033
MusicPlayer::RESUME_OFF
@ RESUME_OFF
Definition: musicplayer.h:173
error
static void error(const char *str,...)
Definition: vbi.cpp:42
FORMAT_S16
@ FORMAT_S16
Definition: audiooutputsettings.h:28
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:550
MusicPlayer::setVolume
void setVolume(int volume)
Definition: musicplayer.cpp:1380
MusicPlayer::toMap
void toMap(InfoMap &infoMap) const
Definition: musicplayer.cpp:1412
mythdb.h
VolumeBase::AdjustCurrentVolume
virtual void AdjustCurrentVolume(int change)
Definition: volumebase.cpp:132
MusicPlayer::sendNotification
void sendNotification(int notificationID, const QString &title, const QString &author, const QString &desc)
Definition: musicplayer.cpp:1620
MusicPlayer::RESUME_TRACK
@ RESUME_TRACK
Definition: musicplayer.h:175
VolumeBase::GetCurrentVolume
virtual uint GetCurrentVolume(void) const
Definition: volumebase.cpp:118
MusicPlayer::getResumeMode
ResumeMode getResumeMode(void)
Definition: musicplayer.cpp:203
OutputEvent
Definition: output.h:30
MythObservable::m_lock
QMutex * m_lock
Definition: mythobservable.h:29
MusicMetadata::setLength
void setLength(int llength)
Definition: musicmetadata.h:206
MusicPlayer::loadPlaylist
void loadPlaylist(void)
Definition: musicplayer.cpp:962
MusicPlayerEvent
Definition: musicplayer.h:22
AudioOutput::Reset
virtual void Reset(void)=0
MusicPlayer::loadStreamPlaylist
void loadStreamPlaylist(void)
Definition: musicplayer.cpp:994
decoderhandler.h
title
QString title
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:633
Playlist::enableSaves
void enableSaves(void)
Definition: playlist.h:103
OutputEvent::Stopped
static Type Stopped
Definition: output.h:67
MythCoreContext::emitTVPlaybackStopped
void emitTVPlaybackStopped(void)
Definition: mythcorecontext.h:253
Playlist::shuffleTracks
void shuffleTracks(MusicPlayer::ShuffleMode mode)
Definition: playlist.cpp:155
MusicPlayer::decVolume
void decVolume(void)
Definition: musicplayer.cpp:1371
Playlist
Definition: playlist.h:46
MusicMetadata::setTrack
void setTrack(int ltrack)
Definition: musicmetadata.h:200
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:17
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
arg
arg(title).arg(filename).arg(doDelete))
MusicPlayerEvent::TrackStatsChangedEvent
static Type TrackStatsChangedEvent
Definition: musicplayer.h:47
AudioOutput::SetTimecode
virtual void SetTimecode(int64_t timecode)=0
DecoderEvent::Error
static Type Error
Definition: decoder.h:50
MusicPlayer::setShuffleMode
void setShuffleMode(ShuffleMode mode)
Definition: musicplayer.cpp:1238
MusicMetadata::ID
IdType ID() const
Definition: musicmetadata.h:217
MusicMetadata::setAlbum
void setAlbum(const QString &lalbum, const QString &lalbum_sort=nullptr)
Definition: musicmetadata.h:152
MusicData::m_initialized
bool m_initialized
Definition: musicdata.h:57
MusicPlayerEvent::TrackAddedEvent
static Type TrackAddedEvent
Definition: musicplayer.h:42
MusicPlayer::isPlaying
bool isPlaying(void) const
Definition: musicplayer.h:102
MusicPlayer::MusicPlayer
MusicPlayer(QObject *parent)
Definition: musicplayer.cpp:53
MusicPlayer::m_playMode
PlayMode m_playMode
Definition: musicplayer.h:222
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MusicPlayer::m_resumeModePlayback
ResumeMode m_resumeModePlayback
Definition: musicplayer.h:235
MusicMetadata
Definition: musicmetadata.h:81
MusicPlayer::getStreamList
static StreamList * getStreamList(void)
Definition: musicplayer.cpp:1607
MusicPlayerEvent::MetadataChangedEvent
static Type MetadataChangedEvent
Definition: musicplayer.h:46
MusicPlayer::getMuteState
MuteState getMuteState(void) const
Definition: musicplayer.cpp:1405
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:46
DecoderHandlerEvent::Meta
static Type Meta
Definition: decoderhandler.h:48
MusicPlayer::getCurrentPlaylist
Playlist * getCurrentPlaylist(void)
Definition: musicplayer.cpp:1595
MythObservable::dispatch
void dispatch(const MythEvent &event)
Dispatch an event to all listeners.
Definition: mythobservable.cpp:73
MusicPlayer::seek
void seek(int pos)
Definition: musicplayer.cpp:1105
MusicPlayer::removeListener
void removeListener(QObject *listener)
Definition: musicplayer.cpp:159
DecoderHandler::next
bool next(void)
Definition: decoderhandler.cpp:138
OutputListeners::removeVisual
void removeVisual(MythTV::Visual *v)
Definition: output.cpp:43
MusicMetadata::persist
void persist(void)
Definition: musicmetadata.cpp:184
MythMainWindow::PauseIdleTimer
void PauseIdleTimer(bool pause)
Definition: mythmainwindow.cpp:2305
MusicMetadata::Artist
QString Artist() const
Definition: musicmetadata.h:126
MusicPlayer::setPlayMode
void setPlayMode(PlayMode mode)
Definition: musicplayer.cpp:950
MusicPlayer::pause
void pause(void)
Definition: musicplayer.cpp:286
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &stackname)
Definition: mythmainwindow.cpp:309
MusicPlayer::updateVolatileMetadata
void updateVolatileMetadata(void)
Definition: musicplayer.cpp:1278
Decoder::cond
QWaitCondition * cond()
Definition: decoder.h:84
MythImageNotification
Definition: mythnotification.h:220
MusicPlayer::m_decoderHandler
DecoderHandler * m_decoderHandler
Definition: musicplayer.h:218
MythObservable::m_listeners
QSet< QObject * > m_listeners
Definition: mythobservable.h:30
musicutils.h
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
AudioOutput::OpenAudio
static AudioOutput * OpenAudio(const QString &main_device, const QString &passthru_device, AudioFormat format, int channels, AVCodecID codec, int samplerate, AudioOutputSource source, bool set_initial_vol, bool passthru, int upmixer_startup=0, AudioOutputSettings *custom=nullptr)
Definition: audiooutput.cpp:58
MusicPlayer::changeCurrentTrack
void changeCurrentTrack(int trackNo)
change the current track to the given track
Definition: musicplayer.cpp:1133
gCDdevice
QString gCDdevice
Definition: musicplayer.cpp:36
MusicPlayer::m_resumeModeRadio
ResumeMode m_resumeModeRadio
Definition: musicplayer.h:237
MuteState
MuteState
Definition: volumebase.h:6
PlaylistContainer::getActive
Playlist * getActive(void)
Definition: playlistcontainer.h:45
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MusicPlayer::sendTrackStatsChangedEvent
void sendTrackStatsChangedEvent(int trackID)
Definition: musicplayer.cpp:1338
MusicPlayer::m_lastTrackStart
int m_lastTrackStart
Definition: musicplayer.h:247
cddecoder.h
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
MusicPlayer::ResumeMode
ResumeMode
Definition: musicplayer.h:173
MusicPlayer::getCurrentMetadata
MusicMetadata * getCurrentMetadata(void)
get the metadata for the current track in the playlist
Definition: musicplayer.cpp:1155
MusicPlayer::getNotificationID
int getNotificationID(const QString &hostname)
Definition: musicplayer.cpp:1612
MythTV::Visual
Definition: visual.h:17
DecoderHandler
Class for starting stream decoding.
Definition: decoderhandler.h:71
OutputEvent::Error
static Type Error
Definition: output.h:68
MythCoreContext::UnregisterForPlayback
void UnregisterForPlayback(QObject *sender)
Definition: mythcorecontext.cpp:1938
MusicPlayer::SHUFFLE_OFF
@ SHUFFLE_OFF
Definition: musicplayer.h:164
MusicPlayer::m_lastplayDelay
int m_lastplayDelay
Definition: musicplayer.h:231
MusicPlayer::toggleRepeatMode
RepeatMode toggleRepeatMode(void)
Definition: musicplayer.cpp:1192
DecoderHandlerEvent
Events sent by the DecoderHandler and it's helper classes.
Definition: decoderhandler.h:27
MusicPlayerEvent::TrackChangeEvent
static Type TrackChangeEvent
Definition: musicplayer.h:40
AUDIOOUTPUT_MUSIC
@ AUDIOOUTPUT_MUSIC
Definition: audiosettings.h:24
MusicPlayerEvent::PlayedTracksChangedEvent
static Type PlayedTracksChangedEvent
Definition: musicplayer.h:51
MusicPlayer::removeVisual
void removeVisual(MainVisual *visual)
Definition: musicplayer.cpp:189
DecoderHandlerEvent::getBufferStatus
void getBufferStatus(int *available, int *maxSize) const
Definition: decoderhandler.cpp:62
MusicPlayer::incVolume
void incVolume(void)
Definition: musicplayer.cpp:1362
AudioOutput::Pause
virtual void Pause(bool paused)=0
CdDecoder
Definition: cddecoder.h:27
Decoder::unlock
virtual void unlock(void)
Definition: decoder.h:81
VolumeBase::ToggleMute
virtual void ToggleMute(void)
Definition: volumebase.cpp:144
MusicData::reloadMusic
void reloadMusic(void) const
reload music after a scan, rip or import
Definition: musicdata.cpp:57
MusicPlayer::toggleShuffleMode
ShuffleMode toggleShuffleMode(void)
Definition: musicplayer.cpp:1211
MusicPlayer::m_currentTrack
int m_currentTrack
Definition: musicplayer.h:212
Playlist::removeTrack
void removeTrack(MusicMetadata::IdType trackID)
Definition: playlist.cpp:117
MusicPlayer::m_wasPlaying
bool m_wasPlaying
Definition: musicplayer.h:227
DecoderEvent
Definition: decoder.h:30
OutputListeners::setBufferSize
void setBufferSize(unsigned int sz)
Definition: output.h:108
MusicData::m_all_streams
AllStream * m_all_streams
Definition: musicdata.h:56
AllStream::getStreams
StreamList * getStreams(void)
Definition: musicmetadata.h:488
PlaylistContainer::getStreamPlaylist
Playlist * getStreamPlaylist(void)
Definition: playlistcontainer.h:48
MusicPlayer::setupDecoderHandler
void setupDecoderHandler(void)
Definition: musicplayer.cpp:1490
MusicPlayer::PlayMode
PlayMode
Definition: musicplayer.h:63
MusicMetadata::setTitle
void setTitle(const QString &ltitle, const QString &ltitle_sort=nullptr)
Definition: musicmetadata.h:164
MusicPlayer::m_output
AudioOutput * m_output
Definition: musicplayer.h:217
MusicPlayer::nextAuto
void nextAuto(void)
Definition: musicplayer.cpp:485
Playlist::getTrackCount
int getTrackCount(void)
Definition: playlist.h:82
MythErrorNotification
Definition: mythnotification.h:362
MusicPlayer::REPEAT_TRACK
@ REPEAT_TRACK
Definition: musicplayer.h:159
VolumeBase::GetMuteState
virtual MuteState GetMuteState(void) const
Definition: volumebase.cpp:150
MusicPlayer::sendTrackUnavailableEvent
void sendTrackUnavailableEvent(int trackID)
Definition: musicplayer.cpp:1350
SendStringListThread
send a message to the master BE without blocking the UI thread
Definition: musicdata.h:22
Decoder::stop
virtual void stop()=0
Playlist::addTrack
void addTrack(MusicMetadata::IdType trackID, bool update_display)
Given a tracks ID, add that track to this playlist.
Definition: playlist.cpp:63
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:634
MusicPlayer::stopDecoder
void stopDecoder(void)
Definition: musicplayer.cpp:353
MusicPlayer::m_shuffleMode
ShuffleMode m_shuffleMode
Definition: musicplayer.h:233
MusicPlayer::incSpeed
void incSpeed()
Definition: musicplayer.cpp:1314
MusicPlayer::RESUME_FIRST
@ RESUME_FIRST
Definition: musicplayer.h:174
Playlist::disableSaves
void disableSaves(void)
whether any changes should be saved to the DB
Definition: playlist.h:102
MusicPlayer::m_autoShowPlayer
bool m_autoShowPlayer
Definition: musicplayer.h:226
MythCoreContext::RegisterForPlayback
void RegisterForPlayback(QObject *sender, const char *method)
Definition: mythcorecontext.cpp:1917
MusicPlayer::SHUFFLE_ARTIST
@ SHUFFLE_ARTIST
Definition: musicplayer.h:168
MusicPlayer::savePosition
void savePosition(void)
Definition: musicplayer.cpp:1048
MusicMetadata::setFilename
void setFilename(const QString &lfilename)
Definition: musicmetadata.cpp:967
kMuteOff
@ kMuteOff
Definition: volumebase.h:7
MythObservable::hasListeners
bool hasListeners(void)
Definition: mythobservable.h:23
MusicPlayer::playlistChanged
void playlistChanged(int playlistID)
Definition: musicplayer.cpp:1484
MusicPlayer::sendMetadataChangedEvent
void sendMetadataChangedEvent(int trackID)
Definition: musicplayer.cpp:1332
MusicPlayer::hasClient
bool hasClient(void)
Definition: musicplayer.h:105
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1646
uint
unsigned int uint
Definition: compat.h:140
MusicPlayer::removeTrack
void removeTrack(int trackID)
Definition: musicplayer.cpp:1577
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MusicData::m_all_playlists
PlaylistContainer * m_all_playlists
Definition: musicdata.h:54
MusicPlayer::next
void next(void)
Definition: musicplayer.cpp:417
MusicPlayer::isPaused
bool isPaused(void)
Definition: musicplayer.h:103
CdDecoder::setDevice
void setDevice(const QString &dev)
Definition: cddecoder.cpp:107
MusicPlayerEvent::AllTracksRemovedEvent
static Type AllTracksRemovedEvent
Definition: musicplayer.h:45
MusicPlayer::m_allowRestorePos
bool m_allowRestorePos
Definition: musicplayer.h:229
MusicPlayer::updateLastplay
void updateLastplay(void)
Definition: musicplayer.cpp:1267
MusicPlayer::showMiniPlayer
void showMiniPlayer(void) const
Definition: musicplayer.cpp:1116
MusicPlayer
Definition: musicplayer.h:55
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:930
musicdata.h
MusicPlayer::m_updatedLastplay
bool m_updatedLastplay
Definition: musicplayer.h:228
MusicPlayer::SHUFFLE_RANDOM
@ SHUFFLE_RANDOM
Definition: musicplayer.h:165
StreamList
QList< MusicMetadata * > StreamList
Definition: musicmetadata.h:473
MusicMetadata::Album
QString Album() const
Definition: musicmetadata.h:150
gMusicData
MusicData * gMusicData
Definition: musicdata.cpp:20
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:924
Playlist::moveTrackUpDown
void moveTrackUpDown(bool flag, int where_its_at)
Definition: playlist.cpp:128
DecoderHandler::start
void start(MusicMetadata *mdata)
Definition: decoderhandler.cpp:75
DecoderEvent::Finished
static Type Finished
Definition: decoder.h:49
MusicMetadata::IdType
uint32_t IdType
Definition: musicmetadata.h:86
MusicPlayer::getNextMetadata
MusicMetadata * getNextMetadata(void)
get the metadata for the next track in the playlist
Definition: musicplayer.cpp:1167
mthreadpool.h
DecoderHandlerEvent::Error
static Type Error
Definition: decoderhandler.h:52
mythuihelper.h
MainVisual
Definition: mainvisual.h:34
MusicPlayer::decoderHandlerReady
void decoderHandlerReady(void)
Definition: musicplayer.cpp:1504
MusicPlayer::previous
void previous(void)
Definition: musicplayer.cpp:454
MusicPlayer::m_visualisers
QSet< QObject * > m_visualisers
Definition: musicplayer.h:220
MythCoreContext::InWantingPlayback
bool InWantingPlayback(void)
Returns true if a client has requested playback.
Definition: mythcorecontext.cpp:2037
isRunning
static bool isRunning(const char *program)
Returns true if a program containing the specified string is running on this machine.
Definition: mythtv/programs/mythshutdown/main.cpp:203
MusicMetadata::reloadMetadata
void reloadMetadata(void)
Definition: musicmetadata.cpp:437
MusicMetadata::dumpToDatabase
void dumpToDatabase(void)
Definition: musicmetadata.cpp:678
DecoderEvent::Stopped
static Type Stopped
Definition: decoder.h:48
MusicPlayer::getDecoderHandler
DecoderHandler * getDecoderHandler(void)
Definition: musicplayer.h:116
MusicPlayer::decSpeed
void decSpeed()
Definition: musicplayer.cpp:1320
MusicMetadata::setArtist
void setArtist(const QString &lartist, const QString &lartist_sort=nullptr)
Definition: musicmetadata.h:128
MusicPlayerEvent::TrackUnavailableEvent
static Type TrackUnavailableEvent
Definition: musicplayer.h:44
MusicPlayer::activePlaylistChanged
void activePlaylistChanged(int trackID, bool deleted)
Definition: musicplayer.cpp:1421
MusicMetadata::Hostname
QString Hostname(void)
Definition: musicmetadata.h:229
MusicPlayer::m_canShowPlayer
bool m_canShowPlayer
Definition: musicplayer.h:225
MusicPlayer::setSpeed
void setSpeed(float speed)
Definition: musicplayer.cpp:1305
MusicPlayer::setRepeatMode
void setRepeatMode(RepeatMode mode)
Definition: musicplayer.h:181
MusicPlayer::m_repeatMode
RepeatMode m_repeatMode
Definition: musicplayer.h:234
MusicPlayer::REPEAT_OFF
@ REPEAT_OFF
Definition: musicplayer.h:158
metaio.h
MusicPlayer::RepeatMode
RepeatMode
Definition: musicplayer.h:158
MusicPlayer::addTrack
void addTrack(int trackID, bool updateUI)
Definition: musicplayer.cpp:1590
MusicPlayer::SHUFFLE_ALBUM
@ SHUFFLE_ALBUM
Definition: musicplayer.h:167
AudioOutput::SetStretchFactor
virtual void SetStretchFactor(float factor)
Definition: audiooutput.cpp:253
constants.h
MusicPlayerEvent::PlaylistChangedEvent
static Type PlaylistChangedEvent
Definition: musicplayer.h:50
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:14
OutputEvent::Info
static Type Info
Definition: output.h:65
MusicMetadata::LastPlay
QDateTime LastPlay() const
Definition: musicmetadata.h:243
audiooutput.h
Decoder::setOutput
void setOutput(AudioOutput *o)
Definition: decoder.cpp:46
MusicPlayerEvent::VolumeChangeEvent
static Type VolumeChangeEvent
Definition: musicplayer.h:41
MusicPlayer::m_playedList
QList< MusicMetadata * > m_playedList
Definition: musicplayer.h:246
DecoderHandler::getMetadata
MusicMetadata & getMetadata()
Definition: decoderhandler.h:95
MusicPlayerEvent::TrackRemovedEvent
static Type TrackRemovedEvent
Definition: musicplayer.h:43
MusicPlayer::customEvent
void customEvent(QEvent *event) override
Definition: musicplayer.cpp:542
MiniPlayer
Definition: miniplayer.h:11
MusicPlayer::isMuted
bool isMuted(void) const
Definition: musicplayer.h:82
GetNotificationCenter
MythNotificationCenter * GetNotificationCenter(void)
Definition: mythmainwindow.cpp:127
MusicPlayer::m_currentTime
int m_currentTime
Definition: musicplayer.h:213
mythcontext.h
miniplayer.h
MythNotificationCenter::UnRegister
void UnRegister(void *from, int id, bool closeimemdiately=false)
Unregister the client.
Definition: mythnotificationcenter.cpp:1375
MusicPlayer::m_resumeModeEditor
ResumeMode m_resumeModeEditor
Definition: musicplayer.h:236
MusicPlayer::sendVolumeChangedEvent
void sendVolumeChangedEvent(void)
Definition: musicplayer.cpp:1326
mainvisual.h
MusicPlayer::~MusicPlayer
~MusicPlayer(void) override
Definition: musicplayer.cpp:86
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:107
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:272
Playlist::getTrackPosition
int getTrackPosition(MusicMetadata::IdType trackID)
Definition: playlist.h:90
MusicPlayerEvent::CDChangedEvent
static Type CDChangedEvent
Definition: musicplayer.h:49
MusicPlayer::loadSettings
void loadSettings(void)
Definition: musicplayer.cpp:212
MusicPlayer::PLAYMODE_RADIO
@ PLAYMODE_RADIO
Definition: musicplayer.h:66
MusicPlayer::sendAlbumArtChangedEvent
void sendAlbumArtChangedEvent(int trackID)
Definition: musicplayer.cpp:1344
MusicPlayer::m_oneshotMetadata
MusicMetadata * m_oneshotMetadata
Definition: musicplayer.h:215
MusicPlayer::play
void play(void)
Definition: musicplayer.cpp:304
MusicPlayer::restorePosition
void restorePosition(void)
Definition: musicplayer.cpp:1065
MusicMetadata::setLastPlay
void setLastPlay()
Definition: musicmetadata.cpp:1199
MythCoreContext::WantingPlayback
void WantingPlayback(QObject *sender)
All the objects that have registered using MythCoreContext::RegisterForPlayback but sender will be ca...
Definition: mythcorecontext.cpp:1958
MusicData::m_all_music
AllMusic * m_all_music
Definition: musicdata.h:55
MusicPlayer::sendCDChangedEvent
void sendCDChangedEvent(void)
Definition: musicplayer.cpp:1356
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:856
LASTPLAY_DELAY
#define LASTPLAY_DELAY
Definition: musicplayer.h:15
DecoderHandler::stop
void stop(void)
Definition: decoderhandler.cpp:176
MusicPlayer::playFile
void playFile(const MusicMetadata &mdata)
Definition: musicplayer.cpp:223
Decoder::lock
virtual void lock(void)
Definition: decoder.h:80
MusicPlayer::m_isPlaying
bool m_isPlaying
Definition: musicplayer.h:223
Playlist::removeAllTracks
void removeAllTracks(void)
Definition: playlist.cpp:87
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
MusicPlayer::stop
void stop(bool stopAll=false)
Definition: musicplayer.cpp:237
MusicPlayer::m_errorCount
int m_errorCount
Definition: musicplayer.h:251
MusicPlayer::m_playSpeed
float m_playSpeed
Definition: musicplayer.h:239
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:899
MThread::wait
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:309
DMAP
QMap< QString, QString > DMAP
Definition: mythnotification.h:23
MusicPlayer::getBufferStatus
void getBufferStatus(int *bufferAvailable, int *bufferSize) const
Definition: musicplayer.cpp:944
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:81
MusicPlayerEvent::AlbumArtChangedEvent
static Type AlbumArtChangedEvent
Definition: musicplayer.h:48
Decoder::seek
virtual void seek(double)=0
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:307
mythmainwindow.h
MusicPlayer::getVolume
uint getVolume(void) const
Definition: musicplayer.cpp:1389
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:49
MythCoreContext::dispatch
void dispatch(const MythEvent &event)
Definition: mythcorecontext.cpp:1733
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
AudioOutput::PauseUntilBuffered
virtual void PauseUntilBuffered(void)=0
MusicPlayer::m_isAutoplay
bool m_isAutoplay
Definition: musicplayer.h:224
AudioOutput::IsPaused
virtual bool IsPaused(void) const =0
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:342
MusicPlayer::addListener
void addListener(QObject *listener)
Definition: musicplayer.cpp:143
MusicPlayer::RESUME_EXACT
@ RESUME_EXACT
Definition: musicplayer.h:176
decoder.h
MusicPlayer::ShuffleMode
ShuffleMode
Definition: musicplayer.h:164
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:916
musicplayer.h
MythNotification::Info
static Type Info
Definition: mythnotification.h:32
MusicPlayer::REPEAT_ALL
@ REPEAT_ALL
Definition: musicplayer.h:160
MythNotificationCenter::Queue
bool Queue(const MythNotification &notification)
Queue a notification Queue() is thread-safe and can be called from anywhere.
Definition: mythnotificationcenter.cpp:1351
MusicPlayer::moveTrackUpDown
void moveTrackUpDown(bool moveUp, int whichTrack)
Definition: musicplayer.cpp:1015