#define DEBUG_PREFIX "InfoPlug" #include "amarok.h" #include "amarokconfig.h" #include "collectiondb.h" #include "config.h" #include "debug.h" #include "enginecontroller.h" #include "playlist.h" #include "infoplug.h" #include "statusbar.h" #include <fcntl.h> #include <sys/poll.h> InfoPlug* InfoPlug::instance() { static InfoPlug infoplug; return &infoplug; } InfoPlug::InfoPlug() : EngineObserver(EngineController::instance()), m_enabled(false), m_sock((int) 0) { } void InfoPlug::shutdown() { m_enabled = false; while (m_sock) { sleep(5); } if (m_sock) { ::shutdown(m_sock, SHUT_RDWR); m_sock = false; } ThreadWeaver::instance()->abortAllJobsNamed("InfoPlugServer"); } InfoPlug::~InfoPlug() { } void InfoPlug::starter() { m_enabled = true; ThreadWeaver::instance()->queueJob(new InfoPlugServer(this)); } InfoPlugServer::InfoPlugServer(InfoPlug* parent) : Job("InfoPlugServer"), m_parent(parent) { } InfoPlugServer::~InfoPlugServer() { m_parent->m_enabled = false; if (m_parent->m_sock) { shutdown(m_parent->m_sock, SHUT_RDWR); } } bool InfoPlugServer::doJob() { int bind; socklen_t clientAddrLen; struct sockaddr_in clientAddr, serverAddr; struct timeval timeout; QString info; int status, retval, opts; struct pollfd pfd; // Reset data char version[100]; serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(5353); if (!m_parent->m_enabled) { return false; } m_parent->m_sock = ::socket(PF_INET, SOCK_DGRAM, 0); if (m_parent->m_sock == -1) { warning() << "InfoPlug: socket errno: " << errno << endl; return false; } bind = ::bind(m_parent->m_sock, (struct sockaddr*) &serverAddr, sizeof(serverAddr)); if (bind == -1) { warning() << "InfoPlug: bind errno: " << errno << endl; return false; } opts = fcntl(m_parent->m_sock, F_GETFL); if (opts < 0) { perror("fcntl(F_GETFL)"); } fcntl(m_parent->m_sock, F_SETFL, O_ASYNC | O_NONBLOCK); pfd.fd = m_parent->m_sock; pfd.events = POLLIN; while(true) { if (!m_parent->m_enabled) { if (m_parent->m_sock) { ::shutdown(m_parent->m_sock, SHUT_RDWR); m_parent->m_sock = false; } return false; } else { timeout.tv_sec = 1; timeout.tv_usec = 0; info = ""; clientAddrLen = sizeof(clientAddr); retval = poll(&pfd, 1, 1000); if (retval < 0) { perror("poll()"); } else if (retval) { if (recvfrom(m_parent->m_sock, NULL, 0, 0, (struct sockaddr *) &clientAddr, &clientAddrLen) == -1) { warning() << "InfoPlug: recvfrom errno: " << errno << endl; sleep(1); } else { warning() << "============== InfoPlug: connection from: " << inet_ntoa(clientAddr.sin_addr) << endl; /* * Collect data here and put it in data. */ const MetaBundle &bundle = EngineController::instance()->bundle(); QueryBuilder qb; qb.addReturnValue(QueryBuilder::tabStats, QueryBuilder::valPlayCounter); qb.addMatches(QueryBuilder::tabStats, bundle.url().path()); snprintf(version, 100, "Interface: InfoPlug\nVersion: %d.%d\n", INFOPLUG_VERSION_MA, INFOPLUG_VERSION_MI); info.append(version); status = EngineController::engine()->state(); if (status == Engine::Playing) info.append("Status: Playing\n"); // snprintf(plStatus, 1000, "Status: Playing\n"); else if (status == Engine::Paused) info.append("Status: Playing\n"); // snprintf(plStatus, 1000, "Status: Paused\n"); else info.append("Status: Stopped\n"); // snprintf(plStatus, 1000, "Status: Stopped\n"); if (status == Engine::Playing || status == Engine::Paused) { info += "Artist: "+ bundle.artist(); info += "\nTitle: "+ bundle.title(); info += "\nAlbum: "+ bundle.album(); info += "\nTrack: "+ (bundle.track() ? QString::number(bundle.track()) : QString::null); info += "\nTotal Time: "+ bundle.prettyLength(); info += "\nCurrent Time: "+ bundle.prettyLength(EngineController::engine()->position()/1000, true); info += "\nGenre: "+ bundle.genre(); info += "\nYear: "+ QString::number(bundle.year()); info += "\nComment: "+ bundle.comment(); info += "\nBitrate: "+ bundle.prettyBitrate(); info += "\nSample Rate: "+ bundle.prettySampleRate(); info += "\nRating: "+ QString::number(CollectionDB::instance()->getSongRating(bundle.url().path())); info += "\nScore: "+ QString::number(CollectionDB::instance()->getSongPercentage(bundle.url().path())); info += "\nPlay Count: "+ QString::number(qb.run().first().toInt()); info += "\nVolume: "+ QString::number(EngineController::engine()->volume()); info += "\nURL: "+ bundle.url().url(); info += "\nCover Image: "+ CollectionDB::instance()->albumImage(bundle.artist(), bundle.album(), 0); } if (sendto(m_parent->m_sock, info.utf8(), info.length() + 1, 0, (struct sockaddr *) &clientAddr, sizeof(clientAddr)) == -1) { warning() << "InfoPlug: sendto errno: " << errno << endl; } } /* recvfrom */ } /* for poll */ } /* Was enabled */ } /* While-loop */ return true; } void InfoPlugServer::completeJob() { if (m_parent->m_sock) { ::shutdown(m_parent->m_sock, SHUT_RDWR); m_parent->m_sock = false; } } #include "infoplug.moc"