obs-ffmpeg-srt.h 27 KB

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