[haiku-commits] haiku: hrev50341 - src/add-ons/media/plugins/rtsp_streamer

  • From: b.vitruvio@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 2 Jun 2016 19:12:59 +0200 (CEST)

hrev50341 adds 3 changesets to branch 'master'
old head: f2e31bcc08bacc6356a1ce51547f3637f6f6fad5
new head: 4c7eafb74b56eca40630bba0580d660874dc6268
overview: 
http://cgit.haiku-os.org/haiku/log/?qt=range&q=4c7eafb74b56+%5Ef2e31bcc08ba

----------------------------------------------------------------------------

5029fabd08da: live555: Library order caused missing symbols

228b5c174e73: Implement SetSize in AdapterIO
  
  * Give this choice to inherited classes.

4c7eafb74b56: Include testing version rtsp_streamer
  
  * Rewritten from scratch to use live555 and BAdapterIO.

                                [ Dario Casalinuovo <b.vitruvio@xxxxxxxxx> ]

----------------------------------------------------------------------------

10 files changed, 765 insertions(+), 3 deletions(-)
build/jam/BuildFeatures                          |   4 +-
src/add-ons/media/plugins/Jamfile                |   1 +
src/add-ons/media/plugins/rtsp_streamer/Jamfile  |  30 ++
.../media/plugins/rtsp_streamer/RTSPMediaIO.cpp  | 121 +++++
.../media/plugins/rtsp_streamer/RTSPMediaIO.h    |  67 +++
.../plugins/rtsp_streamer/RTSPStreamerPlugin.cpp |  40 ++
.../plugins/rtsp_streamer/RTSPStreamerPlugin.h   |  20 +
src/add-ons/media/plugins/rtsp_streamer/rtsp.cpp | 447 +++++++++++++++++++
src/add-ons/media/plugins/rtsp_streamer/rtsp.h   |  34 ++
src/kits/media/AdapterIO.cpp                     |   4 +-

############################################################################

Commit:      5029fabd08daddede8ec2e959600a90265183f8d
URL:         http://cgit.haiku-os.org/haiku/commit/?id=5029fabd08da
Author:      Dario Casalinuovo <b.vitruvio@xxxxxxxxx>
Date:        Thu Jun  2 15:28:38 2016 UTC

live555: Library order caused missing symbols

----------------------------------------------------------------------------

diff --git a/build/jam/BuildFeatures b/build/jam/BuildFeatures
index 821911e..0b75ec3 100644
--- a/build/jam/BuildFeatures
+++ b/build/jam/BuildFeatures
@@ -543,15 +543,15 @@ if [ IsPackageAvailable live555_devel ] {
                file: devel live555_devel
                        libraries:
                                $(developLibDir)/libliveMedia.a
+                               $(developLibDir)/libBasicUsageEnvironment.a
                                $(developLibDir)/libgroupsock.a
                                $(developLibDir)/libUsageEnvironment.a
-                               $(developLibDir)/libBasicUsageEnvironment.a
 
                        headers: $(developHeadersDir)
                                $(developHeadersDir)/liveMedia
+                               $(developHeadersDir)/BasicUsageEnvironment
                                $(developHeadersDir)/groupsock
                                $(developHeadersDir)/UsageEnvironment
-                               $(developHeadersDir)/BasicUsageEnvironment
                ;
        EnableBuildFeatures live555 ;
 } else  {

############################################################################

Commit:      228b5c174e73f0223fc3e4ef909d255faab81d6b
URL:         http://cgit.haiku-os.org/haiku/commit/?id=228b5c174e73
Author:      Dario Casalinuovo <b.vitruvio@xxxxxxxxx>
Date:        Thu Jun  2 15:29:29 2016 UTC

Implement SetSize in AdapterIO

* Give this choice to inherited classes.

----------------------------------------------------------------------------

diff --git a/src/kits/media/AdapterIO.cpp b/src/kits/media/AdapterIO.cpp
index d18a290..2db3085 100644
--- a/src/kits/media/AdapterIO.cpp
+++ b/src/kits/media/AdapterIO.cpp
@@ -86,7 +86,9 @@ BAdapterIO::Position() const
 status_t
 BAdapterIO::SetSize(off_t size)
 {
-       return B_UNSUPPORTED;
+       AutoWriteLocker(fLock);
+
+       return fBuffer->SetSize(size);
 }
 
 

############################################################################

Revision:    hrev50341
Commit:      4c7eafb74b56eca40630bba0580d660874dc6268
URL:         http://cgit.haiku-os.org/haiku/commit/?id=4c7eafb74b56
Author:      Dario Casalinuovo <b.vitruvio@xxxxxxxxx>
Date:        Thu Jun  2 16:58:48 2016 UTC

Include testing version rtsp_streamer

* Rewritten from scratch to use live555 and BAdapterIO.

----------------------------------------------------------------------------

diff --git a/src/add-ons/media/plugins/Jamfile 
b/src/add-ons/media/plugins/Jamfile
index c8ead7f..4c11e7f 100644
--- a/src/add-ons/media/plugins/Jamfile
+++ b/src/add-ons/media/plugins/Jamfile
@@ -14,6 +14,7 @@ SubInclude HAIKU_TOP src add-ons media plugins mov_reader ;
 SubInclude HAIKU_TOP src add-ons media plugins mp4_reader ;
 SubInclude HAIKU_TOP src add-ons media plugins musepack ;
 SubInclude HAIKU_TOP src add-ons media plugins raw_decoder ;
+SubInclude HAIKU_TOP src add-ons media plugins rtsp_streamer ;
 SubInclude HAIKU_TOP src add-ons media plugins wav_reader ;
 
 # The following add-ons are GPL licensed, and can only be used with
diff --git a/src/add-ons/media/plugins/rtsp_streamer/Jamfile 
b/src/add-ons/media/plugins/rtsp_streamer/Jamfile
new file mode 100644
index 0000000..54dad62
--- /dev/null
+++ b/src/add-ons/media/plugins/rtsp_streamer/Jamfile
@@ -0,0 +1,30 @@
+SubDir HAIKU_TOP src add-ons media plugins rtsp_streamer ;
+
+UsePrivateHeaders media shared ;
+
+# TODO: Investigate this
+SubDirC++Flags -w ;
+
+local architectureObject ;
+for architectureObject in [ MultiArchSubDirSetup ] {
+       on $(architectureObject) {
+
+               UseBuildFeatureHeaders live555 ;
+
+               Includes [ FGristFiles
+                               rtsp.cpp
+                               RTSPStreamerPlugin.cpp
+                               RTSPMediaIO.cpp ]
+                       : [ BuildFeatureAttribute live555 : headers ] ;
+
+               Addon [ MultiArchDefaultGristFiles rtsp_streamer ] :
+                       RTSPStreamerPlugin.cpp
+                       RTSPMediaIO.cpp
+                       rtsp.cpp
+                       :
+                       [ BuildFeatureAttribute live555 : libraries ]
+                       be media network bnetapi shared
+                       [ TargetLibstdc++ ] [ TargetLibsupc++ ]
+               ;
+       }
+}
diff --git a/src/add-ons/media/plugins/rtsp_streamer/RTSPMediaIO.cpp 
b/src/add-ons/media/plugins/rtsp_streamer/RTSPMediaIO.cpp
new file mode 100644
index 0000000..dcfa0fc
--- /dev/null
+++ b/src/add-ons/media/plugins/rtsp_streamer/RTSPMediaIO.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2016, Dario Casalinuovo. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "RTSPMediaIO.h"
+
+
+#define LIVE555_VERBOSITY 1
+
+
+RTSPMediaIO::RTSPMediaIO(BUrl* ourUrl)
+       :
+       BAdapterIO(
+               B_MEDIA_STREAMING | B_MEDIA_MUTABLE_SIZE | 
B_MEDIA_SEEK_BACKWARD,
+               B_INFINITE_TIMEOUT),
+       fUrl(ourUrl),
+       fInitErr(B_OK),
+       fScheduler(NULL),
+       fEnv(NULL),
+       loopWatchVariable(0)
+{
+       fScheduler = BasicTaskScheduler::createNew();
+       fEnv = BasicUsageEnvironment::createNew(*fScheduler);
+
+       HaikuRTSPClient* client = new HaikuRTSPClient(*fEnv, fUrl->UrlString(),
+               0, BuildInputAdapter());
+       if (client == NULL) {
+               fInitErr = B_ERROR;
+               return;
+       }
+
+       client->sendDescribeCommand(continueAfterDESCRIBE);
+
+       fEnv->taskScheduler().doEventLoop(&loopWatchVariable);
+
+       fInitErr = client->WaitForInit(5000000);
+}
+
+
+RTSPMediaIO::~RTSPMediaIO()
+{
+}
+
+
+status_t
+RTSPMediaIO::InitCheck() const
+{
+       return fInitErr;
+}
+
+
+ssize_t
+RTSPMediaIO::WriteAt(off_t position, const void* buffer, size_t size)
+{
+       return B_NOT_SUPPORTED;
+}
+
+
+HaikuRTSPClient::HaikuRTSPClient(UsageEnvironment& env, char const* rtspURL,
+               portNumBits tunnelOverHTTPPortNum, BInputAdapter* inputAdapter)
+       :
+       RTSPClient(env, rtspURL, LIVE555_VERBOSITY, "Haiku RTSP Streamer",
+               tunnelOverHTTPPortNum, -1),
+       iter(NULL),
+       session(NULL),
+       subsession(NULL),
+       streamTimerTask(NULL),
+       duration(0.0f),
+       fInputAdapter(inputAdapter)
+{
+       fInitPort = create_port(1, "RTSP Client wait port");
+}
+
+
+status_t
+HaikuRTSPClient::WaitForInit(bigtime_t timeout)
+{
+       status_t status = B_ERROR;
+       read_port_etc(fInitPort, NULL, &status,
+               sizeof(status), B_RELATIVE_TIMEOUT, timeout);
+
+       close_port(fInitPort);
+       delete_port(fInitPort);
+       return status;
+}
+
+
+void
+HaikuRTSPClient::NotifyError()
+{
+       status_t status = B_ERROR;
+       write_port(fInitPort, NULL, &status, sizeof(status));
+}
+
+
+void
+HaikuRTSPClient::NotifySucces()
+{
+       status_t status = B_OK;
+       write_port(fInitPort, NULL, &status, sizeof(status));
+}
+
+
+HaikuRTSPClient::~HaikuRTSPClient()
+{
+       delete iter;
+       if (session != NULL) {
+               UsageEnvironment& env = session->envir();
+               env.taskScheduler().unscheduleDelayedTask(streamTimerTask);
+               Medium::close(session);
+       }
+}
+
+
+BInputAdapter*
+HaikuRTSPClient::GetInputAdapter() const
+{
+       return fInputAdapter;
+}
diff --git a/src/add-ons/media/plugins/rtsp_streamer/RTSPMediaIO.h 
b/src/add-ons/media/plugins/rtsp_streamer/RTSPMediaIO.h
new file mode 100644
index 0000000..630c64c
--- /dev/null
+++ b/src/add-ons/media/plugins/rtsp_streamer/RTSPMediaIO.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016, Dario Casalinuovo. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _RTSP_MEDIA_IO_H
+#define _RTSP_MEDIA_IO_H
+
+
+#include <AdapterIO.h>
+#include <Url.h>
+
+#include "rtsp.h"
+
+
+class RTSPMediaIO : public BAdapterIO
+{
+public:
+                                                               
RTSPMediaIO(BUrl* ourUrl);
+       virtual                                         ~RTSPMediaIO();
+
+                       status_t                        InitCheck() const;
+
+       virtual ssize_t                         WriteAt(off_t position, const 
void* buffer,
+                                                                       size_t 
size);
+private:
+       BUrl*                                           fUrl;
+
+       TaskScheduler*                          fScheduler;
+       UsageEnvironment*                       fEnv;
+       char                                            loopWatchVariable;
+
+       status_t                                        fInitErr;
+};
+
+
+class HaikuRTSPClient : public RTSPClient
+{
+public:
+                                                               
HaikuRTSPClient(UsageEnvironment& env,
+                                                                       char 
const* rtspURL,
+                                                                       
portNumBits tunnelOverHTTPPortNum,
+                                                                       
BInputAdapter* fInputAdapter);
+
+                       BInputAdapter*          GetInputAdapter() const;
+
+                       status_t                        WaitForInit(bigtime_t 
timeout);
+
+                       void                            NotifyError();
+                       void                            NotifySucces();
+
+protected:
+       virtual                                         ~HaikuRTSPClient();
+
+public:
+
+       MediaSubsessionIterator*        iter;
+       MediaSession*                           session;
+       MediaSubsession*                        subsession;
+       TaskToken                                       streamTimerTask;
+       double                                          duration;
+
+private:
+                       BInputAdapter*          fInputAdapter;
+                       port_id                         fInitPort;
+};
+
+#endif
diff --git a/src/add-ons/media/plugins/rtsp_streamer/RTSPStreamerPlugin.cpp 
b/src/add-ons/media/plugins/rtsp_streamer/RTSPStreamerPlugin.cpp
new file mode 100644
index 0000000..001d804
--- /dev/null
+++ b/src/add-ons/media/plugins/rtsp_streamer/RTSPStreamerPlugin.cpp
@@ -0,0 +1,40 @@
+
+#include "RTSPStreamerPlugin.h"
+
+#include "RTSPMediaIO.h"
+
+
+RTSPStreamer::RTSPStreamer()
+{
+}
+
+
+RTSPStreamer::~RTSPStreamer()
+{
+}
+
+
+status_t
+RTSPStreamer::Sniff(BUrl* url, BDataIO** source)
+{
+       RTSPMediaIO* ret = new RTSPMediaIO(url);
+       if (ret->InitCheck() == B_OK) {
+               *source = ret;
+               return B_OK;
+       }
+       delete ret;
+       return B_ERROR;
+}
+
+
+Streamer*
+RTSPStreamerPlugin::NewStreamer()
+{
+       return new RTSPStreamer();
+}
+
+
+MediaPlugin *instantiate_plugin()
+{
+       return new RTSPStreamerPlugin();
+}
diff --git a/src/add-ons/media/plugins/rtsp_streamer/RTSPStreamerPlugin.h 
b/src/add-ons/media/plugins/rtsp_streamer/RTSPStreamerPlugin.h
new file mode 100644
index 0000000..eb743be
--- /dev/null
+++ b/src/add-ons/media/plugins/rtsp_streamer/RTSPStreamerPlugin.h
@@ -0,0 +1,20 @@
+#ifndef _RTSP_STREAMER_PLUGIN_H
+#define _RTSP_STREAMER_PLUGIN_H
+
+#include "StreamerPlugin.h"
+
+class RTSPStreamer : public Streamer {
+public:
+                                                               RTSPStreamer();
+       virtual                                         ~RTSPStreamer();
+
+       virtual status_t                        Sniff(BUrl* url, BDataIO** 
source);
+};
+
+
+class RTSPStreamerPlugin : public StreamerPlugin {
+public:
+       virtual Streamer*                       NewStreamer();
+};
+
+#endif // _RTSP_STREAMER_PLUGIN_H
diff --git a/src/add-ons/media/plugins/rtsp_streamer/rtsp.cpp 
b/src/add-ons/media/plugins/rtsp_streamer/rtsp.cpp
new file mode 100644
index 0000000..afe935e
--- /dev/null
+++ b/src/add-ons/media/plugins/rtsp_streamer/rtsp.cpp
@@ -0,0 +1,447 @@
+/**********
+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.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+**********/
+// Copyright (c) 1996-2016, Live Networks, Inc.  All rights reserved
+// Copyright (c) 2016, Dario Casalinuovo. All rights reserved.
+
+
+#include "rtsp.h"
+
+#include <AdapterIO.h>
+
+#include "RTSPMediaIO.h"
+
+
+#define REQUEST_STREAMING_OVER_TCP False
+#define RECEIVE_BUFFER_SIZE 100000
+
+
+UsageEnvironment& operator<<(UsageEnvironment& env,
+       const RTSPClient& rtspClient)
+{
+       return env << "[URL:\"" << rtspClient.url() << "\"]: ";
+}
+
+
+UsageEnvironment& operator<<(UsageEnvironment& env,
+       const MediaSubsession& subsession)
+{
+       return env << subsession.mediumName() << "/" << subsession.codecName();
+}
+
+
+class AdapterSink : public MediaSink
+{
+public:
+                               static          AdapterSink* 
createNew(UsageEnvironment& env,
+                                                               
MediaSubsession& subsession,
+                                                               BInputAdapter* 
inputAdapter,
+                                                               char const* 
streamId = NULL);
+
+private:
+                                                       
AdapterSink(UsageEnvironment& env,
+                                                               
MediaSubsession& subsession,
+                                                               char const* 
streamId,
+                                                               BInputAdapter* 
inputAdapter);
+
+       virtual                                 ~AdapterSink();
+
+                       static void             afterGettingFrame(void* 
clientData,
+                                                               unsigned 
frameSize,
+                                                               unsigned 
numTruncatedBytes,
+                                                               struct timeval 
presentationTime,
+                                                               unsigned 
durationInMicroseconds);
+
+                       void                    afterGettingFrame(unsigned 
frameSize,
+                                                               unsigned 
numTruncatedBytes,
+                                                               struct timeval 
presentationTime,
+                                                               unsigned 
durationInMicroseconds);
+
+private:
+       // redefined virtual functions:
+       virtual Boolean                 continuePlaying();
+
+private:
+       BInputAdapter*                  fInputAdapter;
+       u_int8_t*                               fReceiveBuffer;
+       MediaSubsession&                fSubsession;
+       char*                                   fStreamId;
+};
+
+// Implementation of the RTSP 'response handlers':
+
+void continueAfterDESCRIBE(RTSPClient* rtspClient,
+       int resultCode, char* resultString)
+{
+       UsageEnvironment& env = rtspClient->envir();
+       HaikuRTSPClient* client = (HaikuRTSPClient*) rtspClient;
+       do {
+               if (resultCode != 0) {
+                       env << *rtspClient << "Failed to get a SDP description: 
"
+                               << resultString << "\n";
+                       delete[] resultString;
+
+                       break;
+               }
+
+               char* const sdpDescription = resultString;
+               env << *rtspClient << "Got a SDP description:\n"
+                       << sdpDescription << "\n";
+
+               // Create a media session object from this SDP description:
+               client->session = MediaSession::createNew(env, sdpDescription);
+               delete[] sdpDescription; // because we don't need it anymore
+               if (client->session == NULL) {
+                       env << *rtspClient
+                               << "Failed to create a MediaSession object "
+                                       "from the SDP description: "
+                               << env.getResultMsg() << "\n";
+
+                       break;
+               } else if (!client->session->hasSubsessions()) {
+                       env << *rtspClient << "This session has no media 
subsessions"
+                               " (i.e., no \"m=\" lines)\n";
+
+                       break;
+               }
+
+               // Then, create and set up our data source objects for the 
session.
+               // We do this by iterating over the session's 'subsessions',
+               // calling "MediaSubsession::initiate()",
+               // and then sending a RTSP "SETUP" command, on each one.
+               // (Each 'subsession' will have its own data source.)
+               client->iter = new MediaSubsessionIterator(*client->session);
+               setupNextSubsession(rtspClient);
+               return;
+       } while (0);
+
+       client->NotifyError();
+       // An unrecoverable error occurred with this stream.
+       shutdownStream(rtspClient);
+}
+
+
+void setupNextSubsession(RTSPClient* rtspClient)
+{
+       UsageEnvironment& env = rtspClient->envir();
+       HaikuRTSPClient* client = (HaikuRTSPClient*) rtspClient;
+
+       client->subsession = client->iter->next();
+       if (client->subsession != NULL) {
+               if (!client->subsession->initiate()) {
+
+                       env << *rtspClient << "Failed to initiate the \""
+                               << *client->subsession << "\" subsession: "
+                               << env.getResultMsg() << "\n";
+
+                       // give up on this subsession; go to the next one
+                       setupNextSubsession(rtspClient);
+               }
+               else {
+                       env << *rtspClient << "Initiated the \""
+                               << *client->subsession << "\" subsession (";
+
+                       if (client->subsession->rtcpIsMuxed()) {
+                               env << "client port " << 
client->subsession->clientPortNum();
+                       } else {
+                               env << "client ports " << 
client->subsession->clientPortNum()
+                                       << "-" << 
client->subsession->clientPortNum() + 1;
+                       }
+                       env << ")\n";
+
+                       // Continue setting up this subsession,
+                       // by sending a RTSP "SETUP" command:
+                       rtspClient->sendSetupCommand(*client->subsession,
+                               continueAfterSETUP, False, 
REQUEST_STREAMING_OVER_TCP);
+               }
+               return;
+       }
+
+       // We've finished setting up all of the subsessions.
+       // Now, send a RTSP "PLAY" command to start the streaming:
+       if (client->session->absStartTime() != NULL) {
+               // Special case: The stream is indexed by 'absolute' time,
+               // so send an appropriate "PLAY" command:
+               rtspClient->sendPlayCommand(*client->session, continueAfterPLAY,
+                       client->session->absStartTime(), 
client->session->absEndTime());
+       }
+       else {
+               client->duration = client->session->playEndTime()
+                       - client->session->playStartTime();
+               rtspClient->sendPlayCommand(*client->session, 
continueAfterPLAY);
+       }
+}
+
+
+void continueAfterSETUP(RTSPClient* rtspClient,
+       int resultCode, char* resultString)
+{
+       do {
+               UsageEnvironment& env = rtspClient->envir();
+               HaikuRTSPClient* client = (HaikuRTSPClient*) rtspClient;
+
+               if (resultCode != 0) {
+                       env << *rtspClient << "Failed to set up the \""
+                               << *client->subsession << "\" subsession: "
+                               << resultString << "\n";
+                       break;
+               }
+
+               env << *rtspClient << "Set up the \""
+                       << *client->subsession << "\" subsession (";
+               if (client->subsession->rtcpIsMuxed()) {
+                       env << "client port " << 
client->subsession->clientPortNum();
+               }
+               else {
+                       env << "client ports " << 
client->subsession->clientPortNum()
+                               << "-" << client->subsession->clientPortNum() + 
1;
+               }
+               env << ")\n";
+
+               // Having successfully setup the subsession, create a data sink 
for it,
+               // and call "startPlaying()" on it.
+               // (This will prepare the data sink to receive data; the actual
+               // flow of data from the client won't start happening until 
later,
+               // after we've sent a RTSP "PLAY" command.)
+
+               client->subsession->sink = AdapterSink::createNew(env, 
*client->subsession,
+                       ((HaikuRTSPClient*)rtspClient)->GetInputAdapter(), 
rtspClient->url());
+               // perhaps use your own custom "MediaSink" subclass instead
+               if (client->subsession->sink == NULL) {
+                       env << *rtspClient << "Failed to create a data sink for 
the \""
+                               << *client->subsession << "\" subsession: "
+                               << env.getResultMsg() << "\n";
+                       break;
+               }
+
+               env << *rtspClient << "Created a data sink for the \""
+                       << *client->subsession << "\" subsession\n";
+               // a hack to let subsession handler functions
+               // get the "RTSPClient" from the subsession
+               client->subsession->miscPtr = rtspClient;
+               client->subsession->sink
+                               
->startPlaying(*(client->subsession->readSource()),
+                                       subsessionAfterPlaying, 
client->subsession);
+               // Also set a handler to be called if a RTCP "BYE"
+               // arrives for this subsession:
+               if (client->subsession->rtcpInstance() != NULL) {
+                       client->subsession->rtcpInstance()->setByeHandler(
+                               subsessionByeHandler,
+                               client->subsession);
+               }
+       } while (0);
+       delete[] resultString;
+
+       // Set up the next subsession, if any:
+       setupNextSubsession(rtspClient);
+}
+
+
+void continueAfterPLAY(RTSPClient* rtspClient,
+       int resultCode, char* resultString)
+{
+       Boolean success = False;
+       UsageEnvironment& env = rtspClient->envir();
+       HaikuRTSPClient* client = (HaikuRTSPClient*) rtspClient;
+
+       do {
+               if (resultCode != 0) {
+                       env << *rtspClient << "Failed to start playing session: 
"
+                               << resultString << "\n";
+                       break;
+               }
+
+               // Set a timer to be handled at the end of the stream's
+               // expected duration (if the stream does not already signal its 
end
+               // using a RTCP "BYE").  This is optional.  If, instead, you 
want
+               // to keep the stream active - e.g., so you can later
+               // 'seek' back within it and do another RTSP "PLAY"
+               // - then you can omit this code.
+               // (Alternatively, if you don't want to receive the entire 
stream,
+               // you could set this timer for some shorter value.)
+               if (client->duration > 0) {
+                       // number of seconds extra to delay,
+                       // after the stream's expected duration.  (This is 
optional.)
+                       unsigned const delaySlop = 2;
+                       client->duration += delaySlop;
+                       unsigned uSecsToDelay = (unsigned)(client->duration * 
1000000);
+                       client->streamTimerTask
+                               = 
env.taskScheduler().scheduleDelayedTask(uSecsToDelay,
+                                       (TaskFunc*)streamTimerHandler, 
rtspClient);
+               }
+
+               env << *rtspClient << "Started playing session";
+               if (client->duration > 0) {
+                       env << " (for up to " << client->duration << " 
seconds)";
+               }
+               env << "...\n";
+
+               success = True;
+       } while (0);
+       delete[] resultString;
+
+       if (!success) {
+               client->NotifyError();
+               // An unrecoverable error occurred with this stream.
+               shutdownStream(rtspClient);
+       } else
+               client->NotifySucces();
+}
+
+// Implementation of the other event handlers:
+
+void subsessionAfterPlaying(void* clientData)
+{
+       MediaSubsession* subsession = (MediaSubsession*)clientData;
+       RTSPClient* rtspClient = (RTSPClient*)(subsession->miscPtr);
+
+       // Begin by closing this subsession's stream:
+       Medium::close(subsession->sink);
+       subsession->sink = NULL;
+
+       // Next, check whether *all* subsessions' streams have now been closed:
+       MediaSession& session = subsession->parentSession();
+       MediaSubsessionIterator iter(session);
+       while ((subsession = iter.next()) != NULL) {
+               if (subsession->sink != NULL)
+                       return; // this subsession is still active
+       }
+
+       // All subsessions' streams have now been closed, so shutdown the 
client:
+       shutdownStream(rtspClient);
+}
+
+
+void subsessionByeHandler(void* clientData)
+{
+       MediaSubsession* subsession = (MediaSubsession*)clientData;
+       RTSPClient* rtspClient = (RTSPClient*)subsession->miscPtr;
+       UsageEnvironment& env = rtspClient->envir();
+
+       env << *rtspClient << "Received RTCP \"BYE\" on \""
+               << *subsession << "\" subsession\n";
+
+       // Now act as if the subsession had closed:
+       subsessionAfterPlaying(subsession);
+}
+
+
+void streamTimerHandler(void* clientData)
+{
+       HaikuRTSPClient* client = (HaikuRTSPClient*)clientData;
+
+       client->streamTimerTask = NULL;
+
+       // Shut down the stream:
+       shutdownStream(client);
+}
+
+
+void shutdownStream(RTSPClient* rtspClient, int exitCode)
+{
+       UsageEnvironment& env = rtspClient->envir();
+       HaikuRTSPClient* client = (HaikuRTSPClient*) rtspClient;
+
+       // First, check whether any subsessions have still to be closed:
+       if (client->session != NULL) {
+               Boolean someSubsessionsWereActive = False;
+               MediaSubsessionIterator iter(*client->session);
+               MediaSubsession* subsession;
+
+               while ((subsession = iter.next()) != NULL) {
+                       if (subsession->sink != NULL) {
+                               Medium::close(subsession->sink);
+                               subsession->sink = NULL;
+
+                               if (subsession->rtcpInstance() != NULL) {
+                                       // in case the server sends a RTCP "BYE"
+                                       // while handling "TEARDOWN"
+                                       
subsession->rtcpInstance()->setByeHandler(NULL, NULL);
+                               }
+
+                               someSubsessionsWereActive = True;
+                       }
+               }
+
+               if (someSubsessionsWereActive) {
+                       // Send a RTSP "TEARDOWN" command,
+                       // to tell the server to shutdown the stream.
+                       // Don't bother handling the response to the "TEARDOWN".
+                       rtspClient->sendTeardownCommand(*client->session, NULL);
+               }
+       }
+
+       env << *rtspClient << "Closing the stream.\n";
+       Medium::close(rtspClient);
+       // Note that this will also cause this stream's
+       // "StreamClientState" structure to get reclaimed.
+}
+
+
+AdapterSink* AdapterSink::createNew(UsageEnvironment& env,
+       MediaSubsession& subsession, BInputAdapter* inputAdapter,
+       char const* streamId)
+{
+       return new AdapterSink(env, subsession, streamId, inputAdapter);
+}
+
+
+AdapterSink::AdapterSink(UsageEnvironment& env, MediaSubsession& subsession,
+       char const* streamId, BInputAdapter* inputAdapter)
+       :
+       MediaSink(env),
+       fSubsession(subsession),
+       fInputAdapter(inputAdapter)
+{
+       fStreamId = strDup(streamId);
+       fReceiveBuffer = new u_int8_t[RECEIVE_BUFFER_SIZE];
+}
+
+
+AdapterSink::~AdapterSink()
+{
+       delete[] fReceiveBuffer;
+       delete[] fStreamId;
+}
+
+
+void AdapterSink::afterGettingFrame(void* clientData, unsigned frameSize,
+       unsigned numTruncatedBytes, struct timeval presentationTime,
+       unsigned durationInMicroseconds)
+{
+       AdapterSink* sink = (AdapterSink*)clientData;
+       sink->afterGettingFrame(frameSize, numTruncatedBytes,
+               presentationTime, durationInMicroseconds);
+}
+
+
+void
+AdapterSink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
+       struct timeval presentationTime, unsigned /*durationInMicroseconds*/)
+{
+       fInputAdapter->Write(fReceiveBuffer, frameSize);
+       continuePlaying();
+}
+
+
+Boolean
+AdapterSink::continuePlaying()
+{
+       if (fSource == NULL)
+               return False;
+
+       fSource->getNextFrame(fReceiveBuffer, RECEIVE_BUFFER_SIZE,
+               afterGettingFrame, this,
+               onSourceClosure, this);
+       return True;
+}
diff --git a/src/add-ons/media/plugins/rtsp_streamer/rtsp.h 
b/src/add-ons/media/plugins/rtsp_streamer/rtsp.h
new file mode 100644
index 0000000..a8d2404
--- /dev/null
+++ b/src/add-ons/media/plugins/rtsp_streamer/rtsp.h
@@ -0,0 +1,34 @@
+/**********
+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.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+**********/
+// Copyright (c) 1996-2016, Live Networks, Inc.  All rights reserved
+// Copyright (c) 2016, Dario Casalinuovo. All rights reserved.
+#ifndef _RTSP_H
+#define _RTSP_H
+
+#include "liveMedia.hh"
+#include "BasicUsageEnvironment.hh"
+
+
+void continueAfterDESCRIBE(RTSPClient* rtspClient, int resultCode, char* 
resultString);
+void continueAfterSETUP(RTSPClient* rtspClient, int resultCode, char* 
resultString);
+void continueAfterPLAY(RTSPClient* rtspClient, int resultCode, char* 
resultString);
+
+void subsessionAfterPlaying(void* clientData);
+void subsessionByeHandler(void* clientData);
+void streamTimerHandler(void* clientData);
+void setupNextSubsession(RTSPClient* rtspClient);
+void shutdownStream(RTSPClient* rtspClient, int exitCode = 1);
+
+
+#endif


Other related posts:

  • » [haiku-commits] haiku: hrev50341 - src/add-ons/media/plugins/rtsp_streamer - b . vitruvio