00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "RTSPServerSupportingHTTPStreaming.hh"
00022 #include "RTSPCommon.hh"
00023 #ifndef _WIN32_WCE
00024 #include <sys/stat.h>
00025 #endif
00026 #include <time.h>
00027
00028 RTSPServerSupportingHTTPStreaming*
00029 RTSPServerSupportingHTTPStreaming::createNew(UsageEnvironment& env, Port rtspPort,
00030 UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds) {
00031 int ourSocket = setUpOurSocket(env, rtspPort);
00032 if (ourSocket == -1) return NULL;
00033
00034 return new RTSPServerSupportingHTTPStreaming(env, ourSocket, rtspPort, authDatabase, reclamationTestSeconds);
00035 }
00036
00037 RTSPServerSupportingHTTPStreaming
00038 ::RTSPServerSupportingHTTPStreaming(UsageEnvironment& env, int ourSocket, Port rtspPort,
00039 UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds)
00040 : RTSPServer(env, ourSocket, rtspPort, authDatabase, reclamationTestSeconds) {
00041 }
00042
00043 RTSPServerSupportingHTTPStreaming::~RTSPServerSupportingHTTPStreaming() {
00044 }
00045
00046 RTSPServer::RTSPClientConnection*
00047 RTSPServerSupportingHTTPStreaming::createNewClientConnection(int clientSocket, struct sockaddr_in clientAddr) {
00048 return new RTSPClientConnectionSupportingHTTPStreaming(*this, clientSocket, clientAddr);
00049 }
00050
00051 RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming
00052 ::RTSPClientConnectionSupportingHTTPStreaming(RTSPServer& ourServer, int clientSocket, struct sockaddr_in clientAddr)
00053 : RTSPClientConnection(ourServer, clientSocket, clientAddr),
00054 fClientSessionId(0), fPlaylistSource(NULL), fTCPSink(NULL) {
00055 }
00056
00057 RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::~RTSPClientConnectionSupportingHTTPStreaming() {
00058 Medium::close(fPlaylistSource);
00059 Medium::close(fTCPSink);
00060 }
00061
00062 static char const* lastModifiedHeader(char const* fileName) {
00063 static char buf[200];
00064 buf[0] = '\0';
00065
00066 #ifndef _WIN32_WCE
00067 struct stat sb;
00068 int statResult = stat(fileName, &sb);
00069 if (statResult == 0) {
00070 strftime(buf, sizeof buf, "Last-Modified: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime((const time_t*)&sb.st_mtime));
00071 }
00072 #endif
00073
00074 return buf;
00075 }
00076
00077 void RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming
00078 ::handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* ) {
00079
00080
00081 do {
00082 char const* questionMarkPos = strrchr(urlSuffix, '?');
00083 if (questionMarkPos == NULL) break;
00084 unsigned offsetInSeconds, durationInSeconds;
00085 if (sscanf(questionMarkPos, "?segment=%u,%u", &offsetInSeconds, &durationInSeconds) != 2) break;
00086
00087 char* streamName = strDup(urlSuffix);
00088 streamName[questionMarkPos-urlSuffix] = '\0';
00089
00090 do {
00091 ServerMediaSession* session = fOurServer.lookupServerMediaSession(streamName);
00092 if (session == NULL) {
00093 handleHTTPCmd_notFound();
00094 break;
00095 }
00096
00097
00098
00099 ServerMediaSubsessionIterator iter(*session);
00100 ServerMediaSubsession* subsession = iter.next();
00101 if (subsession == NULL) {
00102
00103 handleHTTPCmd_notFound();
00104 break;
00105 }
00106
00107
00108
00109 ++fClientSessionId;
00110 Port clientRTPPort(0), clientRTCPPort(0), serverRTPPort(0), serverRTCPPort(0);
00111 netAddressBits destinationAddress = 0;
00112 u_int8_t destinationTTL = 0;
00113 Boolean isMulticast = False;
00114 void* streamToken;
00115 subsession->getStreamParameters(fClientSessionId, 0, clientRTPPort,clientRTCPPort, 0,0,0, destinationAddress,destinationTTL, isMulticast, serverRTPPort,serverRTCPPort, streamToken);
00116
00117
00118 double dOffsetInSeconds = (double)offsetInSeconds;
00119 u_int64_t numBytes;
00120 subsession->seekStream(fClientSessionId, streamToken, dOffsetInSeconds, (double)durationInSeconds, numBytes);
00121 unsigned numTSBytesToStream = (unsigned)numBytes;
00122
00123 if (numTSBytesToStream == 0) {
00124
00125 handleHTTPCmd_notSupported();
00126 break;
00127 }
00128
00129
00130 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00131 "HTTP/1.1 200 OK\r\n"
00132 "%s"
00133 "Server: LIVE555 Streaming Media v%s\r\n"
00134 "%s"
00135 "Content-Length: %d\r\n"
00136 "Content-Type: text/plain; charset=ISO-8859-1\r\n"
00137 "\r\n",
00138 dateHeader(),
00139 LIVEMEDIA_LIBRARY_VERSION_STRING,
00140 lastModifiedHeader(streamName),
00141 numTSBytesToStream);
00142
00143 send(fClientOutputSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0);
00144 fResponseBuffer[0] = '\0';
00145
00146
00147 FramedSource* mediaSource = subsession->getStreamSource(streamToken);
00148 if (mediaSource != NULL) {
00149 if (fTCPSink == NULL) fTCPSink = TCPStreamSink::createNew(envir(), fClientOutputSocket);
00150 fTCPSink->startPlaying(*mediaSource, afterStreaming, this);
00151 }
00152 } while(0);
00153
00154 delete[] streamName;
00155 return;
00156 } while (0);
00157
00158
00159
00160
00161
00162 ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix);
00163 if (session == NULL) {
00164 handleHTTPCmd_notFound();
00165 return;
00166 }
00167
00168
00169 float duration = session->duration();
00170 if (duration <= 0.0) {
00171
00172 handleHTTPCmd_notSupported();
00173 return;
00174 }
00175
00176
00177 unsigned const maxIntLen = 10;
00178 char const* const playlistPrefixFmt =
00179 "#EXTM3U\r\n"
00180 "#EXT-X-ALLOW-CACHE:YES\r\n"
00181 "#EXT-X-MEDIA-SEQUENCE:0\r\n"
00182 "#EXT-X-TARGETDURATION:%d\r\n";
00183 unsigned const playlistPrefixFmt_maxLen = strlen(playlistPrefixFmt) + maxIntLen;
00184
00185 char const* const playlistMediaFileSpecFmt =
00186 "#EXTINF:%d,\r\n"
00187 "%s?segment=%d,%d\r\n";
00188 unsigned const playlistMediaFileSpecFmt_maxLen = strlen(playlistMediaFileSpecFmt) + maxIntLen + strlen(urlSuffix) + 2*maxIntLen;
00189
00190 char const* const playlistSuffixFmt =
00191 "#EXT-X-ENDLIST\r\n";
00192 unsigned const playlistSuffixFmt_maxLen = strlen(playlistSuffixFmt);
00193
00194
00195 unsigned const playlistMaxSize = 10000;
00196 unsigned const mediaFileSpecsMaxSize = playlistMaxSize - (playlistPrefixFmt_maxLen + playlistSuffixFmt_maxLen);
00197 unsigned const maxNumMediaFileSpecs = mediaFileSpecsMaxSize/playlistMediaFileSpecFmt_maxLen;
00198
00199 unsigned targetDuration = (unsigned)(duration/maxNumMediaFileSpecs + 1);
00200 if (targetDuration < 10) targetDuration = 10;
00201
00202 char* playlist = new char[playlistMaxSize];
00203 char* s = playlist;
00204 sprintf(s, playlistPrefixFmt, targetDuration);
00205 s += strlen(s);
00206
00207 unsigned durSoFar = 0;
00208 while (1) {
00209 unsigned dur = targetDuration < duration ? targetDuration : (unsigned)duration;
00210 duration -= dur;
00211 sprintf(s, playlistMediaFileSpecFmt, dur, urlSuffix, durSoFar, dur);
00212 s += strlen(s);
00213 if (duration < 1.0) break;
00214
00215 durSoFar += dur;
00216 }
00217
00218 sprintf(s, playlistSuffixFmt);
00219 s += strlen(s);
00220 unsigned playlistLen = s - playlist;
00221
00222
00223 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00224 "HTTP/1.1 200 OK\r\n"
00225 "%s"
00226 "Server: LIVE555 Streaming Media v%s\r\n"
00227 "%s"
00228 "Content-Length: %d\r\n"
00229 "Content-Type: application/vnd.apple.mpegurl\r\n"
00230 "\r\n",
00231 dateHeader(),
00232 LIVEMEDIA_LIBRARY_VERSION_STRING,
00233 lastModifiedHeader(urlSuffix),
00234 playlistLen);
00235
00236
00237 send(fClientOutputSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0);
00238 fResponseBuffer[0] = '\0';
00239
00240
00241
00242 if (fPlaylistSource != NULL) {
00243 if (fTCPSink != NULL) fTCPSink->stopPlaying();
00244 Medium::close(fPlaylistSource);
00245 }
00246 fPlaylistSource = ByteStreamMemoryBufferSource::createNew(envir(), (u_int8_t*)playlist, playlistLen);
00247 if (fTCPSink == NULL) fTCPSink = TCPStreamSink::createNew(envir(), fClientOutputSocket);
00248 fTCPSink->startPlaying(*fPlaylistSource, afterStreaming, this);
00249 }
00250
00251 void RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::afterStreaming(void* clientData) {
00252 RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming* clientConnection
00253 = (RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming*)clientData;
00254
00255 if (clientConnection->fRecursionCount > 0) {
00256
00257 clientConnection->fIsActive = False;
00258 } else {
00259
00260 delete clientConnection;
00261 }
00262 }