Hello,

      In my previous mail I have suggested how to prevent memory leaks in
DarwinInjector.

I want to correct a possible crash in my solution and add some more.

 

1) My solution could cause NULL pointer memory access error when a
DarwinInjector was deleted before a session was created. So a "if (session)"
clause was added before my use of "session" in DarwinInjector's destructor.

 

2) I have added a deletion of MediaSubsession's sessionId in the
MediaSubsession destructor. This way it is safe to delete a session without
causing a memory leak because of sessionId.

 

MediaSubsession::~MediaSubsession() {

...

  delete[] sessionId;//allocated by RTSP, freed only by RTSP Tear-Session

...

}

 

3) When using a couple of DarwinInjector instances/sessions, the first
stream of each does not get to have a track-id of "1", but the value is
being kept incremented. This is because the track-id used is a static
variable in the injector module.

   I had changed the variable to be a member of the injector, to be init as
0 in the constructor, and be passes by reference to be incremented by
SubstreamDescriptor in DarwinInjector::addStream().

 

Attached in DarwinInjector cpp and h files, with my previous and last
modifications, marked with "/**/" on each modified line's start.

 

Eyal Beit-Halachmi

/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**********/
// "liveMedia"
// Copyright (c) 1996-2007 Live Networks, Inc.  All rights reserved.
// An object that redirects one or more RTP/RTCP streams - forming a single
// multimedia session - into a 'Darwin Streaming Server' (for subsequent
// reflection to potentially arbitrarily many remote RTSP clients).
// Implementation.

#include "DarwinInjector.hh"
#include <GroupsockHelper.hh>

////////// SubstreamDescriptor definition //////////

class SubstreamDescriptor {
public:
/**/  SubstreamDescriptor(RTPSink* rtpSink, RTCPInstance* rtcpInstance,unsigned 
&lastTrackId);
  ~SubstreamDescriptor();

  SubstreamDescriptor*& next() { return fNext; }
  RTPSink* rtpSink() const { return fRTPSink; }
  RTCPInstance* rtcpInstance() const { return fRTCPInstance; }
  char const* sdpLines() const { return fSDPLines; }

private:
  SubstreamDescriptor* fNext;
  RTPSink* fRTPSink;
  RTCPInstance* fRTCPInstance;
  char* fSDPLines;
};


////////// DarwinInjector implementation //////////

DarwinInjector* DarwinInjector::createNew(UsageEnvironment& env,
                                          char const* applicationName,
                                          int verbosityLevel) {
  return new DarwinInjector(env, applicationName, verbosityLevel);
}

Boolean DarwinInjector::lookupByName(UsageEnvironment& env, char const* name,
                                     DarwinInjector*& result) {
  result = NULL; // unless we succeed

  Medium* medium;
  if (!Medium::lookupByName(env, name, medium)) return False;

  if (!medium->isDarwinInjector()) {
    env.setResultMsg(name, " is not a 'Darwin injector'");
    return False;
  }

  result = (DarwinInjector*)medium;
  return True;
}

DarwinInjector::DarwinInjector(UsageEnvironment& env,
                               char const* applicationName, int verbosityLevel)
  : Medium(env),
    fApplicationName(strDup(applicationName)), fVerbosityLevel(verbosityLevel),
    fRTSPClient(NULL), fSubstreamSDPSizes(0),
/**/    fHeadSubstream(NULL), fTailSubstream(NULL), session(NULL), 
lastTrackId(0) {
} 

DarwinInjector::~DarwinInjector() {
/**/  // Tear down media subsessions for gracefull closure and mem leaks 
prevention
/**/  if(session)
/**/  {
/**/    MediaSubsessionIterator iter(*session);
/**/    MediaSubsession* subsession;
/**/    while ((subsession = iter.next()) != NULL)
/**/      fRTSPClient->teardownMediaSubsession(*subsession);// Inform other 
side. Release subsessions ids
/**/    Medium::close(session);// Also free subsessions ids
/**/    session=NULL;
/**/  }
  delete fHeadSubstream;
  delete[] (char*)fApplicationName;
  Medium::close(fRTSPClient);
}

void DarwinInjector::addStream(RTPSink* rtpSink, RTCPInstance* rtcpInstance) {
  if (rtpSink == NULL) return; // "rtpSink" should be non-NULL

/**/  SubstreamDescriptor* newDescriptor = new SubstreamDescriptor(rtpSink, 
rtcpInstance, lastTrackId);
  if (fHeadSubstream == NULL) {
    fHeadSubstream = fTailSubstream = newDescriptor;
  } else {
    fTailSubstream->next() = newDescriptor;
    fTailSubstream = newDescriptor;
  }

  fSubstreamSDPSizes += strlen(newDescriptor->sdpLines());
}

Boolean DarwinInjector
::setDestination(char const* remoteRTSPServerNameOrAddress,
                 char const* remoteFileName,
                 char const* sessionName,
                 char const* sessionInfo,
                 portNumBits remoteRTSPServerPortNumber,
                 char const* remoteUserName,
                 char const* remotePassword,
                 char const* sessionAuthor,
                 char const* sessionCopyright) {
  char* sdp = NULL;
  char* url = NULL;
/**/  //MediaSession* session = NULL;//moved to be a member var
  Boolean success = False; // until we learn otherwise

  do {
    // Begin by creating our RTSP client object:
    fRTSPClient = RTSPClient::createNew(envir(), fVerbosityLevel, 
fApplicationName);
    if (fRTSPClient == NULL) break;

    // Get the remote RTSP server's IP address:
    struct in_addr addr;
    {
      NetAddressList addresses(remoteRTSPServerNameOrAddress);
      if (addresses.numAddresses() == 0) break;
      NetAddress const* address = addresses.firstAddress();
      addr.s_addr = *(unsigned*)(address->data());
    }
    char const* remoteRTSPServerAddressStr = our_inet_ntoa(addr);

    // Construct a SDP description for the session that we'll be streaming:
    char const* const sdpFmt =
      "v=0\r\n"
      "o=- %u %u IN IP4 127.0.0.1\r\n"
      "s=%s\r\n"
      "i=%s\r\n"
      "c=IN IP4 %s\r\n"
      "t=0 0\r\n"
      "a=x-qt-text-nam:%s\r\n"
      "a=x-qt-text-inf:%s\r\n"
      "a=x-qt-text-cmt:source application:%s\r\n"
      "a=x-qt-text-aut:%s\r\n"
      "a=x-qt-text-cpy:%s\r\n";
      // plus, %s for each substream SDP
    unsigned sdpLen = strlen(sdpFmt)
      + 20 /* max int len */ + 20 /* max int len */
      + strlen(sessionName)
      + strlen(sessionInfo)
      + strlen(remoteRTSPServerAddressStr)
      + strlen(sessionName)
      + strlen(sessionInfo)
      + strlen(fApplicationName)
      + strlen(sessionAuthor)
      + strlen(sessionCopyright)
      + fSubstreamSDPSizes;
    unsigned const sdpSessionId = our_random();
    unsigned const sdpVersion = sdpSessionId;
    sdp = new char[sdpLen];
    sprintf(sdp, sdpFmt,
            sdpSessionId, sdpVersion, // o= line
            sessionName, // s= line
            sessionInfo, // i= line
            remoteRTSPServerAddressStr, // c= line
            sessionName, // a=x-qt-text-nam: line
            sessionInfo, // a=x-qt-text-inf: line
            fApplicationName, // a=x-qt-text-cmt: line
            sessionAuthor, // a=x-qt-text-aut: line
            sessionCopyright // a=x-qt-text-cpy: line
            );
    char* p = &sdp[strlen(sdp)];
    SubstreamDescriptor* ss;
    for (ss = fHeadSubstream; ss != NULL; ss = ss->next()) {
      sprintf(p, "%s", ss->sdpLines());
      p += strlen(p);
    }

    // Construct a RTSP URL for the remote stream:
    char const* const urlFmt = "rtsp://%s:%u/%s";
    unsigned urlLen
      = strlen(urlFmt) + strlen(remoteRTSPServerNameOrAddress) + 5 /* max short 
len */ + strlen(remoteFileName);
    url = new char[urlLen];
    sprintf(url, urlFmt, remoteRTSPServerNameOrAddress, 
remoteRTSPServerPortNumber, remoteFileName);

    // Do a RTSP "ANNOUNCE" with this SDP description:
    Boolean announceSuccess;
    if (remoteUserName[0] != '\0' || remotePassword[0] != '\0') {
      announceSuccess
        = fRTSPClient->announceWithPassword(url, sdp, remoteUserName, 
remotePassword);
    } else {
      announceSuccess = fRTSPClient->announceSDPDescription(url, sdp);
    }
    if (!announceSuccess) break;

    // Tell the remote server to start receiving the stream from us.
    // (To do this, we first create a "MediaSession" object from the SDP 
description.)
    session = MediaSession::createNew(envir(), sdp);
    if (session == NULL) break;

    ss = fHeadSubstream;
    MediaSubsessionIterator iter(*session);
    MediaSubsession* subsession;
    ss = fHeadSubstream;
    unsigned streamChannelId = 0;
    while ((subsession = iter.next()) != NULL) {
      if (!subsession->initiate()) break;

      if (!fRTSPClient->setupMediaSubsession(*subsession,
                                             True /*streamOutgoing*/,
                                             True /*streamUsingTCP*/)) {
        break;
      }

      // Tell this subsession's RTPSink and RTCPInstance to use
      // the RTSP TCP connection:
      ss->rtpSink()->setStreamSocket(fRTSPClient->socketNum(), 
streamChannelId++);
      if (ss->rtcpInstance() != NULL) {
        ss->rtcpInstance()->setStreamSocket(fRTSPClient->socketNum(),
                                            streamChannelId++);
      }
      ss = ss->next();
    }
    if (subsession != NULL) break; // an error occurred above

    // Tell the RTSP server to start:
    if (!fRTSPClient->playMediaSession(*session)) break;

    // Finally, make sure that the output TCP buffer is a reasonable size:
    increaseSendBufferTo(envir(), fRTSPClient->socketNum(), 100*1024);

    success = True;
  } while (0);

  delete[] sdp;
  delete[] url; 
/**/  //Medium::close(session);//moved to the destructor
  return success;
}

Boolean DarwinInjector::isDarwinInjector() const {
  return True;
}


////////// SubstreamDescriptor implementation //////////

/**///static unsigned lastTrackId = 0;//moved to be a member of DarwinInjector

SubstreamDescriptor::SubstreamDescriptor(RTPSink* rtpSink,
/**/                                     RTCPInstance* rtcpInstance,
/**/                                     unsigned &lastTrackId)
  : fNext(NULL), fRTPSink(rtpSink), fRTCPInstance(rtcpInstance) {
  // Create the SDP description for this substream
  char const* mediaType = fRTPSink->sdpMediaType();
  unsigned char rtpPayloadType = fRTPSink->rtpPayloadType();
  char const* rtpPayloadFormatName = fRTPSink->rtpPayloadFormatName();
  unsigned rtpTimestampFrequency = fRTPSink->rtpTimestampFrequency();
  unsigned numChannels = fRTPSink->numChannels();
  char* rtpmapLine;
  if (rtpPayloadType >= 96) {
    char* encodingParamsPart;
    if (numChannels != 1) {
      encodingParamsPart = new char[1 + 20 /* max int len */];
      sprintf(encodingParamsPart, "/%d", numChannels);
    } else {
      encodingParamsPart = strDup("");
    }
    char const* const rtpmapFmt = "a=rtpmap:%d %s/%d%s\r\n";
    unsigned rtpmapFmtSize = strlen(rtpmapFmt)
      + 3 /* max char len */ + strlen(rtpPayloadFormatName)
      + 20 /* max int len */ + strlen(encodingParamsPart);
    rtpmapLine = new char[rtpmapFmtSize];
    sprintf(rtpmapLine, rtpmapFmt,
            rtpPayloadType, rtpPayloadFormatName,
            rtpTimestampFrequency, encodingParamsPart);
    delete[] encodingParamsPart;
  } else {
    // Static payload type => no "a=rtpmap:" line
    rtpmapLine = strDup("");
  }
  unsigned rtpmapLineSize = strlen(rtpmapLine);
  char const* auxSDPLine = fRTPSink->auxSDPLine();
  if (auxSDPLine == NULL) auxSDPLine = "";
  unsigned auxSDPLineSize = strlen(auxSDPLine);
  
  char const* const sdpFmt =
    "m=%s 0 RTP/AVP %u\r\n"
    "%s" // "a=rtpmap:" line (if present)
    "%s" // auxilliary (e.g., "a=fmtp:") line (if present)
    "a=control:trackID=%u\r\n";
  unsigned sdpFmtSize = strlen(sdpFmt)
    + strlen(mediaType) + 3 /* max char len */
    + rtpmapLineSize
    + auxSDPLineSize
    + 20 /* max int len */;
  char* sdpLines = new char[sdpFmtSize];
  sprintf(sdpLines, sdpFmt,
          mediaType, // m= <media>
          rtpPayloadType, // m= <fmt list>
          rtpmapLine, // a=rtpmap:... (if present)
          auxSDPLine, // optional extra SDP line
          ++lastTrackId); // a=control:<track-id>
  fSDPLines = strDup(sdpLines);
/**/  delete[] rtpmapLine; //added to prevent memory leak !!!
  delete[] sdpLines;
}

SubstreamDescriptor::~SubstreamDescriptor() {
  delete fSDPLines;
  delete fNext;
}

Attachment: DarwinInjector.hh
Description: Binary data

_______________________________________________
live-devel mailing list
live-devel@lists.live555.com
http://lists.live555.com/mailman/listinfo/live-devel

Reply via email to