|
MythTV
0.26-pre
|
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 }
1.7.6.1