You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

638 lines
20 KiB

  1. /*
  2. * protocolcurl.c: IPTV plugin for the Video Disk Recorder
  3. *
  4. * See the README file for copyright information and how to reach the author.
  5. *
  6. */
  7. #include "common.h"
  8. #include "config.h"
  9. #include "log.h"
  10. #include "protocolcurl.h"
  11. #ifdef CURLOPT_RTSPHEADER
  12. #define USE_RTSP
  13. #endif
  14. #define iptv_curl_easy_setopt(X, Y, Z) \
  15. if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { \
  16. error("curl_easy_setopt(%s, %s) failed: %s (%d)", #Y, #Z, curl_easy_strerror(res), res); \
  17. }
  18. #define iptv_curl_easy_perform(X) \
  19. if ((res = curl_easy_perform((X))) != CURLE_OK) { \
  20. error("curl_easy_perform() failed: %s (%d)", curl_easy_strerror(res), res); \
  21. }
  22. cIptvProtocolCurl::cIptvProtocolCurl()
  23. : streamUrlM(""),
  24. streamParamM(0),
  25. streamPortM(0),
  26. mutexM(),
  27. handleM(NULL),
  28. multiM(NULL),
  29. headerListM(NULL),
  30. ringBufferM(new cRingBufferLinear(IPTV_BUFFER_SIZE, 7 * TS_SIZE, false, "IPTV CURL")),
  31. rtspControlM(""),
  32. modeM(eModeUnknown),
  33. timeoutM(),
  34. connectedM(false),
  35. pausedM(false)
  36. {
  37. debug1("%s", __PRETTY_FUNCTION__);
  38. if (ringBufferM) {
  39. ringBufferM->SetTimeouts(100, 0);
  40. ringBufferM->SetIoThrottle();
  41. }
  42. Connect();
  43. }
  44. cIptvProtocolCurl::~cIptvProtocolCurl()
  45. {
  46. debug1("%s", __PRETTY_FUNCTION__);
  47. Disconnect();
  48. // Free allocated memory
  49. DELETE_POINTER(ringBufferM);
  50. }
  51. int cIptvProtocolCurl::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP)
  52. {
  53. cIptvProtocolCurl *obj = reinterpret_cast<cIptvProtocolCurl *>(dataP);
  54. if (obj) {
  55. switch (typeP) {
  56. case CURLINFO_TEXT:
  57. debug8("%s INFO %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
  58. break;
  59. case CURLINFO_HEADER_IN:
  60. debug8("%s HEAD <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
  61. break;
  62. case CURLINFO_HEADER_OUT:
  63. debug8("%s HEAD >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
  64. break;
  65. case CURLINFO_DATA_IN:
  66. debug8("%s DATA <<< %zu", __PRETTY_FUNCTION__, sizeP);
  67. break;
  68. case CURLINFO_DATA_OUT:
  69. debug8("%s DATA >>> %zu", __PRETTY_FUNCTION__, sizeP);
  70. break;
  71. default:
  72. break;
  73. }
  74. }
  75. return 0;
  76. }
  77. size_t cIptvProtocolCurl::WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
  78. {
  79. cIptvProtocolCurl *obj = reinterpret_cast<cIptvProtocolCurl *>(dataP);
  80. size_t len = sizeP * nmembP;
  81. debug16("%s (, %zu, %zu, ) len=%zu", __PRETTY_FUNCTION__, sizeP, nmembP, len);
  82. if (obj && !obj->PutData((unsigned char *)ptrP, (int)len))
  83. return CURL_WRITEFUNC_PAUSE;
  84. return len;
  85. }
  86. size_t cIptvProtocolCurl::WriteRtspCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
  87. {
  88. cIptvProtocolCurl *obj = reinterpret_cast<cIptvProtocolCurl *>(dataP);
  89. size_t len = sizeP * nmembP;
  90. unsigned char *p = (unsigned char *)ptrP;
  91. debug16("%s (, %zu, %zu, ) len=%zu", __PRETTY_FUNCTION__, sizeP, nmembP, len);
  92. // Validate packet header ('$') and channel (0)
  93. if (obj && (p[0] == 0x24) && (p[1] == 0)) {
  94. int length = (p[2] << 8) | p[3];
  95. if (length > 3) {
  96. // Skip interleave header
  97. p += 4;
  98. // http://tools.ietf.org/html/rfc3550
  99. // http://tools.ietf.org/html/rfc2250
  100. // Version
  101. unsigned int v = (p[0] >> 6) & 0x03;
  102. // Extension bit
  103. unsigned int x = (p[0] >> 4) & 0x01;
  104. // CSCR count
  105. unsigned int cc = p[0] & 0x0F;
  106. // Payload type: MPEG2 TS = 33
  107. //unsigned int pt = p[1] & 0x7F;
  108. // Header lenght
  109. unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
  110. // Check if extension
  111. if (x) {
  112. // Extension header length
  113. unsigned int ehl = (((p[headerlen + 2] & 0xFF) << 8) |(p[headerlen + 3] & 0xFF));
  114. // Update header length
  115. headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
  116. }
  117. // Check that rtp is version 2 and payload contains multiple of TS packet data
  118. if ((v == 2) && (((length - headerlen) % TS_SIZE) == 0) && (p[headerlen] == TS_SYNC_BYTE)) {
  119. // Set argument point to payload in read buffer
  120. obj->PutData(&p[headerlen], (length - headerlen));
  121. }
  122. }
  123. }
  124. return len;
  125. }
  126. size_t cIptvProtocolCurl::DescribeCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
  127. {
  128. cIptvProtocolCurl *obj = reinterpret_cast<cIptvProtocolCurl *>(dataP);
  129. size_t len = sizeP * nmembP;
  130. debug16("%s (, %zu, %zu, ) len=%zu", __PRETTY_FUNCTION__, sizeP, nmembP, len);
  131. bool found = false;
  132. cString control = "";
  133. char *p = (char *)ptrP;
  134. char *r = strtok(p, "\r\n");
  135. while (r) {
  136. debug16("%s (, %zu, %zu, ) len=%zu r=%s", __PRETTY_FUNCTION__, sizeP, nmembP, len, r);
  137. // Look for a media name: "video"
  138. if (strstr(r, "m=video")) {
  139. found = true;
  140. }
  141. // ... and find out its' attribute
  142. if (found && strstr(r, "a=control")) {
  143. char *s = NULL;
  144. if (sscanf(r, "a=control:%255ms", &s) == 1)
  145. control = compactspace(s);
  146. free(s);
  147. break;
  148. }
  149. r = strtok(NULL, "\r\n");
  150. }
  151. if (!isempty(*control) && obj)
  152. obj->SetRtspControl(*control);
  153. return len;
  154. }
  155. size_t cIptvProtocolCurl::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
  156. {
  157. //cIptvProtocolCurl *obj = reinterpret_cast<cIptvProtocolCurl *>(dataP);
  158. size_t len = sizeP * nmembP;
  159. debug16("%s (, %zu, %zu, ) len=%zu", __PRETTY_FUNCTION__, sizeP, nmembP, len);
  160. char *p = (char *)ptrP;
  161. char *r = strtok(p, "\r\n");
  162. while (r) {
  163. debug16("%s (, %zu, %zu, ) len=%zu r=%s", __PRETTY_FUNCTION__, sizeP, nmembP, len, r);
  164. r = strtok(NULL, "\r\n");
  165. }
  166. return len;
  167. }
  168. void cIptvProtocolCurl::SetRtspControl(const char *controlP)
  169. {
  170. cMutexLock MutexLock(&mutexM);
  171. debug16("%s (%s)", __PRETTY_FUNCTION__, controlP);
  172. cString protocol = ChangeCase(controlP, false).Truncate(7);
  173. if (startswith(*protocol, "rtsp://")) {
  174. streamUrlM = controlP;
  175. rtspControlM = "";
  176. }
  177. else
  178. rtspControlM = controlP;
  179. }
  180. bool cIptvProtocolCurl::PutData(unsigned char *dataP, int lenP)
  181. {
  182. cMutexLock MutexLock(&mutexM);
  183. debug16("%s (, %d)", __PRETTY_FUNCTION__, lenP);
  184. if (pausedM)
  185. return false;
  186. if (ringBufferM && (lenP >= 0)) {
  187. // Should we pause the transfer ?
  188. if (ringBufferM->Free() < (2 * CURL_MAX_WRITE_SIZE)) {
  189. debug1("%s Pause free=%d available=%d len=%d", __PRETTY_FUNCTION__,
  190. ringBufferM->Free(), ringBufferM->Available(), lenP);
  191. pausedM = true;
  192. return false;
  193. }
  194. int p = ringBufferM->Put(dataP, lenP);
  195. if (p != lenP)
  196. ringBufferM->ReportOverflow(lenP - p);
  197. }
  198. return true;
  199. }
  200. void cIptvProtocolCurl::DelData(int lenP)
  201. {
  202. cMutexLock MutexLock(&mutexM);
  203. debug16("%s", __PRETTY_FUNCTION__);
  204. if (ringBufferM && (lenP >= 0))
  205. ringBufferM->Del(lenP);
  206. }
  207. void cIptvProtocolCurl::ClearData()
  208. {
  209. debug16("%s", __PRETTY_FUNCTION__);
  210. if (ringBufferM)
  211. ringBufferM->Clear();
  212. }
  213. unsigned char *cIptvProtocolCurl::GetData(int &lenP)
  214. {
  215. cMutexLock MutexLock(&mutexM);
  216. debug16("%s", __PRETTY_FUNCTION__);
  217. unsigned char *p = NULL;
  218. lenP = 0;
  219. if (ringBufferM) {
  220. int count = 0;
  221. p = ringBufferM->Get(count);
  222. #if 0
  223. if (p && count >= TS_SIZE) {
  224. if (*p != TS_SYNC_BYTE) {
  225. for (int i = 1; i < count; ++i) {
  226. if (p[i] == TS_SYNC_BYTE) {
  227. count = i;
  228. break;
  229. }
  230. }
  231. error("IPTV skipped %d bytes to sync on TS packet", count);
  232. ringBufferM->Del(count);
  233. lenP = 0;
  234. return NULL;
  235. }
  236. }
  237. #endif
  238. count -= (count % TS_SIZE);
  239. lenP = count;
  240. }
  241. return p;
  242. }
  243. bool cIptvProtocolCurl::Connect()
  244. {
  245. cMutexLock MutexLock(&mutexM);
  246. debug1("%s", __PRETTY_FUNCTION__);
  247. if (connectedM)
  248. return true;
  249. // Initialize the curl session
  250. if (!handleM)
  251. handleM = curl_easy_init();
  252. if (handleM && !isempty(*streamUrlM)) {
  253. CURLcode res = CURLE_OK;
  254. cString netrc = cString::sprintf("%s/netrc", IptvConfig.GetConfigDirectory());
  255. // Verbose output
  256. iptv_curl_easy_setopt(handleM, CURLOPT_VERBOSE, 1L);
  257. iptv_curl_easy_setopt(handleM, CURLOPT_DEBUGFUNCTION, cIptvProtocolCurl::DebugCallback);
  258. iptv_curl_easy_setopt(handleM, CURLOPT_DEBUGDATA, this);
  259. // Set callbacks
  260. iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, cIptvProtocolCurl::WriteCallback);
  261. iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, this);
  262. iptv_curl_easy_setopt(handleM, CURLOPT_HEADERFUNCTION, cIptvProtocolCurl::HeaderCallback);
  263. iptv_curl_easy_setopt(handleM, CURLOPT_WRITEHEADER, this);
  264. // No progress meter and no signaling
  265. iptv_curl_easy_setopt(handleM, CURLOPT_NOPROGRESS, 1L);
  266. iptv_curl_easy_setopt(handleM, CURLOPT_NOSIGNAL, 1L);
  267. // Support netrc
  268. iptv_curl_easy_setopt(handleM, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL);
  269. iptv_curl_easy_setopt(handleM, CURLOPT_NETRC_FILE, *netrc);
  270. // Set timeouts
  271. iptv_curl_easy_setopt(handleM, CURLOPT_CONNECTTIMEOUT, (long)eConnectTimeoutS);
  272. iptv_curl_easy_setopt(handleM, CURLOPT_LOW_SPEED_LIMIT, (long)eLowSpeedLimitBytes);
  273. iptv_curl_easy_setopt(handleM, CURLOPT_LOW_SPEED_TIME, (long)eLowSpeedTimeoutS);
  274. // Set user-agent
  275. iptv_curl_easy_setopt(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
  276. // Set URL
  277. char *p = curl_easy_unescape(handleM, *streamUrlM, 0, NULL);
  278. streamUrlM = p;
  279. curl_free(p);
  280. iptv_curl_easy_setopt(handleM, CURLOPT_URL, *streamUrlM);
  281. // Protocol specific initializations
  282. switch (modeM) {
  283. #ifdef USE_RTSP
  284. case eModeRtsp:
  285. {
  286. cString uri, control, transport, range;
  287. // Create the listening socket for UDP mode
  288. if (!streamParamM)
  289. OpenSocket(streamPortM);
  290. // Request server options
  291. uri = cString::sprintf("%s", *streamUrlM);
  292. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
  293. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
  294. iptv_curl_easy_perform(handleM);
  295. // Request session description - SDP is delivered in message body and not in the header!
  296. iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, cIptvProtocolCurl::DescribeCallback);
  297. iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, this);
  298. uri = cString::sprintf("%s", *streamUrlM);
  299. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
  300. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE);
  301. iptv_curl_easy_perform(handleM);
  302. iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, NULL);
  303. iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, NULL);
  304. // Setup media stream
  305. if (isempty(*rtspControlM))
  306. uri = cString::sprintf("%s", *streamUrlM);
  307. else
  308. uri = cString::sprintf("%s/%s", *streamUrlM, *rtspControlM);
  309. if (streamParamM)
  310. transport = "RTP/AVP/TCP;unicast;interleaved=0-1";
  311. else
  312. transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", streamPortM, streamPortM + 1);
  313. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
  314. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_TRANSPORT, *transport);
  315. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
  316. iptv_curl_easy_perform(handleM);
  317. // Start playing
  318. uri = cString::sprintf("%s/", *streamUrlM);
  319. range = "0.000-";
  320. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
  321. //iptv_curl_easy_setopt(handleM, CURLOPT_RANGE, *range);
  322. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
  323. iptv_curl_easy_perform(handleM);
  324. // Start receiving
  325. if (streamParamM) {
  326. iptv_curl_easy_setopt(handleM, CURLOPT_INTERLEAVEFUNCTION, cIptvProtocolCurl::WriteRtspCallback);
  327. iptv_curl_easy_setopt(handleM, CURLOPT_INTERLEAVEDATA, this);
  328. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_RECEIVE);
  329. iptv_curl_easy_perform(handleM);
  330. }
  331. // Don't add handle into multi set
  332. isActiveM = true;
  333. }
  334. break;
  335. #endif
  336. case eModeHttp:
  337. case eModeHttps:
  338. {
  339. // Limit download speed (bytes/s)
  340. iptv_curl_easy_setopt(handleM, CURLOPT_MAX_RECV_SPEED_LARGE, eMaxDownloadSpeedMBits * 131072L);
  341. // Follow location
  342. iptv_curl_easy_setopt(handleM, CURLOPT_FOLLOWLOCATION, 1L);
  343. // Fail if HTTP return code is >= 400
  344. iptv_curl_easy_setopt(handleM, CURLOPT_FAILONERROR, 1L);
  345. // Set additional headers to prevent caching
  346. headerListM = curl_slist_append(headerListM, "Cache-Control: no-store, no-cache, must-revalidate");
  347. headerListM = curl_slist_append(headerListM, "Cache-Control: post-check=0, pre-check=0");
  348. headerListM = curl_slist_append(headerListM, "Pragma: no-cache");
  349. headerListM = curl_slist_append(headerListM, "Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  350. iptv_curl_easy_setopt(handleM, CURLOPT_HTTPHEADER, headerListM);
  351. // Initialize multi set and add handle into it
  352. if (!multiM)
  353. multiM = curl_multi_init();
  354. if (multiM)
  355. curl_multi_add_handle(multiM, handleM);
  356. }
  357. break;
  358. case eModeFile:
  359. {
  360. // Set timeout
  361. iptv_curl_easy_setopt(handleM, CURLOPT_TIMEOUT_MS, 10L);
  362. // Initialize multi set and add handle into it
  363. if (!multiM)
  364. multiM = curl_multi_init();
  365. if (multiM)
  366. curl_multi_add_handle(multiM, handleM);
  367. }
  368. break;
  369. case eModeUnknown:
  370. default:
  371. break;
  372. }
  373. timeoutM.Set(eKeepAliveIntervalMs);
  374. connectedM = true;
  375. return true;
  376. }
  377. return false;
  378. }
  379. bool cIptvProtocolCurl::Disconnect()
  380. {
  381. cMutexLock MutexLock(&mutexM);
  382. debug1("%s", __PRETTY_FUNCTION__);
  383. if (!connectedM)
  384. return true;
  385. // Terminate curl session
  386. if (handleM) {
  387. // Remove handle from multi set
  388. if (multiM) {
  389. curl_multi_remove_handle(multiM, handleM);
  390. curl_multi_cleanup(multiM);
  391. multiM = NULL;
  392. }
  393. // Mode specific tricks
  394. switch (modeM) {
  395. #ifdef USE_RTSP
  396. case eModeRtsp:
  397. {
  398. CURLcode res = CURLE_OK;
  399. // Teardown rtsp session
  400. cString uri = cString::sprintf("%s/", *streamUrlM);
  401. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
  402. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
  403. iptv_curl_easy_perform(handleM);
  404. rtspControlM = "";
  405. isActiveM = false;
  406. // Close the listening socket
  407. CloseSocket();
  408. }
  409. break;
  410. #endif
  411. case eModeHttp:
  412. case eModeHttps:
  413. case eModeFile:
  414. case eModeUnknown:
  415. default:
  416. break;
  417. }
  418. // Cleanup curl stuff
  419. if (headerListM) {
  420. curl_slist_free_all(headerListM);
  421. headerListM = NULL;
  422. }
  423. curl_easy_cleanup(handleM);
  424. handleM = NULL;
  425. }
  426. ClearData();
  427. connectedM = false;
  428. return true;
  429. }
  430. bool cIptvProtocolCurl::Open(void)
  431. {
  432. debug1("%s", __PRETTY_FUNCTION__);
  433. return Connect();
  434. }
  435. bool cIptvProtocolCurl::Close(void)
  436. {
  437. debug1("%s", __PRETTY_FUNCTION__);
  438. Disconnect();
  439. return true;
  440. }
  441. int cIptvProtocolCurl::Read(unsigned char* bufferAddrP, unsigned int bufferLenP)
  442. {
  443. debug16("%s (, %u)", __PRETTY_FUNCTION__, bufferLenP);
  444. int len = 0;
  445. if (ringBufferM) {
  446. // Fill up the buffer
  447. if (handleM) {
  448. switch (modeM) {
  449. #ifdef USE_RTSP
  450. case eModeRtsp:
  451. {
  452. cMutexLock MutexLock(&mutexM);
  453. CURLcode res = CURLE_OK;
  454. // Remember the heart beat
  455. if (timeoutM.TimedOut()) {
  456. debug1("%s KeepAlive", __PRETTY_FUNCTION__);
  457. cString uri = cString::sprintf("%s", *streamUrlM);
  458. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
  459. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
  460. iptv_curl_easy_perform(handleM);
  461. timeoutM.Set(eKeepAliveIntervalMs);
  462. }
  463. // Check whether UDP or TCP mode used
  464. if (streamParamM) {
  465. iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_RECEIVE);
  466. iptv_curl_easy_perform(handleM);
  467. }
  468. else
  469. return cIptvUdpSocket::Read(bufferAddrP, bufferLenP);
  470. }
  471. break;
  472. #endif
  473. case eModeFile:
  474. case eModeHttp:
  475. case eModeHttps:
  476. if (multiM) {
  477. CURLMcode res;
  478. int running_handles;
  479. do {
  480. cMutexLock MutexLock(&mutexM);
  481. res = curl_multi_perform(multiM, &running_handles);
  482. } while (res == CURLM_CALL_MULTI_PERFORM);
  483. // Use 20% threshold before continuing to filling up the buffer.
  484. mutexM.Lock();
  485. if (pausedM && (ringBufferM->Available() < (IPTV_BUFFER_SIZE / 5))) {
  486. debug1("%s Continue free=%d available=%d", __PRETTY_FUNCTION__,
  487. ringBufferM->Free(), ringBufferM->Available());
  488. pausedM = false;
  489. curl_easy_pause(handleM, CURLPAUSE_CONT);
  490. }
  491. mutexM.Unlock();
  492. // Check if end of file
  493. if (running_handles == 0) {
  494. int msgcount;
  495. mutexM.Lock();
  496. CURLMsg *msg = curl_multi_info_read(multiM, &msgcount);
  497. mutexM.Unlock();
  498. if (msg && (msg->msg == CURLMSG_DONE)) {
  499. debug1("%s Done %s (%d)", __PRETTY_FUNCTION__,
  500. curl_easy_strerror(msg->data.result), msg->data.result);
  501. Disconnect();
  502. Connect();
  503. }
  504. }
  505. }
  506. break;
  507. case eModeUnknown:
  508. default:
  509. break;
  510. }
  511. }
  512. // ... and try to empty it
  513. unsigned char *p = GetData(len);
  514. if (p && (len > 0)) {
  515. len = min(len, (int)bufferLenP);
  516. memcpy(bufferAddrP, p, len);
  517. DelData(len);
  518. debug16("%s Get %d bytes", __PRETTY_FUNCTION__, len);
  519. }
  520. }
  521. return len;
  522. }
  523. bool cIptvProtocolCurl::SetSource(const char* locationP, const int parameterP, const int indexP)
  524. {
  525. debug1("%s (%s, %d, %d)", __PRETTY_FUNCTION__, locationP, parameterP, indexP);
  526. if (!isempty(locationP)) {
  527. // Disconnect
  528. Disconnect();
  529. // Update stream URL
  530. streamUrlM = locationP;
  531. cString protocol = ChangeCase(streamUrlM, false).Truncate(5);
  532. if (startswith(*protocol, "rtsp"))
  533. modeM = eModeRtsp;
  534. else if (startswith(*protocol, "https"))
  535. modeM = eModeHttps;
  536. else if (startswith(*protocol, "http"))
  537. modeM = eModeHttp;
  538. else if (startswith(*protocol, "file"))
  539. modeM = eModeFile;
  540. else
  541. modeM = eModeUnknown;
  542. debug1("%s (%s, %d, %d) protocol=%s mode=%d", __PRETTY_FUNCTION__, locationP, parameterP, indexP, *protocol, modeM);
  543. // Update stream parameter - force UDP mode for RTSP
  544. streamParamM = (modeM == eModeRtsp) ? 0 : parameterP;
  545. // Update listen port
  546. streamPortM = IptvConfig.GetProtocolBasePort() + indexP * 2;
  547. // Reconnect
  548. Connect();
  549. }
  550. return true;
  551. }
  552. bool cIptvProtocolCurl::SetPid(int pidP, int typeP, bool onP)
  553. {
  554. debug16("%s (%d, %d, %d)", __PRETTY_FUNCTION__, pidP, typeP, onP);
  555. return true;
  556. }
  557. cString cIptvProtocolCurl::GetInformation(void)
  558. {
  559. debug16("%s", __PRETTY_FUNCTION__);
  560. return cString::sprintf("%s [%d]", *streamUrlM, streamParamM);
  561. }