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