00001
00002 #include <cstdlib>
00003
00004
00005 #include <QApplication>
00006 #include <QWidget>
00007 #include <QFile>
00008 #include <QList>
00009 #include <QDir>
00010
00011
00012 #include <mythcontext.h>
00013 #include <audiooutput.h>
00014 #include <mythdb.h>
00015 #include <mythdialogbox.h>
00016 #include <mythmainwindow.h>
00017
00018
00019 #include "musicplayer.h"
00020 #include "decoder.h"
00021 #include "decoderhandler.h"
00022 #ifdef HAVE_CDIO
00023 #include "cddecoder.h"
00024 #endif
00025 #include "constants.h"
00026 #include "mainvisual.h"
00027 #include "miniplayer.h"
00028 #include "playlistcontainer.h"
00029
00030
00031 #define LASTPLAY_DELAY 15
00032
00033 MusicPlayer *gPlayer = NULL;
00034
00036
00037 QEvent::Type MusicPlayerEvent::TrackChangeEvent = (QEvent::Type) QEvent::registerEventType();
00038 QEvent::Type MusicPlayerEvent::VolumeChangeEvent = (QEvent::Type) QEvent::registerEventType();
00039 QEvent::Type MusicPlayerEvent::TrackAddedEvent = (QEvent::Type) QEvent::registerEventType();
00040 QEvent::Type MusicPlayerEvent::TrackRemovedEvent = (QEvent::Type) QEvent::registerEventType();
00041 QEvent::Type MusicPlayerEvent::AllTracksRemovedEvent = (QEvent::Type) QEvent::registerEventType();
00042 QEvent::Type MusicPlayerEvent::MetadataChangedEvent = (QEvent::Type) QEvent::registerEventType();
00043 QEvent::Type MusicPlayerEvent::TrackStatsChangedEvent = (QEvent::Type) QEvent::registerEventType();
00044 QEvent::Type MusicPlayerEvent::AlbumArtChangedEvent = (QEvent::Type) QEvent::registerEventType();
00045 QEvent::Type MusicPlayerEvent::CDChangedEvent = (QEvent::Type) QEvent::registerEventType();
00046 QEvent::Type MusicPlayerEvent::PlaylistChangedEvent = (QEvent::Type) QEvent::registerEventType();
00047
00048 MusicPlayer::MusicPlayer(QObject *parent, const QString &dev)
00049 :QObject(parent)
00050 {
00051 setObjectName("MusicPlayer");
00052
00053 m_CDdevice = dev;
00054 m_output = NULL;
00055 m_decoderHandler = NULL;
00056 m_cdWatcher = NULL;
00057 m_currentPlaylist = NULL;
00058 m_currentTrack = -1;
00059
00060 m_currentTime = 0;
00061 m_lastTrackStart = 0;
00062
00063 m_currentMetadata = NULL;
00064 m_oneshotMetadata = NULL;
00065
00066 m_isAutoplay = false;
00067 m_isPlaying = false;
00068 m_isStreaming = false;
00069 m_canShowPlayer = true;
00070 m_wasPlaying = true;
00071 m_updatedLastplay = false;
00072 m_allowRestorePos = true;
00073
00074 m_playSpeed = 1.0;
00075
00076 QString playmode = gCoreContext->GetSetting("PlayMode", "none");
00077 if (playmode.toLower() == "random")
00078 setShuffleMode(SHUFFLE_RANDOM);
00079 else if (playmode.toLower() == "intelligent")
00080 setShuffleMode(SHUFFLE_INTELLIGENT);
00081 else if (playmode.toLower() == "album")
00082 setShuffleMode(SHUFFLE_ALBUM);
00083 else if (playmode.toLower() == "artist")
00084 setShuffleMode(SHUFFLE_ARTIST);
00085 else
00086 setShuffleMode(SHUFFLE_OFF);
00087
00088 QString repeatmode = gCoreContext->GetSetting("RepeatMode", "all");
00089 if (repeatmode.toLower() == "track")
00090 setRepeatMode(REPEAT_TRACK);
00091 else if (repeatmode.toLower() == "all")
00092 setRepeatMode(REPEAT_ALL);
00093 else
00094 setRepeatMode(REPEAT_OFF);
00095
00096 loadSettings();
00097
00098 gCoreContext->addListener(this);
00099 }
00100
00101 MusicPlayer::~MusicPlayer()
00102 {
00103 if (m_cdWatcher)
00104 {
00105 m_cdWatcher->stop();
00106 m_cdWatcher->wait();
00107 delete m_cdWatcher;
00108 }
00109
00110 if (!hasClient())
00111 savePosition();
00112
00113 gCoreContext->removeListener(this);
00114
00115 stop(true);
00116
00117 if (m_decoderHandler)
00118 {
00119 m_decoderHandler->removeListener(this);
00120 m_decoderHandler->deleteLater();
00121 m_decoderHandler = NULL;
00122 }
00123
00124 if (m_oneshotMetadata)
00125 {
00126 delete m_oneshotMetadata;
00127 m_oneshotMetadata = NULL;
00128 }
00129
00130 if (m_shuffleMode == SHUFFLE_INTELLIGENT)
00131 gCoreContext->SaveSetting("PlayMode", "intelligent");
00132 else if (m_shuffleMode == SHUFFLE_RANDOM)
00133 gCoreContext->SaveSetting("PlayMode", "random");
00134 else if (m_shuffleMode == SHUFFLE_ALBUM)
00135 gCoreContext->SaveSetting("PlayMode", "album");
00136 else if (m_shuffleMode == SHUFFLE_ARTIST)
00137 gCoreContext->SaveSetting("PlayMode", "artist");
00138 else
00139 gCoreContext->SaveSetting("PlayMode", "none");
00140
00141 if (m_repeatMode == REPEAT_TRACK)
00142 gCoreContext->SaveSetting("RepeatMode", "track");
00143 else if (m_repeatMode == REPEAT_ALL)
00144 gCoreContext->SaveSetting("RepeatMode", "all");
00145 else
00146 gCoreContext->SaveSetting("RepeatMode", "none");
00147
00148 gCoreContext->SaveSetting("MusicAutoShowPlayer",
00149 (m_autoShowPlayer ? "1" : "0"));
00150 }
00151
00152 void MusicPlayer::addListener(QObject *listener)
00153 {
00154 if (listener && m_output)
00155 m_output->addListener(listener);
00156
00157 if (listener && getDecoder())
00158 getDecoder()->addListener(listener);
00159
00160 if (listener && m_decoderHandler)
00161 m_decoderHandler->addListener(listener);
00162
00163 MythObservable::addListener(listener);
00164
00165 m_isAutoplay = !hasListeners();
00166 }
00167
00168 void MusicPlayer::removeListener(QObject *listener)
00169 {
00170 if (listener && m_output)
00171 m_output->removeListener(listener);
00172
00173 if (listener && getDecoder())
00174 getDecoder()->removeListener(listener);
00175
00176 if (listener && m_decoderHandler)
00177 m_decoderHandler->removeListener(listener);
00178
00179 MythObservable::removeListener(listener);
00180
00181 m_isAutoplay = !hasListeners();
00182 }
00183
00184 void MusicPlayer::addVisual(MainVisual *visual)
00185 {
00186 if (visual && !m_visualisers.contains(visual))
00187 {
00188 if (m_output)
00189 {
00190 m_output->addListener(visual);
00191 m_output->addVisual(visual);
00192 }
00193
00194 m_visualisers.insert(visual);
00195 }
00196 }
00197
00198 void MusicPlayer::removeVisual(MainVisual *visual)
00199 {
00200 if (visual)
00201 {
00202 if (m_output)
00203 {
00204 m_output->removeListener(visual);
00205 m_output->removeVisual(visual);
00206 }
00207
00208 m_visualisers.remove(visual);
00209 }
00210 }
00211
00212 void MusicPlayer::loadSettings(void )
00213 {
00214 QString resumestring = gCoreContext->GetSetting("ResumeMode", "off");
00215 if (resumestring.toLower() == "off")
00216 m_resumeMode = RESUME_OFF;
00217 else if (resumestring.toLower() == "track")
00218 m_resumeMode = RESUME_TRACK;
00219 else
00220 m_resumeMode = RESUME_EXACT;
00221
00222 m_lastplayDelay = gCoreContext->GetNumSetting("MusicLastPlayDelay", LASTPLAY_DELAY);
00223
00224 m_autoShowPlayer = (gCoreContext->GetNumSetting("MusicAutoShowPlayer", 1) > 0);
00225
00226
00227 bool checkCD = gCoreContext->GetNumSetting("AutoLookupCD");
00228 if (checkCD)
00229 {
00230 m_cdWatcher = new CDWatcherThread(m_CDdevice);
00231
00232
00233 }
00234 }
00235
00236
00237 void MusicPlayer::playFile(const Metadata &mdata)
00238 {
00239 if (m_oneshotMetadata)
00240 {
00241 delete m_oneshotMetadata;
00242 m_oneshotMetadata = NULL;
00243 }
00244
00245 m_oneshotMetadata = new Metadata();
00246 *m_oneshotMetadata = mdata;
00247
00248 play();
00249 }
00250
00251 void MusicPlayer::stop(bool stopAll)
00252 {
00253 stopDecoder();
00254
00255 if (m_output)
00256 {
00257 if (m_output->IsPaused())
00258 pause();
00259 m_output->Reset();
00260 }
00261
00262 m_isPlaying = false;
00263
00264 if (stopAll && getDecoder())
00265 {
00266 getDecoder()->removeListener(this);
00267
00268
00269 {
00270 QMutexLocker locker(m_lock);
00271 QSet<QObject*>::const_iterator it = m_listeners.begin();
00272 for (; it != m_listeners.end() ; ++it)
00273 {
00274 getDecoder()->removeListener(*it);
00275 }
00276 }
00277 }
00278
00279 if (stopAll && m_output)
00280 {
00281 m_output->removeListener(this);
00282 delete m_output;
00283 m_output = NULL;
00284 }
00285
00286
00287
00288 OutputEvent oe(OutputEvent::Stopped);
00289 dispatch(oe);
00290
00291 GetMythMainWindow()->PauseIdleTimer(false);
00292 }
00293
00294 void MusicPlayer::pause(void)
00295 {
00296 if (m_output)
00297 {
00298 m_isPlaying = !m_isPlaying;
00299 m_output->Pause(!m_isPlaying);
00300 }
00301
00302 if (getDecoder())
00303 {
00304 getDecoder()->lock();
00305 getDecoder()->cond()->wakeAll();
00306 getDecoder()->unlock();
00307 }
00308
00309 GetMythMainWindow()->PauseIdleTimer(false);
00310 }
00311
00312 void MusicPlayer::play(void)
00313 {
00314 Metadata *meta = getCurrentMetadata();
00315 if (!meta)
00316 return;
00317
00318 stopDecoder();
00319
00320
00321 if (!m_output)
00322 {
00323 if (!openOutputDevice())
00324 return;
00325 }
00326
00327 if (!getDecoderHandler())
00328 setupDecoderHandler();
00329
00330 getDecoderHandler()->start(meta);
00331
00332 m_isStreaming = (meta->Format() == "cast");
00333
00334 GetMythMainWindow()->PauseIdleTimer(true);
00335 }
00336
00337 void MusicPlayer::stopDecoder(void)
00338 {
00339 if (getDecoderHandler())
00340 getDecoderHandler()->stop();
00341 }
00342
00343 bool MusicPlayer::openOutputDevice(void)
00344 {
00345 QString adevice, pdevice;
00346
00347 if (gCoreContext->GetSetting("MusicAudioDevice") == "default")
00348 adevice = gCoreContext->GetSetting("AudioOutputDevice");
00349 else
00350 adevice = gCoreContext->GetSetting("MusicAudioDevice");
00351
00352 pdevice = gCoreContext->GetNumSetting("PassThruDeviceOverride", false) ?
00353 gCoreContext->GetSetting("PassThruOutputDevice") : "auto";
00354
00355 m_output = AudioOutput::OpenAudio(
00356 adevice, pdevice, FORMAT_S16, 2, 0, 44100,
00357 AUDIOOUTPUT_MUSIC, true, false,
00358 gCoreContext->GetNumSetting("MusicDefaultUpmix", 0) + 1);
00359
00360 if (!m_output)
00361 {
00362 LOG(VB_GENERAL, LOG_ERR,
00363 QString("MusicPlayer: Cannot open audio output device: %1").arg(adevice));
00364
00365 return false;
00366 }
00367
00368 if (!m_output->GetError().isEmpty())
00369 {
00370 LOG(VB_GENERAL, LOG_ERR,
00371 QString("MusicPlayer: Cannot open audio output device: %1").arg(adevice));
00372 LOG(VB_GENERAL, LOG_ERR,
00373 QString("Error was: %1").arg(m_output->GetError()));
00374
00375 delete m_output;
00376 m_output = NULL;
00377
00378 return false;
00379 }
00380
00381 m_output->setBufferSize(256 * 1024);
00382
00383 m_output->addListener(this);
00384
00385
00386 QSet<QObject*>::const_iterator it = m_visualisers.begin();
00387
00388 for (; it != m_visualisers.end() ; ++it)
00389 {
00390 m_output->addVisual((MythTV::Visual*)(*it));
00391 }
00392
00393
00394 QMutexLocker locker(m_lock);
00395 it = m_listeners.begin();
00396 for (; it != m_listeners.end() ; ++it)
00397 {
00398 m_output->addListener(*it);
00399 }
00400
00401 return true;
00402 }
00403
00404 void MusicPlayer::next(void)
00405 {
00406 int currentTrack = m_currentTrack;
00407
00408 if (!m_currentPlaylist)
00409 return;
00410
00411 if (m_oneshotMetadata)
00412 {
00413 delete m_oneshotMetadata;
00414 m_oneshotMetadata = NULL;
00415 }
00416 else
00417 currentTrack++;
00418
00419 if (currentTrack >= m_currentPlaylist->getSongs().size())
00420 {
00421 if (m_repeatMode == REPEAT_ALL)
00422 {
00423
00424 currentTrack = 0;
00425 }
00426 else
00427 {
00428 stop();
00429 return;
00430 }
00431 }
00432
00433 changeCurrentTrack(currentTrack);
00434
00435 if (m_currentMetadata)
00436 play();
00437 else
00438 stop();
00439 }
00440
00441 void MusicPlayer::previous(void)
00442 {
00443 int currentTrack = m_currentTrack;
00444
00445 if (!m_currentPlaylist)
00446 return;
00447
00448 if (m_oneshotMetadata)
00449 {
00450 delete m_oneshotMetadata;
00451 m_oneshotMetadata = NULL;
00452 }
00453 else
00454 currentTrack--;
00455
00456 if (currentTrack >= 0)
00457 {
00458 changeCurrentTrack(currentTrack);
00459
00460 if (m_currentMetadata)
00461 play();
00462 else
00463 return;
00464 }
00465 else
00466 {
00467
00468 return;
00469 }
00470 }
00471
00472 void MusicPlayer::nextAuto(void)
00473 {
00474 if (!m_currentPlaylist)
00475 return;
00476
00477 if (m_oneshotMetadata)
00478 {
00479 delete m_oneshotMetadata;
00480 m_oneshotMetadata = NULL;
00481 play();
00482 return;
00483 }
00484
00485 if (m_repeatMode == REPEAT_TRACK)
00486 {
00487 play();
00488 return;
00489 }
00490 else
00491 {
00492 if (!m_decoderHandler->next())
00493 next();
00494 }
00495
00496
00497 if (m_isAutoplay && m_canShowPlayer && m_autoShowPlayer)
00498 {
00499 MythScreenStack *popupStack =
00500 GetMythMainWindow()->GetStack("popup stack");
00501
00502 MiniPlayer *miniplayer = new MiniPlayer(popupStack);
00503
00504 if (miniplayer->Create())
00505 popupStack->AddScreen(miniplayer);
00506 else
00507 delete miniplayer;
00508 }
00509 }
00510
00511 void MusicPlayer::customEvent(QEvent *event)
00512 {
00513
00514 if (event->type() == DecoderHandlerEvent::Ready)
00515 {
00516 decoderHandlerReady();
00517 }
00518 else if (event->type() == DecoderHandlerEvent::OperationStart)
00519 {
00520 }
00521 else if (event->type() == DecoderHandlerEvent::OperationStop)
00522 {
00523 }
00524 else if (event->type() == DecoderHandlerEvent::Info)
00525 {
00526 DecoderHandlerEvent *dxe = dynamic_cast<DecoderHandlerEvent*>(event);
00527 if (!dxe)
00528 return;
00529
00530 if (getCurrentMetadata())
00531 m_displayMetadata = *getCurrentMetadata();
00532 m_displayMetadata.setArtist("");
00533 m_displayMetadata.setTitle(*dxe->getMessage());
00534 }
00535 else if (event->type() == DecoderHandlerEvent::Error)
00536 {
00537 }
00538 else if (event->type() == DecoderHandlerEvent::Meta)
00539 {
00540 DecoderHandlerEvent *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
00541 if (!dhe)
00542 return;
00543
00544 Metadata mdata(*dhe->getMetadata());
00545
00546 if (!m_playedList.isEmpty())
00547 m_playedList.last().setLength((m_currentTime - m_lastTrackStart) * 1000);
00548 m_lastTrackStart = m_currentTime;
00549
00550 mdata.setTrack(m_playedList.count() + 1);
00551
00552 m_playedList.append(mdata);
00553 m_currentMetadata = &m_playedList.last();
00554
00555 if (m_isAutoplay && m_canShowPlayer && m_autoShowPlayer)
00556 {
00557 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00558
00559 MiniPlayer *miniplayer = new MiniPlayer(popupStack);
00560
00561 if (miniplayer->Create())
00562 popupStack->AddScreen(miniplayer);
00563 else
00564 delete miniplayer;
00565 }
00566
00567
00568 MusicPlayerEvent me(MusicPlayerEvent::TrackChangeEvent, -1);
00569 dispatch(me);
00570 }
00571
00572
00573 else if (event->type() == DecoderEvent::Decoding)
00574 {
00575 if (getCurrentMetadata())
00576 m_displayMetadata = *getCurrentMetadata();
00577 }
00578
00579
00580 else if (event->type() == MythEvent::MythEventMessage)
00581 {
00582 MythEvent *me = dynamic_cast<MythEvent*>(event);
00583
00584 if (!me)
00585 return;
00586
00587 if (me->Message().left(14) == "PLAYBACK_START")
00588 {
00589 m_wasPlaying = m_isPlaying;
00590 QString hostname = me->Message().mid(15);
00591
00592 if (hostname == gCoreContext->GetHostName())
00593 {
00594 if (m_isPlaying)
00595 savePosition();
00596 stop(true);
00597 }
00598 }
00599 else if (me->Message().left(12) == "PLAYBACK_END")
00600 {
00601 if (m_wasPlaying)
00602 {
00603 QString hostname = me->Message().mid(13);
00604 if (hostname == gCoreContext->GetHostName())
00605 {
00606 play();
00607 seek(gCoreContext->GetNumSetting(
00608 "MusicBookmarkPosition", 0));
00609 gCoreContext->SaveSetting("MusicBookmark", "");
00610 gCoreContext->SaveSetting("MusicBookmarkPosition", 0);
00611 }
00612
00613 m_wasPlaying = false;
00614 }
00615 }
00616 else if (me->Message().left(13) == "MUSIC_COMMAND")
00617 {
00618 QStringList list = me->Message().simplified().split(' ');
00619
00620 if (list.size() >= 3 && list[1] == gCoreContext->GetHostName())
00621 {
00622 if (list[2] == "PLAY")
00623 play();
00624 else if (list[2] == "STOP")
00625 stop();
00626 else if (list[2] == "PAUSE")
00627 pause();
00628 else if (list[2] == "SET_VOLUME")
00629 {
00630 if (list.size() >= 3)
00631 {
00632 int volume = list[3].toInt();
00633 if (volume >= 0 && volume <= 100)
00634 setVolume(volume);
00635 }
00636 }
00637 else if (list[2] == "GET_VOLUME")
00638 {
00639 QString message = QString("MUSIC_CONTROL ANSWER %1 %2")
00640 .arg(gCoreContext->GetHostName()).arg(getVolume());
00641 MythEvent me(message);
00642 gCoreContext->dispatch(me);
00643 }
00644 else if (list[2] == "PLAY_FILE")
00645 {
00646 int start = me->Message().indexOf("'");
00647 int end = me->Message().lastIndexOf("'");
00648
00649 if (start != -1 && end != -1 && start != end)
00650 {
00651 QString filename = me->Message().mid(start + 1, end - start - 1);
00652 Metadata mdata;
00653 mdata.setFilename(filename);
00654 playFile(mdata);
00655 }
00656 else
00657 LOG(VB_GENERAL, LOG_ERR,
00658 QString("MusicPlayer: got invalid MUSIC_COMMAND "
00659 "PLAY_FILE - %1").arg(me->Message()));
00660 }
00661 else if (list[2] == "PLAY_URL")
00662 {
00663 if (list.size() == 4)
00664 {
00665 QString filename = list[3];
00666 Metadata mdata;
00667 mdata.setFilename(filename);
00668 playFile(mdata);
00669 }
00670 else
00671 LOG(VB_GENERAL, LOG_ERR,
00672 QString("MusicPlayer: got invalid MUSIC_COMMAND "
00673 "PLAY_URL - %1").arg(me->Message()));
00674 }
00675 else if (list[2] == "PLAY_TRACK")
00676 {
00677 if (list.size() == 4)
00678 {
00679 int trackID = list[3].toInt();
00680 Metadata *mdata = gMusicData->all_music->getMetadata(trackID);
00681 if (mdata)
00682 playFile(*mdata);
00683 }
00684 else
00685 LOG(VB_GENERAL, LOG_ERR,
00686 QString("MusicPlayer: got invalid MUSIC_COMMAND "
00687 "PLAY_TRACK - %1").arg(me->Message()));
00688 }
00689 else if (list[2] == "GET_METADATA")
00690 {
00691 QString mdataStr;
00692 Metadata *mdata = getCurrentMetadata();
00693 if (mdata)
00694 mdataStr = QString("%1 by %2 from %3").arg(mdata->Title()).arg(mdata->Artist()).arg(mdata->Album());
00695 else
00696 mdataStr = "Unknown Track2";
00697
00698 QString message = QString("MUSIC_CONTROL ANSWER %1 %2")
00699 .arg(gCoreContext->GetHostName()).arg(mdataStr);
00700 MythEvent me(message);
00701 gCoreContext->dispatch(me);
00702 }
00703 }
00704 else
00705 LOG(VB_GENERAL, LOG_ERR,
00706 QString("MusicPlayer: got unknown/invalid MUSIC_COMMAND "
00707 "- %1").arg(me->Message()));
00708 }
00709 else if (me->Message().startsWith("MUSIC_SETTINGS_CHANGED"))
00710 {
00711 QString startdir = gCoreContext->GetSetting("MusicLocation");
00712 startdir = QDir::cleanPath(startdir);
00713 if (!startdir.isEmpty() && !startdir.endsWith("/"))
00714 startdir += "/";
00715
00716 gMusicData->musicDir = startdir;
00717
00718 loadSettings();
00719 }
00720 }
00721
00722 if (m_isAutoplay)
00723 {
00724 if (event->type() == OutputEvent::Error)
00725 {
00726 OutputEvent *aoe = dynamic_cast<OutputEvent*>(event);
00727
00728 if (!aoe)
00729 return;
00730
00731 LOG(VB_GENERAL, LOG_ERR, QString("Output Error - %1")
00732 .arg(*aoe->errorMessage()));
00733
00734 ShowOkPopup(QString("MythMusic has encountered the following error:\n%1")
00735 .arg(*aoe->errorMessage()));
00736 stop(true);
00737 }
00738 else if (event->type() == DecoderEvent::Error)
00739 {
00740 stop(true);
00741
00742 QApplication::sendPostedEvents();
00743
00744 DecoderEvent *dxe = dynamic_cast<DecoderEvent*>(event);
00745
00746 if (!dxe)
00747 return;
00748
00749 LOG(VB_GENERAL, LOG_ERR, QString("Decoder Error - %1")
00750 .arg(*dxe->errorMessage()));
00751 ShowOkPopup(QString("MythMusic has encountered the following error:\n%1")
00752 .arg(*dxe->errorMessage()));
00753 }
00754 }
00755
00756 if (event->type() == OutputEvent::Info)
00757 {
00758 OutputEvent *oe = dynamic_cast<OutputEvent*>(event);
00759
00760 if (!oe)
00761 return;
00762
00763 m_currentTime = oe->elapsedSeconds();
00764
00765 if (!m_updatedLastplay)
00766 {
00767
00768
00769 if ((m_currentMetadata && m_currentTime >
00770 (m_currentMetadata->Length() / 1000) / 2) ||
00771 m_currentTime >= m_lastplayDelay)
00772 {
00773 updateLastplay();
00774 }
00775 }
00776 }
00777 else if (event->type() == DecoderEvent::Finished)
00778 {
00779 if (m_currentMetadata && m_currentTime != m_currentMetadata->Length() / 1000)
00780 {
00781 LOG(VB_GENERAL, LOG_NOTICE, QString("MusicPlayer: Updating track length was %1s, should be %2s")
00782 .arg(m_currentMetadata->Length() / 1000).arg(m_currentTime));
00783
00784 m_currentMetadata->setLength(m_currentTime * 1000);
00785 m_currentMetadata->dumpToDatabase();
00786
00787
00788 gPlayer->sendMetadataChangedEvent(m_currentMetadata->ID());
00789
00790
00791 MusicPlayerEvent me(MusicPlayerEvent::TrackChangeEvent, m_currentTrack);
00792 dispatch(me);
00793 }
00794 nextAuto();
00795 }
00796 else if (event->type() == DecoderEvent::Stopped)
00797 {
00798 }
00799
00800 QObject::customEvent(event);
00801 }
00802
00803 void MusicPlayer::switchPlayMode(bool playStreams)
00804 {
00805 savePosition();
00806
00807 m_isStreaming = playStreams;
00808
00809 loadPlaylist();
00810 }
00811
00812 void MusicPlayer::loadPlaylist(void)
00813 {
00814 if (m_isStreaming)
00815 {
00816 m_currentPlaylist = gMusicData->all_playlists->getStreamPlaylist();
00817
00818 if (getResumeMode() > MusicPlayer::RESUME_OFF)
00819 {
00820 int bookmark = gCoreContext->GetNumSetting("MusicStreamBookmark", 0);
00821 if (bookmark < 0 || bookmark >= m_currentPlaylist->getSongs().size())
00822 bookmark = 0;
00823
00824 m_currentTrack = bookmark;
00825 }
00826 else
00827 m_currentTrack = 0;
00828
00829 setShuffleMode(SHUFFLE_OFF);
00830 }
00831 else
00832 {
00833 m_currentPlaylist = gMusicData->all_playlists->getActive();
00834
00835 if (getResumeMode() > MusicPlayer::RESUME_OFF)
00836 {
00837 int bookmark = gCoreContext->GetNumSetting("MusicBookmark", 0);
00838 if (bookmark < 0 || bookmark >= m_currentPlaylist->getSongs().size())
00839 bookmark = 0;
00840
00841 m_currentTrack = bookmark;
00842 }
00843 else
00844 m_currentTrack = 0;
00845 }
00846
00847 m_currentMetadata = NULL;
00848
00849
00850 if (m_cdWatcher)
00851 m_cdWatcher->start();
00852 }
00853
00854 void MusicPlayer::moveTrackUpDown(bool moveUp, int whichTrack)
00855 {
00856 if (moveUp && whichTrack <= 0)
00857 return;
00858
00859 if (!moveUp && whichTrack >= m_currentPlaylist->getSongs().size() - 1)
00860 return;
00861
00862 Metadata *currTrack = m_currentPlaylist->getSongs().at(m_currentTrack);
00863
00864 m_currentPlaylist->moveTrackUpDown(moveUp, whichTrack);
00865
00866 m_currentTrack = m_currentPlaylist->getSongs().indexOf(currTrack);
00867 }
00868
00869 bool MusicPlayer::setCurrentTrackPos(int pos)
00870 {
00871 changeCurrentTrack(pos);
00872
00873 if (!m_currentMetadata)
00874 {
00875 stop();
00876 return false;
00877 }
00878
00879 play();
00880
00881 return true;
00882 }
00883
00884 void MusicPlayer::savePosition(void)
00885 {
00886 if (m_isStreaming || !m_currentMetadata)
00887 {
00888
00889 gCoreContext->SaveSetting("MusicBookmark", -1);
00890 gCoreContext->SaveSetting("MusicBookmarkPosition", 0);
00891 }
00892 else
00893 {
00894 gCoreContext->SaveSetting("MusicBookmark", m_currentMetadata->ID());
00895 gCoreContext->SaveSetting("MusicBookmarkPosition", m_currentTime);
00896 }
00897 }
00898
00899 void MusicPlayer::restorePosition(void)
00900 {
00901
00902 if (!m_allowRestorePos)
00903 return;
00904
00905 m_currentTrack = 0;
00906 uint trackID = 0;
00907
00908 if (gPlayer->getResumeMode() > MusicPlayer::RESUME_OFF)
00909 {
00910 trackID = gCoreContext->GetNumSetting("MusicBookmark", 0);
00911
00912 for (int x = 0; x < m_currentPlaylist->getSongs().size(); x++)
00913 {
00914 if (m_currentPlaylist->getSongs().at(x)->ID() == trackID)
00915 {
00916 m_currentTrack = x;
00917 break;
00918 }
00919 }
00920 }
00921
00922 m_currentMetadata = m_currentPlaylist->getSongAt(m_currentTrack);
00923
00924 if (m_currentMetadata)
00925 {
00926 play();
00927
00928 if (gPlayer->getResumeMode() == MusicPlayer::RESUME_EXACT)
00929 seek(gCoreContext->GetNumSetting("MusicBookmarkPosition", 0));
00930 }
00931 }
00932
00933 void MusicPlayer::seek(int pos)
00934 {
00935 if (m_output)
00936 {
00937 if (getDecoder() && getDecoder()->isRunning())
00938 getDecoder()->seek(pos);
00939
00940 m_output->SetTimecode(pos*1000);
00941 }
00942 }
00943
00944 void MusicPlayer::showMiniPlayer(void)
00945 {
00946 if (m_canShowPlayer)
00947 {
00948 MythScreenStack *popupStack =
00949 GetMythMainWindow()->GetStack("popup stack");
00950
00951 MiniPlayer *miniplayer = new MiniPlayer(popupStack);
00952
00953 if (miniplayer->Create())
00954 popupStack->AddScreen(miniplayer);
00955 else
00956 delete miniplayer;
00957 }
00958 }
00959
00961 void MusicPlayer::changeCurrentTrack(int trackNo)
00962 {
00963 if (!m_currentPlaylist)
00964 return;
00965
00966
00967 updateVolatileMetadata();
00968
00969 m_currentTrack = trackNo;
00970
00971
00972 if (m_currentTrack < 0 || m_currentTrack >= m_currentPlaylist->getSongs().size())
00973 {
00974 LOG(VB_GENERAL, LOG_ERR,
00975 QString("MusicPlayer: asked to set the current track to an invalid track no. %1")
00976 .arg(trackNo));
00977 m_currentTrack = -1;
00978 m_currentMetadata = NULL;
00979 return;
00980 }
00981
00982 m_currentMetadata = m_currentPlaylist->getSongAt(m_currentTrack);
00983 }
00984
00986 Metadata *MusicPlayer::getCurrentMetadata(void)
00987 {
00988 if (m_oneshotMetadata)
00989 return m_oneshotMetadata;
00990
00991 if (m_currentMetadata)
00992 return m_currentMetadata;
00993
00994 if (!m_currentPlaylist || !m_currentPlaylist->getSongAt(m_currentTrack))
00995 return NULL;
00996
00997 m_currentMetadata = m_currentPlaylist->getSongAt(m_currentTrack);
00998
00999 return m_currentMetadata;
01000 }
01001
01003 Metadata *MusicPlayer::getNextMetadata(void)
01004 {
01005 if (m_isStreaming)
01006 return NULL;
01007
01008 if (m_oneshotMetadata)
01009 return m_currentMetadata;
01010
01011 if (!m_currentPlaylist || !m_currentPlaylist->getSongAt(m_currentTrack))
01012 return NULL;
01013
01014 if (m_repeatMode == REPEAT_TRACK)
01015 return getCurrentMetadata();
01016
01017
01018 if (m_currentTrack < m_currentPlaylist->getSongs().size() - 1)
01019 return m_currentPlaylist->getSongAt(m_currentTrack + 1);
01020 else
01021 {
01022
01023
01024 if (m_repeatMode == REPEAT_ALL)
01025 return m_currentPlaylist->getSongAt(0);
01026 else
01027 return NULL;
01028 }
01029
01030 return NULL;
01031 }
01032
01033 MusicPlayer::RepeatMode MusicPlayer::toggleRepeatMode(void)
01034 {
01035 switch (m_repeatMode)
01036 {
01037 case REPEAT_OFF:
01038 m_repeatMode = REPEAT_TRACK;
01039 break;
01040 case REPEAT_TRACK:
01041 m_repeatMode = REPEAT_ALL;
01042 break;
01043 case REPEAT_ALL:
01044 m_repeatMode = REPEAT_OFF;
01045 break;
01046 default:
01047 m_repeatMode = REPEAT_OFF;
01048 break;
01049 }
01050
01051 return m_repeatMode;
01052 }
01053
01054 MusicPlayer::ShuffleMode MusicPlayer::toggleShuffleMode(void)
01055 {
01056 switch (m_shuffleMode)
01057 {
01058 case SHUFFLE_OFF:
01059 m_shuffleMode = SHUFFLE_RANDOM;
01060 break;
01061 case SHUFFLE_RANDOM:
01062 m_shuffleMode = SHUFFLE_INTELLIGENT;
01063 break;
01064 case SHUFFLE_INTELLIGENT:
01065 m_shuffleMode = SHUFFLE_ALBUM;
01066 break;
01067 case SHUFFLE_ALBUM:
01068 m_shuffleMode = SHUFFLE_ARTIST;
01069 break;
01070 case SHUFFLE_ARTIST:
01071 m_shuffleMode = SHUFFLE_OFF;
01072 break;
01073 default:
01074 m_shuffleMode = SHUFFLE_OFF;
01075 break;
01076 }
01077
01078 setShuffleMode(m_shuffleMode);
01079
01080 return m_shuffleMode;
01081 }
01082
01083 void MusicPlayer::setShuffleMode(ShuffleMode mode)
01084 {
01085 int curTrackID = -1;
01086 if (getCurrentMetadata())
01087 curTrackID = getCurrentMetadata()->ID();
01088
01089 m_shuffleMode = mode;
01090
01091 if (m_currentPlaylist)
01092 m_currentPlaylist->shuffleTracks(m_shuffleMode);
01093
01094 if (curTrackID != -1)
01095 {
01096 for (int x = 0; x < getPlaylist()->getSongs().size(); x++)
01097 {
01098 Metadata *mdata = getPlaylist()->getSongs().at(x);
01099 if (mdata && mdata->ID() == (Metadata::IdType) curTrackID)
01100 {
01101 m_currentTrack = x;
01102 break;
01103 }
01104 }
01105 }
01106 }
01107
01108 void MusicPlayer::updateLastplay()
01109 {
01110 if (!m_isStreaming && m_currentMetadata)
01111 {
01112 m_currentMetadata->incPlayCount();
01113 m_currentMetadata->setLastPlay();
01114 }
01115
01116 m_updatedLastplay = true;
01117 }
01118
01119 void MusicPlayer::updateVolatileMetadata(void)
01120 {
01121 if (!m_isStreaming && m_currentMetadata && getDecoder())
01122 {
01123 if (m_currentMetadata->hasChanged())
01124 {
01125 m_currentMetadata->persist();
01126 if (getDecoder())
01127 getDecoder()->commitVolatileMetadata(m_currentMetadata);
01128
01129 sendTrackStatsChangedEvent(m_currentMetadata->ID());
01130 }
01131 }
01132 }
01133
01134 void MusicPlayer::setSpeed(float newspeed)
01135 {
01136 if (m_output)
01137 {
01138 m_playSpeed = newspeed;
01139 m_output->SetStretchFactor(m_playSpeed);
01140 }
01141 }
01142
01143 void MusicPlayer::incSpeed()
01144 {
01145 m_playSpeed += 0.05;
01146 setSpeed(m_playSpeed);
01147 }
01148
01149 void MusicPlayer::decSpeed()
01150 {
01151 m_playSpeed -= 0.05;
01152 setSpeed(m_playSpeed);
01153 }
01154
01155 void MusicPlayer::sendVolumeChangedEvent(void)
01156 {
01157 MusicPlayerEvent me(MusicPlayerEvent::VolumeChangeEvent, getVolume(), isMuted());
01158 dispatch(me);
01159 }
01160
01161 void MusicPlayer::sendMetadataChangedEvent(int trackID)
01162 {
01163 MusicPlayerEvent me(MusicPlayerEvent::MetadataChangedEvent, trackID);
01164 dispatch(me);
01165 }
01166
01167 void MusicPlayer::sendTrackStatsChangedEvent(int trackID)
01168 {
01169 MusicPlayerEvent me(MusicPlayerEvent::TrackStatsChangedEvent, trackID);
01170 dispatch(me);
01171 }
01172
01173 void MusicPlayer::sendAlbumArtChangedEvent(int trackID)
01174 {
01175 MusicPlayerEvent me(MusicPlayerEvent::AlbumArtChangedEvent, trackID);
01176 dispatch(me);
01177 }
01178
01179 void MusicPlayer::sendCDChangedEvent(void)
01180 {
01181 MusicPlayerEvent me(MusicPlayerEvent::CDChangedEvent, -1);
01182 dispatch(me);
01183 }
01184
01185 void MusicPlayer::incVolume()
01186 {
01187 if (getOutput())
01188 {
01189 getOutput()->AdjustCurrentVolume(2);
01190 sendVolumeChangedEvent();
01191 }
01192 }
01193
01194 void MusicPlayer::decVolume()
01195 {
01196 if (getOutput())
01197 {
01198 getOutput()->AdjustCurrentVolume(-2);
01199 sendVolumeChangedEvent();
01200 }
01201 }
01202
01203 void MusicPlayer::setVolume(int volume)
01204 {
01205 if (getOutput())
01206 {
01207 getOutput()->SetCurrentVolume(volume);
01208 sendVolumeChangedEvent();
01209 }
01210 }
01211
01212 uint MusicPlayer::getVolume(void) const
01213 {
01214 if (m_output)
01215 return m_output->GetCurrentVolume();
01216 return 0;
01217 }
01218
01219 void MusicPlayer::toggleMute(void)
01220 {
01221 if (m_output)
01222 {
01223 m_output->ToggleMute();
01224 sendVolumeChangedEvent();
01225 }
01226 }
01227
01228 MuteState MusicPlayer::getMuteState(void) const
01229 {
01230 if (m_output)
01231 return m_output->GetMuteState();
01232 return kMuteOff;
01233 }
01234
01235 void MusicPlayer::toMap(QHash<QString, QString> &map)
01236 {
01237 map["volumemute"] = QString("%1%").arg(getVolume()) +
01238 (isMuted() ? " (" + tr("Muted") + ")" : "");
01239 map["volume"] = QString("%1").arg(getVolume());
01240 map["volumepercent"] = QString("%1%").arg(getVolume());
01241 map["mute"] = isMuted() ? tr("Muted") : "";
01242 }
01243
01244 void MusicPlayer::activePlaylistChanged(int trackID, bool deleted)
01245 {
01246 if (trackID == -1)
01247 {
01248 if (deleted)
01249 {
01250
01251 m_currentTrack = -1;
01252 m_currentMetadata = NULL;
01253 stop(true);
01254 MusicPlayerEvent me(MusicPlayerEvent::AllTracksRemovedEvent, 0);
01255 dispatch(me);
01256 }
01257 else
01258 {
01259 MusicPlayerEvent me(MusicPlayerEvent::TrackAddedEvent, trackID);
01260 dispatch(me);
01261 }
01262 }
01263 else
01264 {
01265 if (deleted)
01266 {
01267 MusicPlayerEvent me(MusicPlayerEvent::TrackRemovedEvent, trackID);
01268 dispatch(me);
01269 }
01270 else
01271 {
01272 MusicPlayerEvent me(MusicPlayerEvent::TrackAddedEvent, trackID);
01273 dispatch(me);
01274 }
01275 }
01276 }
01277
01278 void MusicPlayer::playlistChanged(int playlistID)
01279 {
01280 MusicPlayerEvent me(MusicPlayerEvent::PlaylistChangedEvent, playlistID);
01281 dispatch(me);
01282 }
01283
01284 void MusicPlayer::setupDecoderHandler(void)
01285 {
01286 m_decoderHandler = new DecoderHandler();
01287 m_decoderHandler->addListener(this);
01288
01289
01290 {
01291 QMutexLocker locker(m_lock);
01292 QSet<QObject*>::const_iterator it = m_listeners.begin();
01293 for (; it != m_listeners.end() ; ++it)
01294 {
01295 m_decoderHandler->addListener(*it);
01296 }
01297 }
01298 }
01299
01300 void MusicPlayer::decoderHandlerReady(void)
01301 {
01302 LOG(VB_PLAYBACK, LOG_INFO, QString ("decoder handler is ready, decoding %1")
01303 .arg(getDecoder()->getFilename()));
01304
01305 #ifdef HAVE_CDIO
01306 CdDecoder *cddecoder = dynamic_cast<CdDecoder*>(getDecoder());
01307 if (cddecoder)
01308 cddecoder->setDevice(m_CDdevice);
01309 #endif
01310
01311 getDecoder()->setOutput(m_output);
01312
01313 getDecoder()->addListener(this);
01314
01315
01316 {
01317 QMutexLocker locker(m_lock);
01318 QSet<QObject*>::const_iterator it = m_listeners.begin();
01319 for (; it != m_listeners.end() ; ++it)
01320 {
01321 getDecoder()->addListener(*it);
01322 }
01323 }
01324
01325 m_currentTime = 0;
01326
01327 QSet<QObject*>::const_iterator it = m_visualisers.begin();
01328 for (; it != m_visualisers.end() ; ++it)
01329 {
01330
01331
01332
01333 }
01334
01335 if (getDecoder()->initialize())
01336 {
01337 if (m_output)
01338 m_output->Reset();
01339
01340 getDecoder()->start();
01341
01342 if (m_resumeMode == RESUME_EXACT &&
01343 gCoreContext->GetNumSetting("MusicBookmarkPosition", 0) > 0)
01344 {
01345 seek(gCoreContext->GetNumSetting("MusicBookmarkPosition", 0));
01346 gCoreContext->SaveSetting("MusicBookmarkPosition", 0);
01347 }
01348
01349 m_isPlaying = true;
01350 m_updatedLastplay = false;
01351 }
01352 else
01353 {
01354 LOG(VB_PLAYBACK, LOG_ERR, QString("Cannot initialise decoder for %1")
01355 .arg(getDecoder()->getFilename()));
01356 return;
01357 }
01358
01359
01360 MusicPlayerEvent me(MusicPlayerEvent::TrackChangeEvent, m_currentTrack);
01361 dispatch(me);
01362 }
01363
01364 void MusicPlayer::removeTrack(int trackID)
01365 {
01366 Metadata *mdata = gMusicData->all_music->getMetadata(trackID);
01367 if (mdata)
01368 {
01369 int trackPos = gPlayer->getPlaylist()->getSongs().indexOf(mdata);
01370 if (m_currentTrack > 0 && m_currentTrack >= trackPos)
01371 m_currentTrack--;
01372
01373 getPlaylist()->removeTrack(trackID);
01374 }
01375 }
01376
01377 void MusicPlayer::addTrack(int trackID, bool updateUI)
01378 {
01379 getPlaylist()->addTrack(trackID, updateUI);
01380 }
01381
01383
01384 CDWatcherThread::CDWatcherThread(const QString &dev)
01385 {
01386 m_cdDevice = dev;
01387 m_cdStatusChanged = false;
01388 m_stopped = false;
01389 }
01390
01391 void CDWatcherThread::run()
01392 {
01393 #ifdef HAVE_CDIO
01394 while (!m_stopped)
01395 {
01396
01397 QMutexLocker locker(getLock());
01398
01399 m_cdStatusChanged = false;
01400
01401 CdDecoder *decoder = new CdDecoder("cda", NULL, NULL, NULL);
01402 decoder->setDevice(m_cdDevice);
01403 int numTracks = decoder->getNumCDAudioTracks();
01404 bool redo = false;
01405
01406 if (numTracks != gMusicData->all_music->getCDTrackCount())
01407 {
01408 m_cdStatusChanged = true;
01409 LOG(VB_GENERAL, LOG_NOTICE, QString("CD status has changed."));
01410 }
01411
01412 if (numTracks == 0)
01413 {
01414
01415 gMusicData->all_music->clearCDData();
01416 gMusicData->all_playlists->clearCDList();
01417 }
01418 else if (numTracks > 0)
01419 {
01420
01421 Metadata *checker = decoder->getLastMetadata();
01422 if (checker)
01423 {
01424 if (!gMusicData->all_music->checkCDTrack(checker))
01425 {
01426 redo = true;
01427 m_cdStatusChanged = true;
01428 gMusicData->all_music->clearCDData();
01429 gMusicData->all_playlists->clearCDList();
01430 }
01431 else
01432 m_cdStatusChanged = false;
01433 delete checker;
01434 }
01435 else
01436 {
01437 LOG(VB_GENERAL, LOG_ERR, "The cddecoder said it had audio tracks, "
01438 "but it won't tell me about them");
01439 }
01440 }
01441
01442 int tracks = decoder->getNumTracks();
01443 bool setTitle = false;
01444
01445 for (int actual_tracknum = 1;
01446 redo && actual_tracknum <= tracks; actual_tracknum++)
01447 {
01448 Metadata *track = decoder->getMetadata(actual_tracknum);
01449 if (track)
01450 {
01451 gMusicData->all_music->addCDTrack(*track);
01452
01453 if (!setTitle)
01454 {
01455
01456 QString parenttitle = " ";
01457 if (track->FormatArtist().length() > 0)
01458 {
01459 parenttitle += track->FormatArtist();
01460 parenttitle += " ~ ";
01461 }
01462
01463 if (track->Album().length() > 0)
01464 parenttitle += track->Album();
01465 else
01466 {
01467 parenttitle = " " + QObject::tr("Unknown");
01468 LOG(VB_GENERAL, LOG_INFO, "Couldn't find your "
01469 " CD. It may not be in the freedb database.\n"
01470 " More likely, however, is that you need to delete\n"
01471 " ~/.cddb and ~/.cdserverrc and restart MythMusic.");
01472 }
01473 gMusicData->all_music->setCDTitle(parenttitle);
01474 setTitle = true;
01475 }
01476 delete track;
01477 }
01478 }
01479
01480 delete decoder;
01481
01482 if (m_cdStatusChanged)
01483 gPlayer->sendCDChangedEvent();
01484
01485 usleep(1000000);
01486 }
01487 #endif // HAVE_CDIO
01488 }