obs-ffmpeg-srt.h 29 KB

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