http_stream.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. /*
  2. * This file is part of the FreeStreamer project,
  3. * (C)Copyright 2011-2018 Matias Muhonen <mmu@iki.fi> 穆马帝
  4. * See the file ''LICENSE'' for using the code.
  5. *
  6. * https://github.com/muhku/FreeStreamer
  7. */
  8. #include "http_stream.h"
  9. #include "audio_queue.h"
  10. #include "id3_parser.h"
  11. #include "stream_configuration.h"
  12. //#define HS_DEBUG 1
  13. #if !defined (HS_DEBUG)
  14. #define HS_TRACE(...) do {} while (0)
  15. #define HS_TRACE_CFSTRING(X) do {} while (0)
  16. #else
  17. #define HS_TRACE(...) printf(__VA_ARGS__)
  18. #define HS_TRACE_CFSTRING(X) HS_TRACE("%s\n", CFStringGetCStringPtr(X, kCFStringEncodingMacRoman))
  19. #endif
  20. /*
  21. * Comment the following line to disable ID3 tag support:
  22. */
  23. #define INCLUDE_ID3TAG_SUPPORT 1
  24. namespace astreamer {
  25. CFStringRef HTTP_Stream::httpRequestMethod = CFSTR("GET");
  26. CFStringRef HTTP_Stream::httpUserAgentHeader = CFSTR("User-Agent");
  27. CFStringRef HTTP_Stream::httpRangeHeader = CFSTR("Range");
  28. CFStringRef HTTP_Stream::icyMetaDataHeader = CFSTR("Icy-MetaData");
  29. CFStringRef HTTP_Stream::icyMetaDataValue = CFSTR("1"); /* always request ICY metadata, if available */
  30. /* HTTP_Stream: public */
  31. HTTP_Stream::HTTP_Stream() :
  32. m_readStream(0),
  33. m_scheduledInRunLoop(false),
  34. m_readPending(false),
  35. m_url(0),
  36. m_httpHeadersParsed(false),
  37. m_contentType(0),
  38. m_contentLength(0),
  39. m_bytesRead(0),
  40. m_icyStream(false),
  41. m_icyHeaderCR(false),
  42. m_icyHeadersRead(false),
  43. m_icyHeadersParsed(false),
  44. m_icyName(0),
  45. m_icyMetaDataInterval(0),
  46. m_dataByteReadCount(0),
  47. m_metaDataBytesRemaining(0),
  48. m_httpReadBuffer(0),
  49. m_icyReadBuffer(0),
  50. m_id3Parser(new ID3_Parser())
  51. {
  52. m_id3Parser->m_delegate = this;
  53. }
  54. HTTP_Stream::~HTTP_Stream()
  55. {
  56. close();
  57. for (std::vector<CFStringRef>::iterator h = m_icyHeaderLines.begin(); h != m_icyHeaderLines.end(); ++h) {
  58. CFRelease(*h);
  59. }
  60. m_icyHeaderLines.clear();
  61. if (m_contentType) {
  62. CFRelease(m_contentType);
  63. m_contentType = 0;
  64. }
  65. if (m_icyName) {
  66. CFRelease(m_icyName);
  67. m_icyName = 0;
  68. }
  69. if (m_httpReadBuffer) {
  70. delete [] m_httpReadBuffer;
  71. m_httpReadBuffer = 0;
  72. }
  73. if (m_icyReadBuffer) {
  74. delete [] m_icyReadBuffer;
  75. m_icyReadBuffer = 0;
  76. }
  77. if (m_url) {
  78. CFRelease(m_url);
  79. m_url = 0;
  80. }
  81. delete m_id3Parser;
  82. m_id3Parser = 0;
  83. }
  84. Input_Stream_Position HTTP_Stream::position()
  85. {
  86. return m_position;
  87. }
  88. CFStringRef HTTP_Stream::contentType()
  89. {
  90. return m_contentType;
  91. }
  92. size_t HTTP_Stream::contentLength()
  93. {
  94. return m_contentLength;
  95. }
  96. bool HTTP_Stream::open()
  97. {
  98. Input_Stream_Position position;
  99. position.start = 0;
  100. position.end = 0;
  101. m_contentLength = 0;
  102. #ifdef INCLUDE_ID3TAG_SUPPORT
  103. m_id3Parser->reset();
  104. #endif
  105. return open(position);
  106. }
  107. bool HTTP_Stream::open(const Input_Stream_Position& position)
  108. {
  109. bool success = false;
  110. CFStreamClientContext CTX = { 0, this, NULL, NULL, NULL };
  111. /* Already opened a read stream, return */
  112. if (m_readStream) {
  113. goto out;
  114. }
  115. /* Reset state */
  116. m_position = position;
  117. m_readPending = false;
  118. m_httpHeadersParsed = false;
  119. if (m_contentType) {
  120. CFRelease(m_contentType);
  121. m_contentType = NULL;
  122. }
  123. m_icyStream = false;
  124. m_icyHeaderCR = false;
  125. m_icyHeadersRead = false;
  126. m_icyHeadersParsed = false;
  127. if (m_icyName) {
  128. CFRelease(m_icyName);
  129. m_icyName = 0;
  130. }
  131. for (std::vector<CFStringRef>::iterator h = m_icyHeaderLines.begin(); h != m_icyHeaderLines.end(); ++h) {
  132. CFRelease(*h);
  133. }
  134. m_icyHeaderLines.clear();
  135. m_icyMetaDataInterval = 0;
  136. m_dataByteReadCount = 0;
  137. m_metaDataBytesRemaining = 0;
  138. m_bytesRead = 0;
  139. if (!m_url) {
  140. goto out;
  141. }
  142. /* Failed to create a stream */
  143. if (!(m_readStream = createReadStream(m_url))) {
  144. goto out;
  145. }
  146. if (!CFReadStreamSetClient(m_readStream, kCFStreamEventHasBytesAvailable |
  147. kCFStreamEventEndEncountered |
  148. kCFStreamEventErrorOccurred, readCallBack, &CTX)) {
  149. CFRelease(m_readStream);
  150. m_readStream = 0;
  151. goto out;
  152. }
  153. setScheduledInRunLoop(true);
  154. if (!CFReadStreamOpen(m_readStream)) {
  155. /* Open failed: clean */
  156. CFReadStreamSetClient(m_readStream, 0, NULL, NULL);
  157. setScheduledInRunLoop(false);
  158. if (m_readStream) {
  159. CFRelease(m_readStream);
  160. m_readStream = 0;
  161. }
  162. goto out;
  163. }
  164. success = true;
  165. out:
  166. return success;
  167. }
  168. void HTTP_Stream::close()
  169. {
  170. /* The stream has been already closed */
  171. if (!m_readStream) {
  172. return;
  173. }
  174. CFReadStreamSetClient(m_readStream, 0, NULL, NULL);
  175. setScheduledInRunLoop(false);
  176. CFReadStreamClose(m_readStream);
  177. CFRelease(m_readStream);
  178. m_readStream = 0;
  179. }
  180. void HTTP_Stream::setScheduledInRunLoop(bool scheduledInRunLoop)
  181. {
  182. /* The stream has not been opened, or it has been already closed */
  183. if (!m_readStream) {
  184. return;
  185. }
  186. /* The state doesn't change */
  187. if (m_scheduledInRunLoop == scheduledInRunLoop) {
  188. return;
  189. }
  190. if (m_scheduledInRunLoop) {
  191. CFReadStreamUnscheduleFromRunLoop(m_readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
  192. } else {
  193. if (m_readPending) {
  194. m_readPending = false;
  195. readCallBack(m_readStream, kCFStreamEventHasBytesAvailable, this);
  196. }
  197. CFReadStreamScheduleWithRunLoop(m_readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
  198. }
  199. m_scheduledInRunLoop = scheduledInRunLoop;
  200. }
  201. void HTTP_Stream::setUrl(CFURLRef url)
  202. {
  203. if (m_url) {
  204. CFRelease(m_url);
  205. }
  206. if (url) {
  207. m_url = (CFURLRef)CFRetain(url);
  208. } else {
  209. m_url = NULL;
  210. }
  211. }
  212. bool HTTP_Stream::canHandleUrl(CFURLRef url)
  213. {
  214. if (!url) {
  215. return false;
  216. }
  217. CFStringRef scheme = CFURLCopyScheme(url);
  218. if (scheme) {
  219. if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) {
  220. CFRelease(scheme);
  221. // The only scheme we claim not to handle are local files.
  222. return false;
  223. }
  224. CFRelease(scheme);
  225. }
  226. return true;
  227. }
  228. void HTTP_Stream::id3metaDataAvailable(std::map<CFStringRef,CFStringRef> metaData)
  229. {
  230. if (m_delegate) {
  231. m_delegate->streamMetaDataAvailable(metaData);
  232. }
  233. }
  234. void HTTP_Stream::id3tagSizeAvailable(UInt32 tagSize)
  235. {
  236. if (m_delegate) {
  237. m_delegate->streamMetaDataByteSizeAvailable(tagSize);
  238. }
  239. }
  240. /* private */
  241. CFReadStreamRef HTTP_Stream::createReadStream(CFURLRef url)
  242. {
  243. CFReadStreamRef readStream = 0;
  244. CFHTTPMessageRef request = 0;
  245. CFDictionaryRef proxySettings = 0;
  246. Stream_Configuration *config = Stream_Configuration::configuration();
  247. if (!(request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpRequestMethod, url, kCFHTTPVersion1_1))) {
  248. goto out;
  249. }
  250. if (config->userAgent) {
  251. CFHTTPMessageSetHeaderFieldValue(request, httpUserAgentHeader, config->userAgent);
  252. }
  253. CFHTTPMessageSetHeaderFieldValue(request, icyMetaDataHeader, icyMetaDataValue);
  254. if (m_position.start > 0 && m_position.end > m_position.start) {
  255. CFStringRef rangeHeaderValue = CFStringCreateWithFormat(NULL,
  256. NULL,
  257. CFSTR("bytes=%llu-%llu"),
  258. m_position.start,
  259. m_position.end);
  260. CFHTTPMessageSetHeaderFieldValue(request, httpRangeHeader, rangeHeaderValue);
  261. CFRelease(rangeHeaderValue);
  262. } else if (m_position.start > 0 && m_position.end < m_position.start) {
  263. CFStringRef rangeHeaderValue = CFStringCreateWithFormat(NULL,
  264. NULL,
  265. CFSTR("bytes=%llu-"),
  266. m_position.start);
  267. CFHTTPMessageSetHeaderFieldValue(request, httpRangeHeader, rangeHeaderValue);
  268. CFRelease(rangeHeaderValue);
  269. }
  270. if (config->predefinedHttpHeaderValues) {
  271. const CFIndex numKeys = CFDictionaryGetCount(config->predefinedHttpHeaderValues);
  272. if (numKeys > 0) {
  273. CFTypeRef *keys = (CFTypeRef *) malloc(numKeys * sizeof(CFTypeRef));
  274. if (keys) {
  275. CFDictionaryGetKeysAndValues(config->predefinedHttpHeaderValues, (const void **) keys, NULL);
  276. for (CFIndex i=0; i < numKeys; i++) {
  277. CFTypeRef key = keys[i];
  278. if (CFGetTypeID(key) == CFStringGetTypeID()) {
  279. const void *value = CFDictionaryGetValue(config->predefinedHttpHeaderValues, (const void *) key);
  280. if (value) {
  281. CFStringRef headerKey = (CFStringRef) key;
  282. CFTypeRef valueRef = (CFTypeRef) value;
  283. if (CFGetTypeID(valueRef) == CFStringGetTypeID()) {
  284. CFStringRef headerValue = (CFStringRef) valueRef;
  285. HS_TRACE("Setting predefined HTTP header ");
  286. HS_TRACE_CFSTRING(headerKey);
  287. HS_TRACE_CFSTRING(headerValue);
  288. CFHTTPMessageSetHeaderFieldValue(request, headerKey, headerValue);
  289. }
  290. }
  291. }
  292. }
  293. free(keys);
  294. }
  295. }
  296. }
  297. if (!(readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request))) {
  298. goto out;
  299. }
  300. CFReadStreamSetProperty(readStream,
  301. kCFStreamNetworkServiceType,
  302. kCFStreamNetworkServiceTypeBackground);
  303. CFReadStreamSetProperty(readStream,
  304. kCFStreamPropertyHTTPShouldAutoredirect,
  305. kCFBooleanTrue);
  306. proxySettings = CFNetworkCopySystemProxySettings();
  307. if (proxySettings) {
  308. CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxySettings);
  309. CFRelease(proxySettings);
  310. }
  311. out:
  312. if (request) {
  313. CFRelease(request);
  314. }
  315. return readStream;
  316. }
  317. void HTTP_Stream::parseHttpHeadersIfNeeded(const UInt8 *buf, const CFIndex bufSize)
  318. {
  319. if (m_httpHeadersParsed) {
  320. return;
  321. }
  322. m_httpHeadersParsed = true;
  323. /* If the response has the "ICY 200 OK" string,
  324. * we are dealing with the ShoutCast protocol.
  325. * The HTTP headers won't be available.
  326. */
  327. if (bufSize >= 10 &&
  328. buf[0] == 0x49 && buf[1] == 0x43 && buf[2] == 0x59 &&
  329. buf[3] == 0x20 && buf[4] == 0x32 && buf[5] == 0x30 &&
  330. buf[6] == 0x30 && buf[7] == 0x20 && buf[8] == 0x4F &&
  331. buf[9] == 0x4B) {
  332. m_icyStream = true;
  333. HS_TRACE("Detected an IceCast stream\n");
  334. // This is an ICY stream, don't try to parse the HTTP headers
  335. return;
  336. }
  337. HS_TRACE("A regular HTTP stream\n");
  338. CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(m_readStream, kCFStreamPropertyHTTPResponseHeader);
  339. CFIndex statusCode = 0;
  340. if (response) {
  341. /*
  342. * If the server responded with the icy-metaint header, the response
  343. * body will be encoded in the ShoutCast protocol.
  344. */
  345. CFStringRef icyMetaIntString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("icy-metaint"));
  346. if (icyMetaIntString) {
  347. m_icyStream = true;
  348. m_icyHeadersParsed = true;
  349. m_icyHeadersRead = true;
  350. m_icyMetaDataInterval = CFStringGetIntValue(icyMetaIntString);
  351. CFRelease(icyMetaIntString);
  352. }
  353. HS_TRACE("icy-metaint: %zu\n", m_icyMetaDataInterval);
  354. statusCode = CFHTTPMessageGetResponseStatusCode(response);
  355. HS_TRACE("HTTP response code %zu", statusCode);
  356. CFStringRef icyNameString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("icy-name"));
  357. if (icyNameString) {
  358. if (m_icyName) {
  359. CFRelease(m_icyName);
  360. }
  361. m_icyName = icyNameString;
  362. if (m_delegate) {
  363. std::map<CFStringRef,CFStringRef> metadataMap;
  364. metadataMap[CFSTR("IcecastStationName")] = CFStringCreateCopy(kCFAllocatorDefault, m_icyName);
  365. m_delegate->streamMetaDataAvailable(metadataMap);
  366. }
  367. }
  368. if (m_contentType) {
  369. CFRelease(m_contentType);
  370. }
  371. m_contentType = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Type"));
  372. HS_TRACE("Content-type: ");
  373. HS_TRACE_CFSTRING(m_contentType);
  374. CFStringRef contentLengthString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Length"));
  375. if (contentLengthString) {
  376. m_contentLength = CFStringGetIntValue(contentLengthString);
  377. CFRelease(contentLengthString);
  378. }
  379. CFRelease(response);
  380. }
  381. if (m_delegate &&
  382. (statusCode == 200 || statusCode == 206)) {
  383. m_delegate->streamIsReadyRead();
  384. } else {
  385. if (m_delegate) {
  386. CFStringRef statusCodeString = CFStringCreateWithFormat(NULL,
  387. NULL,
  388. CFSTR("HTTP response code %d"),
  389. (unsigned int)statusCode);
  390. m_delegate->streamErrorOccurred(statusCodeString);
  391. if (statusCodeString) {
  392. CFRelease(statusCodeString);
  393. }
  394. }
  395. }
  396. }
  397. void HTTP_Stream::parseICYStream(const UInt8 *buf, const CFIndex bufSize)
  398. {
  399. HS_TRACE("Parsing an IceCast stream, received %li bytes\n", bufSize);
  400. CFIndex offset = 0;
  401. CFIndex bytesFound = 0;
  402. if (!m_icyHeadersRead) {
  403. HS_TRACE("ICY headers not read, reading\n");
  404. for (; offset < bufSize; offset++) {
  405. if (m_icyHeaderCR && buf[offset] == '\n') {
  406. if (bytesFound > 0) {
  407. m_icyHeaderLines.push_back(createMetaDataStringWithMostReasonableEncoding(&buf[offset-bytesFound-1], bytesFound));
  408. bytesFound = 0;
  409. HS_TRACE_CFSTRING(m_icyHeaderLines[m_icyHeaderLines.size()-1]);
  410. continue;
  411. }
  412. HS_TRACE("End of ICY headers\n");
  413. m_icyHeadersRead = true;
  414. break;
  415. }
  416. if (buf[offset] == '\r') {
  417. m_icyHeaderCR = true;
  418. continue;
  419. } else {
  420. m_icyHeaderCR = false;
  421. }
  422. bytesFound++;
  423. }
  424. } else if (!m_icyHeadersParsed) {
  425. HS_TRACE("ICY headers not parsed, parsing\n");
  426. const CFStringRef icyContentTypeHeader = CFSTR("content-type:");
  427. const CFStringRef icyMetaDataHeader = CFSTR("icy-metaint:");
  428. const CFStringRef icyNameHeader = CFSTR("icy-name:");
  429. const CFIndex icyContenTypeHeaderLength = CFStringGetLength(icyContentTypeHeader);
  430. const CFIndex icyMetaDataHeaderLength = CFStringGetLength(icyMetaDataHeader);
  431. const CFIndex icyNameHeaderLength = CFStringGetLength(icyNameHeader);
  432. for (std::vector<CFStringRef>::iterator h = m_icyHeaderLines.begin(); h != m_icyHeaderLines.end(); ++h) {
  433. CFStringRef line = *h;
  434. const CFIndex lineLength = CFStringGetLength(line);
  435. if (lineLength == 0) {
  436. continue;
  437. }
  438. HS_TRACE_CFSTRING(line);
  439. if (CFStringCompareWithOptions(line,
  440. icyContentTypeHeader,
  441. CFRangeMake(0, icyContenTypeHeaderLength),
  442. 0) == kCFCompareEqualTo) {
  443. if (m_contentType) {
  444. CFRelease(m_contentType);
  445. m_contentType = 0;
  446. }
  447. m_contentType = CFStringCreateWithSubstring(kCFAllocatorDefault,
  448. line,
  449. CFRangeMake(icyContenTypeHeaderLength, lineLength - icyContenTypeHeaderLength));
  450. }
  451. if (CFStringCompareWithOptions(line,
  452. icyMetaDataHeader,
  453. CFRangeMake(0, icyMetaDataHeaderLength),
  454. 0) == kCFCompareEqualTo) {
  455. CFStringRef metadataInterval = CFStringCreateWithSubstring(kCFAllocatorDefault,
  456. line,
  457. CFRangeMake(icyMetaDataHeaderLength, lineLength - icyMetaDataHeaderLength));
  458. if (metadataInterval) {
  459. m_icyMetaDataInterval = CFStringGetIntValue(metadataInterval);
  460. CFRelease(metadataInterval);
  461. } else {
  462. m_icyMetaDataInterval = 0;
  463. }
  464. }
  465. if (CFStringCompareWithOptions(line,
  466. icyNameHeader,
  467. CFRangeMake(0, icyNameHeaderLength),
  468. 0) == kCFCompareEqualTo) {
  469. if (m_icyName) {
  470. CFRelease(m_icyName);
  471. }
  472. m_icyName = CFStringCreateWithSubstring(kCFAllocatorDefault,
  473. line,
  474. CFRangeMake(icyNameHeaderLength, lineLength - icyNameHeaderLength));
  475. }
  476. }
  477. m_icyHeadersParsed = true;
  478. offset++;
  479. if (m_delegate) {
  480. m_delegate->streamIsReadyRead();
  481. }
  482. }
  483. Stream_Configuration *config = Stream_Configuration::configuration();
  484. if (!m_icyReadBuffer) {
  485. m_icyReadBuffer = new UInt8[config->httpConnectionBufferSize];
  486. }
  487. HS_TRACE("Reading ICY stream for playback\n");
  488. UInt32 i=0;
  489. for (; offset < bufSize; offset++) {
  490. // is this a metadata byte?
  491. if (m_metaDataBytesRemaining > 0) {
  492. m_metaDataBytesRemaining--;
  493. if (m_metaDataBytesRemaining == 0) {
  494. m_dataByteReadCount = 0;
  495. if (m_delegate && !m_icyMetaData.empty()) {
  496. std::map<CFStringRef,CFStringRef> metadataMap;
  497. CFStringRef metaData = createMetaDataStringWithMostReasonableEncoding(&m_icyMetaData[0],
  498. m_icyMetaData.size());
  499. if (!metaData) {
  500. // Metadata encoding failed, cannot parse.
  501. m_icyMetaData.clear();
  502. continue;
  503. }
  504. CFArrayRef tokens = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault,
  505. metaData,
  506. CFSTR(";"));
  507. for (CFIndex i=0, max=CFArrayGetCount(tokens); i < max; i++) {
  508. CFStringRef token = (CFStringRef) CFArrayGetValueAtIndex(tokens, i);
  509. CFRange foundRange;
  510. if (CFStringFindWithOptions(token,
  511. CFSTR("='"),
  512. CFRangeMake(0, CFStringGetLength(token)),
  513. NULL,
  514. &foundRange) == true) {
  515. CFRange keyRange = CFRangeMake(0, foundRange.location);
  516. CFStringRef metadaKey = CFStringCreateWithSubstring(kCFAllocatorDefault,
  517. token,
  518. keyRange);
  519. CFRange valueRange = CFRangeMake(foundRange.location + 2, CFStringGetLength(token) - keyRange.length - 3);
  520. CFStringRef metadaValue = CFStringCreateWithSubstring(kCFAllocatorDefault,
  521. token,
  522. valueRange);
  523. metadataMap[metadaKey] = metadaValue;
  524. }
  525. }
  526. CFRelease(tokens);
  527. CFRelease(metaData);
  528. if (m_icyName) {
  529. metadataMap[CFSTR("IcecastStationName")] = CFStringCreateCopy(kCFAllocatorDefault, m_icyName);
  530. }
  531. m_delegate->streamMetaDataAvailable(metadataMap);
  532. }
  533. m_icyMetaData.clear();
  534. continue;
  535. }
  536. m_icyMetaData.push_back(buf[offset]);
  537. continue;
  538. }
  539. // is this the interval byte?
  540. if (m_icyMetaDataInterval > 0 && m_dataByteReadCount == m_icyMetaDataInterval) {
  541. m_metaDataBytesRemaining = buf[offset] * 16;
  542. if (m_metaDataBytesRemaining == 0) {
  543. m_dataByteReadCount = 0;
  544. }
  545. continue;
  546. }
  547. // a data byte
  548. m_dataByteReadCount++;
  549. m_icyReadBuffer[i++] = buf[offset];
  550. }
  551. if (m_delegate && i > 0) {
  552. m_delegate->streamHasBytesAvailable(m_icyReadBuffer, i);
  553. }
  554. }
  555. #define TRY_ENCODING(STR,ENC) STR = CFStringCreateWithBytes(kCFAllocatorDefault, bytes, numBytes, ENC, false); \
  556. if (STR != NULL) { return STR; }
  557. CFStringRef HTTP_Stream::createMetaDataStringWithMostReasonableEncoding(const UInt8 *bytes, const CFIndex numBytes)
  558. {
  559. CFStringRef metaData;
  560. TRY_ENCODING(metaData, kCFStringEncodingUTF8);
  561. TRY_ENCODING(metaData, kCFStringEncodingISOLatin1);
  562. TRY_ENCODING(metaData, kCFStringEncodingWindowsLatin1);
  563. TRY_ENCODING(metaData, kCFStringEncodingNextStepLatin);
  564. TRY_ENCODING(metaData, kCFStringEncodingISOLatin2);
  565. TRY_ENCODING(metaData, kCFStringEncodingISOLatin3);
  566. TRY_ENCODING(metaData, kCFStringEncodingISOLatin4);
  567. TRY_ENCODING(metaData, kCFStringEncodingISOLatinCyrillic);
  568. TRY_ENCODING(metaData, kCFStringEncodingISOLatinArabic);
  569. TRY_ENCODING(metaData, kCFStringEncodingISOLatinGreek);
  570. TRY_ENCODING(metaData, kCFStringEncodingISOLatinHebrew);
  571. TRY_ENCODING(metaData, kCFStringEncodingISOLatin5);
  572. TRY_ENCODING(metaData, kCFStringEncodingISOLatin6);
  573. TRY_ENCODING(metaData, kCFStringEncodingISOLatinThai);
  574. TRY_ENCODING(metaData, kCFStringEncodingISOLatin7);
  575. TRY_ENCODING(metaData, kCFStringEncodingISOLatin8);
  576. TRY_ENCODING(metaData, kCFStringEncodingISOLatin9);
  577. TRY_ENCODING(metaData, kCFStringEncodingWindowsLatin2);
  578. TRY_ENCODING(metaData, kCFStringEncodingWindowsCyrillic);
  579. TRY_ENCODING(metaData, kCFStringEncodingWindowsGreek);
  580. TRY_ENCODING(metaData, kCFStringEncodingWindowsLatin5);
  581. TRY_ENCODING(metaData, kCFStringEncodingWindowsHebrew);
  582. TRY_ENCODING(metaData, kCFStringEncodingWindowsArabic);
  583. TRY_ENCODING(metaData, kCFStringEncodingKOI8_R);
  584. TRY_ENCODING(metaData, kCFStringEncodingBig5);
  585. TRY_ENCODING(metaData, kCFStringEncodingASCII);
  586. return metaData;
  587. }
  588. #undef TRY_ENCODING
  589. void HTTP_Stream::readCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
  590. {
  591. HTTP_Stream *THIS = static_cast<HTTP_Stream*>(clientCallBackInfo);
  592. Stream_Configuration *config = Stream_Configuration::configuration();
  593. CFStringRef reportedNetworkError = NULL;
  594. switch (eventType) {
  595. case kCFStreamEventHasBytesAvailable: {
  596. if (!THIS->m_httpReadBuffer) {
  597. THIS->m_httpReadBuffer = new UInt8[config->httpConnectionBufferSize];
  598. }
  599. while (CFReadStreamHasBytesAvailable(stream)) {
  600. if (!THIS->m_scheduledInRunLoop) {
  601. /*
  602. * This is critical - though the stream has data available,
  603. * do not try to feed the audio queue with data, if it has
  604. * indicated that it doesn't want more data due to buffers
  605. * full.
  606. */
  607. THIS->m_readPending = true;
  608. break;
  609. }
  610. CFIndex bytesRead = CFReadStreamRead(stream, THIS->m_httpReadBuffer, config->httpConnectionBufferSize);
  611. if (CFReadStreamGetStatus(stream) == kCFStreamStatusError ||
  612. bytesRead < 0) {
  613. if (THIS->contentLength() > 0) {
  614. /*
  615. * Try to recover gracefully if we have a non-continuous stream
  616. */
  617. Input_Stream_Position currentPosition = THIS->position();
  618. Input_Stream_Position recoveryPosition;
  619. recoveryPosition.start = currentPosition.start + THIS->m_bytesRead;
  620. recoveryPosition.end = THIS->contentLength();
  621. HS_TRACE("Recovering HTTP stream, start %llu\n", recoveryPosition.start);
  622. THIS->open(recoveryPosition);
  623. break;
  624. }
  625. CFErrorRef streamError = CFReadStreamCopyError(stream);
  626. if (streamError) {
  627. CFStringRef errorDesc = CFErrorCopyDescription(streamError);
  628. if (errorDesc) {
  629. reportedNetworkError = CFStringCreateCopy(kCFAllocatorDefault, errorDesc);
  630. CFRelease(errorDesc);
  631. }
  632. CFRelease(streamError);
  633. }
  634. if (THIS->m_delegate) {
  635. THIS->m_delegate->streamErrorOccurred(reportedNetworkError);
  636. if (reportedNetworkError) {
  637. CFRelease(reportedNetworkError);
  638. reportedNetworkError = NULL;
  639. }
  640. }
  641. break;
  642. }
  643. if (bytesRead > 0) {
  644. THIS->m_bytesRead += bytesRead;
  645. HS_TRACE("Read %li bytes, total %llu\n", bytesRead, THIS->m_bytesRead);
  646. THIS->parseHttpHeadersIfNeeded(THIS->m_httpReadBuffer, bytesRead);
  647. #ifdef INCLUDE_ID3TAG_SUPPORT
  648. if (!THIS->m_icyStream && THIS->m_id3Parser->wantData()) {
  649. THIS->m_id3Parser->feedData(THIS->m_httpReadBuffer, (UInt32)bytesRead);
  650. }
  651. #endif
  652. if (THIS->m_icyStream) {
  653. HS_TRACE("Parsing ICY stream\n");
  654. THIS->parseICYStream(THIS->m_httpReadBuffer, bytesRead);
  655. } else {
  656. if (THIS->m_delegate) {
  657. HS_TRACE("Not an ICY stream; calling the delegate back\n");
  658. THIS->m_delegate->streamHasBytesAvailable(THIS->m_httpReadBuffer, (UInt32)bytesRead);
  659. }
  660. }
  661. }
  662. }
  663. if (reportedNetworkError) {
  664. CFRelease(reportedNetworkError);
  665. reportedNetworkError = NULL;
  666. }
  667. break;
  668. }
  669. case kCFStreamEventEndEncountered: {
  670. // This should concerns only non-continous streams
  671. if (THIS->m_bytesRead < THIS->contentLength()) {
  672. HS_TRACE("End of stream, but we have read only %llu bytes on a total of %li. Missing: %llu\n", THIS->m_bytesRead, THIS->contentLength(), (THIS->contentLength() - THIS->m_bytesRead));
  673. Input_Stream_Position currentPosition = THIS->position();
  674. Input_Stream_Position recoveryPosition;
  675. recoveryPosition.start = currentPosition.start + THIS->m_bytesRead;
  676. recoveryPosition.end = THIS->contentLength();
  677. HS_TRACE("Reopen for the end of the file from byte position: %llu\n", recoveryPosition.start);
  678. THIS->close();
  679. THIS->open(recoveryPosition);
  680. break;
  681. }
  682. if (THIS->m_delegate) {
  683. THIS->m_delegate->streamEndEncountered();
  684. }
  685. break;
  686. }
  687. case kCFStreamEventErrorOccurred: {
  688. if (THIS->m_delegate) {
  689. CFStringRef reportedNetworkError = NULL;
  690. CFErrorRef streamError = CFReadStreamCopyError(stream);
  691. if (streamError) {
  692. CFStringRef errorDesc = CFErrorCopyDescription(streamError);
  693. if (errorDesc) {
  694. reportedNetworkError = CFStringCreateCopy(kCFAllocatorDefault, errorDesc);
  695. CFRelease(errorDesc);
  696. }
  697. CFRelease(streamError);
  698. }
  699. THIS->m_delegate->streamErrorOccurred(reportedNetworkError);
  700. if (reportedNetworkError) {
  701. CFRelease(reportedNetworkError);
  702. }
  703. }
  704. break;
  705. }
  706. }
  707. }
  708. } // namespace astreamer