obs-ffmpeg-srt.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /*
  2. * The following code is a port of FFmpeg/avformat/libsrt.c for obs-studio.
  3. * Port by [email protected].
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #pragma once
  18. #include <obs-module.h>
  19. #include "obs-ffmpeg-url.h"
  20. #include <srt/srt.h>
  21. #include <libavformat/avformat.h>
  22. #define POLLING_TIME 100 /// Time in milliseconds between interrupt check
  23. /* This is for MPEG-TS (7 TS packets) */
  24. #ifndef SRT_LIVE_DEFAULT_PAYLOAD_SIZE
  25. #define SRT_LIVE_DEFAULT_PAYLOAD_SIZE 1316
  26. #endif
  27. enum SRTMode {
  28. SRT_MODE_CALLER = 0,
  29. SRT_MODE_LISTENER = 1,
  30. SRT_MODE_RENDEZVOUS = 2
  31. };
  32. typedef struct SRTContext {
  33. SRTSOCKET fd;
  34. int eid;
  35. int64_t rw_timeout;
  36. int64_t listen_timeout;
  37. int recv_buffer_size;
  38. int send_buffer_size;
  39. int64_t maxbw;
  40. int pbkeylen;
  41. char *passphrase;
  42. #if SRT_VERSION_VALUE >= 0x010302
  43. int enforced_encryption;
  44. int kmrefreshrate;
  45. int kmpreannounce;
  46. int64_t snddropdelay;
  47. #endif
  48. int mss;
  49. int ffs;
  50. int ipttl;
  51. int iptos;
  52. int64_t inputbw;
  53. int oheadbw;
  54. int64_t latency;
  55. int tlpktdrop;
  56. int nakreport;
  57. int64_t connect_timeout;
  58. int payload_size;
  59. int64_t rcvlatency;
  60. int64_t peerlatency;
  61. enum SRTMode mode;
  62. int sndbuf;
  63. int rcvbuf;
  64. int lossmaxttl;
  65. int minversion;
  66. char *streamid;
  67. char *smoother;
  68. int messageapi;
  69. SRT_TRANSTYPE transtype;
  70. int linger;
  71. int tsbpd;
  72. double time; // time in s in order to post logs at definite intervals
  73. } SRTContext;
  74. static int libsrt_neterrno(URLContext *h)
  75. {
  76. int os_errno;
  77. int err = srt_getlasterror(&os_errno);
  78. blog(LOG_ERROR, "[obs-ffmpeg mpegts muxer / libsrt] : %s\n",
  79. srt_getlasterror_str());
  80. if (err == SRT_EASYNCRCV || err == SRT_EASYNCSND)
  81. return AVERROR(EAGAIN);
  82. return os_errno ? AVERROR(os_errno) : AVERROR_UNKNOWN;
  83. }
  84. static int libsrt_getsockopt(URLContext *h, SRTSOCKET fd, SRT_SOCKOPT optname,
  85. const char *optnamestr, void *optval, int *optlen)
  86. {
  87. if (srt_getsockopt(fd, 0, optname, optval, optlen) < 0) {
  88. blog(LOG_INFO,
  89. "[obs-ffmpeg mpegts muxer / libsrt] : failed to get option %s on socket: %s\n",
  90. optnamestr, srt_getlasterror_str());
  91. return AVERROR(EIO);
  92. }
  93. return 0;
  94. }
  95. static int libsrt_socket_nonblock(SRTSOCKET socket, int enable)
  96. {
  97. int ret, blocking = enable ? 0 : 1;
  98. /* Setting SRTO_{SND,RCV}SYN options to 1 enable blocking mode, setting them to 0 enable non-blocking mode. */
  99. ret = srt_setsockopt(socket, 0, SRTO_SNDSYN, &blocking,
  100. sizeof(blocking));
  101. if (ret < 0)
  102. return ret;
  103. return srt_setsockopt(socket, 0, SRTO_RCVSYN, &blocking,
  104. sizeof(blocking));
  105. }
  106. static int libsrt_epoll_create(URLContext *h, SRTSOCKET fd, int write)
  107. {
  108. int modes = SRT_EPOLL_ERR | (write ? SRT_EPOLL_OUT : SRT_EPOLL_IN);
  109. int eid = srt_epoll_create();
  110. if (eid < 0)
  111. return libsrt_neterrno(h);
  112. if (srt_epoll_add_usock(eid, fd, &modes) < 0) {
  113. srt_epoll_release(eid);
  114. return libsrt_neterrno(h);
  115. }
  116. return eid;
  117. }
  118. static int libsrt_network_wait_fd(URLContext *h, int eid, int write)
  119. {
  120. int ret, len = 1, errlen = 1;
  121. SRTSOCKET ready[1];
  122. SRTSOCKET error[1];
  123. if (write) {
  124. ret = srt_epoll_wait(eid, error, &errlen, ready, &len,
  125. POLLING_TIME, 0, 0, 0, 0);
  126. } else {
  127. ret = srt_epoll_wait(eid, ready, &len, error, &errlen,
  128. POLLING_TIME, 0, 0, 0, 0);
  129. }
  130. if (ret < 0) {
  131. if (srt_getlasterror(NULL) == SRT_ETIMEOUT)
  132. ret = AVERROR(EAGAIN);
  133. else
  134. ret = libsrt_neterrno(h);
  135. } else {
  136. ret = errlen ? AVERROR(EIO) : 0;
  137. }
  138. return ret;
  139. }
  140. int check_interrupt(AVIOInterruptCB *cb)
  141. {
  142. if (cb && cb->callback)
  143. return cb->callback(cb->opaque);
  144. return 0;
  145. }
  146. static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int write,
  147. int64_t timeout,
  148. AVIOInterruptCB *int_cb)
  149. {
  150. int ret;
  151. int64_t wait_start = 0;
  152. while (1) {
  153. if (check_interrupt(int_cb))
  154. return AVERROR_EXIT;
  155. ret = libsrt_network_wait_fd(h, eid, write);
  156. if (ret != AVERROR(EAGAIN))
  157. return ret;
  158. if (timeout > 0) {
  159. if (!wait_start)
  160. wait_start = av_gettime_relative();
  161. else if (av_gettime_relative() - wait_start > timeout)
  162. return AVERROR(ETIMEDOUT);
  163. }
  164. }
  165. }
  166. static int libsrt_listen(int eid, SRTSOCKET fd, const struct sockaddr *addr,
  167. socklen_t addrlen, URLContext *h, int64_t timeout)
  168. {
  169. int ret;
  170. int reuse = 1;
  171. /* Max streamid length plus an extra space for the terminating null character */
  172. char streamid[513];
  173. int streamid_len = sizeof(streamid);
  174. if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse,
  175. sizeof(reuse))) {
  176. blog(LOG_WARNING,
  177. "[obs-ffmpeg mpegts muxer / libsrt] : setsockopt(SRTO_REUSEADDR) failed\n");
  178. }
  179. if (srt_bind(fd, addr, addrlen))
  180. return libsrt_neterrno(h);
  181. if (srt_listen(fd, 1))
  182. return libsrt_neterrno(h);
  183. ret = libsrt_network_wait_fd_timeout(h, eid, 1, timeout,
  184. &h->interrupt_callback);
  185. if (ret < 0)
  186. return ret;
  187. ret = srt_accept(fd, NULL, NULL);
  188. if (ret < 0)
  189. return libsrt_neterrno(h);
  190. if (libsrt_socket_nonblock(ret, 1) < 0)
  191. blog(LOG_DEBUG,
  192. "[obs-ffmpeg mpegts muxer / libsrt] : libsrt_socket_nonblock failed\n");
  193. if (!libsrt_getsockopt(h, ret, SRTO_STREAMID, "SRTO_STREAMID", streamid,
  194. &streamid_len))
  195. /* Note: returned streamid_len doesn't count the terminating null character */
  196. blog(LOG_INFO,
  197. "[obs-ffmpeg mpegts muxer / libsrt] : accept streamid [%s], length %d\n",
  198. streamid, streamid_len);
  199. return ret;
  200. }
  201. static int libsrt_listen_connect(int eid, SRTSOCKET fd,
  202. const struct sockaddr *addr, socklen_t addrlen,
  203. int64_t timeout, URLContext *h,
  204. int will_try_next)
  205. {
  206. int ret;
  207. if (srt_connect(fd, addr, addrlen) < 0)
  208. return libsrt_neterrno(h);
  209. ret = libsrt_network_wait_fd_timeout(h, eid, 1, timeout,
  210. &h->interrupt_callback);
  211. if (ret < 0) {
  212. if (will_try_next) {
  213. blog(LOG_WARNING,
  214. "[obs-ffmpeg mpegts muxer / libsrt] : Connection to %s failed (%s), trying next address\n",
  215. h->url, av_err2str(ret));
  216. } else {
  217. blog(LOG_ERROR,
  218. "[obs-ffmpeg mpegts muxer / libsrt] : Connection to %s failed: %s\n",
  219. h->url, av_err2str(ret));
  220. }
  221. }
  222. return ret;
  223. }
  224. static int libsrt_setsockopt(URLContext *h, SRTSOCKET fd, SRT_SOCKOPT optname,
  225. const char *optnamestr, const void *optval,
  226. int optlen)
  227. {
  228. if (srt_setsockopt(fd, 0, optname, optval, optlen) < 0) {
  229. blog(LOG_ERROR,
  230. "[obs-ffmpeg mpegts muxer / libsrt] : failed to set option %s on socket: %s\n",
  231. optnamestr, srt_getlasterror_str());
  232. return AVERROR(EIO);
  233. }
  234. return 0;
  235. }
  236. /* - The "POST" options can be altered any time on a connected socket.
  237. They MAY have also some meaning when set prior to connecting; such
  238. option is SRTO_RCVSYN, which makes connect/accept call asynchronous.
  239. Because of that this option is treated special way in this app. */
  240. static int libsrt_set_options_post(URLContext *h, SRTSOCKET fd)
  241. {
  242. SRTContext *s = (SRTContext *)h->priv_data;
  243. if ((s->inputbw >= 0 &&
  244. libsrt_setsockopt(h, fd, SRTO_INPUTBW, "SRTO_INPUTBW", &s->inputbw,
  245. sizeof(s->inputbw)) < 0) ||
  246. (s->oheadbw >= 0 &&
  247. libsrt_setsockopt(h, fd, SRTO_OHEADBW, "SRTO_OHEADBW", &s->oheadbw,
  248. sizeof(s->oheadbw)) < 0)) {
  249. return AVERROR(EIO);
  250. }
  251. return 0;
  252. }
  253. /* - The "PRE" options must be set prior to connecting and can't be altered
  254. on a connected socket, however if set on a listening socket, they are
  255. derived by accept-ed socket. */
  256. static int libsrt_set_options_pre(URLContext *h, SRTSOCKET fd)
  257. {
  258. SRTContext *s = (SRTContext *)h->priv_data;
  259. int yes = 1;
  260. int latency = (int)(s->latency / 1000);
  261. int rcvlatency = (int)(s->rcvlatency / 1000);
  262. int peerlatency = (int)(s->peerlatency / 1000);
  263. #if SRT_VERSION_VALUE >= 0x010302
  264. int snddropdelay = s->snddropdelay > 0 ? (int)(s->snddropdelay / 1000)
  265. : (int)(s->snddropdelay);
  266. #endif
  267. int connect_timeout = (int)(s->connect_timeout);
  268. if ((s->mode == SRT_MODE_RENDEZVOUS &&
  269. libsrt_setsockopt(h, fd, SRTO_RENDEZVOUS, "SRTO_RENDEZVOUS", &yes,
  270. sizeof(yes)) < 0) ||
  271. (s->transtype != SRTT_INVALID &&
  272. libsrt_setsockopt(h, fd, SRTO_TRANSTYPE, "SRTO_TRANSTYPE",
  273. &s->transtype, sizeof(s->transtype)) < 0) ||
  274. (s->maxbw >= 0 &&
  275. libsrt_setsockopt(h, fd, SRTO_MAXBW, "SRTO_MAXBW", &s->maxbw,
  276. sizeof(s->maxbw)) < 0) ||
  277. (s->pbkeylen >= 0 &&
  278. libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN",
  279. &s->pbkeylen, sizeof(s->pbkeylen)) < 0) ||
  280. (s->passphrase &&
  281. libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE",
  282. s->passphrase,
  283. (int)strlen(s->passphrase)) < 0) ||
  284. #if SRT_VERSION_VALUE >= 0x010302
  285. #if SRT_VERSION_VALUE >= 0x010401
  286. (s->enforced_encryption >= 0 &&
  287. libsrt_setsockopt(h, fd, SRTO_ENFORCEDENCRYPTION,
  288. "SRTO_ENFORCEDENCRYPTION",
  289. &s->enforced_encryption,
  290. sizeof(s->enforced_encryption)) < 0) ||
  291. #else
  292. /* SRTO_STRICTENC == SRTO_ENFORCEDENCRYPTION (53), but for compatibility, we used SRTO_STRICTENC */
  293. (s->enforced_encryption >= 0 &&
  294. libsrt_setsockopt(h, fd, SRTO_STRICTENC, "SRTO_STRICTENC",
  295. &s->enforced_encryption,
  296. sizeof(s->enforced_encryption)) < 0) ||
  297. #endif
  298. (s->kmrefreshrate >= 0 &&
  299. libsrt_setsockopt(h, fd, SRTO_KMREFRESHRATE, "SRTO_KMREFRESHRATE",
  300. &s->kmrefreshrate,
  301. sizeof(s->kmrefreshrate)) < 0) ||
  302. (s->kmpreannounce >= 0 &&
  303. libsrt_setsockopt(h, fd, SRTO_KMPREANNOUNCE, "SRTO_KMPREANNOUNCE",
  304. &s->kmpreannounce,
  305. sizeof(s->kmpreannounce)) < 0) ||
  306. (s->snddropdelay >= -1 &&
  307. libsrt_setsockopt(h, fd, SRTO_SNDDROPDELAY, "SRTO_SNDDROPDELAY",
  308. &snddropdelay, sizeof(snddropdelay)) < 0) ||
  309. #endif
  310. (s->mss >= 0 && libsrt_setsockopt(h, fd, SRTO_MSS, "SRTO_MSS",
  311. &s->mss, sizeof(s->mss)) < 0) ||
  312. (s->ffs >= 0 && libsrt_setsockopt(h, fd, SRTO_FC, "SRTO_FC",
  313. &s->ffs, sizeof(s->ffs)) < 0) ||
  314. (s->ipttl >= 0 &&
  315. libsrt_setsockopt(h, fd, SRTO_IPTTL, "SRTO_IPTTL", &s->ipttl,
  316. sizeof(s->ipttl)) < 0) ||
  317. (s->iptos >= 0 &&
  318. libsrt_setsockopt(h, fd, SRTO_IPTOS, "SRTO_IPTOS", &s->iptos,
  319. sizeof(s->iptos)) < 0) ||
  320. (s->latency >= 0 &&
  321. libsrt_setsockopt(h, fd, SRTO_LATENCY, "SRTO_LATENCY", &latency,
  322. sizeof(latency)) < 0) ||
  323. (s->rcvlatency >= 0 &&
  324. libsrt_setsockopt(h, fd, SRTO_RCVLATENCY, "SRTO_RCVLATENCY",
  325. &rcvlatency, sizeof(rcvlatency)) < 0) ||
  326. (s->peerlatency >= 0 &&
  327. libsrt_setsockopt(h, fd, SRTO_PEERLATENCY, "SRTO_PEERLATENCY",
  328. &peerlatency, sizeof(peerlatency)) < 0) ||
  329. (s->tlpktdrop >= 0 &&
  330. libsrt_setsockopt(h, fd, SRTO_TLPKTDROP, "SRTO_TLPKTDROP",
  331. &s->tlpktdrop, sizeof(s->tlpktdrop)) < 0) ||
  332. (s->nakreport >= 0 &&
  333. libsrt_setsockopt(h, fd, SRTO_NAKREPORT, "SRTO_NAKREPORT",
  334. &s->nakreport, sizeof(s->nakreport)) < 0) ||
  335. (connect_timeout >= 0 &&
  336. libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO",
  337. &connect_timeout,
  338. sizeof(connect_timeout)) < 0) ||
  339. (s->sndbuf >= 0 &&
  340. libsrt_setsockopt(h, fd, SRTO_SNDBUF, "SRTO_SNDBUF", &s->sndbuf,
  341. sizeof(s->sndbuf)) < 0) ||
  342. (s->rcvbuf >= 0 &&
  343. libsrt_setsockopt(h, fd, SRTO_RCVBUF, "SRTO_RCVBUF", &s->rcvbuf,
  344. sizeof(s->rcvbuf)) < 0) ||
  345. (s->lossmaxttl >= 0 &&
  346. libsrt_setsockopt(h, fd, SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL",
  347. &s->lossmaxttl, sizeof(s->lossmaxttl)) < 0) ||
  348. (s->minversion >= 0 &&
  349. libsrt_setsockopt(h, fd, SRTO_MINVERSION, "SRTO_MINVERSION",
  350. &s->minversion, sizeof(s->minversion)) < 0) ||
  351. (s->streamid &&
  352. libsrt_setsockopt(h, fd, SRTO_STREAMID, "SRTO_STREAMID",
  353. s->streamid, (int)strlen(s->streamid)) < 0) ||
  354. #if SRT_VERSION_VALUE >= 0x010401
  355. (s->smoother &&
  356. libsrt_setsockopt(h, fd, SRTO_CONGESTION, "SRTO_CONGESTION",
  357. s->smoother, (int)strlen(s->smoother)) < 0) ||
  358. #else
  359. (s->smoother &&
  360. libsrt_setsockopt(h, fd, SRTO_SMOOTHER, "SRTO_SMOOTHER",
  361. s->smoother, (int)strlen(s->smoother)) < 0) ||
  362. #endif
  363. (s->messageapi >= 0 &&
  364. libsrt_setsockopt(h, fd, SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI",
  365. &s->messageapi, sizeof(s->messageapi)) < 0) ||
  366. (s->payload_size >= 0 &&
  367. libsrt_setsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE",
  368. &s->payload_size,
  369. sizeof(s->payload_size)) < 0) ||
  370. (/*(h->flags & AVIO_FLAG_WRITE) &&*/
  371. libsrt_setsockopt(h, fd, SRTO_SENDER, "SRTO_SENDER", &yes,
  372. sizeof(yes)) < 0) ||
  373. (s->tsbpd >= 0 &&
  374. libsrt_setsockopt(h, fd, SRTO_TSBPDMODE, "SRTO_TSBPDMODE",
  375. &s->tsbpd, sizeof(s->tsbpd)) < 0)) {
  376. return AVERROR(EIO);
  377. }
  378. if (s->linger >= 0) {
  379. struct linger lin;
  380. lin.l_linger = s->linger;
  381. lin.l_onoff = lin.l_linger > 0 ? 1 : 0;
  382. if (libsrt_setsockopt(h, fd, SRTO_LINGER, "SRTO_LINGER", &lin,
  383. sizeof(lin)) < 0)
  384. return AVERROR(EIO);
  385. }
  386. return 0;
  387. }
  388. static int libsrt_setup(URLContext *h, const char *uri)
  389. {
  390. struct addrinfo hints = {0}, *ai, *cur_ai;
  391. int port;
  392. SRTSOCKET fd;
  393. SRTContext *s = (SRTContext *)h->priv_data;
  394. const char *p;
  395. char buf[1024];
  396. int ret;
  397. char hostname[1024], proto[1024], path[1024];
  398. char portstr[10];
  399. int64_t open_timeout = 0;
  400. int eid, write_eid;
  401. av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
  402. &port, path, sizeof(path), uri);
  403. if (strcmp(proto, "srt")) // should not happen !
  404. return AVERROR(EINVAL);
  405. if (port <= 0 || port >= 65536) {
  406. blog(LOG_ERROR,
  407. "[obs-ffmpeg mpegts muxer / libsrt] : Port missing in uri\n");
  408. return OBS_OUTPUT_CONNECT_FAILED;
  409. }
  410. p = strchr(uri, '?');
  411. if (p) {
  412. if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
  413. s->rw_timeout = strtoll(buf, NULL, 10);
  414. }
  415. if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
  416. s->listen_timeout = strtoll(buf, NULL, 10);
  417. }
  418. }
  419. if (s->rw_timeout >= 0) {
  420. open_timeout = h->rw_timeout = s->rw_timeout;
  421. }
  422. hints.ai_family = AF_UNSPEC;
  423. hints.ai_socktype = SOCK_DGRAM;
  424. snprintf(portstr, sizeof(portstr), "%d", port);
  425. if (s->mode == SRT_MODE_LISTENER)
  426. hints.ai_flags |= AI_PASSIVE;
  427. ret = getaddrinfo(hostname[0] ? hostname : NULL, portstr, &hints, &ai);
  428. if (ret) {
  429. blog(LOG_ERROR,
  430. "[obs-ffmpeg mpegts muxer / libsrt] : Failed to resolve hostname %s: %s\n",
  431. hostname, gai_strerror(ret));
  432. return OBS_OUTPUT_CONNECT_FAILED;
  433. }
  434. cur_ai = ai;
  435. restart:
  436. fd = srt_create_socket();
  437. if (fd < 0) {
  438. ret = libsrt_neterrno(h);
  439. goto fail;
  440. }
  441. if ((ret = libsrt_set_options_pre(h, fd)) < 0) {
  442. goto fail;
  443. }
  444. /* Set the socket's send or receive buffer sizes, if specified.
  445. If unspecified or setting fails, system default is used. */
  446. if (s->recv_buffer_size > 0) {
  447. srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_RCVBUF,
  448. &s->recv_buffer_size,
  449. sizeof(s->recv_buffer_size));
  450. }
  451. if (s->send_buffer_size > 0) {
  452. srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_SNDBUF,
  453. &s->send_buffer_size,
  454. sizeof(s->send_buffer_size));
  455. }
  456. if (libsrt_socket_nonblock(fd, 1) < 0)
  457. blog(LOG_DEBUG,
  458. "[obs-ffmpeg mpegts muxer / libsrt] : libsrt_socket_nonblock failed\n");
  459. ret = write_eid = libsrt_epoll_create(h, fd, 1);
  460. if (ret < 0)
  461. goto fail1;
  462. if (s->mode == SRT_MODE_LISTENER) {
  463. // multi-client
  464. ret = libsrt_listen(write_eid, fd, cur_ai->ai_addr,
  465. (socklen_t)cur_ai->ai_addrlen, h,
  466. s->listen_timeout);
  467. srt_epoll_release(write_eid);
  468. if (ret < 0)
  469. goto fail1;
  470. srt_close(fd);
  471. fd = ret;
  472. } else {
  473. if (s->mode == SRT_MODE_RENDEZVOUS) {
  474. if (srt_bind(fd, cur_ai->ai_addr,
  475. (int)(cur_ai->ai_addrlen))) {
  476. ret = libsrt_neterrno(h);
  477. srt_epoll_release(write_eid);
  478. goto fail1;
  479. }
  480. }
  481. ret = libsrt_listen_connect(write_eid, fd, cur_ai->ai_addr,
  482. (socklen_t)(cur_ai->ai_addrlen),
  483. open_timeout, h, !!cur_ai->ai_next);
  484. srt_epoll_release(write_eid);
  485. if (ret < 0) {
  486. if (ret == AVERROR_EXIT)
  487. goto fail1;
  488. else
  489. goto fail;
  490. }
  491. }
  492. if ((ret = libsrt_set_options_post(h, fd)) < 0) {
  493. goto fail;
  494. }
  495. int packet_size = 0;
  496. int optlen = sizeof(packet_size);
  497. ret = libsrt_getsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE",
  498. &packet_size, &optlen);
  499. if (ret < 0)
  500. goto fail1;
  501. if (packet_size > 0)
  502. h->max_packet_size = packet_size;
  503. ret = eid = libsrt_epoll_create(h, fd, 1 /*flags & AVIO_FLAG_WRITE*/);
  504. if (eid < 0)
  505. goto fail1;
  506. s->fd = fd;
  507. s->eid = eid;
  508. freeaddrinfo(ai);
  509. return 0;
  510. fail:
  511. if (cur_ai->ai_next) {
  512. /* Retry with the next sockaddr */
  513. cur_ai = cur_ai->ai_next;
  514. if (fd >= 0)
  515. srt_close(fd);
  516. ret = 0;
  517. goto restart;
  518. }
  519. fail1:
  520. if (fd >= 0)
  521. srt_close(fd);
  522. freeaddrinfo(ai);
  523. return ret;
  524. }
  525. static void libsrt_set_defaults(SRTContext *s)
  526. {
  527. s->rw_timeout = -1;
  528. s->listen_timeout = -1;
  529. s->send_buffer_size = -1;
  530. s->recv_buffer_size = -1;
  531. s->payload_size = SRT_LIVE_DEFAULT_PAYLOAD_SIZE;
  532. s->maxbw = -1;
  533. s->pbkeylen = -1;
  534. s->passphrase = NULL;
  535. s->mss = -1;
  536. s->ffs = -1;
  537. s->ipttl = -1;
  538. s->iptos = -1;
  539. s->inputbw = -1;
  540. s->oheadbw = -1;
  541. s->latency = -1;
  542. s->rcvlatency = -1;
  543. s->peerlatency = -1;
  544. s->tlpktdrop = -1;
  545. s->nakreport = -1;
  546. s->connect_timeout = -1;
  547. s->mode = SRT_MODE_CALLER;
  548. s->sndbuf = -1;
  549. s->rcvbuf = -1;
  550. s->lossmaxttl = -1;
  551. s->minversion = -1;
  552. s->streamid = NULL;
  553. s->smoother = NULL;
  554. s->messageapi = -1;
  555. s->transtype = SRTT_LIVE;
  556. s->linger = -1;
  557. s->tsbpd = -1;
  558. }
  559. static int libsrt_open(URLContext *h, const char *uri)
  560. {
  561. SRTContext *s = (SRTContext *)h->priv_data;
  562. const char *p;
  563. char buf[1024];
  564. int ret = 0;
  565. if (srt_startup() < 0) {
  566. blog(LOG_ERROR,
  567. "[obs-ffmpeg mpegts muxer / libsrt] : libsrt failed to load.\n");
  568. return OBS_OUTPUT_CONNECT_FAILED;
  569. } else {
  570. blog(LOG_INFO,
  571. "[obs-ffmpeg mpegts muxer / libsrt] : libsrt v.%s loaded.\n",
  572. SRT_VERSION_STRING);
  573. }
  574. libsrt_set_defaults(s);
  575. /* SRT options (srt/srt.h) */
  576. p = strchr(uri, '?');
  577. if (p) {
  578. if (av_find_info_tag(buf, sizeof(buf), "maxbw", p)) {
  579. s->maxbw = strtoll(buf, NULL, 10);
  580. }
  581. if (av_find_info_tag(buf, sizeof(buf), "pbkeylen", p)) {
  582. s->pbkeylen = strtol(buf, NULL, 10);
  583. }
  584. if (av_find_info_tag(buf, sizeof(buf), "passphrase", p)) {
  585. av_freep(&s->passphrase);
  586. s->passphrase = av_strndup(buf, strlen(buf));
  587. }
  588. #if SRT_VERSION_VALUE >= 0x010302
  589. if (av_find_info_tag(buf, sizeof(buf), "enforced_encryption",
  590. p)) {
  591. s->enforced_encryption = strtol(buf, NULL, 10);
  592. }
  593. if (av_find_info_tag(buf, sizeof(buf), "kmrefreshrate", p)) {
  594. s->kmrefreshrate = strtol(buf, NULL, 10);
  595. }
  596. if (av_find_info_tag(buf, sizeof(buf), "kmpreannounce", p)) {
  597. s->kmpreannounce = strtol(buf, NULL, 10);
  598. }
  599. if (av_find_info_tag(buf, sizeof(buf), "snddropdelay", p)) {
  600. s->snddropdelay = strtoll(buf, NULL, 10);
  601. }
  602. #endif
  603. if (av_find_info_tag(buf, sizeof(buf), "mss", p)) {
  604. s->mss = strtol(buf, NULL, 10);
  605. }
  606. if (av_find_info_tag(buf, sizeof(buf), "ffs", p)) {
  607. s->ffs = strtol(buf, NULL, 10);
  608. }
  609. if (av_find_info_tag(buf, sizeof(buf), "ipttl", p)) {
  610. s->ipttl = strtol(buf, NULL, 10);
  611. }
  612. if (av_find_info_tag(buf, sizeof(buf), "iptos", p)) {
  613. s->iptos = strtol(buf, NULL, 10);
  614. }
  615. if (av_find_info_tag(buf, sizeof(buf), "inputbw", p)) {
  616. s->inputbw = strtoll(buf, NULL, 10);
  617. }
  618. if (av_find_info_tag(buf, sizeof(buf), "oheadbw", p)) {
  619. s->oheadbw = strtol(buf, NULL, 10);
  620. }
  621. if (av_find_info_tag(buf, sizeof(buf), "latency", p)) {
  622. s->latency = strtoll(buf, NULL, 10);
  623. }
  624. if (av_find_info_tag(buf, sizeof(buf), "tsbpddelay", p)) {
  625. s->latency = strtoll(buf, NULL, 10);
  626. }
  627. if (av_find_info_tag(buf, sizeof(buf), "rcvlatency", p)) {
  628. s->rcvlatency = strtoll(buf, NULL, 10);
  629. }
  630. if (av_find_info_tag(buf, sizeof(buf), "peerlatency", p)) {
  631. s->peerlatency = strtoll(buf, NULL, 10);
  632. }
  633. if (av_find_info_tag(buf, sizeof(buf), "tlpktdrop", p)) {
  634. s->tlpktdrop = strtol(buf, NULL, 10);
  635. }
  636. if (av_find_info_tag(buf, sizeof(buf), "nakreport", p)) {
  637. s->nakreport = strtol(buf, NULL, 10);
  638. }
  639. if (av_find_info_tag(buf, sizeof(buf), "connect_timeout", p)) {
  640. s->connect_timeout = strtoll(buf, NULL, 10);
  641. }
  642. if (av_find_info_tag(buf, sizeof(buf), "payload_size", p) ||
  643. av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
  644. s->payload_size = strtol(buf, NULL, 10);
  645. }
  646. if (av_find_info_tag(buf, sizeof(buf), "mode", p)) {
  647. if (!strcmp(buf, "caller")) {
  648. s->mode = SRT_MODE_CALLER;
  649. } else if (!strcmp(buf, "listener")) {
  650. s->mode = SRT_MODE_LISTENER;
  651. } else if (!strcmp(buf, "rendezvous")) {
  652. s->mode = SRT_MODE_RENDEZVOUS;
  653. } else {
  654. ret = AVERROR(EINVAL);
  655. goto err;
  656. }
  657. }
  658. if (av_find_info_tag(buf, sizeof(buf), "sndbuf", p)) {
  659. s->sndbuf = strtol(buf, NULL, 10);
  660. }
  661. if (av_find_info_tag(buf, sizeof(buf), "rcvbuf", p)) {
  662. s->rcvbuf = strtol(buf, NULL, 10);
  663. }
  664. if (av_find_info_tag(buf, sizeof(buf), "lossmaxttl", p)) {
  665. s->lossmaxttl = strtol(buf, NULL, 10);
  666. }
  667. if (av_find_info_tag(buf, sizeof(buf), "minversion", p)) {
  668. s->minversion = strtol(buf, NULL, 0);
  669. }
  670. if (av_find_info_tag(buf, sizeof(buf), "streamid", p)) {
  671. av_freep(&s->streamid);
  672. s->streamid = av_strdup(buf);
  673. if (!s->streamid) {
  674. ret = AVERROR(ENOMEM);
  675. goto err;
  676. }
  677. }
  678. if (av_find_info_tag(buf, sizeof(buf), "smoother", p)) {
  679. av_freep(&s->smoother);
  680. s->smoother = av_strdup(buf);
  681. if (!s->smoother) {
  682. ret = AVERROR(ENOMEM);
  683. goto err;
  684. }
  685. }
  686. if (av_find_info_tag(buf, sizeof(buf), "messageapi", p)) {
  687. s->messageapi = strtol(buf, NULL, 10);
  688. }
  689. if (av_find_info_tag(buf, sizeof(buf), "transtype", p)) {
  690. if (!strcmp(buf, "live")) {
  691. s->transtype = SRTT_LIVE;
  692. } else if (!strcmp(buf, "file")) {
  693. s->transtype = SRTT_FILE;
  694. } else {
  695. ret = AVERROR(EINVAL);
  696. goto err;
  697. }
  698. }
  699. if (av_find_info_tag(buf, sizeof(buf), "linger", p)) {
  700. s->linger = strtol(buf, NULL, 10);
  701. }
  702. }
  703. ret = libsrt_setup(h, uri);
  704. if (ret < 0)
  705. goto err;
  706. #ifdef _WIN32
  707. struct timeb timebuffer;
  708. ftime(&timebuffer);
  709. s->time = (double)timebuffer.time + 0.001 * (double)timebuffer.millitm;
  710. #else
  711. struct timespec timesp;
  712. clock_gettime(CLOCK_REALTIME, &timesp);
  713. s->time = (double)timesp.tv_sec + 0.000000001 * (double)timesp.tv_nsec;
  714. #endif
  715. return 0;
  716. err:
  717. av_freep(&s->smoother);
  718. av_freep(&s->streamid);
  719. srt_cleanup();
  720. return ret;
  721. }
  722. static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
  723. {
  724. SRTContext *s = (SRTContext *)h->priv_data;
  725. int ret;
  726. SRT_TRACEBSTATS perf;
  727. ret = libsrt_network_wait_fd_timeout(h, s->eid, 1, h->rw_timeout,
  728. &h->interrupt_callback);
  729. if (ret)
  730. return ret;
  731. ret = srt_send(s->fd, (char *)buf, size);
  732. if (ret < 0) {
  733. ret = libsrt_neterrno(h);
  734. } else {
  735. /* log every 60 seconds the rtt and link bandwidth
  736. * rtt: round-trip time
  737. * link bandwidth: bandwidth from ingest to egress
  738. */
  739. #ifdef _WIN32
  740. struct timeb timebuffer;
  741. ftime(&timebuffer);
  742. double time = (double)timebuffer.time +
  743. 0.001 * (double)timebuffer.millitm;
  744. #else
  745. struct timespec timesp;
  746. clock_gettime(CLOCK_REALTIME, &timesp);
  747. double time = (double)timesp.tv_sec +
  748. 0.000000001 * (double)timesp.tv_nsec;
  749. #endif
  750. if (time > (s->time + 60.0)) {
  751. srt_bistats(s->fd, &perf, 0, 1);
  752. blog(LOG_INFO,
  753. "[obs-ffmpeg mpegts muxer / libsrt] : rtt [%.2f ms], link bandwidth [%.1f Mbps]\n",
  754. perf.msRTT, perf.mbpsBandwidth);
  755. s->time = time;
  756. }
  757. }
  758. return ret;
  759. }
  760. static int libsrt_close(URLContext *h)
  761. {
  762. SRTContext *s = (SRTContext *)h->priv_data;
  763. /* Log stream stats. */
  764. SRT_TRACEBSTATS perf;
  765. srt_bstats(s->fd, &perf, 1);
  766. blog(LOG_INFO,
  767. "[obs-ffmpeg mpegts muxer / libsrt] : Stream stats\n\n"
  768. "time elapsed [%.1f sec]\nmean speed [%.1f Mbp]\n"
  769. "total bytes sent [%.1f MB]\nbytes retransmitted [%.1f %%]\n"
  770. "bytes dropped [%.1f %%]\n\n",
  771. (double)perf.msTimeStamp / 1000.0, perf.mbpsSendRate,
  772. (double)perf.byteSentTotal / 1000000.0,
  773. perf.byteSentTotal
  774. ? perf.byteRetransTotal / perf.byteSentTotal * 100.0
  775. : 0,
  776. perf.byteSentTotal
  777. ? perf.byteSndDropTotal / perf.byteSentTotal * 100.0
  778. : 0);
  779. srt_epoll_release(s->eid);
  780. int err = srt_close(s->fd);
  781. if (err < 0) {
  782. blog(LOG_ERROR, "[obs-ffmpeg mpegts muxer / libsrt] : %s\n",
  783. srt_getlasterror_str());
  784. return -1;
  785. }
  786. srt_cleanup();
  787. blog(LOG_INFO, "[obs-ffmpeg mpegts muxer / libsrt] : closing srt");
  788. return 0;
  789. }