MythTV  0.26-pre
mediarenderer.cpp
Go to the documentation of this file.
00001 
00002 // Program Name: mediarenderer.cpp
00003 //
00004 // Purpose - uPnp Media Renderer main Class
00005 //
00006 // Created By  : David Blain                    Created On : Jan. 15, 2007
00007 // Modified By :                                Modified On:
00008 //
00010 
00011 #include <QTextStream>
00012 
00013 #include "upnpsubscription.h"
00014 #include "mediarenderer.h"
00015 #include "mythversion.h"
00016 #include "upnpscanner.h"
00017 #include "mythfexml.h"
00018 #include "compat.h"
00019 #include "mythmiscutil.h"
00020 
00021 #include "serviceHosts/frontendServiceHost.h"
00022 
00023 class MythFrontendStatus : public HttpServerExtension
00024 {
00025   public:
00026     MythFrontendStatus(const QString &sSharePath)
00027       : HttpServerExtension("MythFrontendStatus", sSharePath) { }
00028 
00029     virtual QStringList GetBasePaths() { return QStringList( "/" ); }
00030 
00031     virtual bool ProcessRequest(HTTPRequest *pRequest)
00032     {
00033         if (!pRequest)
00034             return false;
00035 
00036         if (pRequest->m_sBaseUrl != "/")
00037             return false;
00038 
00039         if (pRequest->m_sMethod == "getDeviceDesc")
00040             return false;
00041 
00042         pRequest->m_eResponseType = ResponseTypeHTML;
00043         pRequest->m_mapRespHeaders["Cache-Control"] =
00044             "no-cache=\"Ext\", max-age = 5000";
00045 
00046         SSDPCacheEntries* cache = NULL;
00047         QString ipaddress = QString();
00048 /*      QStringList::const_iterator sit = UPnp::g_IPAddrList.begin();
00049         for (; sit != UPnp::g_IPAddrList.end(); ++sit)
00050         {
00051             if (QHostAddress(*sit).protocol() == QAbstractSocket::IPv4Protocol)
00052             {
00053                 ipaddress = *sit;
00054                 break;
00055             }
00056         }*/
00057         if (!UPnp::g_IPAddrList.isEmpty())
00058             ipaddress = UPnp::g_IPAddrList.at(0);
00059 
00060         QString hostname   = gCoreContext->GetHostName();
00061         QDateTime qdtNow   = QDateTime::currentDateTime();
00062         QString masterhost = gCoreContext->GetMasterHostName();
00063         QString masterip   = gCoreContext->GetSetting("MasterServerIP");
00064         QString masterport = gCoreContext->GetSettingOnHost("BackendStatusPort",
00065                                                             masterhost, "6544");
00066 
00067         QTextStream stream ( &pRequest->m_response );
00068         stream.setCodec("UTF-8");
00069 
00070         stream
00071            << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
00072            << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
00073            << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
00074            << " xml:lang=\"en\" lang=\"en\">\r\n"
00075            << "<head>\r\n"
00076            << "  <meta http-equiv=\"Content-Type\""
00077            << "content=\"text/html; charset=UTF-8\" />\r\n"
00078            << "  <title>MythFrontend Status - "
00079            << MythDateTimeToString(qdtNow, kDateTimeShort) << " - "
00080            << MYTH_BINARY_VERSION << "</title>\r\n"
00081            << "  <link rel=\"stylesheet\" href=\"/css/site.css\"   type=\"text/css\">\r\n"
00082            << "  <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
00083            << "</head>\r\n"
00084            << "<body>\r\n\r\n"
00085            << "  <h1 class=\"status\">MythFrontend Status</h1>\r\n";
00086 
00087         // This frontend
00088         stream
00089            << "  <div class=\"content\">\r\n"
00090            << "    <h2 class=\"status\">This Frontend</h2>\r\n"
00091            << "Name : " << hostname << "<br />\r\n"
00092            << "Version : " << MYTH_BINARY_VERSION << "\r\n"
00093            << "  </div>\r\n";
00094 
00095         // Other frontends
00096 
00097         // This will not work with multiple frontends on the same machine (upnp
00098         // setup will fail on a second frontend anyway) and the ip address
00099         // filtering of the current frontend may not work in all situations
00100 
00101         cache = SSDP::Find("urn:schemas-mythtv-org:service:MythFrontend:1");
00102         if (cache)
00103         {
00104             stream
00105                << "  <div class=\"content\">\r\n"
00106                << "    <h2 class=\"status\">Other Frontends</h2>\r\n";
00107 
00108             EntryMap map;
00109             cache->GetEntryMap(map);
00110             cache->Release();
00111             cache = NULL;
00112 
00113             QMapIterator< QString, DeviceLocation * > i(map);
00114             while (i.hasNext())
00115             {
00116                 i.next();
00117                 QUrl url(i.value()->m_sLocation);
00118                 if (url.host() != ipaddress)
00119                 {
00120                     stream << "<br />" << url.host() << "&nbsp(<a href=\""
00121                            << url.toString(QUrl::RemovePath)
00122                            << "\">Status page</a>)\r\n";
00123                 }
00124                 i.value()->Release();
00125             }
00126             stream << "  </div>\r\n";
00127         }
00128 
00129         // Master backend
00130         stream
00131            << "  <div class=\"content\">\r\n"
00132            << "    <h2 class=\"status\">MythTV Backends</h2>\r\n"
00133            << "Master: " << masterhost << "&nbsp(<a href=\"http://"
00134            << masterip << ":" << masterport
00135            << "\">Status page</a>)\r\n";
00136 
00137         // Slave backends
00138         cache = SSDP::Find("urn:schemas-mythtv-org:device:SlaveMediaServer:1");
00139         if (cache)
00140         {
00141             EntryMap map;
00142             cache->GetEntryMap(map);
00143             cache->Release();
00144             cache = NULL;
00145 
00146             QMapIterator< QString, DeviceLocation * > i(map);
00147             while (i.hasNext())
00148             {
00149                 i.next();
00150                 QUrl url(i.value()->m_sLocation);
00151                 stream << "<br />" << "Slave: " << url.host()
00152                        << "&nbsp(<a href=\""
00153                        << url.toString(QUrl::RemovePath)
00154                        << "\">Status page</a>)\r\n";
00155                 i.value()->Release();
00156             }
00157         }
00158 
00159         stream
00160            << "  </div>\r\n";
00161 
00162         stream
00163            << "  <div class=\"content\">\r\n"
00164            << "    <h2 class=\"status\">Services</h2>\r\n"
00165            << "    <a href=\"MythFE/GetRemote\">Remote Control</a>\r\n"
00166            << "  </div>\r\n";
00167 
00168         double load[3];
00169         if (getloadavg(load, 3) != -1)
00170         {
00171             stream
00172                << "  <div class=\"content\">\r\n"
00173                << "    <h2 class=\"status\">Machine Information</h2>\r\n"
00174                << "    <div class=\"loadstatus\">\r\n"
00175                << "      This machine's load average:"
00176                << "\r\n      <ul>\r\n        <li>"
00177                << "1 Minute: " << QString::number(load[0]) << "</li>\r\n"
00178                << "        <li>5 Minutes: " << QString::number(load[1]) << "</li>\r\n"
00179                << "        <li>15 Minutes: " << QString::number(load[2])
00180                << "</li>\r\n      </ul>\r\n"
00181                << "    </div>\r\n"
00182                << "  </div>\r\n";
00183         }
00184 
00185         stream << "</body>\r\n</html>\r\n";
00186         stream.flush();
00187 
00188         return true;
00189     }
00190 };
00191 
00194 //
00195 // UPnp MediaRenderer Class implementaion
00196 //
00199 
00201 //
00203 
00204 MediaRenderer::MediaRenderer()
00205 {
00206     LOG(VB_UPNP, LOG_INFO, "MediaRenderer::Begin");
00207 
00208     // ----------------------------------------------------------------------
00209     // Initialize Configuration class (XML file for frontend)
00210     // ----------------------------------------------------------------------
00211 
00212     SetConfiguration( new XmlConfiguration( "config.xml" ));
00213 
00214     // ----------------------------------------------------------------------
00215     // Create mini HTTP Server
00216     // ----------------------------------------------------------------------
00217 
00218     int nPort = g_pConfig->GetValue( "UPnP/MythFrontend/ServicePort", 6547 );
00219 
00220     m_pHttpServer = new HttpServer();
00221 
00222     if (!m_pHttpServer)
00223         return;
00224 
00225     if (!m_pHttpServer->listen(nPort))
00226     {
00227         LOG(VB_GENERAL, LOG_ERR, "MediaRenderer::HttpServer Create Error");
00228         delete m_pHttpServer;
00229         m_pHttpServer = NULL;
00230         return;
00231     }
00232 
00233     // ----------------------------------------------------------------------
00234     // Initialize UPnp Stack
00235     // ----------------------------------------------------------------------
00236 
00237     if (Initialize( nPort, m_pHttpServer ))
00238     {
00239         // ------------------------------------------------------------------
00240         // Create device Description
00241         // ------------------------------------------------------------------
00242 
00243         LOG(VB_UPNP, LOG_INFO, "MediaRenderer::Creating UPnp Description");
00244 
00245         UPnpDevice &device = g_UPnpDeviceDesc.m_rootDevice;
00246 
00247         device.m_sDeviceType   = "urn:schemas-upnp-org:device:MediaRenderer:1";
00248         device.m_sFriendlyName      = "MythTV AV Renderer";
00249         device.m_sManufacturer      = "MythTV";
00250         device.m_sManufacturerURL   = "http://www.mythtv.org";
00251         device.m_sModelDescription  = "MythTV AV Media Renderer";
00252         device.m_sModelName         = "MythTV AV Media Renderer";
00253         device.m_sModelURL          = "http://www.mythtv.org";
00254         device.m_sUPC               = "";
00255         device.m_sPresentationURL   = "/";
00256 
00257         // ------------------------------------------------------------------
00258         // Register any HttpServerExtensions...
00259         // ------------------------------------------------------------------
00260 
00261         LOG(VB_UPNP, LOG_INFO,
00262             "MediaRenderer::Registering MythFrontendStatus service.");
00263         m_pHttpServer->RegisterExtension(
00264             new MythFrontendStatus(m_pHttpServer->GetSharePath()));
00265 
00266         QString sSinkProtocols = "http-get:*:image/gif:*,"
00267                                  "http-get:*:image/jpeg:*,"
00268                                  "http-get:*:image/png:*,"
00269                                  "http-get:*:video/avi:*,"
00270                                  "http-get:*:audio/mpeg:*,"
00271                                  "http-get:*:audio/wav:*,"
00272                                  "http-get:*:video/mpeg:*,"
00273                                  "http-get:*:video/nupplevideo:*,"
00274                                  "http-get:*:video/x-ms-wmv:*";
00275         // ------------------------------------------------------------------
00276         // Register the MythFEXML protocol...
00277         // ------------------------------------------------------------------
00278         LOG(VB_UPNP, LOG_INFO, "MediaRenderer::Registering MythFEXML Service.");
00279         m_pHttpServer->RegisterExtension(
00280             new MythFEXML(RootDevice(), m_pHttpServer->GetSharePath()));
00281 
00282         LOG(VB_UPNP, LOG_INFO, "MediaRenderer::Registering Status Service.");
00283         m_pHttpServer->RegisterExtension(new FrontendServiceHost(m_pHttpServer->GetSharePath()));
00284 
00285 #if 0
00286         LOG(VB_UPNP, LOG_INFO,
00287             "MediaRenderer::Registering AVTransport Service.");
00288         m_pUPnpAVT = new UPnpAVTransport( RootDevice() );
00289         m_pHttpServer->RegisterExtension( m_pUPnpAVT );
00290 #endif
00291 
00292         LOG(VB_UPNP, LOG_INFO, "MediaRenderer::Registering CMGR Service.");
00293         // HttpServer will be responsible for deleting UPnpCMGR
00294         m_pUPnpCMGR = new UPnpCMGR(
00295             RootDevice(), m_pHttpServer->GetSharePath(), "", sSinkProtocols);
00296         m_pHttpServer->RegisterExtension( m_pUPnpCMGR );
00297 
00298 #if 0
00299         LOG(VB_UPNP, LOG_INFO, 
00300             "MediaRenderer::Registering RenderingControl Service.");
00301         m_pUPnpRCTL= new UPnpRCTL( RootDevice() );
00302         m_pHttpServer->RegisterExtension( m_pUPnpRCTL );
00303 #endif
00304 
00305         UPNPSubscription *subscription = NULL;
00306         if (getenv("MYTHTV_UPNPSCANNER"))
00307         {
00308             LOG(VB_UPNP, LOG_INFO,
00309                 "MediaRenderer: Registering subscription service.");
00310 
00311             subscription = new UPNPSubscription(
00312                 m_pHttpServer->GetSharePath(), nPort);
00313             m_pHttpServer->RegisterExtension(subscription);
00314         }
00315 
00316         Start();
00317 
00318         // Start scanning for UPnP media servers
00319         if (subscription)
00320             UPNPScanner::Enable(true, subscription);
00321 
00322         // ensure the frontend is aware of all backends (slave and master) and
00323         // other frontends
00324         SSDP::Instance()->PerformSearch("ssdp:all");
00325     }
00326     else
00327     {
00328         LOG(VB_GENERAL, LOG_ERR,
00329             "MediaRenderer::Unable to Initialize UPnp Stack");
00330     }
00331 
00332     LOG(VB_UPNP, LOG_INFO, "MediaRenderer::End");
00333 }
00334 
00336 //
00338 
00339 MediaRenderer::~MediaRenderer()
00340 {
00341     UPNPScanner::Enable(false);
00342     delete m_pHttpServer;
00343 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends