25#include "AudioLogger.h"
28#include "BasicUsageEnvironment.hh"
30#include "RTSPClient.hh"
35#define REQUEST_STREAMING_OVER_TCP false
38#define RTSP_CLIENT_VERBOSITY_LEVEL 1
41#define RTSP_SINK_BUFFER_SIZE 1024
45#undef DEBUG_PRINT_EACH_RECEIVED_FRAME
46#define DEBUG_PRINT_EACH_RECEIVED_FRAME 0
112 scheduler = BasicTaskScheduler::createNew();
163 Serial.print(
"Local Address: ");
207 const RTSPClient& rtspClient) {
208 return env <<
"[URL:\"" << rtspClient.url() <<
"\"]: ";
214 const MediaSubsession& subsession) {
215 return env << subsession.mediumName() <<
"/" << subsession.codecName();
242 int verbosityLevel = 0,
243 char const* applicationName = NULL,
244 portNumBits tunnelOverHTTPPortNum = 0);
247 OurRTSPClient(UsageEnvironment& env,
char const* rtspURL,
int verbosityLevel,
248 char const* applicationName, portNumBits tunnelOverHTTPPortNum);
267 UsageEnvironment& env,
270 char const* streamId = NULL);
273 OurSink(UsageEnvironment& env, MediaSubsession& subsession,
274 char const* streamId);
278 static void afterGettingFrame(
void* clientData,
unsigned frameSize,
279 unsigned numTruncatedBytes,
280 struct timeval presentationTime,
281 unsigned durationInMicroseconds);
282 void afterGettingFrame(
unsigned frameSize,
unsigned numTruncatedBytes,
283 struct timeval presentationTime,
284 unsigned durationInMicroseconds);
288 virtual Boolean continuePlaying();
291 u_int8_t* fReceiveBuffer;
292 MediaSubsession& fSubsession;
302 if (rtspClient == NULL) {
303 env <<
"Failed to create a RTSP client for URL \"" << rtspURL
304 <<
"\": " << env.getResultMsg() <<
"\n";
322 char* resultString) {
324 UsageEnvironment& env = rtspClient->envir();
327 if (resultCode != 0) {
328 env << *rtspClient <<
"Failed to get a SDP description: " << resultString
330 delete[] resultString;
334 char*
const sdpDescription = resultString;
335 env << *rtspClient <<
"Got a SDP description:\n" << sdpDescription <<
"\n";
338 scs.
session = MediaSession::createNew(env, sdpDescription);
339 delete[] sdpDescription;
342 <<
"Failed to create a MediaSession object from the SDP description: "
343 << env.getResultMsg() <<
"\n";
345 }
else if (!scs.
session->hasSubsessions()) {
347 <<
"This session has no media subsessions (i.e., no \"m=\" lines)\n";
355 scs.
iter =
new MediaSubsessionIterator(*scs.
session);
365 UsageEnvironment& env = rtspClient->envir();
371 env << *rtspClient <<
"Failed to initiate the \"" << *scs.
subsession
372 <<
"\" subsession: " << env.getResultMsg() <<
"\n";
376 env << *rtspClient <<
"Initiated the \"" << *scs.
subsession
377 <<
"\" subsession (";
379 env <<
"client port " << scs.
subsession->clientPortNum();
381 env <<
"client ports " << scs.
subsession->clientPortNum() <<
"-"
395 if (scs.
session->absStartTime() != NULL) {
408 char* resultString) {
410 UsageEnvironment& env = rtspClient->envir();
413 if (resultCode != 0) {
414 env << *rtspClient <<
"Failed to set up the \"" << *scs.
subsession
415 <<
"\" subsession: " << resultString <<
"\n";
419 env << *rtspClient <<
"Set up the \"" << *scs.
subsession
420 <<
"\" subsession (";
422 env <<
"client port " << scs.
subsession->clientPortNum();
424 env <<
"client ports " << scs.
subsession->clientPortNum() <<
"-"
438 env << *rtspClient <<
"Failed to create a data sink for the \""
439 << *scs.
subsession <<
"\" subsession: " << env.getResultMsg() <<
"\n";
443 env << *rtspClient <<
"Created a data sink for the \"" << *scs.
subsession
444 <<
"\" subsession\n";
453 scs.
subsession->rtcpInstance()->setByeWithReasonHandler(
457 delete[] resultString;
464 char* resultString) {
465 Boolean success = False;
468 UsageEnvironment& env = rtspClient->envir();
471 if (resultCode != 0) {
472 env << *rtspClient <<
"Failed to start playing session: " << resultString
484 unsigned const delaySlop =
488 unsigned uSecsToDelay = (unsigned)(scs.
duration * 1000000);
493 env << *rtspClient <<
"Started playing session";
495 env <<
" (for up to " << scs.
duration <<
" seconds)";
501 delete[] resultString;
512 MediaSubsession* subsession = (MediaSubsession*)clientData;
513 RTSPClient* rtspClient = (RTSPClient*)(subsession->miscPtr);
516 Medium::close(subsession->sink);
517 subsession->sink = NULL;
520 MediaSession& session = subsession->parentSession();
521 MediaSubsessionIterator iter(session);
522 while ((subsession = iter.next()) != NULL) {
523 if (subsession->sink != NULL)
return;
531 MediaSubsession* subsession = (MediaSubsession*)clientData;
532 RTSPClient* rtspClient = (RTSPClient*)subsession->miscPtr;
533 UsageEnvironment& env = rtspClient->envir();
535 env << *rtspClient <<
"Received RTCP \"BYE\"";
536 if (reason != NULL) {
537 env <<
" (reason:\"" << reason <<
"\")";
538 delete[] (
char*)reason;
540 env <<
" on \"" << *subsession <<
"\" subsession\n";
557 UsageEnvironment& env = rtspClient->envir();
562 Boolean someSubsessionsWereActive = False;
563 MediaSubsessionIterator iter(*scs.
session);
564 MediaSubsession* subsession;
566 while ((subsession = iter.next()) != NULL) {
567 if (subsession->sink != NULL) {
568 Medium::close(subsession->sink);
569 subsession->sink = NULL;
571 if (subsession->rtcpInstance() != NULL) {
572 subsession->rtcpInstance()->setByeHandler(
577 someSubsessionsWereActive = True;
581 if (someSubsessionsWereActive) {
584 rtspClient->sendTeardownCommand(*scs.
session, NULL);
588 env << *rtspClient <<
"Closing the stream.\n";
589 Medium::close(rtspClient);
608 char const* rtspURL,
int verbosityLevel,
609 char const* applicationName,
610 portNumBits tunnelOverHTTPPortNum) {
611 return new OurRTSPClient(env, rtspURL, verbosityLevel, applicationName,
612 tunnelOverHTTPPortNum);
616 int verbosityLevel,
char const* applicationName,
617 portNumBits tunnelOverHTTPPortNum)
618 : RTSPClient(env, rtspURL, verbosityLevel, applicationName,
619 tunnelOverHTTPPortNum, -1) {}
629 streamTimerTask(NULL),
637 UsageEnvironment& env =
session->envir();
647 MediaSubsession& subsession,
648 char const* streamId) {
649 return new OurSink(env, subsession, streamId);
652OurSink::OurSink(UsageEnvironment& env, MediaSubsession& subsession,
653 char const* streamId)
654 : MediaSink(env), fSubsession(subsession) {
655 fStreamId = strDup(streamId);
660 delete[] fReceiveBuffer;
664void OurSink::afterGettingFrame(
void* clientData,
unsigned frameSize,
665 unsigned numTruncatedBytes,
666 struct timeval presentationTime,
667 unsigned durationInMicroseconds) {
668 OurSink* sink = (OurSink*)clientData;
669 sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime,
670 durationInMicroseconds);
673void OurSink::afterGettingFrame(
unsigned frameSize,
674 unsigned numTruncatedBytes,
675 struct timeval presentationTime,
679#ifdef DEBUG_PRINT_EACH_RECEIVED_FRAME
680 if (fStreamId != NULL) envir() <<
"Stream \"" << fStreamId <<
"\"; ";
681 envir() << fSubsession.mediumName() <<
"/" << fSubsession.codecName()
682 <<
":\tReceived " << frameSize <<
" bytes";
683 if (numTruncatedBytes > 0)
684 envir() <<
" (with " << numTruncatedBytes <<
" bytes truncated)";
685 char uSecsStr[6 + 1];
687 snprintf(uSecsStr,7 ,
"%06u", (
unsigned)presentationTime.tv_usec);
688 envir() <<
".\tPresentation time: " << (int)presentationTime.tv_sec <<
"."
690 if (fSubsession.rtpSource() != NULL &&
691 !fSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP()) {
695#ifdef DEBUG_PRINT_NPT
696 envir() <<
"\tNPT: " << fSubsession.getNormalPlayTime(presentationTime);
703 size_t writtenSize =
rtspOutput->write(fReceiveBuffer, frameSize);
704 assert(writtenSize == frameSize);
711Boolean OurSink::continuePlaying() {
712 if (fSource == NULL)
return False;
717 afterGettingFrame,
this, onSourceClosure,
this);
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define REQUEST_STREAMING_OVER_TCP
Definition RTSPClient555.h:35
#define RTSP_CLIENT_VERBOSITY_LEVEL
Definition RTSPClient555.h:38
#define RTSP_SINK_BUFFER_SIZE
Definition RTSPClient555.h:41
#define assert(T)
Definition avr.h:10