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 
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  Decoder *decoder = getDecoder();
295  if (decoder)
296  {
297  decoder->lock();
298  decoder->cond()->wakeAll();
299  decoder->unlock();
300  }
301 
303 }
304 
306 {
307  stopDecoder();
308 
310  if (!meta)
311  return;
312 
313  if (meta->Filename() == METADATA_INVALID_FILENAME)
314  {
315  // put an upper limit on the number of consecutive track unavailable errors
316  if (m_errorCount >= 1000)
317  {
318  ShowOkPopup(tr("Got too many track unavailable errors. Maybe the host with the music on is off-line?"));
319  stop(true);
320  m_errorCount = 0;
321  return;
322  }
323 
324  if (m_errorCount < 5)
325  {
326  MythErrorNotification n(tr("Track Unavailable"), tr("MythMusic"), QString("Cannot find file '%1'").arg(meta->Filename(false)));
328  }
329 
330  m_errorCount++;
331 
332  sendTrackUnavailableEvent(meta->ID());
333  next();
334  return;
335  }
336 
337  // Notify others that we are about to play
339 
340  if (!m_output)
341  {
342  if (!openOutputDevice())
343  return;
344  }
345 
346  if (!getDecoderHandler())
348 
349  getDecoderHandler()->start(meta);
350 
352 }
353 
355 {
356  if (getDecoderHandler())
357  getDecoderHandler()->stop();
358 }
359 
361 {
362  QString adevice;
363  QString pdevice;
364 
365  adevice = gCoreContext->GetSetting("MusicAudioDevice", "default");
366  if (adevice == "default" || adevice.isEmpty())
367  adevice = gCoreContext->GetSetting("AudioOutputDevice");
368  else
369  adevice = gCoreContext->GetSetting("MusicAudioDevice");
370 
371  pdevice = gCoreContext->GetBoolSetting("PassThruDeviceOverride", false) ?
372  gCoreContext->GetSetting("PassThruOutputDevice") : "auto";
373 
375  adevice, pdevice, FORMAT_S16, 2, AV_CODEC_ID_NONE, 44100,
376  AUDIOOUTPUT_MUSIC, true, false,
377  gCoreContext->GetNumSetting("MusicDefaultUpmix", 0) + 1);
378 
379  if (!m_output)
380  {
381  LOG(VB_GENERAL, LOG_ERR,
382  QString("MusicPlayer: Cannot open audio output device: %1").arg(adevice));
383 
384  return false;
385  }
386 
387  if (!m_output->GetError().isEmpty())
388  {
389  LOG(VB_GENERAL, LOG_ERR,
390  QString("MusicPlayer: Cannot open audio output device: %1").arg(adevice));
391  LOG(VB_GENERAL, LOG_ERR,
392  QString("Error was: %1").arg(m_output->GetError()));
393 
394  delete m_output;
395  m_output = nullptr;
396 
397  return false;
398  }
399 
400  m_output->setBufferSize(256 * 1024);
401 
402  m_output->addListener(this);
403 
404  // add any visuals to the audio output
405  // NOLINTNEXTLINE(modernize-loop-convert)
406  for (auto it = m_visualisers.begin(); it != m_visualisers.end() ; ++it)
408 
409  // add any listeners to the audio output
410  QMutexLocker locker(m_lock);
411  // NOLINTNEXTLINE(modernize-loop-convert)
412  for (auto it = m_listeners.begin(); it != m_listeners.end() ; ++it)
413  m_output->addListener(*it);
414 
415  return true;
416 }
417 
419 {
420  int currentTrack = m_currentTrack;
421 
422  if (!getCurrentPlaylist())
423  return;
424 
425  if (m_oneshotMetadata)
426  {
427  delete m_oneshotMetadata;
428  m_oneshotMetadata = nullptr;
429  }
430  else
431  currentTrack++;
432 
433  if (currentTrack >= getCurrentPlaylist()->getTrackCount())
434  {
435  if (m_repeatMode == REPEAT_ALL)
436  {
437  // start playing again from first track
438  currentTrack = 0;
439  }
440  else
441  {
442  stop();
443  return;
444  }
445  }
446 
447  changeCurrentTrack(currentTrack);
448 
449  if (getCurrentMetadata())
450  play();
451  else
452  stop();
453 }
454 
456 {
457  int currentTrack = m_currentTrack;
458 
459  if (!getCurrentPlaylist())
460  return;
461 
462  if (m_oneshotMetadata)
463  {
464  delete m_oneshotMetadata;
465  m_oneshotMetadata = nullptr;
466  }
467  else
468  currentTrack--;
469 
470  if (currentTrack >= 0)
471  {
472  changeCurrentTrack(currentTrack);
473 
474  if (getCurrentMetadata())
475  play();
476  else
477  return;//stop();
478  }
479  else
480  {
481  // FIXME take repeat mode into account
482  return; //stop();
483  }
484 }
485 
487 {
488  if (!getCurrentPlaylist())
489  return;
490 
491  if (m_oneshotMetadata)
492  {
493  delete m_oneshotMetadata;
494  m_oneshotMetadata = nullptr;
495  stop(true);
496  return;
497  }
498 
499  if (m_repeatMode == REPEAT_TRACK)
500  {
501  play();
502  return;
503  }
504  if (!m_decoderHandler->next())
505  next();
506 
507  // if we don't already have a gui attached show the miniplayer if configured to do so
509  {
510  MythScreenStack *popupStack =
511  GetMythMainWindow()->GetStack("popup stack");
512 
513  auto *miniplayer = new MiniPlayer(popupStack);
514 
515  if (miniplayer->Create())
516  popupStack->AddScreen(miniplayer);
517  else
518  delete miniplayer;
519  }
520 }
521 
523 {
525  {
526  play();
527 
528  m_wasPlaying = false;
529  }
530 }
531 
533 {
534  if (m_output)
535  {
537 
538  savePosition();
539  stop(true);
540  }
541 }
542 
543 void MusicPlayer::customEvent(QEvent *event)
544 {
545  // handle decoderHandler events
546  if (event->type() == DecoderHandlerEvent::Ready)
547  {
548  m_errorCount = 0;
550  }
551  else if (event->type() == DecoderHandlerEvent::Meta)
552  {
553  auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
554  if (!dhe)
555  return;
556 
557  auto *mdata = new MusicMetadata(*dhe->getMetadata());
558 
560 
561  if (getCurrentMetadata())
562  {
563  mdata->setID(getCurrentMetadata()->ID());
564  mdata->setHostname(gCoreContext->GetMasterHostName());
565  mdata->setTrack(m_playedList.count() + 1);
566  mdata->setBroadcaster(getCurrentMetadata()->Broadcaster());
567  mdata->setChannel(getCurrentMetadata()->Channel());
568 
569  getCurrentMetadata()->setTitle(mdata->Title());
570  getCurrentMetadata()->setArtist(mdata->Artist());
571  getCurrentMetadata()->setAlbum(mdata->Album());
572  getCurrentMetadata()->setTrack(mdata->Track());
573  }
574 
575  m_playedList.append(mdata);
576 
578  {
579  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
580 
581  auto *miniplayer = new MiniPlayer(popupStack);
582 
583  if (miniplayer->Create())
584  popupStack->AddScreen(miniplayer);
585  else
586  delete miniplayer;
587  }
588 
589  // tell any listeners we've added a new track to the played list
591  dispatch(me);
592  }
593  // handle MythEvent events
594  else if (event->type() == MythEvent::MythEventMessage)
595  {
596  auto *me = dynamic_cast<MythEvent*>(event);
597  if (!me)
598  return;
599 
600  if (me->Message().left(13) == "MUSIC_COMMAND")
601  {
602  QStringList list = me->Message().simplified().split(' ');
603 
604  if (list.size() >= 3 && list[1] == gCoreContext->GetHostName())
605  {
606  if (list[2] == "PLAY")
607  play();
608  else if (list[2] == "STOP")
609  stop();
610  else if (list[2] == "PAUSE")
611  pause();
612  else if (list[2] == "SET_VOLUME")
613  {
614  if (list.size() >= 3)
615  {
616  int volume = list[3].toInt();
617  if (volume >= 0 && volume <= 100)
618  setVolume(volume);
619  }
620  }
621  else if (list[2] == "GET_VOLUME")
622  {
623  QString message = QString("MUSIC_CONTROL ANSWER %1 %2")
624  .arg(gCoreContext->GetHostName()).arg(getVolume());
625  MythEvent me2(message);
626  gCoreContext->dispatch(me2);
627  }
628  else if (list[2] == "PLAY_FILE")
629  {
630  int start = me->Message().indexOf("'");
631  int end = me->Message().lastIndexOf("'");
632 
633  if (start != -1 && end != -1 && start != end)
634  {
635  QString filename = me->Message().mid(start + 1, end - start - 1);
636  MusicMetadata mdata;
637  mdata.setFilename(filename);
638  playFile(mdata);
639  }
640  else
641  {
642  LOG(VB_GENERAL, LOG_ERR,
643  QString("MusicPlayer: got invalid MUSIC_COMMAND "
644  "PLAY_FILE - %1").arg(me->Message()));
645  }
646  }
647  else if (list[2] == "PLAY_URL")
648  {
649  if (list.size() == 4)
650  {
651  QString filename = list[3];
652  MusicMetadata mdata;
653  mdata.setFilename(filename);
654  playFile(mdata);
655  }
656  else
657  {
658  LOG(VB_GENERAL, LOG_ERR,
659  QString("MusicPlayer: got invalid MUSIC_COMMAND "
660  "PLAY_URL - %1").arg(me->Message()));
661  }
662  }
663  else if (list[2] == "PLAY_TRACK")
664  {
665  if (list.size() == 4)
666  {
667  int trackID = list[3].toInt();
668  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackID);
669  if (mdata)
670  playFile(*mdata);
671  }
672  else
673  {
674  LOG(VB_GENERAL, LOG_ERR,
675  QString("MusicPlayer: got invalid MUSIC_COMMAND "
676  "PLAY_TRACK - %1").arg(me->Message()));
677  }
678  }
679  else if (list[2] == "GET_METADATA")
680  {
681  QString mdataStr;
683  if (mdata)
684  mdataStr = QString("%1 by %2 from %3").arg(mdata->Title()).arg(mdata->Artist()).arg(mdata->Album());
685  else
686  mdataStr = "Unknown Track2";
687 
688  QString message = QString("MUSIC_CONTROL ANSWER %1 %2")
689  .arg(gCoreContext->GetHostName()).arg(mdataStr);
690  MythEvent me2(message);
691  gCoreContext->dispatch(me2);
692  }
693  else if (list[2] == "GET_STATUS")
694  {
695  QString statusStr = "STOPPED";
696 
697  if (gPlayer->isPlaying())
698  statusStr = "PLAYING";
699  else if (gPlayer->isPaused())
700  statusStr = "PAUSED";
701 
702  QString message = QString("MUSIC_CONTROL ANSWER %1 %2")
703  .arg(gCoreContext->GetHostName()).arg(statusStr);
704  MythEvent me2(message);
705  gCoreContext->dispatch(me2);
706  }
707  }
708  else
709  {
710  LOG(VB_GENERAL, LOG_ERR,
711  QString("MusicPlayer: got unknown/invalid MUSIC_COMMAND "
712  "- %1").arg(me->Message()));
713  }
714  }
715  else if (me->Message().startsWith("MUSIC_SETTINGS_CHANGED"))
716  {
717  loadSettings();
718  }
719  else if (me->Message().startsWith("MUSIC_METADATA_CHANGED"))
720  {
722  {
723  QStringList list = me->Message().simplified().split(' ');
724  if (list.size() == 2)
725  {
726  int songID = list[1].toInt();
727  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(songID);
728 
729  if (mdata)
730  {
731  mdata->reloadMetadata();
732 
733  // tell any listeners the metadata has changed for this track
734  sendMetadataChangedEvent(songID);
735  }
736  }
737  }
738  }
739  else if (me->Message().startsWith("MUSIC_SCANNER_STARTED"))
740  {
741  QStringList list = me->Message().simplified().split(' ');
742  if (list.size() == 2)
743  {
744  QString host = list[1];
745  int id = getNotificationID(host);
746  sendNotification(id,
747  tr("A music file scan has started on %1").arg(host),
748  tr("Music File Scanner"),
749  tr("This may take a while I'll give a shout when finished"));
750  }
751  }
752  else if (me->Message().startsWith("MUSIC_SCANNER_FINISHED"))
753  {
754  QStringList list = me->Message().simplified().split(' ');
755  if (list.size() == 6)
756  {
757  QString host = list[1];
758  int id = getNotificationID(host);
759  int totalTracks = list[2].toInt();
760  int newTracks = list[3].toInt();
761  int totalCoverart = list[4].toInt();
762  int newCoverart = list[5].toInt();
763 
764  QString summary = QString("Total Tracks: %2, new tracks: %3,\nTotal Coverart: %4, New CoverArt %5")
765  .arg(totalTracks).arg(newTracks).arg(totalCoverart).arg(newCoverart);
766  sendNotification(id,
767  tr("A music file scan has finished on %1").arg(host),
768  tr("Music File Scanner"), summary);
769 
771  }
772  }
773  else if (me->Message().startsWith("MUSIC_SCANNER_ERROR"))
774  {
775  QStringList list = me->Message().simplified().split(' ');
776  if (list.size() == 3)
777  {
778  QString host = list[1];
779  QString error = list[2];
780  int id = getNotificationID(host);
781 
782  if (error == "Already_Running")
783  {
784  sendNotification(id, tr(""),
785  tr("Music File Scanner"),
786  tr("Can't run the music file scanner because it is already running on %1").arg(host));
787  }
788  else if (error == "Stalled")
789  {
790  sendNotification(id, tr(""),
791  tr("Music File Scanner"),
792  tr("The music file scanner has been running for more than 60 minutes on %1.\nResetting and trying again")
793  .arg(host));
794  }
795  }
796  }
797  }
798 
799  if (event->type() == OutputEvent::Error)
800  {
801  auto *aoe = dynamic_cast<OutputEvent *>(event);
802 
803  if (!aoe)
804  return;
805 
806  LOG(VB_GENERAL, LOG_ERR, QString("Audio Output Error: %1").arg(*aoe->errorMessage()));
807 
808  MythErrorNotification n(tr("Audio Output Error"), tr("MythMusic"), *aoe->errorMessage());
810 
811  m_errorCount++;
812 
813  if (m_errorCount <= 5)
814  nextAuto();
815  else
816  {
817  m_errorCount = 0;
818  stop(true);
819  }
820  }
821  else if (event->type() == DecoderEvent::Error)
822  {
823  auto *dxe = dynamic_cast<DecoderEvent *>(event);
824 
825  if (!dxe)
826  return;
827 
828  LOG(VB_GENERAL, LOG_ERR, QString("Decoder Error: %2").arg(*dxe->errorMessage()));
829 
830  MythErrorNotification n(tr("Decoder Error"), tr("MythMusic"), *dxe->errorMessage());
832 
833  m_errorCount++;
834 
835  if (m_playMode != PLAYMODE_RADIO && m_errorCount <= 5)
836  nextAuto();
837  else
838  {
839  m_errorCount = 0;
840  stop(true);
841  }
842  }
843  else if (event->type() == DecoderHandlerEvent::Error)
844  {
845  auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
846 
847  if (!dhe)
848  return;
849 
850  LOG(VB_GENERAL, LOG_ERR, QString("Decoder Handler Error - %1").arg(*dhe->getMessage()));
851 
852  MythErrorNotification n(tr("Decoder Handler Error"), tr("MythMusic"), *dhe->getMessage());
854 
855  m_errorCount++;
856 
857  if (m_errorCount <= 5)
858  nextAuto();
859  else
860  {
861  m_errorCount = 0;
862  stop(true);
863  }
864  }
865  else if (event->type() == OutputEvent::Info)
866  {
867  auto *oe = dynamic_cast<OutputEvent*>(event);
868 
869  if (!oe)
870  return;
871 
872  if (m_playMode != PLAYMODE_RADIO)
873  m_currentTime = oe->elapsedSeconds();
874  else
875  m_currentTime = oe->elapsedSeconds() - m_lastTrackStart;
876 
878  {
879  // we update the lastplay and playcount after playing
880  // for m_lastplayDelay seconds or half the total track time
882  (getCurrentMetadata()->Length() / 1000) / 2) ||
884  {
885  updateLastplay();
886  }
887  }
888 
889  // update the current tracks time in the last played list
890  if (m_playMode == PLAYMODE_RADIO)
891  {
892  if (!m_playedList.isEmpty())
893  {
894  m_playedList.last()->setLength(m_currentTime * 1000);
895  // this will update any track lengths displayed on screen
897  }
898  }
899  }
900  else if (event->type() == DecoderEvent::Finished)
901  {
902  if (m_oneshotMetadata)
903  {
904  delete m_oneshotMetadata;
905  m_oneshotMetadata = nullptr;
906  stop(true);
907  }
908  else
909  {
911  m_currentTime != getCurrentMetadata()->Length() / 1000)
912  {
913  LOG(VB_GENERAL, LOG_NOTICE, QString("MusicPlayer: Updating track length was %1s, should be %2s")
914  .arg(getCurrentMetadata()->Length() / 1000).arg(m_currentTime));
915 
918 
919  // this will update any track lengths displayed on screen
921 
922  // this will force the playlist stats to update
924  dispatch(me);
925  }
926 
927  nextAuto();
928  }
929  }
930  else if (event->type() == DecoderEvent::Stopped)
931  {
932  }
933  else if (event->type() == DecoderHandlerEvent::BufferStatus)
934  {
935  auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
936  if (!dhe)
937  return;
938 
940  }
941 
942  QObject::customEvent(event);
943 }
944 
945 void MusicPlayer::getBufferStatus(int *bufferAvailable, int *bufferSize) const
946 {
947  *bufferAvailable = m_bufferAvailable;
948  *bufferSize = m_bufferSize;
949 }
950 
952 {
953  if (m_playMode == mode)
954  return;
955 
956  savePosition();
957 
958  m_playMode = mode;
959 
960  loadPlaylist();
961 }
962 
964 {
965  if (m_playMode == PLAYMODE_RADIO)
966  {
968  {
969  int bookmark = gCoreContext->GetNumSetting("MusicRadioBookmark", 0);
970  if (bookmark < 0 || bookmark >= getCurrentPlaylist()->getTrackCount())
971  bookmark = 0;
972 
973  m_currentTrack = bookmark;
974  }
975  else
976  m_currentTrack = 0;
977 
979  }
980  else
981  {
983  {
984  int bookmark = gCoreContext->GetNumSetting("MusicBookmark", 0);
985  if (bookmark < 0 || bookmark >= getCurrentPlaylist()->getTrackCount())
986  bookmark = 0;
987 
988  m_currentTrack = bookmark;
989  }
990  else
991  m_currentTrack = 0;
992  }
993 }
994 
996 {
998 
999  // create the radio playlist
1003 
1004  for (int x = 0; x < list->count(); x++)
1005  {
1006  MusicMetadata *mdata = list->at(x);
1007  gMusicData->m_all_playlists->getStreamPlaylist()->addTrack(mdata->ID(), false);
1008 
1009  if (mdata->ID() == id)
1010  m_currentTrack = x;
1011  }
1012 
1014 }
1015 
1016 void MusicPlayer::moveTrackUpDown(bool moveUp, int whichTrack)
1017 {
1018  if (!getCurrentPlaylist())
1019  return;
1020 
1021  if (moveUp && whichTrack <= 0)
1022  return;
1023 
1024  if (!moveUp && whichTrack >= getCurrentPlaylist()->getTrackCount() - 1)
1025  return;
1026 
1028 
1029  getCurrentPlaylist()->moveTrackUpDown(moveUp, whichTrack);
1030 
1032 }
1033 
1035 {
1036  changeCurrentTrack(pos);
1037 
1038  if (!getCurrentMetadata())
1039  {
1040  stop();
1041  return false;
1042  }
1043 
1044  play();
1045 
1046  return true;
1047 }
1048 
1050 {
1051  // can't save a bookmark if we don't know what we are playing
1052  if (!getCurrentMetadata())
1053  return;
1054 
1055  if (m_playMode == PLAYMODE_RADIO)
1056  {
1057  gCoreContext->SaveSetting("MusicRadioBookmark", getCurrentMetadata()->ID());
1058  }
1059  else
1060  {
1061  gCoreContext->SaveSetting("MusicBookmark", getCurrentMetadata()->ID());
1062  gCoreContext->SaveSetting("MusicBookmarkPosition", m_currentTime);
1063  }
1064 }
1065 
1067 {
1068  // if we are switching views we don't wont to restore the position
1069  if (!m_allowRestorePos)
1070  return;
1071 
1072  m_currentTrack = 0;
1073  uint id = -1;
1074 
1076  {
1077  if (m_playMode == PLAYMODE_RADIO)
1078  id = gCoreContext->GetNumSetting("MusicRadioBookmark", 0);
1079  else
1080  id = gCoreContext->GetNumSetting("MusicBookmark", 0);
1081  }
1082 
1083  if (getCurrentPlaylist())
1084  {
1085  for (int x = 0; x < getCurrentPlaylist()->getTrackCount(); x++)
1086  {
1087  if (getCurrentPlaylist()->getSongAt(x) &&
1088  getCurrentPlaylist()->getSongAt(x)->ID() == id)
1089  {
1090  m_currentTrack = x;
1091  break;
1092  }
1093  }
1094  }
1095 
1096  if (getCurrentMetadata())
1097  {
1099  play();
1100 
1102  seek(gCoreContext->GetNumSetting("MusicBookmarkPosition", 0));
1103  }
1104 }
1105 
1106 void MusicPlayer::seek(int pos)
1107 {
1108  if (m_output)
1109  {
1110  Decoder *decoder = getDecoder();
1111  if (decoder && decoder->isRunning())
1112  decoder->seek(pos);
1113 
1114  m_output->SetTimecode(pos*1000);
1115  }
1116 }
1117 
1119 {
1120  if (m_canShowPlayer)
1121  {
1122  MythScreenStack *popupStack =
1123  GetMythMainWindow()->GetStack("popup stack");
1124 
1125  auto *miniplayer = new MiniPlayer(popupStack);
1126 
1127  if (miniplayer->Create())
1128  popupStack->AddScreen(miniplayer);
1129  else
1130  delete miniplayer;
1131  }
1132 }
1133 
1136 {
1137  if (!getCurrentPlaylist())
1138  return;
1139 
1140  // check to see if we need to save the current tracks volatile metadata (playcount, last played etc)
1142 
1143  m_currentTrack = trackNo;
1144 
1145  // sanity check the current track
1146  if (m_currentTrack < 0 || m_currentTrack >= getCurrentPlaylist()->getTrackCount())
1147  {
1148  LOG(VB_GENERAL, LOG_ERR,
1149  QString("MusicPlayer: asked to set the current track to an invalid track no. %1")
1150  .arg(trackNo));
1151  m_currentTrack = -1;
1152  return;
1153  }
1154 }
1155 
1158 {
1159  if (m_oneshotMetadata)
1160  return m_oneshotMetadata;
1161 
1162  if (!getCurrentPlaylist() || !getCurrentPlaylist()->getSongAt(m_currentTrack))
1163  return nullptr;
1164 
1166 }
1167 
1170 {
1171  if (m_playMode == PLAYMODE_RADIO)
1172  return nullptr;
1173 
1174  if (m_oneshotMetadata)
1175  return getCurrentMetadata();
1176 
1177  if (!getCurrentPlaylist() || !getCurrentPlaylist()->getSongAt(m_currentTrack))
1178  return nullptr;
1179 
1180  if (m_repeatMode == REPEAT_TRACK)
1181  return getCurrentMetadata();
1182 
1183  // if we are not playing the last track then just return the next track
1184  if (m_currentTrack < getCurrentPlaylist()->getTrackCount() - 1)
1186 
1187  // if we are playing the last track then we need to take the
1188  // repeat mode into account
1189  if (m_repeatMode == REPEAT_ALL)
1190  return getCurrentPlaylist()->getSongAt(0);
1191  return nullptr;
1192 }
1193 
1195 {
1196  switch (m_repeatMode)
1197  {
1198  case REPEAT_OFF:
1200  break;
1201  case REPEAT_TRACK:
1203  break;
1204  case REPEAT_ALL:
1205  default:
1207  break;
1208  }
1209 
1210  return m_repeatMode;
1211 }
1212 
1214 {
1215  switch (m_shuffleMode)
1216  {
1217  case SHUFFLE_OFF:
1219  break;
1220  case SHUFFLE_RANDOM:
1222  break;
1223  case SHUFFLE_INTELLIGENT:
1225  break;
1226  case SHUFFLE_ALBUM:
1228  break;
1229  case SHUFFLE_ARTIST:
1230  default:
1232  break;
1233  }
1234 
1236 
1237  return m_shuffleMode;
1238 }
1239 
1241 {
1242  int curTrackID = -1;
1243  if (getCurrentMetadata())
1244  curTrackID = getCurrentMetadata()->ID();
1245 
1246  // only save the mode if we are playing tracks
1247  if (m_playMode != PLAYMODE_RADIO)
1248  m_shuffleMode = mode;
1249 
1250  if (!getCurrentPlaylist())
1251  return;
1252 
1254 
1255  if (curTrackID != -1)
1256  {
1257  for (int x = 0; x < getCurrentPlaylist()->getTrackCount(); x++)
1258  {
1260  if (mdata && mdata->ID() == (MusicMetadata::IdType) curTrackID)
1261  {
1262  m_currentTrack = x;
1263  break;
1264  }
1265  }
1266  }
1267 }
1268 
1270 {
1272  {
1275  }
1276 
1277  m_updatedLastplay = true;
1278 }
1279 
1281 {
1283  {
1284  if (getCurrentMetadata()->hasChanged())
1285  {
1287 
1288  // only write the last played, playcount & rating to the tag if it's enabled by the user
1289  if (GetMythDB()->GetNumSetting("AllowTagWriting", 0) == 1)
1290  {
1291  QStringList strList;
1292  strList << QString("MUSIC_TAG_UPDATE_VOLATILE")
1294  << QString::number(getCurrentMetadata()->ID())
1295  << QString::number(getCurrentMetadata()->Rating())
1296  << QString::number(getCurrentMetadata()->Playcount())
1297  << getCurrentMetadata()->LastPlay().toString(Qt::ISODate);
1298  auto *thread = new SendStringListThread(strList);
1299  MThreadPool::globalInstance()->start(thread, "UpdateVolatile");
1300  }
1301 
1303  }
1304  }
1305 }
1306 
1307 void MusicPlayer::setSpeed(float newspeed)
1308 {
1309  if (m_output)
1310  {
1311  m_playSpeed = newspeed;
1313  }
1314 }
1315 
1317 {
1318  m_playSpeed += 0.05F;
1320 }
1321 
1323 {
1324  m_playSpeed -= 0.05F;
1326 }
1327 
1329 {
1331  dispatch(me);
1332 }
1333 
1335 {
1337  dispatch(me);
1338 }
1339 
1341 {
1343  dispatch(me);
1344 }
1345 
1347 {
1349  dispatch(me);
1350 }
1351 
1353 {
1355  dispatch(me);
1356 }
1357 
1359 {
1361  dispatch(me);
1362 }
1363 
1365 {
1366  if (getOutput())
1367  {
1370  }
1371 }
1372 
1374 {
1375  if (getOutput())
1376  {
1379  }
1380 }
1381 
1382 void MusicPlayer::setVolume(int volume)
1383 {
1384  if (getOutput())
1385  {
1386  getOutput()->SetCurrentVolume(volume);
1388  }
1389 }
1390 
1392 {
1393  if (m_output)
1394  return m_output->GetCurrentVolume();
1395  return 0;
1396 }
1397 
1399 {
1400  if (m_output)
1401  {
1402  m_output->ToggleMute();
1404  }
1405 }
1406 
1408 {
1409  if (m_output)
1410  return m_output->GetMuteState();
1411  return kMuteOff;
1412 }
1413 
1414 void MusicPlayer::toMap(InfoMap &map) const
1415 {
1416  map["volumemute"] = isMuted() ? tr("%1% (Muted)", "Zero Audio Volume").arg(getVolume()) :
1417  QString("%1%").arg(getVolume());
1418  map["volume"] = QString("%1").arg(getVolume());
1419  map["volumepercent"] = QString("%1%").arg(getVolume());
1420  map["mute"] = isMuted() ? tr("Muted") : "";
1421 }
1422 
1423 void MusicPlayer::activePlaylistChanged(int trackID, bool deleted)
1424 {
1425  if (trackID == -1)
1426  {
1427  if (deleted)
1428  {
1430  dispatch(me);
1431  }
1432  else
1433  {
1435  dispatch(me);
1436  }
1437  }
1438  else
1439  {
1440  if (deleted)
1441  {
1443  dispatch(me);
1444  }
1445  else
1446  {
1448  dispatch(me);
1449  }
1450  }
1451 
1452  // if we don't have any tracks to play stop here
1453  if (!getCurrentPlaylist() || getCurrentPlaylist()->getTrackCount() == 0)
1454  {
1455  m_currentTrack = -1;
1456  if (isPlaying())
1457  stop(true);
1458  return;
1459  }
1460 
1461  int trackPos = -1;
1462 
1463  // make sure the current playing track is still valid
1464  if (isPlaying() && getDecoderHandler())
1465  {
1466  for (int x = 0; x < getCurrentPlaylist()->getTrackCount(); x++)
1467  {
1469  {
1470  trackPos = x;
1471  break;
1472  }
1473  }
1474  }
1475 
1476  if (trackPos != m_currentTrack)
1477  m_currentTrack = trackPos;
1478 
1479  if (!getCurrentMetadata())
1480  {
1481  m_currentTrack = -1;
1482  stop(true);
1483  }
1484 }
1485 
1486 void MusicPlayer::playlistChanged(int playlistID)
1487 {
1489  dispatch(me);
1490 }
1491 
1493 {
1496 
1497  // add any listeners to the decoderHandler
1498  {
1499  QMutexLocker locker(m_lock);
1500  // NOLINTNEXTLINE(modernize-loop-convert)
1501  for (auto it = m_listeners.begin(); it != m_listeners.end() ; ++it)
1503  }
1504 }
1505 
1507 {
1508  Decoder *decoder = getDecoder();
1509  if (!decoder)
1510  return;
1511 
1512  LOG(VB_PLAYBACK, LOG_INFO, QString ("decoder handler is ready, decoding %1")
1513  .arg(decoder->getURL()));
1514 
1515 #ifdef HAVE_CDIO
1516  auto *cddecoder = dynamic_cast<CdDecoder*>(decoder);
1517  if (cddecoder)
1518  cddecoder->setDevice(gCDdevice);
1519 #endif
1520 
1521  // Decoder thread can't be running while being initialized
1522  if (decoder->isRunning())
1523  {
1524  decoder->stop();
1525  decoder->wait();
1526  }
1527 
1528  decoder->setOutput(m_output);
1529  //decoder-> setBlockSize(2 * 1024);
1530  decoder->addListener(this);
1531 
1532  // add any listeners to the decoder
1533  {
1534  QMutexLocker locker(m_lock);
1535  // NOLINTNEXTLINE(modernize-loop-convert)
1536  for (auto it = m_listeners.begin(); it != m_listeners.end() ; ++it)
1537  decoder->addListener(*it);
1538  }
1539 
1540  m_currentTime = 0;
1541  m_lastTrackStart = 0;
1542 
1543  // NOLINTNEXTLINE(modernize-loop-convert)
1544  for (auto it = m_visualisers.begin(); it != m_visualisers.end() ; ++it)
1545  {
1546  //m_output->addVisual((MythTV::Visual*)(*it));
1547  //(*it)->setDecoder(decoder);
1548  //m_visual->setOutput(m_output);
1549  }
1550 
1551  if (decoder->initialize())
1552  {
1553  if (m_output)
1555 
1556  decoder->start();
1557 
1559  gCoreContext->GetNumSetting("MusicBookmarkPosition", 0) > 0)
1560  {
1561  seek(gCoreContext->GetNumSetting("MusicBookmarkPosition", 0));
1562  gCoreContext->SaveSetting("MusicBookmarkPosition", 0);
1563  }
1564 
1565  m_isPlaying = true;
1566  m_updatedLastplay = false;
1567  }
1568  else
1569  {
1570  LOG(VB_PLAYBACK, LOG_ERR, QString("Cannot initialise decoder for %1")
1571  .arg(decoder->getURL()));
1572  return;
1573  }
1574 
1575  // tell any listeners we've started playing a new track
1577  dispatch(me);
1578 }
1579 
1580 void MusicPlayer::removeTrack(int trackID)
1581 {
1582  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackID);
1583  if (mdata)
1584  {
1585  int trackPos = getCurrentPlaylist()->getTrackPosition(mdata->ID());
1586  if (m_currentTrack > 0 && m_currentTrack >= trackPos)
1587  m_currentTrack--;
1588 
1589  getCurrentPlaylist()->removeTrack(trackID);
1590  }
1591 }
1592 
1593 void MusicPlayer::addTrack(int trackID, bool updateUI)
1594 {
1595  getCurrentPlaylist()->addTrack(trackID, updateUI);
1596 }
1597 
1599 {
1601  return nullptr;
1602 
1603  if (m_playMode == PLAYMODE_RADIO)
1604  {
1606  }
1608 }
1609 
1611 {
1612  return gMusicData->m_all_streams->getStreams();
1613 }
1614 
1616 {
1617  if (m_notificationMap.find(hostname) == m_notificationMap.end())
1618  m_notificationMap.insert(hostname, GetNotificationCenter()->Register(this));
1619 
1620  return m_notificationMap[hostname];
1621 }
1622 
1623 void MusicPlayer::sendNotification(int notificationID, const QString &title, const QString &author, const QString &desc)
1624 {
1625  QString image = "musicscanner.png";
1626  if (!GetMythUI()->FindThemeFile(image))
1627  LOG(VB_GENERAL, LOG_ERR, "MusicPlayer: sendNotification failed to find the 'musicscanner.png' image");
1628 
1629  DMAP map;
1630  map["asar"] = title;
1631  map["minm"] = author;
1632  map["asal"] = desc;
1633 
1634  auto *n = new MythImageNotification(MythNotification::Info, image, map);
1635 
1636  n->SetId(notificationID);
1637  n->SetParent(this);
1638  n->SetDuration(5);
1639  n->SetFullScreen(false);
1641  delete n;
1642 }
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:35
MusicPlayer::StopPlayback
void StopPlayback(void)
Definition: musicplayer.cpp:532
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:122
DecoderHandlerEvent::BufferStatus
static Type BufferStatus
Definition: decoderhandler.h:49
MusicPlayer::toggleMute
void toggleMute(void)
Definition: musicplayer.cpp:1398
MusicPlayer::openOutputDevice
bool openOutputDevice(void)
Definition: musicplayer.cpp:360
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:522
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:1086
MusicMetadata::Filename
QString Filename(bool find=true)
Definition: musicmetadata.cpp:966
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:288
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:828
METADATA_INVALID_FILENAME
#define METADATA_INVALID_FILENAME
Definition: musicmetadata.h:73
MusicMetadata::incPlayCount
void incPlayCount()
Definition: musicmetadata.cpp:1198
MusicPlayer::m_bufferSize
int m_bufferSize
Definition: musicplayer.h:249
MusicPlayer::setCurrentTrackPos
bool setCurrentTrackPos(int pos)
Definition: musicplayer.cpp:1034
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
MusicPlayer::setVolume
void setVolume(int volume)
Definition: musicplayer.cpp:1382
MusicPlayer::toMap
void toMap(InfoMap &infoMap) const
Definition: musicplayer.cpp:1414
mythdb.h
VolumeBase::AdjustCurrentVolume
virtual void AdjustCurrentVolume(int change)
Definition: volumebase.cpp:131
MusicPlayer::sendNotification
void sendNotification(int notificationID, const QString &title, const QString &author, const QString &desc)
Definition: musicplayer.cpp:1623
MusicPlayer::RESUME_TRACK
@ RESUME_TRACK
Definition: musicplayer.h:175
VolumeBase::GetCurrentVolume
virtual uint GetCurrentVolume(void) const
Definition: volumebase.cpp:117
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:963
MusicPlayerEvent
Definition: musicplayer.h:22
AudioOutput::Reset
virtual void Reset(void)=0
MusicPlayer::loadStreamPlaylist
void loadStreamPlaylist(void)
Definition: musicplayer.cpp:995
decoderhandler.h
title
QString title
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:636
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:278
Playlist::shuffleTracks
void shuffleTracks(MusicPlayer::ShuffleMode mode)
Definition: playlist.cpp:152
MusicPlayer::decVolume
void decVolume(void)
Definition: musicplayer.cpp:1373
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:1240
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:1610
MusicPlayerEvent::MetadataChangedEvent
static Type MetadataChangedEvent
Definition: musicplayer.h:46
MusicPlayer::getMuteState
MuteState getMuteState(void) const
Definition: musicplayer.cpp:1407
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:45
DecoderHandlerEvent::Meta
static Type Meta
Definition: decoderhandler.h:48
MusicPlayer::getCurrentPlaylist
Playlist * getCurrentPlaylist(void)
Definition: musicplayer.cpp:1598
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:1106
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:42
MusicMetadata::persist
void persist(void)
Definition: musicmetadata.cpp:179
MusicMetadata::Artist
QString Artist() const
Definition: musicmetadata.h:126
MusicPlayer::setPlayMode
void setPlayMode(PlayMode mode)
Definition: musicplayer.cpp:951
MusicPlayer::pause
void pause(void)
Definition: musicplayer.cpp:286
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &stackname)
Definition: mythmainwindow.cpp:329
MusicPlayer::updateVolatileMetadata
void updateVolatileMetadata(void)
Definition: musicplayer.cpp:1280
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:56
MusicPlayer::changeCurrentTrack
void changeCurrentTrack(int trackNo)
change the current track to the given track
Definition: musicplayer.cpp:1135
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:47
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MusicPlayer::sendTrackStatsChangedEvent
void sendTrackStatsChangedEvent(int trackID)
Definition: musicplayer.cpp:1340
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:1157
MusicPlayer::getNotificationID
int getNotificationID(const QString &hostname)
Definition: musicplayer.cpp:1615
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)
Unregister sender from being called when TVPlaybackAboutToStart signal is emitted.
Definition: mythcorecontext.cpp:1939
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:1194
DecoderHandlerEvent
Events sent by the DecoderHandler and it's helper classes.
Definition: decoderhandler.h:27
Decoder
Definition: decoder.h:66
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:1364
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:143
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:1213
MusicPlayer::m_currentTrack
int m_currentTrack
Definition: musicplayer.h:212
Playlist::removeTrack
void removeTrack(MusicMetadata::IdType trackID)
Definition: playlist.cpp:114
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:50
MusicPlayer::setupDecoderHandler
void setupDecoderHandler(void)
Definition: musicplayer.cpp:1492
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:486
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:149
MusicPlayer::sendTrackUnavailableEvent
void sendTrackUnavailableEvent(int trackID)
Definition: musicplayer.cpp:1352
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:60
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:637
MusicPlayer::stopDecoder
void stopDecoder(void)
Definition: musicplayer.cpp:354
MusicPlayer::m_shuffleMode
ShuffleMode m_shuffleMode
Definition: musicplayer.h:233
MusicPlayer::incSpeed
void incSpeed()
Definition: musicplayer.cpp:1316
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
MythCoreContext::RegisterForPlayback
void RegisterForPlayback(QObject *sender, PlaybackStartCb method)
Register sender for TVPlaybackAboutToStart signal.
Definition: mythcorecontext.cpp:1918
MusicPlayer::m_autoShowPlayer
bool m_autoShowPlayer
Definition: musicplayer.h:226
MusicPlayer::SHUFFLE_ARTIST
@ SHUFFLE_ARTIST
Definition: musicplayer.h:168
MusicPlayer::savePosition
void savePosition(void)
Definition: musicplayer.cpp:1049
MusicMetadata::setFilename
void setFilename(const QString &lfilename)
Definition: musicmetadata.cpp:960
kMuteOff
@ kMuteOff
Definition: volumebase.h:7
MythObservable::hasListeners
bool hasListeners(void)
Definition: mythobservable.h:23
Decoder::getURL
QString getURL(void) const
Definition: decoder.h:86
MusicPlayer::playlistChanged
void playlistChanged(int playlistID)
Definition: musicplayer.cpp:1486
MusicPlayer::sendMetadataChangedEvent
void sendMetadataChangedEvent(int trackID)
Definition: musicplayer.cpp:1334
MusicPlayer::hasClient
bool hasClient(void)
Definition: musicplayer.h:105
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1633
uint
unsigned int uint
Definition: compat.h:141
MusicPlayer::removeTrack
void removeTrack(int trackID)
Definition: musicplayer.cpp:1580
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MusicData::m_all_playlists
PlaylistContainer * m_all_playlists
Definition: musicdata.h:54
MusicPlayer::next
void next(void)
Definition: musicplayer.cpp:418
MusicPlayer::isPaused
bool isPaused(void)
Definition: musicplayer.h:103
CdDecoder::setDevice
void setDevice(const QString &dev)
Definition: cddecoder.cpp:106
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:1269
MusicPlayer::showMiniPlayer
void showMiniPlayer(void) const
Definition: musicplayer.cpp:1118
MusicPlayer
Definition: musicplayer.h:55
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:933
musicdata.h
MythCoreContext::TVPlaybackAborted
void TVPlaybackAborted(void)
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:927
Playlist::moveTrackUpDown
void moveTrackUpDown(bool flag, int where_its_at)
Definition: playlist.cpp:125
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:1169
mthreadpool.h
DecoderHandlerEvent::Error
static Type Error
Definition: decoderhandler.h:52
mythuihelper.h
MainVisual
Definition: mainvisual.h:33
MusicPlayer::decoderHandlerReady
void decoderHandlerReady(void)
Definition: musicplayer.cpp:1506
MusicPlayer::previous
void previous(void)
Definition: musicplayer.cpp:455
Decoder::initialize
virtual bool initialize()=0
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:2036
MusicMetadata::reloadMetadata
void reloadMetadata(void)
Definition: musicmetadata.cpp:432
MusicMetadata::dumpToDatabase
void dumpToDatabase(void)
Definition: musicmetadata.cpp:672
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:1322
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:1423
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:1307
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:1593
MusicPlayer::SHUFFLE_ALBUM
@ SHUFFLE_ALBUM
Definition: musicplayer.h:167
AudioOutput::SetStretchFactor
virtual void SetStretchFactor(float factor)
Definition: audiooutput.cpp:251
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:543
MiniPlayer
Definition: miniplayer.h:11
MusicPlayer::isMuted
bool isMuted(void) const
Definition: musicplayer.h:82
GetNotificationCenter
MythNotificationCenter * GetNotificationCenter(void)
Definition: mythmainwindow.cpp:128
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:1328
mainvisual.h
MusicPlayer::~MusicPlayer
~MusicPlayer(void) override
Definition: musicplayer.cpp:86
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:108
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:268
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:1346
MusicPlayer::m_oneshotMetadata
MusicMetadata * m_oneshotMetadata
Definition: musicplayer.h:215
MusicPlayer::play
void play(void)
Definition: musicplayer.cpp:305
MusicPlayer::restorePosition
void restorePosition(void)
Definition: musicplayer.cpp:1066
MusicMetadata::setLastPlay
void setLastPlay()
Definition: musicmetadata.cpp:1192
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:1358
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:859
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:84
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::TVPlaybackStopped
void TVPlaybackStopped(void)
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:902
MThread::wait
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:305
DMAP
QMap< QString, QString > DMAP
Definition: mythnotification.h:23
MusicPlayer::getBufferStatus
void getBufferStatus(int *bufferAvailable, int *bufferSize) const
Definition: musicplayer.cpp:945
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
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:306
mythmainwindow.h
MusicPlayer::getVolume
uint getVolume(void) const
Definition: musicplayer.cpp:1391
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
MythCoreContext::dispatch
void dispatch(const MythEvent &event)
Definition: mythcorecontext.cpp:1734
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:557
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:341
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
MythMainWindow::PauseIdleTimer
void PauseIdleTimer(bool Pause)
Pause the idle timeout timer.
Definition: mythmainwindow.cpp:2198
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:919
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:1016