MythTV  0.26-pre
iptvfeederrtsp.cpp
Go to the documentation of this file.
00001 
00006 #include <algorithm>
00007 
00008 #include "iptvfeederrtsp.h"
00009 
00010 // Live555 headers
00011 #include <RTSPClient.hh>
00012 #include <BasicUsageEnvironment.hh>
00013 #include <MediaSession.hh>
00014 
00015 // MythTV headers
00016 #include "iptvmediasink.h"
00017 #include "mythcontext.h"
00018 #include "mythlogging.h"
00019 #include "tspacket.h"
00020 
00021 #define LOC QString("IPTVFeedRTSP:")
00022 
00026 class RTSPData
00027 {
00028   public:
00029     RTSPData(MediaSubsession *pMediaSubSession) :
00030         mediaSubSession(pMediaSubSession)
00031     {
00032     }
00033 
00034     void SubsessionAfterPlayingCB(void);
00035     void SubsessionByeHandlerCB(void);
00036 
00037   private:
00038     MediaSubsession *mediaSubSession;
00039 };
00040 
00041 void RTSPData::SubsessionAfterPlayingCB(void)
00042 {
00043     MediaSubsession *subsession = mediaSubSession;
00044     Medium::close(subsession->sink);
00045     subsession->sink = NULL;
00046 }
00047 
00048 static void sub_after_playing_cb(void *clientData)
00049 {
00050     ((RTSPData*)clientData)->SubsessionAfterPlayingCB();
00051 }
00052 
00053 void RTSPData::SubsessionByeHandlerCB(void)
00054 {
00055     SubsessionAfterPlayingCB();
00056 }
00057 
00058 static void sub_bye_handler_cb(void *clientData)
00059 {
00060     ((RTSPData*)clientData)->SubsessionByeHandlerCB();
00061 }
00062 
00064 
00065 IPTVFeederRTSP::IPTVFeederRTSP() :
00066     _rtsp_client(NULL),
00067     _session(NULL)
00068 {
00069     LOG(VB_RECORD, LOG_INFO, LOC + "ctor -- success");
00070 }
00071 
00072 IPTVFeederRTSP::~IPTVFeederRTSP()
00073 {
00074     LOG(VB_RECORD, LOG_INFO, LOC + "dtor -- begin");
00075     Close();
00076     LOG(VB_RECORD, LOG_INFO, LOC + "dtor -- end");
00077 }
00078 
00079 bool IPTVFeederRTSP::IsRTSP(const QString &url)
00080 {
00081     return url.startsWith("rtsp://", Qt::CaseInsensitive);
00082 }
00083 
00084 bool IPTVFeederRTSP::Open(const QString &url)
00085 {
00086     LOG(VB_RECORD, LOG_INFO, LOC + QString("Open(%1) -- begin").arg(url));
00087 
00088     QMutexLocker locker(&_lock);
00089 
00090     if (_rtsp_client)
00091     {
00092         LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end 1");
00093 
00094         return true;
00095     }
00096 
00097     // Begin by setting up our usage environment:
00098     if (!InitEnv())
00099         return false;
00100 
00101     // Create our client object:
00102     _rtsp_client = RTSPClient::createNew(*_live_env, 0, "myRTSP", 0);
00103     if (!_rtsp_client)
00104     {
00105         LOG(VB_GENERAL, LOG_ERR, LOC +
00106             QString("Failed to create RTSP client: %1")
00107                 .arg(_live_env->getResultMsg()));
00108         FreeEnv();
00109         return false;
00110     }
00111 
00112     // Setup URL for the current session
00113     char *sdpDescription = _rtsp_client->describeURL(
00114         url.toLatin1().constData());
00115 
00116     _rtsp_client->describeStatus();
00117 
00118     if (!sdpDescription)
00119     {
00120         LOG(VB_GENERAL, LOG_ERR, LOC +
00121             QString("Failed to get a SDP description from URL: %1 %2")
00122                 .arg(url).arg(_live_env->getResultMsg()));
00123         return false;
00124     }
00125 
00126     // Create a media session object from this SDP description:
00127     _session = MediaSession::createNew(*_live_env, sdpDescription);
00128 
00129     delete[] sdpDescription;
00130 
00131     if (!_session)
00132     {
00133         LOG(VB_GENERAL, LOG_ERR, LOC +
00134             QString("Failed to create MediaSession: %1")
00135                 .arg(_live_env->getResultMsg()));
00136         return false;
00137     }
00138     else if (!_session->hasSubsessions())
00139     {
00140         LOG(VB_GENERAL, LOG_ERR, LOC + "This session has no media subsessions");
00141         Close();
00142         return false;
00143     }
00144 
00145     // Then, setup the "RTPSource"s for the session:
00146     MediaSubsessionIterator iter(*_session);
00147     MediaSubsession *subsession;
00148     bool madeProgress = false;
00149 
00150     while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */
00151     {
00152         if (!subsession->initiate(-1))
00153         {
00154             LOG(VB_GENERAL, LOG_ERR, LOC +
00155                 QString("Can't create receiver for: %1 / %2 subsession: %3")
00156                     .arg(subsession->mediumName())
00157                     .arg(subsession->codecName())
00158                     .arg(_live_env->getResultMsg()));
00159         }
00160         else
00161         {
00162             madeProgress = true;
00163 
00164             if (subsession->rtpSource() != NULL)
00165             {
00166                 unsigned const thresh = 1000000; // 1 second
00167                 subsession->rtpSource()->
00168                     setPacketReorderingThresholdTime(thresh);
00169             }
00170         }
00171     }
00172 
00173     if (!madeProgress)
00174         return false;
00175 
00176     // Perform additional 'setup' on each subsession, before playing them:
00177     madeProgress = false;
00178     iter.reset();
00179     while ((subsession = iter.next()) != NULL)
00180     {
00181         if (subsession->clientPortNum() == 0)
00182             continue; // port # was not set
00183 
00184         if (_rtsp_client->setupMediaSubsession(*subsession, false, false))
00185         {
00186             madeProgress = true;
00187         }
00188         else
00189         {
00190             LOG(VB_GENERAL, LOG_ERR, LOC +
00191                 QString("Failed to setup: %1 %2 : %3")
00192                     .arg(subsession->mediumName())
00193                     .arg(subsession->codecName())
00194                     .arg(_live_env->getResultMsg()));
00195         }
00196     }
00197 
00198     if (!madeProgress)
00199         return false;
00200 
00201     // Create and start "FileSink"s for each subsession:
00202     // FileSink while receive Mpeg2 TS Data & will feed them to mythtv
00203     madeProgress = false;
00204     iter.reset();
00205 
00206     while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */
00207     {
00208         if (!subsession->readSource())
00209             continue; // was not initiated
00210 
00211         IPTVMediaSink *iptvMediaSink = IPTVMediaSink::CreateNew(
00212             *_live_env, TSPacket::kSize * 128*1024);
00213 
00214         subsession->sink = iptvMediaSink;
00215         if (!subsession->sink)
00216         {
00217             LOG(VB_GENERAL, LOG_ERR, QString("IPTV # Failed to create sink: %1")
00218                     .arg(_live_env->getResultMsg()));
00219         }
00220 
00221         vector<TSDataListener*>::iterator it = _listeners.begin();
00222         for (; it != _listeners.end(); ++it)
00223             iptvMediaSink->AddListener(*it);
00224 
00225         subsession->sink->startPlaying(*(subsession->readSource()),
00226                                        sub_after_playing_cb,
00227                                        new RTSPData(subsession));
00228 
00229         if (subsession->rtcpInstance())
00230         {
00231             subsession->rtcpInstance()->setByeHandler(
00232                 sub_bye_handler_cb, new RTSPData(subsession));
00233         }
00234 
00235         madeProgress = true;
00236     }
00237 
00238     if (!madeProgress)
00239         return false;
00240 
00241     // Setup player
00242     if (!(_rtsp_client->playMediaSession(*_session)))
00243     {
00244         LOG(VB_GENERAL, LOG_ERR, LOC +
00245             QString("Failed to start playing session: %1")
00246                 .arg(_live_env->getResultMsg()));
00247         return false;
00248     }
00249 
00250     LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end");
00251     return true;
00252 }
00253 
00254 void IPTVFeederRTSP::Close(void)
00255 {
00256     LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin");
00257     Stop();
00258 
00259     LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- middle 1");
00260 
00261     _lock.lock();
00262     if (_session)
00263     {
00264         // Ensure RTSP cleanup, remove old RTSP session
00265         MediaSubsessionIterator iter(*_session);
00266         MediaSubsession *subsession;
00267         while ((subsession = iter.next())) /*<-extra braces for pedantic gcc*/
00268         {
00269             Medium::close(subsession->sink);
00270             subsession->sink = NULL;
00271         }
00272 
00273         _rtsp_client->teardownMediaSession(*_session);
00274 
00275         // Close all RTSP descriptor
00276         Medium::close(_session);
00277         _session = NULL;
00278     }
00279     _lock.unlock();
00280 
00281     if (_rtsp_client)
00282     {
00283         Medium::close(_rtsp_client);
00284         _rtsp_client = NULL;
00285     }
00286 
00287     FreeEnv();
00288 
00289     LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end");
00290 }
00291 
00292 void IPTVFeederRTSP::AddListener(TSDataListener *item)
00293 {
00294     LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- begin")
00295                        .arg((uint64_t)item,0,16));
00296     if (!item)
00297     {
00298         LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end 0")
00299                            .arg((uint64_t)item,0,16));
00300         return;
00301     }
00302 
00303     // avoid duplicates
00304     RemoveListener(item);
00305 
00306     // add to local list
00307     QMutexLocker locker(&_lock);
00308     _listeners.push_back(item);
00309 
00310     // if there is a session, add to each subsession->sink
00311     if (!_session)
00312     {
00313         LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end 1")
00314                            .arg((uint64_t)item,0,16));
00315         return;
00316     }
00317 
00318     MediaSubsessionIterator mit(*_session);
00319     MediaSubsession *subsession;
00320     while ((subsession = mit.next())) /* <- extra braces for pedantic gcc */
00321     {
00322         IPTVMediaSink *sink = NULL;
00323         if ((sink = dynamic_cast<IPTVMediaSink*>(subsession->sink)))
00324             sink->AddListener(item);
00325     }
00326     LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end 2")
00327                        .arg((uint64_t)item,0,16));
00328 }
00329 
00330 void IPTVFeederRTSP::RemoveListener(TSDataListener *item)
00331 {
00332     LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- begin")
00333                        .arg((uint64_t)item,0,16));;
00334     QMutexLocker locker(&_lock);
00335     vector<TSDataListener*>::iterator it =
00336         find(_listeners.begin(), _listeners.end(), item);
00337 
00338     if (it == _listeners.end())
00339     {
00340         LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 1")
00341                            .arg((uint64_t)item,0,16));
00342         return;
00343     }
00344 
00345     // remove from local list..
00346     *it = *_listeners.rbegin();
00347     _listeners.resize(_listeners.size() - 1);
00348 
00349     // if there is a session, remove from each subsession->sink
00350     if (!_session)
00351     {
00352         LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 2")
00353                            .arg((uint64_t)item,0,16));
00354         return;
00355     }
00356 
00357     MediaSubsessionIterator mit(*_session);
00358     MediaSubsession *subsession;
00359     while ((subsession = mit.next())) /* <- extra braces for pedantic gcc */
00360     {
00361         IPTVMediaSink *sink = NULL;
00362         if ((sink = dynamic_cast<IPTVMediaSink*>(subsession->sink)))
00363             sink->RemoveListener(item);
00364     }
00365     LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 3")
00366                        .arg((uint64_t)item,0,16));
00367 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends