|
|
@ -34,14 +34,6 @@ class HLSServer : public RTSPServer
|
|
|
|
: RTSPServer::RTSPClientConnection(ourServer, clientSocket, clientAddr), fClientSessionId(0), fTCPSink(NULL) {
|
|
|
|
: RTSPServer::RTSPClientConnection(ourServer, clientSocket, clientAddr), fClientSessionId(0), fTCPSink(NULL) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~HLSClientConnection() {
|
|
|
|
|
|
|
|
if (fTCPSink != NULL)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
fTCPSink->stopPlaying();
|
|
|
|
|
|
|
|
Medium::close(fTCPSink);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
|
|
void sendHeader(const char* contentType, unsigned int contentLength)
|
|
|
|
void sendHeader(const char* contentType, unsigned int contentLength)
|
|
|
@ -68,9 +60,11 @@ class HLSServer : public RTSPServer
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (fTCPSink != NULL)
|
|
|
|
if (fTCPSink != NULL)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
FramedSource* oldSource = fTCPSink->source();
|
|
|
|
fTCPSink->stopPlaying();
|
|
|
|
fTCPSink->stopPlaying();
|
|
|
|
Medium::close(fTCPSink);
|
|
|
|
Medium::close(fTCPSink);
|
|
|
|
fTCPSink = NULL;
|
|
|
|
fTCPSink = NULL;
|
|
|
|
|
|
|
|
Medium::close(oldSource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (source != NULL)
|
|
|
|
if (source != NULL)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -79,25 +73,28 @@ class HLSServer : public RTSPServer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void sendPlayList(char const* urlSuffix)
|
|
|
|
ServerMediaSubsession* getSubsesion(const char* urlSuffix)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// First, make sure that the named file exists, and is streamable:
|
|
|
|
ServerMediaSubsession* subsession = NULL;
|
|
|
|
ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix);
|
|
|
|
ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix);
|
|
|
|
if (session == NULL) {
|
|
|
|
if (session != NULL)
|
|
|
|
handleHTTPCmd_notFound();
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
ServerMediaSubsessionIterator iter(*session);
|
|
|
|
|
|
|
|
subsession = iter.next();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return subsession;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// To be able to construct a playlist for the requested file, we need to know its duration:
|
|
|
|
void sendPlayList(char const* urlSuffix)
|
|
|
|
float duration = session->duration();
|
|
|
|
{
|
|
|
|
if (duration <= 0.0) {
|
|
|
|
ServerMediaSubsession* subsession = this->getSubsesion(urlSuffix);
|
|
|
|
|
|
|
|
if (subsession == NULL) {
|
|
|
|
handleHTTPCmd_notSupported();
|
|
|
|
handleHTTPCmd_notSupported();
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ServerMediaSubsessionIterator iter(*session);
|
|
|
|
float duration = subsession->duration();
|
|
|
|
ServerMediaSubsession* subsession = iter.next();
|
|
|
|
if (duration <= 0.0) {
|
|
|
|
if (subsession == NULL) {
|
|
|
|
|
|
|
|
handleHTTPCmd_notSupported();
|
|
|
|
handleHTTPCmd_notSupported();
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -127,32 +124,29 @@ class HLSServer : public RTSPServer
|
|
|
|
this->streamSource(ByteStreamMemoryBufferSource::createNew(envir(), playListBuffer, playList.size()));
|
|
|
|
this->streamSource(ByteStreamMemoryBufferSource::createNew(envir(), playListBuffer, playList.size()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* /*fullRequestStr*/) {
|
|
|
|
void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* /*fullRequestStr*/)
|
|
|
|
// If "urlSuffix" ends with "?segment=<offset-in-seconds>,<duration-in-seconds>", then strip this off, and send the
|
|
|
|
{
|
|
|
|
// specified segment. Otherwise, construct and send a playlist that consists of segments from the specified file.
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
char const* questionMarkPos = strrchr(urlSuffix, '?');
|
|
|
|
char const* questionMarkPos = strrchr(urlSuffix, '?');
|
|
|
|
if (questionMarkPos == NULL) break;
|
|
|
|
if (questionMarkPos == NULL)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
this->sendPlayList(urlSuffix);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
unsigned offsetInSeconds;
|
|
|
|
unsigned offsetInSeconds;
|
|
|
|
if (sscanf(questionMarkPos, "?segment=%u", &offsetInSeconds) != 1) break;
|
|
|
|
if (sscanf(questionMarkPos, "?segment=%u", &offsetInSeconds) != 1)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
handleHTTPCmd_notSupported();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char* streamName = strDup(urlSuffix);
|
|
|
|
char* streamName = strDup(urlSuffix);
|
|
|
|
streamName[questionMarkPos-urlSuffix] = '\0';
|
|
|
|
streamName[questionMarkPos-urlSuffix] = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
do {
|
|
|
|
ServerMediaSession* session = fOurServer.lookupServerMediaSession(streamName);
|
|
|
|
ServerMediaSubsession* subsession = this->getSubsesion(streamName);
|
|
|
|
if (session == NULL) {
|
|
|
|
|
|
|
|
handleHTTPCmd_notFound();
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We can't send multi-subsession streams over HTTP (because there's no defined way to multiplex more than one subsession).
|
|
|
|
|
|
|
|
// Therefore, use the first (and presumed only) substream:
|
|
|
|
|
|
|
|
ServerMediaSubsessionIterator iter(*session);
|
|
|
|
|
|
|
|
ServerMediaSubsession* subsession = iter.next();
|
|
|
|
|
|
|
|
if (subsession == NULL) {
|
|
|
|
if (subsession == NULL) {
|
|
|
|
// Treat an 'empty' ServerMediaSession the same as one that doesn't exist at all:
|
|
|
|
handleHTTPCmd_notSupported();
|
|
|
|
handleHTTPCmd_notFound();
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -182,14 +176,10 @@ class HLSServer : public RTSPServer
|
|
|
|
|
|
|
|
|
|
|
|
// stream body
|
|
|
|
// stream body
|
|
|
|
this->streamSource(subsession->getStreamSource(streamToken));
|
|
|
|
this->streamSource(subsession->getStreamSource(streamToken));
|
|
|
|
|
|
|
|
|
|
|
|
} while(0);
|
|
|
|
} while(0);
|
|
|
|
|
|
|
|
|
|
|
|
delete[] streamName;
|
|
|
|
delete[] streamName;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this->sendPlayList(urlSuffix);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void afterStreaming(void* clientData)
|
|
|
|
static void afterStreaming(void* clientData)
|
|
|
@ -201,7 +191,7 @@ class HLSServer : public RTSPServer
|
|
|
|
clientConnection->fIsActive = False; // will cause the object to get deleted at the end of handling the request
|
|
|
|
clientConnection->fIsActive = False; // will cause the object to get deleted at the end of handling the request
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// We're no longer handling a request; delete the object now:
|
|
|
|
// We're no longer handling a request; delete the object now:
|
|
|
|
delete clientConnection;
|
|
|
|
// delete clientConnection;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
private:
|
|
|
|