00001
00002 #include <cstdlib>
00003
00004
00005 #include <iostream>
00006
00007 using namespace std;
00008
00009
00010 #include <qapplication.h>
00011 #include <qurl.h>
00012 #include <qwidget.h>
00013
00014
00015 #include <mythtv/mythcontext.h>
00016 #include <mythtv/audiooutput.h>
00017 #include <mythtv/mythdbcon.h>
00018
00019
00020 #include "musicplayer.h"
00021 #include "decoder.h"
00022 #include "cddecoder.h"
00023 #include "constants.h"
00024 #include "mainvisual.h"
00025 #include "miniplayer.h"
00026 #include "playlist.h"
00027
00028
00029 #define LASTPLAY_DELAY 15
00030
00031 MusicPlayer *gPlayer = NULL;
00032
00034
00035 MusicPlayer::MusicPlayer(QObject *parent, const QString &dev)
00036 :QObject(parent)
00037 {
00038 m_CDdevice = dev;
00039 m_decoder = NULL;
00040 m_input = NULL;
00041 m_output = NULL;
00042
00043 m_playlistTree = NULL;
00044 m_currentNode = NULL;
00045 m_currentMetadata = NULL;
00046
00047 m_listener = NULL;
00048 m_visual = NULL;
00049
00050 m_isAutoplay = false;
00051 m_isPlaying = false;
00052 m_canShowPlayer = true;
00053 m_wasPlaying = true;
00054 m_updatedLastplay = false;
00055
00056 m_playSpeed = 1.0;
00057
00058 QString playmode = gContext->GetSetting("PlayMode", "none");
00059 if (playmode.lower() == "random")
00060 setShuffleMode(SHUFFLE_RANDOM);
00061 else if (playmode.lower() == "intelligent")
00062 setShuffleMode(SHUFFLE_INTELLIGENT);
00063 else if (playmode.lower() == "album")
00064 setShuffleMode(SHUFFLE_ALBUM);
00065 else if (playmode.lower() == "artist")
00066 setShuffleMode(SHUFFLE_ARTIST);
00067 else
00068 setShuffleMode(SHUFFLE_OFF);
00069
00070 QString repeatmode = gContext->GetSetting("RepeatMode", "all");
00071 if (repeatmode.lower() == "track")
00072 setRepeatMode(REPEAT_TRACK);
00073 else if (repeatmode.lower() == "all")
00074 setRepeatMode(REPEAT_ALL);
00075 else
00076 setRepeatMode(REPEAT_OFF);
00077
00078 QString resumestring = gContext->GetSetting("ResumeMode", "off");
00079 if (resumestring.lower() == "off")
00080 m_resumeMode = RESUME_OFF;
00081 else if (resumestring.lower() == "track")
00082 m_resumeMode = RESUME_TRACK;
00083 else
00084 m_resumeMode = RESUME_EXACT;
00085
00086 m_lastplayDelay = gContext->GetNumSetting("MusicLastPlayDelay", LASTPLAY_DELAY);
00087
00088 m_autoShowPlayer = (gContext->GetNumSetting("MusicAutoShowPlayer", 1) > 0);
00089
00090 gContext->addListener(this);
00091 }
00092
00093 MusicPlayer::~MusicPlayer()
00094 {
00095 if (!hasClient())
00096 savePosition();
00097
00098 gContext->removeListener(this);
00099
00100 stop(true);
00101
00102 if (m_playlistTree)
00103 delete m_playlistTree;
00104
00105 if (m_currentMetadata)
00106 {
00107 delete m_currentMetadata;
00108 m_currentMetadata = NULL;
00109 }
00110
00111 if (m_shuffleMode == SHUFFLE_INTELLIGENT)
00112 gContext->SaveSetting("PlayMode", "intelligent");
00113 else if (m_shuffleMode == SHUFFLE_RANDOM)
00114 gContext->SaveSetting("PlayMode", "random");
00115 else if (m_shuffleMode == SHUFFLE_ALBUM)
00116 gContext->SaveSetting("PlayMode", "album");
00117 else if (m_shuffleMode == SHUFFLE_ARTIST)
00118 gContext->SaveSetting("PlayMode", "artist");
00119 else
00120 gContext->SaveSetting("PlayMode", "none");
00121
00122 if (m_repeatMode == REPEAT_TRACK)
00123 gContext->SaveSetting("RepeatMode", "track");
00124 else if (m_repeatMode == REPEAT_ALL)
00125 gContext->SaveSetting("RepeatMode", "all");
00126 else
00127 gContext->SaveSetting("RepeatMode", "none");
00128
00129 gContext->SaveSetting("MusicAutoShowPlayer", (m_autoShowPlayer ? "1" : "0"));
00130 }
00131
00132 void MusicPlayer::setListener(QObject *listener)
00133 {
00134 if (m_listener && m_output)
00135 m_output->removeListener(m_listener);
00136
00137 if (m_listener && m_decoder)
00138 m_decoder->removeListener(m_listener);
00139
00140 m_listener = listener;
00141
00142 if (m_listener && m_output)
00143 m_output->addListener(m_listener);
00144
00145 if (m_listener && m_decoder)
00146 m_decoder->addListener(m_listener);
00147
00148 (listener == NULL) ? m_isAutoplay = true : m_isAutoplay = false;
00149 }
00150
00151 void MusicPlayer::setVisual(MainVisual *visual)
00152 {
00153 if (m_visual && m_output)
00154 {
00155 m_output->removeListener(m_visual);
00156 m_output->removeVisual(m_visual);
00157 }
00158
00159 m_visual = visual;
00160
00161 if (m_visual && m_output)
00162 {
00163 m_output->addListener(m_visual);
00164 m_output->addVisual(m_visual);
00165 }
00166 }
00167
00168 void MusicPlayer::playFile(const Metadata &meta)
00169 {
00170 playFile(meta.Filename());
00171 m_currentMetadata = new Metadata(meta);
00172 m_currentNode = NULL;
00173 }
00174
00175 void MusicPlayer::playFile(const QString &filename)
00176 {
00177 m_currentFile = filename;
00178 play();
00179 }
00180
00181 void MusicPlayer::stop(bool stopAll)
00182 {
00183 stopDecoder();
00184
00185 if (m_output)
00186 {
00187 if (m_output->GetPause())
00188 {
00189 pause();
00190 }
00191 m_output->Reset();
00192 }
00193
00194 if (m_input)
00195 delete m_input;
00196 m_input = NULL;
00197
00198 m_isPlaying = false;
00199
00200 if (stopAll && m_decoder)
00201 {
00202 m_decoder->removeListener(this);
00203 if (m_listener)
00204 m_decoder->removeListener(m_listener);
00205
00206 delete m_decoder;
00207 m_decoder = NULL;
00208 m_listener = NULL;
00209 }
00210
00211 if (stopAll && m_output)
00212 {
00213 m_output->removeListener(this);
00214 if (m_listener)
00215 m_output->removeListener(m_listener);
00216
00217 if (m_visual)
00218 {
00219 m_output->removeListener(m_visual);
00220 m_output->removeVisual(m_visual);
00221 }
00222 delete m_output;
00223 m_output = NULL;
00224 m_visual = NULL;
00225 }
00226 }
00227
00228 void MusicPlayer::pause(void)
00229 {
00230 if (m_output)
00231 {
00232 m_isPlaying = !m_isPlaying;
00233 m_output->Pause(!m_isPlaying);
00234 }
00235
00236 if (m_decoder)
00237 {
00238 m_decoder->lock();
00239 m_decoder->cond()->wakeAll();
00240 m_decoder->unlock();
00241 }
00242 }
00243
00244 void MusicPlayer::play(void)
00245 {
00246 stopDecoder();
00247
00248 if (!m_output)
00249 openOutputDevice();
00250
00251 if (m_input)
00252 delete m_input;
00253
00254 m_input = new QFile(m_currentFile);
00255
00256 if (m_decoder && !m_decoder->factory()->supports(m_currentFile))
00257 {
00258 m_decoder->removeListener(this);
00259
00260 if (m_listener)
00261 m_decoder->removeListener(m_listener);
00262
00263 delete m_decoder;
00264 m_decoder = NULL;
00265 }
00266
00267 if (!m_decoder)
00268 {
00269 m_decoder = Decoder::create(m_currentFile, m_input, m_output, true);
00270 if (!m_decoder)
00271 {
00272 VERBOSE(VB_IMPORTANT, "MusicPlayer: Failed to create decoder for playback");
00273 return;
00274 }
00275
00276 if (m_currentFile.contains("cda") == 1)
00277 dynamic_cast<CdDecoder*>(m_decoder)->setDevice(m_CDdevice);
00278
00279 m_decoder->setBlockSize(2 * 1024);
00280
00281 m_decoder->addListener(this);
00282
00283 if (m_listener)
00284 m_decoder->addListener(m_listener);
00285 }
00286 else
00287 {
00288 m_decoder->setInput(m_input);
00289 m_decoder->setFilename(m_currentFile);
00290 m_decoder->setOutput(m_output);
00291 }
00292
00293 if (m_decoder->initialize())
00294 {
00295 if (m_output)
00296 m_output->Reset();
00297
00298 m_decoder->start();
00299
00300 m_isPlaying = true;
00301
00302 if (m_currentNode)
00303 {
00304 if (m_currentNode->getInt() > 0)
00305 {
00306 m_currentMetadata = Metadata::getMetadataFromID(m_currentNode->getInt());
00307 m_updatedLastplay = false;
00308 }
00309 else
00310 {
00311
00312 CdDecoder *cddecoder = dynamic_cast<CdDecoder*>(m_decoder);
00313 if (m_decoder)
00314 m_currentMetadata = cddecoder->getMetadata(-m_currentNode->getInt());
00315 }
00316 }
00317 }
00318 }
00319
00320 void MusicPlayer::stopDecoder(void)
00321 {
00322 if (m_decoder && m_decoder->running())
00323 {
00324 m_decoder->lock();
00325 m_decoder->stop();
00326 m_decoder->unlock();
00327 }
00328
00329 if (m_decoder)
00330 {
00331 m_decoder->lock();
00332 m_decoder->cond()->wakeAll();
00333 m_decoder->unlock();
00334 }
00335
00336 if (m_decoder)
00337 m_decoder->wait();
00338
00339 if (m_currentMetadata)
00340 {
00341 if (m_currentMetadata->hasChanged())
00342 m_currentMetadata->persist();
00343 delete m_currentMetadata;
00344 }
00345 m_currentMetadata = NULL;
00346 }
00347
00348 void MusicPlayer::openOutputDevice(void)
00349 {
00350 QString adevice;
00351
00352 if (gContext->GetSetting("MusicAudioDevice") == "default")
00353 adevice = gContext->GetSetting("AudioOutputDevice");
00354 else
00355 adevice = gContext->GetSetting("MusicAudioDevice");
00356
00357
00358 m_output = AudioOutput::OpenAudio(adevice, "default", 16, 2, 44100,
00359 AUDIOOUTPUT_MUSIC, true, false);
00360 m_output->setBufferSize(256 * 1024);
00361 m_output->SetBlocking(false);
00362
00363 m_output->addListener(this);
00364
00365 if (m_listener)
00366 m_output->addListener(m_listener);
00367
00368 if (m_visual)
00369 {
00370 m_output->addListener((QObject*) m_visual);
00371 m_output->addVisual(m_visual);
00372 }
00373 }
00374
00375 void MusicPlayer::next(void)
00376 {
00377 if (!m_currentNode)
00378 return;
00379
00380 GenericTree *node = m_currentNode->nextSibling(1, ((int) m_shuffleMode) + 1);
00381 if (node)
00382 {
00383 m_currentNode = node;
00384 }
00385 else
00386 {
00387 if (m_repeatMode == REPEAT_ALL)
00388 {
00389
00390 GenericTree *parent = m_currentNode->getParent();
00391 if (parent)
00392 {
00393 node = parent->getChildAt(0, ((int) m_shuffleMode) + 1);
00394 if (node)
00395 m_currentNode = node;
00396 else
00397 return;
00398 }
00399 }
00400 else
00401 return;
00402 }
00403
00404 QString filename = getFilenameFromID(node->getInt());
00405 if (!filename.isEmpty())
00406 playFile(filename);
00407 else
00408 stop();
00409 }
00410
00411 void MusicPlayer::previous(void)
00412 {
00413 if (!m_currentNode)
00414 return;
00415
00416 GenericTree *node = m_currentNode->prevSibling(1, ((int) m_shuffleMode) + 1);
00417 if (node)
00418 {
00419 m_currentNode = node;
00420 QString filename = getFilenameFromID(node->getInt());
00421 if (!filename.isEmpty())
00422 playFile(filename);
00423 else
00424 return;
00425 }
00426 else
00427 {
00428
00429 return;
00430 }
00431 }
00432
00433 void MusicPlayer::nextAuto(void)
00434 {
00435 if (!m_isAutoplay)
00436 return;
00437
00438 if (!m_currentNode)
00439 return;
00440
00441 if (m_repeatMode == REPEAT_TRACK)
00442 {
00443 play();
00444 return;
00445 }
00446 else
00447 next();
00448
00449 if (m_canShowPlayer && m_autoShowPlayer)
00450 {
00451 MiniPlayer *popup = new MiniPlayer(gContext->GetMainWindow(), this);
00452 popup->showPlayer(10);
00453 popup->deleteLater();
00454 popup = NULL;
00455 }
00456 }
00457
00458 void MusicPlayer::customEvent(QCustomEvent *event)
00459 {
00460 if (m_isAutoplay)
00461 {
00462 switch ((int)event->type())
00463 {
00464 case OutputEvent::Error:
00465 {
00466 OutputEvent *aoe = (OutputEvent *) event;
00467
00468 VERBOSE(VB_IMPORTANT, QString("Output Error - %1")
00469 .arg(*aoe->errorMessage()));
00470 MythPopupBox::showOkPopup(gContext->GetMainWindow(),
00471 "Output Error:",
00472 QString("MythMusic has encountered the following error:\n%1")
00473 .arg(*aoe->errorMessage()));
00474 stop(true);
00475
00476 break;
00477 }
00478
00479 case DecoderEvent::Finished:
00480 {
00481 nextAuto();
00482 break;
00483 }
00484
00485 case DecoderEvent::Error:
00486 {
00487 stop(true);
00488
00489 QApplication::sendPostedEvents();
00490
00491 DecoderEvent *dxe = (DecoderEvent *) event;
00492
00493 VERBOSE(VB_IMPORTANT, QString("Decoder Error - %1")
00494 .arg(*dxe->errorMessage()));
00495 MythPopupBox::showOkPopup(gContext->GetMainWindow(),
00496 "Decoder Error",
00497 QString("MythMusic has encountered the following error:\n%1")
00498 .arg(*dxe->errorMessage()));
00499 break;
00500 }
00501
00502 case MythEvent::MythEventMessage:
00503 {
00504 MythEvent *me = (MythEvent *) event;
00505 if (me->Message().left(14) == "PLAYBACK_START")
00506 {
00507 m_wasPlaying = m_isPlaying;
00508 QString hostname = me->Message().mid(15);
00509
00510 if (hostname == gContext->GetHostName())
00511 {
00512 if (m_isPlaying)
00513 savePosition();
00514 stop(true);
00515 }
00516 }
00517
00518 if (me->Message().left(12) == "PLAYBACK_END")
00519 {
00520 if (m_wasPlaying)
00521 {
00522 QString hostname = me->Message().mid(13);
00523 if (hostname == gContext->GetHostName())
00524 {
00525 play();
00526 seek(gContext->GetNumSetting("MusicBookmarkPosition", 0));
00527 gContext->SaveSetting("MusicBookmark", "");
00528 gContext->SaveSetting("MusicBookmarkPosition", 0);
00529 }
00530
00531 m_wasPlaying = false;
00532 }
00533 }
00534
00535 break;
00536 }
00537 }
00538 }
00539
00540
00541 if ((int)event->type() == OutputEvent::Info)
00542 {
00543 OutputEvent *oe = (OutputEvent *) event;
00544 m_currentTime = oe->elapsedSeconds();
00545
00546 if (!m_updatedLastplay)
00547 {
00548
00549
00550 if ((m_currentMetadata && m_currentTime > (m_currentMetadata->Length() / 1000) / 2) ||
00551 m_currentTime >= m_lastplayDelay)
00552 updateLastplay();
00553 }
00554 }
00555
00556 QObject::customEvent(event);
00557 }
00558
00559 QString MusicPlayer::getFilenameFromID(int id)
00560 {
00561 QString filename = "";
00562
00563 if (id > 0)
00564 {
00565 QString aquery = "SELECT CONCAT_WS('/', "
00566 "music_directories.path, music_songs.filename) AS filename "
00567 "FROM music_songs "
00568 "LEFT JOIN music_directories ON music_songs.directory_id=music_directories.directory_id "
00569 "WHERE music_songs.song_id = :ID";
00570
00571 MSqlQuery query(MSqlQuery::InitCon());
00572 query.prepare(aquery);
00573 query.bindValue(":ID", id);
00574 if (!query.exec() || query.numRowsAffected() < 1)
00575 MythContext::DBError("get filename", query);
00576
00577 if (query.isActive() && query.size() > 0)
00578 {
00579 query.first();
00580 filename = QString::fromUtf8(query.value(0).toString());
00581 if (!filename.contains("://"))
00582 filename = Metadata::GetStartdir() + filename;
00583 }
00584 }
00585 else
00586 {
00587
00588 CdDecoder *cddecoder = dynamic_cast<CdDecoder*>(m_decoder);
00589 if (cddecoder)
00590 {
00591 Metadata *meta = cddecoder->getMetadata(-id);
00592 if (meta)
00593 filename = meta->Filename();
00594 }
00595 }
00596 return filename;
00597 }
00598
00599 GenericTree *MusicPlayer::constructPlaylist(void)
00600 {
00601 QString position = "";
00602
00603 if (m_playlistTree)
00604 {
00605 position = getRouteToCurrent();
00606 delete m_playlistTree;
00607 }
00608
00609 m_playlistTree = new GenericTree(tr("playlist root"), 0);
00610 m_playlistTree->setAttribute(0, 0);
00611 m_playlistTree->setAttribute(1, 0);
00612 m_playlistTree->setAttribute(2, 0);
00613 m_playlistTree->setAttribute(3, 0);
00614 m_playlistTree->setAttribute(4, 0);
00615
00616 GenericTree *active_playlist_node =
00617 gMusicData->all_playlists->writeTree(m_playlistTree);
00618
00619 if (position != "" )
00620 restorePosition(position);
00621
00622 return active_playlist_node;
00623 }
00624
00625 QString MusicPlayer::getRouteToCurrent(void)
00626 {
00627 QStringList route;
00628
00629 if (m_currentNode)
00630 {
00631 GenericTree *climber = m_currentNode;
00632
00633 route.push_front(QString::number(climber->getInt()));
00634 while((climber = climber->getParent()))
00635 {
00636 route.push_front(QString::number(climber->getInt()));
00637 }
00638 }
00639 return route.join(",");
00640 }
00641
00642 void MusicPlayer::savePosition(void)
00643 {
00644 if (m_resumeMode != RESUME_OFF)
00645 {
00646 gContext->SaveSetting("MusicBookmark", getRouteToCurrent());
00647 if (m_resumeMode == RESUME_EXACT)
00648 gContext->SaveSetting("MusicBookmarkPosition", m_currentTime);
00649 }
00650 }
00651
00652 void MusicPlayer::restorePosition(const QString &position)
00653 {
00654 QValueList <int> branches_to_current_node;
00655
00656 if (position != "")
00657 {
00658 QStringList list = QStringList::split(",", position);
00659
00660 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it)
00661 branches_to_current_node.append((*it).toInt());
00662
00663
00664 m_currentNode = m_playlistTree->findNode(branches_to_current_node);
00665
00666 if (m_currentNode)
00667 return;
00668 }
00669
00670
00671 branches_to_current_node.clear();
00672 branches_to_current_node.append(0);
00673 branches_to_current_node.append(1);
00674 branches_to_current_node.append(0);
00675 m_currentNode = m_playlistTree->findNode(branches_to_current_node);
00676 if (m_currentNode)
00677 {
00678 m_currentNode = m_currentNode->getChildAt(0, -1);
00679 if (m_currentNode)
00680 {
00681 m_currentFile = getFilenameFromID(m_currentNode->getInt());
00682 if (m_currentFile != "")
00683 play();
00684 }
00685 }
00686 }
00687
00688 void MusicPlayer::seek(int pos)
00689 {
00690 if (m_output)
00691 {
00692 m_output->Reset();
00693 m_output->SetTimecode(pos*1000);
00694
00695 if (m_decoder && m_decoder->running())
00696 {
00697 m_decoder->lock();
00698 m_decoder->seek(pos);
00699 m_decoder->unlock();
00700 }
00701 }
00702 }
00703
00704 void MusicPlayer::showMiniPlayer(void)
00705 {
00706 if (m_canShowPlayer)
00707 {
00708 MiniPlayer *popup = new MiniPlayer(gContext->GetMainWindow(), this);
00709 popup->exec();
00710 popup->deleteLater();
00711 popup = NULL;
00712 }
00713 }
00714
00715 Metadata *MusicPlayer::getCurrentMetadata(void)
00716 {
00717 if (m_currentMetadata)
00718 return m_currentMetadata;
00719
00720 if (!m_currentNode)
00721 return NULL;
00722
00723 m_currentMetadata = Metadata::getMetadataFromID(m_currentNode->getInt());
00724
00725 return m_currentMetadata;
00726 }
00727
00728 void MusicPlayer::refreshMetadata(void)
00729 {
00730 if (m_currentMetadata)
00731 {
00732 delete m_currentMetadata;
00733 m_currentMetadata = NULL;
00734 }
00735
00736 getCurrentMetadata();
00737 }
00738
00739 MusicPlayer::RepeatMode MusicPlayer::toggleRepeatMode(void)
00740 {
00741 switch (m_repeatMode)
00742 {
00743 case REPEAT_OFF:
00744 m_repeatMode = REPEAT_TRACK;
00745 break;
00746 case REPEAT_TRACK:
00747 m_repeatMode = REPEAT_ALL;
00748 break;
00749 case REPEAT_ALL:
00750 m_repeatMode = REPEAT_OFF;
00751 break;
00752 default:
00753 m_repeatMode = REPEAT_OFF;
00754 break;
00755 }
00756
00757 return m_repeatMode;
00758 }
00759
00760 MusicPlayer::ShuffleMode MusicPlayer::toggleShuffleMode(void)
00761 {
00762 switch (m_shuffleMode)
00763 {
00764 case SHUFFLE_OFF:
00765 m_shuffleMode = SHUFFLE_RANDOM;
00766 break;
00767 case SHUFFLE_RANDOM:
00768 m_shuffleMode = SHUFFLE_INTELLIGENT;
00769 break;
00770 case SHUFFLE_INTELLIGENT:
00771 m_shuffleMode = SHUFFLE_ALBUM;
00772 break;
00773 case SHUFFLE_ALBUM:
00774 m_shuffleMode = SHUFFLE_ARTIST;
00775 break;
00776 case SHUFFLE_ARTIST:
00777 m_shuffleMode = SHUFFLE_OFF;
00778 break;
00779 default:
00780 m_shuffleMode = SHUFFLE_OFF;
00781 break;
00782 }
00783
00784 return m_shuffleMode;
00785 }
00786
00787 void MusicPlayer::updateLastplay()
00788 {
00789
00790 if (m_currentNode && m_currentNode->getInt() > 0)
00791 {
00792 if (m_currentMetadata)
00793 {
00794 m_currentMetadata->incPlayCount();
00795 m_currentMetadata->setLastPlay();
00796 }
00797
00798 if (gMusicData->all_music)
00799 {
00800 Metadata *mdata = gMusicData->all_music->getMetadata(m_currentNode->getInt());
00801 if (mdata)
00802 {
00803 mdata->incPlayCount();
00804 mdata->setLastPlay();
00805 }
00806 }
00807 }
00808
00809 m_updatedLastplay = true;
00810 }
00811
00812 void MusicPlayer::setSpeed(float newspeed)
00813 {
00814 if (m_output)
00815 {
00816 m_playSpeed = newspeed;
00817 m_output->SetStretchFactor(m_playSpeed);
00818 }
00819 }
00820
00821 void MusicPlayer::incSpeed()
00822 {
00823 m_playSpeed += 0.05;
00824 setSpeed(m_playSpeed);
00825 }
00826
00827 void MusicPlayer::decSpeed()
00828 {
00829 m_playSpeed -= 0.05;
00830 setSpeed(m_playSpeed);
00831 }