00001
00006 #include <algorithm>
00007
00008 #include "iptvfeederrtsp.h"
00009
00010
00011 #include <RTSPClient.hh>
00012 #include <BasicUsageEnvironment.hh>
00013 #include <MediaSession.hh>
00014
00015
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
00098 if (!InitEnv())
00099 return false;
00100
00101
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
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
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
00146 MediaSubsessionIterator iter(*_session);
00147 MediaSubsession *subsession;
00148 bool madeProgress = false;
00149
00150 while ((subsession = iter.next()))
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;
00167 subsession->rtpSource()->
00168 setPacketReorderingThresholdTime(thresh);
00169 }
00170 }
00171 }
00172
00173 if (!madeProgress)
00174 return false;
00175
00176
00177 madeProgress = false;
00178 iter.reset();
00179 while ((subsession = iter.next()) != NULL)
00180 {
00181 if (subsession->clientPortNum() == 0)
00182 continue;
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
00202
00203 madeProgress = false;
00204 iter.reset();
00205
00206 while ((subsession = iter.next()))
00207 {
00208 if (!subsession->readSource())
00209 continue;
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
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
00265 MediaSubsessionIterator iter(*_session);
00266 MediaSubsession *subsession;
00267 while ((subsession = iter.next()))
00268 {
00269 Medium::close(subsession->sink);
00270 subsession->sink = NULL;
00271 }
00272
00273 _rtsp_client->teardownMediaSession(*_session);
00274
00275
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
00304 RemoveListener(item);
00305
00306
00307 QMutexLocker locker(&_lock);
00308 _listeners.push_back(item);
00309
00310
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()))
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
00346 *it = *_listeners.rbegin();
00347 _listeners.resize(_listeners.size() - 1);
00348
00349
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()))
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 }