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 "tspacket.h"
00019
00020 #define LOC QString("IPTVFeedRTSP:")
00021 #define LOC_ERR QString("IPTVFeedRTSP, Error:")
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 VERBOSE(VB_RECORD, LOC + "ctor -- success");
00070 }
00071
00072 IPTVFeederRTSP::~IPTVFeederRTSP()
00073 {
00074 VERBOSE(VB_RECORD, LOC + "dtor -- begin");
00075 Close();
00076 VERBOSE(VB_RECORD, LOC + "dtor -- end");
00077 }
00078
00079 bool IPTVFeederRTSP::IsRTSP(const QString &url)
00080 {
00081 return url.startsWith("rtsp://", false);
00082 }
00083
00084 bool IPTVFeederRTSP::Open(const QString &url)
00085 {
00086 VERBOSE(VB_RECORD, LOC + QString("Open(%1) -- begin").arg(url));
00087
00088 QMutexLocker locker(&_lock);
00089
00090 if (_rtsp_client)
00091 {
00092 VERBOSE(VB_RECORD, 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 VERBOSE(VB_IMPORTANT, LOC_ERR +
00106 QString("Failed to create RTSP client: %1")
00107 .arg(_live_env->getResultMsg()));
00108 FreeEnv();
00109 }
00110
00111
00112 char *sdpDescription = _rtsp_client->describeURL(url);
00113 _rtsp_client->describeStatus();
00114
00115 if (!sdpDescription)
00116 {
00117 VERBOSE(VB_IMPORTANT, LOC + QString(
00118 "Failed to get a SDP "
00119 "description from URL: %1 %2")
00120 .arg(url).arg(_live_env->getResultMsg()));
00121 return false;
00122 }
00123
00124
00125 _session = MediaSession::createNew(*_live_env, sdpDescription);
00126
00127 delete[] sdpDescription;
00128
00129 if (!_session)
00130 {
00131 VERBOSE(VB_IMPORTANT, LOC +
00132 QString("Failed to create MediaSession: %1")
00133 .arg(_live_env->getResultMsg()));
00134 return false;
00135 }
00136 else if (!_session->hasSubsessions())
00137 {
00138 VERBOSE(VB_IMPORTANT, LOC +
00139 "This session has no media subsessions");
00140 Close();
00141 return false;
00142 }
00143
00144
00145 MediaSubsessionIterator iter(*_session);
00146 MediaSubsession *subsession;
00147 bool madeProgress = false;
00148
00149 while ((subsession = iter.next()))
00150 {
00151 if (!subsession->initiate(-1))
00152 {
00153 VERBOSE(VB_IMPORTANT, LOC +
00154 QString("Can't create receiver for: "
00155 "%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 VERBOSE(VB_IMPORTANT, 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::SIZE * 128*1024);
00213
00214 subsession->sink = iptvMediaSink;
00215 if (!subsession->sink)
00216 {
00217 VERBOSE(VB_IMPORTANT,
00218 QString("IPTV # Failed to create sink: %1")
00219 .arg(_live_env->getResultMsg()));
00220 }
00221
00222 vector<TSDataListener*>::iterator it = _listeners.begin();
00223 for (; it != _listeners.end(); ++it)
00224 iptvMediaSink->AddListener(*it);
00225
00226 subsession->sink->startPlaying(*(subsession->readSource()),
00227 sub_after_playing_cb,
00228 new RTSPData(subsession));
00229
00230 if (subsession->rtcpInstance())
00231 {
00232 subsession->rtcpInstance()->setByeHandler(
00233 sub_bye_handler_cb, new RTSPData(subsession));
00234 }
00235
00236 madeProgress = true;
00237 }
00238
00239 if (!madeProgress)
00240 return false;
00241
00242
00243 if (!(_rtsp_client->playMediaSession(*_session)))
00244 {
00245 VERBOSE(VB_IMPORTANT, LOC +
00246 QString("Failed to start playing session: %1")
00247 .arg(_live_env->getResultMsg()));
00248 return false;
00249 }
00250
00251 VERBOSE(VB_RECORD, LOC + "Open() -- end");
00252 return true;
00253 }
00254
00255 void IPTVFeederRTSP::Close(void)
00256 {
00257 VERBOSE(VB_RECORD, LOC + "Close() -- begin");
00258 Stop();
00259
00260 VERBOSE(VB_RECORD, LOC + "Close() -- middle 1");
00261
00262 _lock.lock();
00263 if (_session)
00264 {
00265
00266 MediaSubsessionIterator iter(*_session);
00267 MediaSubsession *subsession;
00268 while ((subsession = iter.next()))
00269 {
00270 Medium::close(subsession->sink);
00271 subsession->sink = NULL;
00272 }
00273
00274 _rtsp_client->teardownMediaSession(*_session);
00275
00276
00277 Medium::close(_session);
00278 _session = NULL;
00279 }
00280 _lock.unlock();
00281
00282 if (_rtsp_client)
00283 {
00284 Medium::close(_rtsp_client);
00285 _rtsp_client = NULL;
00286 }
00287
00288 FreeEnv();
00289
00290 VERBOSE(VB_RECORD, LOC + "Close() -- end");
00291 }
00292
00293 void IPTVFeederRTSP::AddListener(TSDataListener *item)
00294 {
00295 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- begin");
00296 if (!item)
00297 {
00298 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end 0");
00299 return;
00300 }
00301
00302
00303 RemoveListener(item);
00304
00305
00306 QMutexLocker locker(&_lock);
00307 _listeners.push_back(item);
00308
00309
00310 if (!_session)
00311 {
00312 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end 1");
00313 return;
00314 }
00315
00316 MediaSubsessionIterator mit(*_session);
00317 MediaSubsession *subsession;
00318 while ((subsession = mit.next()))
00319 {
00320 IPTVMediaSink *sink = NULL;
00321 if ((sink = dynamic_cast<IPTVMediaSink*>(subsession->sink)))
00322 sink->AddListener(item);
00323 }
00324 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end 2");
00325 }
00326
00327 void IPTVFeederRTSP::RemoveListener(TSDataListener *item)
00328 {
00329 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- begin");
00330 QMutexLocker locker(&_lock);
00331 vector<TSDataListener*>::iterator it =
00332 find(_listeners.begin(), _listeners.end(), item);
00333
00334 if (it == _listeners.end())
00335 {
00336 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end 1");
00337 return;
00338 }
00339
00340
00341 *it = *_listeners.rbegin();
00342 _listeners.resize(_listeners.size() - 1);
00343
00344
00345 if (!_session)
00346 {
00347 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end 2");
00348 return;
00349 }
00350
00351 MediaSubsessionIterator mit(*_session);
00352 MediaSubsession *subsession;
00353 while ((subsession = mit.next()))
00354 {
00355 IPTVMediaSink *sink = NULL;
00356 if ((sink = dynamic_cast<IPTVMediaSink*>(subsession->sink)))
00357 sink->RemoveListener(item);
00358 }
00359 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end 3");
00360 }