1 // ------------------------------------------------
6 // (c) 2002-4 peercast.org
7 // ------------------------------------------------
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 // ------------------------------------------------
27 #include "chkMemoryLeak.h"
28 #define DEBUG_NEW new(__FILE__, __LINE__)
32 // ------------------------------------------------
33 void URLSource::stream(Channel *ch)
37 while (ch->thread.active && !peercastInst->isQuitting)
43 url = streamURL(ch,url.cstr());
50 // ------------------------------------------------
51 int URLSource::getSourceRate()
54 return inputStream->bytesInPerSec;
59 // ------------------------------------------------
60 ::String URLSource::streamURL(Channel *ch, const char *url)
64 if (peercastInst->isQuitting || !ch->thread.active)
71 char *fileName = urlTmp.cstr();
74 ChannelStream *source=NULL;
76 LOG_CHANNEL("Fetch URL=%s",fileName);
81 // get the source protocol
82 if (strnicmp(fileName,"http://",7)==0)
84 ch->info.srcProtocol = ChanInfo::SP_HTTP;
87 else if (strnicmp(fileName,"mms://",6)==0)
89 ch->info.srcProtocol = ChanInfo::SP_MMS;
92 else if (strnicmp(fileName,"pcp://",6)==0)
94 ch->info.srcProtocol = ChanInfo::SP_PCP;
97 else if (strnicmp(fileName,"file://",7)==0)
99 ch->info.srcProtocol = ChanInfo::SP_FILE;
104 ch->info.srcProtocol = ChanInfo::SP_FILE;
107 // default to mp3 for shoutcast servers
108 if (ch->info.contentType == ChanInfo::T_PLS)
109 ch->info.contentType = ChanInfo::T_MP3;
112 ch->setStatus(Channel::S_CONNECTING);
114 if ((ch->info.srcProtocol == ChanInfo::SP_HTTP) || (ch->info.srcProtocol == ChanInfo::SP_PCP) || (ch->info.srcProtocol == ChanInfo::SP_MMS))
117 if ((ch->info.contentType == ChanInfo::T_WMA) || (ch->info.contentType == ChanInfo::T_WMV))
118 ch->info.srcProtocol = ChanInfo::SP_MMS;
121 LOG_CHANNEL("Channel source is HTTP");
123 ClientSocket *inputSocket = sys->createSocket();
125 throw StreamException("Channel cannot create socket");
128 inputStream = inputSocket;
131 char *dir = strstr(fileName,"/");
136 LOG_CHANNEL("Fetch Host=%s",fileName);
138 LOG_CHANNEL("Fetch Dir=%s",dir);
142 host.fromStrName(fileName,80);
144 inputSocket->open(host);
145 inputSocket->connect();
147 HTTP http(*inputSocket);
148 http.writeLineF("GET /%s HTTP/1.0",dir?dir:"");
150 http.writeLineF("%s %s",HTTP_HS_HOST,fileName);
151 http.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
152 http.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
154 if (ch->info.srcProtocol == ChanInfo::SP_MMS)
156 http.writeLineF("%s %s",HTTP_HS_AGENT,"NSPlayer/4.1.0.3856");
157 http.writeLine("Pragma: no-cache,rate=1.000000,request-context=1");
158 //http.writeLine("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=22605256,max-duration=0");
159 http.writeLine("Pragma: xPlayStrm=1");
160 http.writeLine("Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}");
161 http.writeLine("Pragma: stream-switch-count=2");
162 http.writeLine("Pragma: stream-switch-entry=ffff:1:0 ffff:2:0");
165 http.writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);
166 http.writeLineF("%s %d",PCX_HS_PCP,1);
167 http.writeLine("Icy-MetaData:1"); // fix by ravon
172 int res = http.readResponse();
175 String name = ch->info.name;
177 while (http.nextHeader())
180 LOG_CHANNEL("Fetch HTTP: %s",http.cmdLine);
182 ChanInfo tmpInfo = ch->info;
183 Servent::readICYHeader(http, ch->info, NULL, 0);
185 if (!tmpInfo.name.isEmpty())
186 ch->info.name = tmpInfo.name;
187 if (!tmpInfo.genre.isEmpty())
188 ch->info.genre = tmpInfo.genre;
189 if (!tmpInfo.url.isEmpty())
190 ch->info.url = tmpInfo.url;
192 if (http.isHeader("icy-metaint"))
193 ch->icyMetaInterval = http.getArgInt();
194 else if (http.isHeader("Location:"))
195 nextURL.set(http.getArgStr());
197 char *arg = http.getArgStr();
200 if (http.isHeader("content-type"))
202 if (stristr(arg,MIME_XSCPLS))
203 pls = new PlayList(PlayList::T_SCPLS, 1000);
204 else if (stristr(arg,MIME_PLS))
205 pls = new PlayList(PlayList::T_PLS, 1000);
206 else if (stristr(arg,MIME_XPLS))
207 pls = new PlayList(PlayList::T_PLS, 1000);
208 else if (stristr(arg,MIME_M3U))
209 pls = new PlayList(PlayList::T_PLS, 1000);
210 else if (stristr(arg,MIME_TEXT))
211 pls = new PlayList(PlayList::T_PLS, 1000);
212 else if (stristr(arg,MIME_ASX))
213 pls = new PlayList(PlayList::T_ASX, 1000);
214 else if (stristr(arg,MIME_MMS))
215 ch->info.srcProtocol = ChanInfo::SP_MMS;
221 if ((!nextURL.isEmpty()) && (res==302))
223 LOG_CHANNEL("Channel redirect: %s",nextURL.cstr());
224 inputSocket->close();
232 LOG_ERROR("HTTP response: %d",res);
233 throw StreamException("Bad HTTP connect");
237 }else if (ch->info.srcProtocol == ChanInfo::SP_FILE)
240 LOG_CHANNEL("Channel source is FILE");
242 FileStream *fs = new FileStream();
243 fs->openReadOnly(fileName);
246 ChanInfo::TYPE fileType = ChanInfo::T_UNKNOWN;
247 // if filetype is unknown, try and figure it out from file extension.
248 //if ((info.srcType == ChanInfo::T_UNKNOWN) || (info.srcType == ChanInfo::T_PLAYLIST))
250 const char *ext = fileName+strlen(fileName);
258 fileType = ChanInfo::getTypeFromStr(ext);
262 if (ch->info.bitrate)
263 ch->readDelay = true;
266 if (fileType == ChanInfo::T_PLS)
267 pls = new PlayList(PlayList::T_PLS, 1000);
268 else if (fileType == ChanInfo::T_ASX)
269 pls = new PlayList(PlayList::T_ASX, 1000);
271 ch->info.contentType = fileType;
275 throw StreamException("Unsupported URL");
282 LOG_CHANNEL("Channel is Playlist");
284 pls->read(*inputStream);
286 inputStream->close();
293 LOG_CHANNEL("Playlist: %d URLs",pls->numURLs);
294 while ((ch->thread.active) && (pls->numURLs) && (!peercastInst->isQuitting))
298 url = pls->urls[urlNum%pls->numURLs];
303 url = streamURL(ch,url.cstr());
304 }catch(StreamException &)
313 // if we didn`t get a channel id from the source, then create our own (its an original broadcast)
314 if (!ch->info.id.isSet())
316 ch->info.id = chanMgr->broadcastID;
317 ch->info.id.encode(NULL,ch->info.name.cstr(),ch->info.genre,ch->info.bitrate);
320 if (ch->info.contentType == ChanInfo::T_ASX)
321 ch->info.contentType = ChanInfo::T_WMV;
323 ch->setStatus(Channel::S_BROADCASTING);
325 inputStream->setReadTimeout(60); // use longer read timeout
327 source = ch->createSource();
329 ch->readStream(*inputStream,source);
331 inputStream->close();
334 }catch(StreamException &e)
336 ch->setStatus(Channel::S_ERROR);
337 LOG_ERROR("Channel error: %s",e.msg);
342 ch->setStatus(Channel::S_CLOSING);