obs-ffmpeg-srt.h 25 KB

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