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