|
MythTV
0.26-pre
|
00001 // ANSI C includes 00002 #include <cstdlib> 00003 00004 // qt 00005 #include <QApplication> 00006 #include <QWidget> 00007 #include <QFile> 00008 #include <QList> 00009 #include <QDir> 00010 00011 // mythtv 00012 #include <mythcontext.h> 00013 #include <audiooutput.h> 00014 #include <mythdb.h> 00015 #include <mythdialogbox.h> 00016 #include <mythmainwindow.h> 00017 00018 // mythmusic 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 // how long to wait before updating the lastplay and playcount fields 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 // Do we check the CD? 00227 bool checkCD = gCoreContext->GetNumSetting("AutoLookupCD"); 00228 if (checkCD) 00229 { 00230 m_cdWatcher = new CDWatcherThread(m_CDdevice); 00231 // don't start the cd watcher here 00232 // since the playlists haven't been loaded yet 00233 } 00234 } 00235 00236 // this stops playing the playlist and plays the file pointed to by mdata 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 // remove any listeners from the decoder 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 // because we don't actually stop the audio output we have to fake a Stopped 00287 // event so any listeners can act on it 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 // wake up threads 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 // add any visuals to the audio output 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 // add any listeners to the audio output 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 // start playing again from first track 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;//stop(); 00464 } 00465 else 00466 { 00467 // FIXME take repeat mode into account 00468 return; //stop(); 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 // if we don't already have a gui attached show the miniplayer if configured to do so 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 // handle decoderHandler events 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 // tell any listeners we've started playing a new track 00568 MusicPlayerEvent me(MusicPlayerEvent::TrackChangeEvent, -1); 00569 dispatch(me); 00570 } 00571 00572 // handle decoder events 00573 else if (event->type() == DecoderEvent::Decoding) 00574 { 00575 if (getCurrentMetadata()) 00576 m_displayMetadata = *getCurrentMetadata(); 00577 } 00578 00579 // handle MythEvent events 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 // we update the lastplay and playcount after playing 00768 // for m_lastplayDelay seconds or half the total track time 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 // this will update any track lengths displayed on screen 00788 gPlayer->sendMetadataChangedEvent(m_currentMetadata->ID()); 00789 00790 // this will force the playlist stats to update 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 // now we have the playlist loaded we can start the cd watcher 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 // FIXME 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 // if we are switching views we don't wont to restore the position 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 // check to see if we need to save the current tracks volatile metadata (playcount, last played etc) 00967 updateVolatileMetadata(); 00968 00969 m_currentTrack = trackNo; 00970 00971 // sanity check the current track 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 // if we are not playing the last track then just return the next track 01018 if (m_currentTrack < m_currentPlaylist->getSongs().size() - 1) 01019 return m_currentPlaylist->getSongAt(m_currentTrack + 1); 01020 else 01021 { 01022 // if we are playing the last track then we need to take the 01023 // repeat mode into account 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 // all tracks were removed 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 // add any listeners to the decoderHandler 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 //getDecoder()-> setBlockSize(2 * 1024); 01313 getDecoder()->addListener(this); 01314 01315 // add any listeners to the decoder 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 //m_output->addVisual((MythTV::Visual*)(*it)); 01331 //(*it)->setDecoder(getDecoder()); 01332 //m_visual->setOutput(m_output); 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 // tell any listeners we've started playing a new track 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 // lock all_music and cd_status_changed while running thread 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 // No CD, or no recognizable CD 01415 gMusicData->all_music->clearCDData(); 01416 gMusicData->all_playlists->clearCDList(); 01417 } 01418 else if (numTracks > 0) 01419 { 01420 // Check the last track to see if it's changed 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 }
1.7.6.1