diff --git a/server/cmd/serve.go b/server/cmd/serve.go index 2c7dfde5..b6a78077 100644 --- a/server/cmd/serve.go +++ b/server/cmd/serve.go @@ -20,6 +20,7 @@ func init() { neko.Service.Server, neko.Service.WebRTC, neko.Service.Remote, + neko.Service.Broadcast, neko.Service.WebSocket, } diff --git a/server/internal/broadcast/manager.go b/server/internal/broadcast/manager.go index 8937ffab..d6ebbe0b 100644 --- a/server/internal/broadcast/manager.go +++ b/server/internal/broadcast/manager.go @@ -12,14 +12,16 @@ type BroadcastManager struct { logger zerolog.Logger pipeline *gst.Pipeline remote *config.Remote + config *config.Broadcast enabled bool url string } -func New(remote *config.Remote) *BroadcastManager { +func New(remote *config.Remote, config *config.Broadcast) *BroadcastManager { return &BroadcastManager{ logger: log.With().Str("module", "remote").Logger(), remote: remote, + config: config, enabled: false, url: "", } @@ -34,6 +36,7 @@ func (manager *BroadcastManager) Start() { manager.pipeline, err = gst.CreateRTMPPipeline( manager.remote.Device, manager.remote.Display, + manager.config.Pipeline, manager.url, ) diff --git a/server/internal/gst/gst.go b/server/internal/gst/gst.go index e2679de5..c3fcc56c 100644 --- a/server/internal/gst/gst.go +++ b/server/internal/gst/gst.go @@ -56,7 +56,7 @@ const ( audioClockRate = 48000 pcmClockRate = 8000 videoSrc = "ximagesrc xid=%s show-pointer=true use-damage=false ! video/x-raw ! videoconvert ! queue ! " - audioSrc = "pulsesrc device=%s ! audioconvert ! " + audioSrc = "pulsesrc device=%s ! audio/x-raw,channels=2 ! audioconvert ! " ) func init() { @@ -65,11 +65,18 @@ func init() { } // CreateRTMPPipeline creates a GStreamer Pipeline -func CreateRTMPPipeline(pipelineDevice string, pipelineDisplay string, pipelineRTMP string) (*Pipeline, error) { +func CreateRTMPPipeline(pipelineDevice string, pipelineDisplay string, pipelineSrc string, pipelineRTMP string) (*Pipeline, error) { video := fmt.Sprintf(videoSrc, pipelineDisplay) audio := fmt.Sprintf(audioSrc, pipelineDevice) - return CreatePipeline(fmt.Sprintf("flvmux name=mux ! rtmpsink location='%s live=1' %s voaacenc ! mux. %s x264enc bframes=0 key-int-max=60 byte-stream=true tune=zerolatency speed-preset=veryfast ! mux.", pipelineRTMP, audio, video), "", 0) + var pipelineStr string + if pipelineSrc != "" { + pipelineStr = fmt.Sprintf(pipelineSrc, pipelineRTMP, pipelineDevice, pipelineDisplay) + } else { + pipelineStr = fmt.Sprintf("flvmux name=mux ! rtmpsink location='%s live=1' %s audio/x-raw,channels=2 ! audioconvert ! voaacenc ! mux. %s x264enc bframes=0 key-int-max=60 byte-stream=true tune=zerolatency speed-preset=veryfast ! mux.", pipelineRTMP, audio, video) + } + + return CreatePipeline(pipelineStr, "", 0) } // CreateAppPipeline creates a GStreamer Pipeline diff --git a/server/internal/types/config/broadcast.go b/server/internal/types/config/broadcast.go new file mode 100644 index 00000000..22ef94ac --- /dev/null +++ b/server/internal/types/config/broadcast.go @@ -0,0 +1,23 @@ +package config + +import ( + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type Broadcast struct { + Pipeline string +} + +func (Broadcast) Init(cmd *cobra.Command) error { + cmd.PersistentFlags().String("broadcast_pipeline", "", "audio codec parameters to use for broadcasting") + if err := viper.BindPFlag("broadcast_pipeline", cmd.PersistentFlags().Lookup("broadcast_pipeline")); err != nil { + return err + } + + return nil +} + +func (s *Broadcast) Set() { + s.Pipeline = viper.GetString("broadcast_pipeline") +} diff --git a/server/neko.go b/server/neko.go index 7d4dabbe..6c3d6163 100644 --- a/server/neko.go +++ b/server/neko.go @@ -62,6 +62,7 @@ func init() { Root: &config.Root{}, Server: &config.Server{}, Remote: &config.Remote{}, + Broadcast: &config.Broadcast{}, WebRTC: &config.WebRTC{}, WebSocket: &config.WebSocket{}, } @@ -100,6 +101,7 @@ type Neko struct { Version *Version Root *config.Root Remote *config.Remote + Broadcast *config.Broadcast Server *config.Server WebRTC *config.WebRTC WebSocket *config.WebSocket @@ -118,7 +120,7 @@ func (neko *Neko) Preflight() { } func (neko *Neko) Start() { - broadcastManager := broadcast.New(neko.Remote) + broadcastManager := broadcast.New(neko.Remote, neko.Broadcast) remoteManager := remote.New(neko.Remote, broadcastManager) remoteManager.Start()