diff --git a/README.md b/README.md index 2f78450..e19bee0 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Features: - SRT stream input, supported by FFMpeg, OBS and Gstreamer. - Low-latency streaming, sub-second with web player. - Authentification of incoming stream using LDAP server. +- Possibility to forward stream to other streaming servers. ## Installation on Debian/Ubuntu diff --git a/docs/ghostream.example.yml b/docs/ghostream.example.yml index 7130496..daea1de 100644 --- a/docs/ghostream.example.yml +++ b/docs/ghostream.example.yml @@ -17,6 +17,13 @@ auth: # uri: ldap://127.0.0.1:389 # userdn: cn=users,dc=example,dc=com +# Configure stream forwarding +forwarding: + # Example to forward a stream named "demo" to Twitch and YouTube + #demo: + # - rtmp://live-cdg.twitch.tv/app/STREAM_KEY + # - rtmp://a.rtmp.youtube.com/live2/STREAM_KEY + # Prometheus monitoring endpoint monitoring: listenAddress: 127.0.0.1:2112 @@ -46,9 +53,3 @@ webrtc: # STUN servers, you should host your own Coturn instance STUNServers: - stun:stun.l.google.com:19302 - -# Configuration for the multicast feature -multicast: - outputs: - # demo: - # - rtmp://localhost:1925 diff --git a/docs/ghostream.service b/docs/ghostream.service index 1a9487a..2980d82 100644 --- a/docs/ghostream.service +++ b/docs/ghostream.service @@ -4,7 +4,6 @@ After=syslog.target [Service] User=www-data -EnvironmentFile=-/etc/default/ghostream ExecStart=/usr/bin/ghostream Restart=on-failure diff --git a/main.go b/main.go index e1c9342..fc76592 100644 --- a/main.go +++ b/main.go @@ -3,13 +3,13 @@ package main import ( - "gitlab.crans.org/nounous/ghostream/stream/multicast" "log" "strings" "github.com/spf13/viper" "gitlab.crans.org/nounous/ghostream/auth" "gitlab.crans.org/nounous/ghostream/internal/monitoring" + "gitlab.crans.org/nounous/ghostream/stream/forwarding" "gitlab.crans.org/nounous/ghostream/stream/srt" "gitlab.crans.org/nounous/ghostream/stream/webrtc" "gitlab.crans.org/nounous/ghostream/web" @@ -58,7 +58,7 @@ func loadConfiguration() { viper.SetDefault("WebRTC.MinPortUDP", 10000) viper.SetDefault("WebRTC.MaxPortUDP", 10005) viper.SetDefault("WebRTC.STUNServers", []string{"stun:stun.l.google.com:19302"}) - viper.SetDefault("Multicast.Outputs", make(map[string][]string)) + viper.SetDefault("Forwarding", make(map[string][]string)) // Copy STUN configuration to clients viper.Set("Web.STUNServers", viper.Get("WebRTC.STUNServers")) @@ -69,8 +69,8 @@ func main() { loadConfiguration() cfg := struct { Auth auth.Options + Forwarding forwarding.Options Monitoring monitoring.Options - Multicast multicast.Options Srt srt.Options Web web.Options WebRTC webrtc.Options @@ -96,10 +96,10 @@ func main() { go web.Serve(remoteSdpChan, localSdpChan, &cfg.Web) go webrtc.Serve(remoteSdpChan, localSdpChan, &cfg.WebRTC) - // Init multicast - err = multicast.New(&cfg.Multicast) + // Init stream forwarding + err = forwarding.New(&cfg.Forwarding) if err != nil { - log.Fatalln("Failed to load multicast app:", err) + log.Fatalln("Failed to init stream forwarding:", err) } // Wait for routines diff --git a/main_test.go b/main_test.go index 7650bd7..e56643e 100644 --- a/main_test.go +++ b/main_test.go @@ -1,14 +1,15 @@ package main import ( + "testing" + "github.com/spf13/viper" "gitlab.crans.org/nounous/ghostream/auth" "gitlab.crans.org/nounous/ghostream/internal/monitoring" - "gitlab.crans.org/nounous/ghostream/stream/multicast" + "gitlab.crans.org/nounous/ghostream/stream/forwarding" "gitlab.crans.org/nounous/ghostream/stream/srt" "gitlab.crans.org/nounous/ghostream/stream/webrtc" "gitlab.crans.org/nounous/ghostream/web" - "testing" ) // TestLoadConfiguration tests the configuration file loading and the init of some parameters @@ -16,8 +17,8 @@ func TestLoadConfiguration(t *testing.T) { loadConfiguration() cfg := struct { Auth auth.Options + Forwarding forwarding.Options Monitoring monitoring.Options - Multicast multicast.Options Srt srt.Options Web web.Options WebRTC webrtc.Options diff --git a/stream/multicast/muticast.go b/stream/forwarding/forwarding.go similarity index 86% rename from stream/multicast/muticast.go rename to stream/forwarding/forwarding.go index 5b1d96c..4a1150f 100644 --- a/stream/multicast/muticast.go +++ b/stream/forwarding/forwarding.go @@ -1,4 +1,4 @@ -package multicast +package forwarding import ( "bufio" @@ -7,11 +7,9 @@ import ( "os/exec" ) -// Options to configure the multicast: -//for each stream key, we can have several additional stream URL where the main stream is redirected to -type Options struct { - Outputs map[string][]string -} +// Options to configure the stream forwarding. +// For each stream name, user can provide several URL to forward stream to +type Options map[string][]string var ( options Options @@ -27,12 +25,12 @@ func New(cfg *Options) error { // RegisterStream Declare a new open stream and create ffmpeg instances func RegisterStream(streamKey string) { - if len(options.Outputs[streamKey]) == 0 { + if len(options[streamKey]) == 0 { return } params := []string{"-re", "-i", "pipe:0"} - for _, stream := range options.Outputs[streamKey] { + for _, stream := range options[streamKey] { params = append(params, "-f", "flv", "-preset", "ultrafast", "-tune", "zerolatency", "-c", "copy", stream) } diff --git a/stream/forwarding/forwarding_test.go b/stream/forwarding/forwarding_test.go new file mode 100644 index 0000000..3fee73b --- /dev/null +++ b/stream/forwarding/forwarding_test.go @@ -0,0 +1 @@ +package forwarding diff --git a/stream/multicast/multicast_test.go b/stream/multicast/multicast_test.go deleted file mode 100644 index aa01d64..0000000 --- a/stream/multicast/multicast_test.go +++ /dev/null @@ -1 +0,0 @@ -package multicast diff --git a/stream/srt/srt.go b/stream/srt/srt.go index d333aa9..0f15472 100644 --- a/stream/srt/srt.go +++ b/stream/srt/srt.go @@ -1,13 +1,12 @@ package srt import ( - "gitlab.crans.org/nounous/ghostream/stream/multicast" "log" "net" "strconv" "github.com/haivision/srtgo" - "github.com/pion/rtp" + "gitlab.crans.org/nounous/ghostream/stream/forwarding" ) // Options holds web package configuration @@ -57,42 +56,33 @@ func Serve(cfg *Options) { // Create a new buffer buff := make([]byte, 2048) - // Setup linked multicasts - multicast.RegisterStream("demo") // FIXME Replace with real stream key + // Setup stream forwarding + forwarding.RegisterStream("demo") // FIXME Replace with real stream key // Read RTP packets forever and send them to the WebRTC Client for { n, err := s.Read(buff, 10000) if err != nil { log.Println("Error occured while reading SRT socket:", err) - multicast.CloseConnection("demo") + forwarding.CloseConnection("demo") break } if n == 0 { // End of stream log.Printf("Received no bytes, stopping stream.") - multicast.CloseConnection("demo") + forwarding.CloseConnection("demo") break } log.Printf("Received %d bytes", n) // Send raw packet to other streams - multicast.SendPacket("demo", buff[:n]) - - // Unmarshal incoming packet - packet := &rtp.Packet{} - if err := packet.Unmarshal(buff[:n]); err != nil { - log.Println("Error occured while unmarshaling SRT:", err) - multicast.CloseConnection("demo") - break - } + forwarding.SendPacket("demo", buff[:n]) // TODO: Send to WebRTC - //payloadType := uint8(22) // FIXME put vp8 payload - //packet.Header.PayloadType = payloadType - //err := videoTrack.WriteRTP(packet) + // See https://github.com/ebml-go/webm/blob/master/reader.go + //err := videoTrack.WriteSample(media.Sample{Data: data, Samples: uint32(sampleCount)}) } } }