{"id":13906323,"url":"https://github.com/datarhei/gosrt","last_synced_at":"2025-05-15T07:06:11.327Z","repository":{"id":44152267,"uuid":"308081952","full_name":"datarhei/gosrt","owner":"datarhei","description":"Implementation of the SRT protocol in pure Go","archived":false,"fork":false,"pushed_at":"2025-05-06T05:13:56.000Z","size":1444,"stargazers_count":145,"open_issues_count":3,"forks_count":24,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-05-06T06:25:26.474Z","etag":null,"topics":["broadcasting","datarhei","foss-gmbh","go","low-latency","multimedia","restreamer","srt","transport"],"latest_commit_sha":null,"homepage":"https://datarhei.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/datarhei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-10-28T16:47:28.000Z","updated_at":"2025-05-06T05:12:51.000Z","dependencies_parsed_at":"2023-11-28T11:35:27.183Z","dependency_job_id":"75af02d4-a778-4d3b-b874-980816f82d5a","html_url":"https://github.com/datarhei/gosrt","commit_stats":{"total_commits":235,"total_committers":10,"mean_commits":23.5,"dds":0.5574468085106383,"last_synced_commit":"dea401da6935e02e21fee36613f126ae1c9aa3da"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarhei%2Fgosrt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarhei%2Fgosrt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarhei%2Fgosrt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarhei%2Fgosrt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datarhei","download_url":"https://codeload.github.com/datarhei/gosrt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292042,"owners_count":22046426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["broadcasting","datarhei","foss-gmbh","go","low-latency","multimedia","restreamer","srt","transport"],"created_at":"2024-08-06T23:01:33.536Z","updated_at":"2025-05-15T07:06:06.318Z","avatar_url":"https://github.com/datarhei.png","language":"Go","funding_links":[],"categories":["HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"# GoSRT\n\nImplementation of the SRT protocol in pure Go with minimal dependencies.\n\n\u003cp align=\"left\"\u003e\n  \u003ca href=\"http://srtalliance.org/\"\u003e\n    \u003cimg alt=\"SRT\" src=\"https://github.com/datarhei/misc/blob/main/img/gosrt.png?raw=true\" width=\"600\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![Tests](https://github.com/datarhei/gosrt/actions/workflows/go-tests.yml/badge.svg)\n[![codecov](https://codecov.io/gh/datarhei/gosrt/branch/main/graph/badge.svg?token=90YMPZRAFK)](https://codecov.io/gh/datarhei/gosrt)\n[![Go Report Card](https://goreportcard.com/badge/github.com/datarhei/gosrt)](https://goreportcard.com/report/github.com/datarhei/gosrt)\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/datarhei/gosrt)](https://pkg.go.dev/github.com/datarhei/gosrt)\n\n-   [SRT reference implementation](https://github.com/Haivision/srt)\n-   [SRT RFC](https://haivision.github.io/srt-rfc/draft-sharabayko-srt.html)\n-   [SRT Technical Overview](https://github.com/Haivision/srt/files/2489142/SRT_Protocol_TechnicalOverview_DRAFT_2018-10-17.pdf)\n\n## Implementations\n\nThis implementation of the SRT protocol has live streaming of video/audio in mind. Because of this, the buffer mode and File Transfer\nCongestion Control (FileCC) are not implemented.\n\n|     |                                           |\n| --- | ----------------------------------------- |\n| ✅  | Handshake v4 and v5                       |\n| ✅  | Message mode                              |\n| ✅  | Caller-Listener Handshake                 |\n| ✅  | Timestamp-Based Packet Delivery (TSBPD)   |\n| ✅  | Too-Late Packet Drop (TLPKTDROP)          |\n| ✅  | Live Congestion Control (LiveCC)          |\n| ✅  | NAK and Peridoc NAK                       |\n| ✅  | Encryption                                |\n| ❌  | Buffer mode                               |\n| ❌  | Rendezvous Handshake                      |\n| ❌  | File Transfer Congestion Control (FileCC) |\n| ❌  | Connection Bonding                        |\n\nThe parts that are implemented are based on what has been published in the SRT RFC.\n\n## Requirements\n\nA Go version of 1.20+ is required.\n\n## Installation\n\n```shell\ngo get github.com/datarhei/gosrt\n```\n\n## Caller example\n\n```go\nimport \"github.com/datarhei/gosrt\"\n\nconn, err := srt.Dial(\"srt\", \"golang.org:6000\", srt.Config{\n    StreamId: \"...\",\n})\nif err != nil {\n    // handle error\n}\n\nbuffer := make([]byte, 2048)\n\nfor {\n    n, err := conn.Read(buffer)\n    if err != nil {\n        // handle error\n    }\n\n    // handle received data\n}\n\nconn.Close()\n```\n\nIn the `contrib/client` directory you'll find a complete example of a SRT client.\n\n## Listener example\n\n```go\nimport \"github.com/datarhei/gosrt\"\n\nln, err := srt.Listen(\"srt\", \":6000\", srt.Config{...})\nif err != nil {\n    // handle error\n}\n\nfor {\n    req, err := ln.Accept2()\n    if err != nil {\n        // handle error\n    }\n\n    go func(req ConnRequest) {\n        // check connection request by inspecting the connection request\n        // and either rejecting it ...\n\n        if somethingIsWrong {\n            req.Reject(srt.REJ_PEER)\n            return\n        }\n\n        // ... or accepting it ...\n\n        conn, err := req.Accept()\n        if err != nil {\n            return\n        }\n\n        // ... and decide whether it is a publishing or subscribing connection.\n\n        if publish {\n            handlePublish(conn)\n        } else {\n            handleSubscribe(conn)\n        }\n    }(req)\n}\n```\n\nIn the `contrib/server` directory you'll find a complete example of a SRT server. For your convenience\nthis module provides the `Server` type which is a light framework for creating your own SRT server. The\nexample server is based on this type.\n\n## Contributed client\n\nIn the `contrib/client` directory you'll find an example implementation of a SRT client.\n\nBuild the client application with\n\n```shell\ncd contrib/client \u0026\u0026 go build\n```\n\nThe application requires only two options:\n\n| Option  | Description          |\n| ------- | -------------------- |\n| `-from` | Address to read from |\n| `-to`   | Address to write to  |\n\nBoth options accept an address. Valid addresses are: `-` for `stdin`, resp. `stdout`, a `srt://` address, or an `udp://` address.\n\n### SRT URL\n\nA SRT URL is of the form `srt://[host]:[port]/?[options]` where options are in the form of a `HTTP` query string. These are the\nknown options (similar to [srt-live-transmit](https://github.com/Haivision/srt/blob/master/docs/apps/srt-live-transmit.md)):\n\n| Option               | Values                 | Description                                                             |\n| -------------------- | ---------------------- | ----------------------------------------------------------------------- |\n| `mode`               | `listener` or `caller` | Enforce listener or caller mode.                                        |\n| `congestion`         | `live`                 | Congestion control. Currently only `live` is supported.                 |\n| `conntimeo`          | `ms`                   | Connection timeout.                                                     |\n| `drifttracer`        | `bool`                 | Enable drift tracer. Not implemented.                                   |\n| `enforcedencryption` | `bool`                 | Accept connection only if both parties have encryption enabled.         |\n| `fc`                 | `bytes`                | Flow control window size.                                               |\n| `inputbw`            | `bytes`                | Input bandwidth. Ignored.                                               |\n| `iptos`              | 0...255                | IP socket type of service. Broken.                                      |\n| `ipttl`              | 1...255                | Defines IP socket \"time to live\" option. Broken.                        |\n| `ipv6only`           | `bool`                 | Use IPv6 only. Not implemented.                                         |\n| `kmpreannounce`      | `packets`              | Duration of Stream Encryption key switchover.                           |\n| `kmrefreshrate`      | `packets`              | Stream encryption key refresh rate.                                     |\n| `latency`            | `ms`                   | Maximum accepted transmission latency.                                  |\n| `lossmaxttl`         | `ms`                   | Packet reorder tolerance. Not implemented.                              |\n| `maxbw`              | `bytes`                | Bandwidth limit. Ignored.                                               |\n| `mininputbw`         | `bytes`                | Minimum allowed estimate of `inputbw`.                                  |\n| `messageapi`         | `bool`                 | Enable SRT message mode. Must be `false`.                               |\n| `mss`                | 76...                  | MTU size.                                                               |\n| `nakreport`          | `bool`                 | Enable periodic NAK reports.                                            |\n| `oheadbw`            | 10...100               | Limits bandwidth overhead. Percents. Ignored.                           |\n| `packetfilter`       | `string`               | Set up the packet filter. Not implemented.                              |\n| `passphrase`         | `string`               | Password for the encrypted transmission.                                |\n| `payloadsize`        | `bytes`                | Maximum payload size.                                                   |\n| `pbkeylen`           | `16`, `24`, or `32`    | Crypto key length in bytes.                                             |\n| `peeridletimeo`      | `ms`                   | Peer idle timeout.                                                      |\n| `peerlatency`        | `ms`                   | Minimum receiver latency to be requested by sender.                     |\n| `rcvbuf`             | `bytes`                | Receiver buffer size.                                                   |\n| `rcvlatency`         | `ms`                   | Receiver-side latency.                                                  |\n| `sndbuf`             | `bytes`                | Sender buffer size.                                                     |\n| `snddropdelay`       | `ms`                   | Sender's delay before dropping packets.                                 |\n| `streamid`           | `string`               | Stream ID (settable in caller mode only, visible on the listener peer). |\n| `tlpktdrop`          | `bool`                 | Drop too late packets.                                                  |\n| `transtype`          | `live`                 | Transmission type. Must be `live`.                                      |\n| `tsbpdmode`          | `bool`                 | Enable timestamp-based packet delivery mode.                            |\n\n### Usage\n\nReading from a SRT sender and play with `ffplay`:\n\n```shell\n./client -from \"srt://127.0.0.1:6001/?mode=listener\u0026streamid=...\" -to - | ffplay -f mpegts -i -\n```\n\nReading from UDP and sending to a SRT server:\n\n```shell\n./client -from udp://:6000 -to \"srt://127.0.0.1:6001/?mode=caller\u0026streamid=...\"\n```\n\nSimulate point-to-point transfer on localhost. Open one console and start `ffmpeg` (you need at least version 4.3.2, built with SRT enabled) to send to an UDP address:\n\n```shell\nffmpeg \\\n    -f lavfi \\\n    -re \\\n    -i testsrc2=rate=25:size=640x360 \\\n    -codec:v libx264 \\\n    -b:v 1024k \\\n    -maxrate:v 1024k \\\n    -bufsize:v 1024k \\\n    -preset ultrafast \\\n    -r 25 \\\n    -g 50 \\\n    -pix_fmt yuv420p \\\n    -flags2 local_header \\\n    -f mpegts \\\n    \"udp://127.0.0.1:6000?pkt_size=1316\"\n```\n\nIn another console read from the UDP and start a SRT listenr:\n\n```shell\n./client -from udp://:6000 -to \"srt://127.0.0.1:6001/?mode=listener\u0026streamid=foobar\"\n```\n\nIn the third console connect to that stream and play the video with `ffplay`:\n\n```shell\n./client -from \"srt://127.0.0.1:6001/?mode=caller\u0026streamid=foobar\" -to - | ffplay -f mpegts -i -\n```\n\n## Contributed server\n\nIn the `contrib/server` directory you'll find an example implementation of a SRT server. This server allows you to publish\na stream that can be read by many clients.\n\nBuild the client application with\n\n```shell\ncd contrib/server \u0026\u0026 go build\n```\n\nThe application has these options:\n\n| Option        | Default   | Description                                |\n| ------------- | --------- | ------------------------------------------ |\n| `-addr`       | required  | Address to listen on                       |\n| `-app`        | `/`       | Path prefix for streamid                   |\n| `-token`      | (not set) | Token query param for streamid             |\n| `-passphrase` | (not set) | Passphrase for de- and enrcypting the data |\n| `-logtopics`  | (not set) | Topics for the log output                  |\n| `-profile`    | `false`   | Enable profiling                           |\n\nThis example server expects the streamID (without any prefix) to be an URL path with optional query parameter, e.g. `/live/stream`. If the `-app`\noption is used, then the path must start with that path, e.g. the value is `/live` then the streamID must start with that value. The `-token`\noption can be used to define a token for that stream as some kind of access control, e.g. with `-token foobar` the streamID might look like\n`/live/stream?token=foobar`.\n\nUse `-passphrase` in order to enable and enforce encryption.\n\nUse `-logtopics` in order to write debug output. The value are a comma separated list of topics you want to be written to `stderr`, e.g. `connection,listen`. Check the [Logging](#logging) section in order to find out more about the different topics.\n\nUse `-profile` in order to write a CPU profile.\n\n### StreamID\n\nIn SRT the StreamID is used to transport somewhat arbitrary information from the caller to the listener. The provided example server uses this\nmachanism to decide who is the sender and who is the receiver. The server must know if the connecting client wants to publish a stream or\nif it wants to subscribe to a stream.\n\nThe example server looks for the `publish:` prefix in the StreamID. If this prefix is present, the server assumes that it is the receiver\nand the client will send the data. The subcribing clients must use the same StreamID (withouth the `publish:` prefix) in order to be able to\nreceive data.\n\nIf you implement your own server you are free to interpret the streamID as you wish.\n\n### Usage\n\nRunning a server listening on port 6001 with defaults:\n\n```shell\n./server -addr \":6001\"\n```\n\nNow you can use the contributed client to publish a stream:\n\n```shell\n./client -from ... -to \"srt://127.0.0.1:6001/?mode=caller\u0026streamid=publish:/live/stream\"\n```\n\nor directly from `ffmpeg`:\n\n```shell\nffmpeg \\\n    -f lavfi \\\n    -re \\\n    -i testsrc2=rate=25:size=640x360 \\\n    -codec:v libx264 \\\n    -b:v 1024k \\\n    -maxrate:v 1024k \\\n    -bufsize:v 1024k \\\n    -preset ultrafast \\\n    -r 25 \\\n    -g 50 \\\n    -pix_fmt yuv420p \\\n    -flags2 local_header \\\n    -f mpegts \\\n    -transtype live \\\n    \"srt://127.0.0.1:6001?streamid=publish:/live/stream\"\n```\n\nIf the server is not on localhost, you might adjust the `peerlatency` in order to avoid packet loss: `-peerlatency 1000000`.\n\nNow you can play the stream:\n\n```shell\nffplay -f mpegts -transtype live -i \"srt://127.0.0.1:6001?streamid=/live/stream\"\n```\n\nYou will most likely first see some error messages from `ffplay` because it tries to make sense of the received data until a keyframe arrives. If you\nget more errors during playback, you might increase the receive buffer by adding e.g. `-rcvlatency 1000000` to the command line.\n\n### Encryption\n\nThe stream can be encrypted with a passphrase. First start the server with a passphrase. If you are using `srt-live-transmit`, the passphrase has to be at least 10 characters long otherwise it will not be accepted.\n\n```shell\n./server -addr :6001 -passphrase foobarfoobar\n```\n\nSend an encrpyted stream to the server:\n\n```shell\nffmpeg \\\n    -f lavfi \\\n    -re \\\n    -i testsrc2=rate=25:size=640x360 \\\n    -codec:v libx264 \\\n    -b:v 1024k \\\n    -maxrate:v 1024k \\\n    -bufsize:v 1024k \\\n    -preset ultrafast \\\n    -r 25 \\\n    -g 50 \\\n    -pix_fmt yuv420p \\\n    -flags2 local_header \\\n    -f mpegts \\\n    -transtype live \\\n    \"srt://127.0.0.1:6001?streamid=publish:/live/stream\u0026passphrase=foobarfoobar\"\n```\n\nReceive an encrypted stream from the server:\n\n```shell\nffplay -f mpegts -transtype live -i \"srt://127.0.0.1:6001?streamid=/live/stream\u0026passphrase=foobarfoobar\"\n```\n\nYou will most likely first see some error messages from `ffplay` because it tries to make sense of the received data until a keyframe arrives. If you\nget more errors during playback, you might increase the receive buffer by adding e.g. `-rcvlatency 1000000` to the command line.\n\n## Logging\n\nThis SRT module has a built-in logging facility for debugging purposes. Check the `Logger` interface and the `NewLogger(topics []string)` function. Because logging everything would be too much output if you wonly want to debug something specific, you have the possibility to limit the logging to specific areas like everything regarding a connection or only the handshake. That's why there are various topics.\n\nIn the contributed server you see an example of how logging is used. Here's the essence:\n\n```go\nlogger := srt.NewLogger([]string{\"connection\", \"handshake\"})\n\nconfig := srt.DefaultConfig\nconfig.Logger = logger\n\nln, err := srt.Listen(\"udp\", \":6000\", config)\nif err != nil {\n    // handle error\n}\n\ngo func() {\n    for m := range logger.Listen() {\n        fmt.Fprintf(os.Stderr, \"%#08x %s (in %s:%d)\\n%s \\n\", m.SocketId, m.Topic, m.File, m.Line, m.Message)\n    }\n}()\n\nfor {\n    conn, mode, err := ln.Accept(acceptFn)\n    ...\n}\n```\n\nCurrently known topics are:\n\n```\nconnection:close\nconnection:error\nconnection:filter\nconnection:new\nconnection:rtt\nconnection:tsbpd\ncontrol:recv:ACK:cif\ncontrol:recv:ACK:dump\ncontrol:recv:ACK:error\ncontrol:recv:ACKACK:dump\ncontrol:recv:ACKACK:error\ncontrol:recv:KM:cif\ncontrol:recv:KM:dump\ncontrol:recv:KM:error\ncontrol:recv:NAK:cif\ncontrol:recv:NAK:dump\ncontrol:recv:NAK:error\ncontrol:recv:keepalive:dump\ncontrol:recv:shutdown:dump\ncontrol:send:ACK:cif\ncontrol:send:ACK:dump\ncontrol:send:ACKACK:dump\ncontrol:send:KM:cif\ncontrol:send:KM:dump\ncontrol:send:KM:error\ncontrol:send:NAK:cif\ncontrol:send:NAK:dump\ncontrol:send:keepalive:dump\ncontrol:send:shutdown:cif\ncontrol:send:shutdown:dump\ndata:recv:dump\ndata:send:dump\ndial\nhandshake:recv:cif\nhandshake:recv:dump\nhandshake:recv:error\nhandshake:send:cif\nhandshake:send:dump\nlisten\npacket:recv:dump\npacket:send:dump\n```\n\nYou can run `make logtopics` in order to extract the list of topics.\n\n## Docker\n\nThe docker image you can build with `docker build -t srt .` provides the example SRT client and server as mentioned in the paragraph above.\nE.g. run the server with `docker run -it --rm -p 6001:6001/udp srt srt-server -addr :6001`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatarhei%2Fgosrt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatarhei%2Fgosrt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatarhei%2Fgosrt/lists"}