mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
add v2 compatible config.
This commit is contained in:
parent
f2eab73847
commit
dbf9fc6ebc
@ -87,6 +87,27 @@ func (c *serve) Init(cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// V2 configuration
|
||||||
|
|
||||||
|
if err := c.configs.Desktop.InitV2(cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.configs.Capture.InitV2(cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.configs.WebRTC.InitV2(cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.configs.Member.InitV2(cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.configs.Session.InitV2(cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.configs.Server.InitV2(cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +121,13 @@ func (c *serve) PreRun(cmd *cobra.Command, args []string) {
|
|||||||
c.configs.Session.Set()
|
c.configs.Session.Set()
|
||||||
c.configs.Plugins.Set()
|
c.configs.Plugins.Set()
|
||||||
c.configs.Server.Set()
|
c.configs.Server.Set()
|
||||||
|
|
||||||
|
c.configs.Desktop.SetV2()
|
||||||
|
c.configs.Capture.SetV2()
|
||||||
|
c.configs.WebRTC.SetV2()
|
||||||
|
c.configs.Member.SetV2()
|
||||||
|
c.configs.Session.SetV2()
|
||||||
|
c.configs.Server.SetV2()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serve) Start(cmd *cobra.Command) {
|
func (c *serve) Start(cmd *cobra.Command) {
|
||||||
|
@ -2,7 +2,9 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pion/webrtc/v3"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@ -12,6 +14,17 @@ import (
|
|||||||
"github.com/demodesk/neko/pkg/utils"
|
"github.com/demodesk/neko/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Legacy capture configuration
|
||||||
|
type HwEnc int
|
||||||
|
|
||||||
|
// Legacy capture configuration
|
||||||
|
const (
|
||||||
|
HwEncUnset HwEnc = iota
|
||||||
|
HwEncNone
|
||||||
|
HwEncVAAPI
|
||||||
|
HwEncNVENC
|
||||||
|
)
|
||||||
|
|
||||||
type Capture struct {
|
type Capture struct {
|
||||||
Display string
|
Display string
|
||||||
|
|
||||||
@ -167,6 +180,132 @@ func (Capture) Init(cmd *cobra.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (Capture) InitV2(cmd *cobra.Command) error {
|
||||||
|
cmd.PersistentFlags().String("display", "", "XDisplay to capture")
|
||||||
|
if err := viper.BindPFlag("display", cmd.PersistentFlags().Lookup("display")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("video_codec", "", "video codec to be used")
|
||||||
|
if err := viper.BindPFlag("video_codec", cmd.PersistentFlags().Lookup("video_codec")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: video codec
|
||||||
|
cmd.PersistentFlags().Bool("vp8", false, "DEPRECATED: use video_codec")
|
||||||
|
if err := viper.BindPFlag("vp8", cmd.PersistentFlags().Lookup("vp8")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: video codec
|
||||||
|
cmd.PersistentFlags().Bool("vp9", false, "DEPRECATED: use video_codec")
|
||||||
|
if err := viper.BindPFlag("vp9", cmd.PersistentFlags().Lookup("vp9")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: video codec
|
||||||
|
cmd.PersistentFlags().Bool("av1", false, "DEPRECATED: use video_codec")
|
||||||
|
if err := viper.BindPFlag("av1", cmd.PersistentFlags().Lookup("av1")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: video codec
|
||||||
|
cmd.PersistentFlags().Bool("h264", false, "DEPRECATED: use video_codec")
|
||||||
|
if err := viper.BindPFlag("h264", cmd.PersistentFlags().Lookup("h264")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("hwenc", "", "use hardware accelerated encoding")
|
||||||
|
if err := viper.BindPFlag("hwenc", cmd.PersistentFlags().Lookup("hwenc")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Int("video_bitrate", 0, "video bitrate in kbit/s")
|
||||||
|
if err := viper.BindPFlag("video_bitrate", cmd.PersistentFlags().Lookup("video_bitrate")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Int("max_fps", 0, "maximum fps delivered via WebRTC, 0 is for no maximum")
|
||||||
|
if err := viper.BindPFlag("max_fps", cmd.PersistentFlags().Lookup("max_fps")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("video", "", "video codec parameters to use for streaming")
|
||||||
|
if err := viper.BindPFlag("video", cmd.PersistentFlags().Lookup("video")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// audio
|
||||||
|
//
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("device", "", "audio device to capture")
|
||||||
|
if err := viper.BindPFlag("device", cmd.PersistentFlags().Lookup("device")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("audio_codec", "", "audio codec to be used")
|
||||||
|
if err := viper.BindPFlag("audio_codec", cmd.PersistentFlags().Lookup("audio_codec")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: audio codec
|
||||||
|
cmd.PersistentFlags().Bool("opus", false, "DEPRECATED: use audio_codec")
|
||||||
|
if err := viper.BindPFlag("opus", cmd.PersistentFlags().Lookup("opus")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: audio codec
|
||||||
|
cmd.PersistentFlags().Bool("g722", false, "DEPRECATED: use audio_codec")
|
||||||
|
if err := viper.BindPFlag("g722", cmd.PersistentFlags().Lookup("g722")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: audio codec
|
||||||
|
cmd.PersistentFlags().Bool("pcmu", false, "DEPRECATED: use audio_codec")
|
||||||
|
if err := viper.BindPFlag("pcmu", cmd.PersistentFlags().Lookup("pcmu")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: audio codec
|
||||||
|
cmd.PersistentFlags().Bool("pcma", false, "DEPRECATED: use audio_codec")
|
||||||
|
if err := viper.BindPFlag("pcma", cmd.PersistentFlags().Lookup("pcma")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// audio codecs
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Int("audio_bitrate", 0, "audio bitrate in kbit/s")
|
||||||
|
if err := viper.BindPFlag("audio_bitrate", cmd.PersistentFlags().Lookup("audio_bitrate")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("audio", "", "audio codec parameters to use for streaming")
|
||||||
|
if err := viper.BindPFlag("audio", cmd.PersistentFlags().Lookup("audio")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// broadcast
|
||||||
|
//
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("broadcast_pipeline", "", "custom gst pipeline used for broadcasting, strings {url} {device} {display} will be replaced")
|
||||||
|
if err := viper.BindPFlag("broadcast_pipeline", cmd.PersistentFlags().Lookup("broadcast_pipeline")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("broadcast_url", "", "a default default URL for broadcast streams, can be disabled/changed later by admins in the GUI")
|
||||||
|
if err := viper.BindPFlag("broadcast_url", cmd.PersistentFlags().Lookup("broadcast_url")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Bool("broadcast_autostart", false, "automatically start broadcasting when neko starts and broadcast_url is set")
|
||||||
|
if err := viper.BindPFlag("broadcast_autostart", cmd.PersistentFlags().Lookup("broadcast_autostart")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Capture) Set() {
|
func (s *Capture) Set() {
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
@ -251,3 +390,135 @@ func (s *Capture) Set() {
|
|||||||
s.MicrophoneEnabled = viper.GetBool("capture.microphone.enabled")
|
s.MicrophoneEnabled = viper.GetBool("capture.microphone.enabled")
|
||||||
s.MicrophoneDevice = viper.GetString("capture.microphone.device")
|
s.MicrophoneDevice = viper.GetString("capture.microphone.device")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Capture) SetV2() {
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
//
|
||||||
|
// video
|
||||||
|
//
|
||||||
|
|
||||||
|
if display := viper.GetString("display"); display != "" {
|
||||||
|
s.Display = display
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_DISPLAY' which is deprecated, please use 'DISPLAY' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if videoCodec := viper.GetString("video_codec"); videoCodec != "" {
|
||||||
|
s.VideoCodec, ok = codec.ParseStr(videoCodec)
|
||||||
|
if !ok || s.VideoCodec.Type != webrtc.RTPCodecTypeVideo {
|
||||||
|
log.Warn().Str("codec", videoCodec).Msgf("unknown video codec, using Vp8")
|
||||||
|
s.VideoCodec = codec.VP8()
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_VIDEO_CODEC' which is deprecated, please use 'NEKO_CAPTURE_VIDEO_CODEC' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.GetBool("vp8") {
|
||||||
|
s.VideoCodec = codec.VP8()
|
||||||
|
log.Warn().Msg("you are using deprecated config setting 'NEKO_VP8=true', use 'NEKO_CAPTURE_VIDEO_CODEC=vp8' instead")
|
||||||
|
} else if viper.GetBool("vp9") {
|
||||||
|
s.VideoCodec = codec.VP9()
|
||||||
|
log.Warn().Msg("you are using deprecated config setting 'NEKO_VP9=true', use 'NEKO_CAPTURE_VIDEO_CODEC=vp9' instead")
|
||||||
|
} else if viper.GetBool("h264") {
|
||||||
|
s.VideoCodec = codec.H264()
|
||||||
|
log.Warn().Msg("you are using deprecated config setting 'NEKO_H264=true', use 'NEKO_CAPTURE_VIDEO_CODEC=h264' instead")
|
||||||
|
} else if viper.GetBool("av1") {
|
||||||
|
s.VideoCodec = codec.AV1()
|
||||||
|
log.Warn().Msg("you are using deprecated config setting 'NEKO_AV1=true', use 'NEKO_CAPTURE_VIDEO_CODEC=av1' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
videoHWEnc := HwEncUnset
|
||||||
|
if hwenc := strings.ToLower(viper.GetString("hwenc")); hwenc != "" {
|
||||||
|
switch hwenc {
|
||||||
|
case "none":
|
||||||
|
videoHWEnc = HwEncNone
|
||||||
|
case "vaapi":
|
||||||
|
videoHWEnc = HwEncVAAPI
|
||||||
|
case "nvenc":
|
||||||
|
videoHWEnc = HwEncNVENC
|
||||||
|
default:
|
||||||
|
log.Warn().Str("hwenc", hwenc).Msgf("unknown video hw encoder, using CPU")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
videoBitrate := viper.GetUint("video_bitrate")
|
||||||
|
videoMaxFPS := int16(viper.GetInt("max_fps"))
|
||||||
|
videoPipeline := viper.GetString("video")
|
||||||
|
|
||||||
|
// video pipeline
|
||||||
|
if videoHWEnc != HwEncUnset || videoBitrate != 0 || videoMaxFPS != 0 || videoPipeline != "" {
|
||||||
|
pipeline, err := NewVideoPipeline(s.VideoCodec, s.Display, videoPipeline, videoMaxFPS, videoBitrate, videoHWEnc)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Msg("unable to create video pipeline, using default")
|
||||||
|
} else {
|
||||||
|
s.VideoPipelines = map[string]types.VideoConfig{
|
||||||
|
"main": {
|
||||||
|
GstPipeline: pipeline,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// TODO: add deprecated warning and proper alternative
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// audio
|
||||||
|
//
|
||||||
|
|
||||||
|
if audioDevice := viper.GetString("device"); audioDevice != "" {
|
||||||
|
s.AudioDevice = audioDevice
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_DEVICE' which is deprecated, please use 'NEKO_CAPTURE_AUDIO_DEVICE' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if audioCodec := viper.GetString("audio_codec"); audioCodec != "" {
|
||||||
|
s.AudioCodec, ok = codec.ParseStr(audioCodec)
|
||||||
|
if !ok || s.AudioCodec.Type != webrtc.RTPCodecTypeAudio {
|
||||||
|
log.Warn().Str("codec", audioCodec).Msgf("unknown audio codec, using Opus")
|
||||||
|
s.AudioCodec = codec.Opus()
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_AUDIO_CODEC' which is deprecated, please use 'NEKO_CAPTURE_AUDIO_CODEC' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.GetBool("opus") {
|
||||||
|
s.AudioCodec = codec.Opus()
|
||||||
|
log.Warn().Msg("you are using deprecated config setting 'NEKO_OPUS=true', use 'NEKO_CAPTURE_AUDIO_CODEC=opus' instead")
|
||||||
|
} else if viper.GetBool("g722") {
|
||||||
|
s.AudioCodec = codec.G722()
|
||||||
|
log.Warn().Msg("you are using deprecated config setting 'NEKO_G722=true', use 'NEKO_CAPTURE_AUDIO_CODEC=g722' instead")
|
||||||
|
} else if viper.GetBool("pcmu") {
|
||||||
|
s.AudioCodec = codec.PCMU()
|
||||||
|
log.Warn().Msg("you are using deprecated config setting 'NEKO_PCMU=true', use 'NEKO_CAPTURE_AUDIO_CODEC=pcmu' instead")
|
||||||
|
} else if viper.GetBool("pcma") {
|
||||||
|
s.AudioCodec = codec.PCMA()
|
||||||
|
log.Warn().Msg("you are using deprecated config setting 'NEKO_PCMA=true', use 'NEKO_CAPTURE_AUDIO_CODEC=pcma' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
audioBitrate := viper.GetUint("audio_bitrate")
|
||||||
|
audioPipeline := viper.GetString("audio")
|
||||||
|
|
||||||
|
// audio pipeline
|
||||||
|
if audioBitrate != 0 || audioPipeline != "" {
|
||||||
|
pipeline, err := NewAudioPipeline(s.AudioCodec, s.AudioDevice, audioPipeline, audioBitrate)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Msg("unable to create audio pipeline, using default")
|
||||||
|
} else {
|
||||||
|
s.AudioPipeline = pipeline
|
||||||
|
}
|
||||||
|
// TODO: add deprecated warning and proper alternative
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// broadcast
|
||||||
|
//
|
||||||
|
|
||||||
|
if viper.IsSet("broadcast_pipeline") {
|
||||||
|
s.BroadcastPipeline = viper.GetString("broadcast_pipeline")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_BROADCAST_PIPELINE' which is deprecated, please use 'NEKO_CAPTURE_BROADCAST_PIPELINE' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("broadcast_url") {
|
||||||
|
s.BroadcastUrl = viper.GetString("broadcast_url")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_BROADCAST_URL' which is deprecated, please use 'NEKO_CAPTURE_BROADCAST_URL' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("broadcast_autostart") {
|
||||||
|
s.BroadcastAutostart = viper.GetBool("broadcast_autostart")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_BROADCAST_AUTOSTART' which is deprecated, please use 'NEKO_CAPTURE_BROADCAST_AUTOSTART' instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
235
server/internal/config/capture_pipeline.go
Normal file
235
server/internal/config/capture_pipeline.go
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
// Legacy pipeline configuration for gstreamer.
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/demodesk/neko/pkg/gst"
|
||||||
|
"github.com/demodesk/neko/pkg/types/codec"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
apt-get install \
|
||||||
|
libgstreamer1.0-0 \
|
||||||
|
gstreamer1.0-plugins-base \
|
||||||
|
gstreamer1.0-plugins-good \
|
||||||
|
gstreamer1.0-plugins-bad \
|
||||||
|
gstreamer1.0-plugins-ugly\
|
||||||
|
gstreamer1.0-libav \
|
||||||
|
gstreamer1.0-doc \
|
||||||
|
gstreamer1.0-tools \
|
||||||
|
gstreamer1.0-x \
|
||||||
|
gstreamer1.0-alsa \
|
||||||
|
gstreamer1.0-pulseaudio
|
||||||
|
|
||||||
|
gst-inspect-1.0 --version
|
||||||
|
gst-inspect-1.0 plugin
|
||||||
|
gst-launch-1.0 ximagesrc show-pointer=true use-damage=false ! video/x-raw,framerate=30/1 ! videoconvert ! queue ! vp8enc error-resilient=partitions keyframe-max-dist=10 auto-alt-ref=true cpu-used=5 deadline=1 ! autovideosink
|
||||||
|
gst-launch-1.0 pulsesrc ! audioconvert ! opusenc ! autoaudiosink
|
||||||
|
*/
|
||||||
|
|
||||||
|
const (
|
||||||
|
videoSrc = "ximagesrc display-name=%s show-pointer=true use-damage=false ! video/x-raw,framerate=%d/1 ! videoconvert ! queue ! "
|
||||||
|
audioSrc = "pulsesrc device=%s ! audio/x-raw,channels=2 ! audioconvert ! "
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewBroadcastPipeline(device string, display string, pipelineSrc string, url string) string {
|
||||||
|
video := fmt.Sprintf(videoSrc, display, 25)
|
||||||
|
audio := fmt.Sprintf(audioSrc, device)
|
||||||
|
|
||||||
|
var pipelineStr string
|
||||||
|
if pipelineSrc != "" {
|
||||||
|
// replace RTMP url
|
||||||
|
pipelineStr = strings.Replace(pipelineSrc, "{url}", url, -1)
|
||||||
|
// replace audio device
|
||||||
|
pipelineStr = strings.Replace(pipelineStr, "{device}", device, -1)
|
||||||
|
// replace display
|
||||||
|
pipelineStr = strings.Replace(pipelineStr, "{display}", display, -1)
|
||||||
|
} 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.", url, audio, video)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipelineStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVideoPipeline(rtpCodec codec.RTPCodec, display string, pipelineSrc string, fps int16, bitrate uint, hwenc HwEnc) (string, error) {
|
||||||
|
pipelineStr := " ! appsink name=appsinkvideo"
|
||||||
|
|
||||||
|
// if using custom pipeline
|
||||||
|
if pipelineSrc != "" {
|
||||||
|
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, display)
|
||||||
|
return pipelineStr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// use default fps if not set
|
||||||
|
if fps == 0 {
|
||||||
|
fps = 25
|
||||||
|
}
|
||||||
|
|
||||||
|
switch rtpCodec.Name {
|
||||||
|
case codec.VP8().Name:
|
||||||
|
if hwenc == HwEncVAAPI {
|
||||||
|
if err := gst.CheckPlugins([]string{"ximagesrc", "vaapi"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// vp8 encode is missing from gstreamer.freedesktop.org/documentation
|
||||||
|
// note that it was removed from some recent intel CPUs: https://trac.ffmpeg.org/wiki/Hardware/QuickSync
|
||||||
|
// https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-vaapi-plugins/html/gstreamer-vaapi-plugins-vaapivp8enc.html
|
||||||
|
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! vaapivp8enc rate-control=vbr bitrate=%d keyframe-period=180"+pipelineStr, display, fps, bitrate)
|
||||||
|
} else {
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/vpx/vp8enc.html?gi-language=c
|
||||||
|
// gstreamer1.0-plugins-good
|
||||||
|
// vp8enc error-resilient=partitions keyframe-max-dist=10 auto-alt-ref=true cpu-used=5 deadline=1
|
||||||
|
if err := gst.CheckPlugins([]string{"ximagesrc", "vpx"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = strings.Join([]string{
|
||||||
|
fmt.Sprintf(videoSrc, display, fps),
|
||||||
|
"vp8enc",
|
||||||
|
fmt.Sprintf("target-bitrate=%d", bitrate*650),
|
||||||
|
"cpu-used=4",
|
||||||
|
"end-usage=cbr",
|
||||||
|
"threads=4",
|
||||||
|
"deadline=1",
|
||||||
|
"undershoot=95",
|
||||||
|
fmt.Sprintf("buffer-size=%d", bitrate*4),
|
||||||
|
fmt.Sprintf("buffer-initial-size=%d", bitrate*2),
|
||||||
|
fmt.Sprintf("buffer-optimal-size=%d", bitrate*3),
|
||||||
|
"keyframe-max-dist=25",
|
||||||
|
"min-quantizer=4",
|
||||||
|
"max-quantizer=20",
|
||||||
|
pipelineStr,
|
||||||
|
}, " ")
|
||||||
|
}
|
||||||
|
case codec.VP9().Name:
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/vpx/vp9enc.html?gi-language=c
|
||||||
|
// gstreamer1.0-plugins-good
|
||||||
|
// vp9enc
|
||||||
|
if err := gst.CheckPlugins([]string{"ximagesrc", "vpx"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = fmt.Sprintf(videoSrc+"vp9enc target-bitrate=%d cpu-used=-5 threads=4 deadline=1 keyframe-max-dist=30 auto-alt-ref=true"+pipelineStr, display, fps, bitrate*1000)
|
||||||
|
case codec.AV1().Name:
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/aom/av1enc.html?gi-language=c
|
||||||
|
// gstreamer1.0-plugins-bad
|
||||||
|
// av1enc usage-profile=1
|
||||||
|
// TODO: check for plugin.
|
||||||
|
if err := gst.CheckPlugins([]string{"ximagesrc", "vpx"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = strings.Join([]string{
|
||||||
|
fmt.Sprintf(videoSrc, display, fps),
|
||||||
|
"av1enc",
|
||||||
|
fmt.Sprintf("target-bitrate=%d", bitrate*650),
|
||||||
|
"cpu-used=4",
|
||||||
|
"end-usage=cbr",
|
||||||
|
// "usage-profile=realtime",
|
||||||
|
"undershoot=95",
|
||||||
|
"keyframe-max-dist=25",
|
||||||
|
"min-quantizer=4",
|
||||||
|
"max-quantizer=20",
|
||||||
|
pipelineStr,
|
||||||
|
}, " ")
|
||||||
|
case codec.H264().Name:
|
||||||
|
if err := gst.CheckPlugins([]string{"ximagesrc"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
vbvbuf := uint(1000)
|
||||||
|
if bitrate > 1000 {
|
||||||
|
vbvbuf = bitrate
|
||||||
|
}
|
||||||
|
|
||||||
|
if hwenc == HwEncVAAPI {
|
||||||
|
if err := gst.CheckPlugins([]string{"vaapi"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! vaapih264enc rate-control=vbr bitrate=%d keyframe-period=180 quality-level=7 ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate)
|
||||||
|
} else if hwenc == HwEncNVENC {
|
||||||
|
if err := gst.CheckPlugins([]string{"nvcodec"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! nvh264enc name=encoder preset=2 gop-size=25 spatial-aq=true temporal-aq=true bitrate=%d vbv-buffer-size=%d rc-mode=6 ! h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate, vbvbuf)
|
||||||
|
} else {
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/openh264/openh264enc.html?gi-language=c#openh264enc
|
||||||
|
// gstreamer1.0-plugins-bad
|
||||||
|
// openh264enc multi-thread=4 complexity=high bitrate=3072000 max-bitrate=4096000
|
||||||
|
if err := gst.CheckPlugins([]string{"openh264"}); err == nil {
|
||||||
|
pipelineStr = fmt.Sprintf(videoSrc+"openh264enc multi-thread=4 complexity=high bitrate=%d max-bitrate=%d ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate*1000, (bitrate+1024)*1000)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/x264/index.html?gi-language=c
|
||||||
|
// gstreamer1.0-plugins-ugly
|
||||||
|
// video/x-raw,format=I420 ! x264enc bframes=0 key-int-max=60 byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline
|
||||||
|
if err := gst.CheckPlugins([]string{"x264"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! x264enc threads=4 bitrate=%d key-int-max=60 vbv-buf-capacity=%d byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate, vbvbuf)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("unknown codec %s", rtpCodec.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipelineStr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAudioPipeline(rtpCodec codec.RTPCodec, device string, pipelineSrc string, bitrate uint) (string, error) {
|
||||||
|
pipelineStr := " ! appsink name=appsinkaudio"
|
||||||
|
|
||||||
|
// if using custom pipeline
|
||||||
|
if pipelineSrc != "" {
|
||||||
|
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, device)
|
||||||
|
return pipelineStr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch rtpCodec.Name {
|
||||||
|
case codec.Opus().Name:
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/opus/opusenc.html
|
||||||
|
// gstreamer1.0-plugins-base
|
||||||
|
// opusenc
|
||||||
|
if err := gst.CheckPlugins([]string{"pulseaudio", "opus"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = fmt.Sprintf(audioSrc+"opusenc inband-fec=true bitrate=%d"+pipelineStr, device, bitrate*1000)
|
||||||
|
case codec.G722().Name:
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/libav/avenc_g722.html?gi-language=c
|
||||||
|
// gstreamer1.0-libav
|
||||||
|
// avenc_g722
|
||||||
|
if err := gst.CheckPlugins([]string{"pulseaudio", "libav"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = fmt.Sprintf(audioSrc+"avenc_g722 bitrate=%d"+pipelineStr, device, bitrate*1000)
|
||||||
|
case codec.PCMU().Name:
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/mulaw/mulawenc.html?gi-language=c
|
||||||
|
// gstreamer1.0-plugins-good
|
||||||
|
// audio/x-raw, rate=8000 ! mulawenc
|
||||||
|
if err := gst.CheckPlugins([]string{"pulseaudio", "mulaw"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = fmt.Sprintf(audioSrc+"audio/x-raw, rate=8000 ! mulawenc"+pipelineStr, device)
|
||||||
|
case codec.PCMA().Name:
|
||||||
|
// https://gstreamer.freedesktop.org/documentation/alaw/alawenc.html?gi-language=c
|
||||||
|
// gstreamer1.0-plugins-good
|
||||||
|
// audio/x-raw, rate=8000 ! alawenc
|
||||||
|
if err := gst.CheckPlugins([]string{"pulseaudio", "alaw"}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineStr = fmt.Sprintf(audioSrc+"audio/x-raw, rate=8000 ! alawenc"+pipelineStr, device)
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("unknown codec %s", rtpCodec.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipelineStr, nil
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
@ -58,6 +59,15 @@ func (Desktop) Init(cmd *cobra.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (Desktop) InitV2(cmd *cobra.Command) error {
|
||||||
|
cmd.PersistentFlags().String("screen", "", "default screen resolution and framerate")
|
||||||
|
if err := viper.BindPFlag("screen", cmd.PersistentFlags().Lookup("screen")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Desktop) Set() {
|
func (s *Desktop) Set() {
|
||||||
// Display is provided by env variable
|
// Display is provided by env variable
|
||||||
s.Display = os.Getenv("DISPLAY")
|
s.Display = os.Getenv("DISPLAY")
|
||||||
@ -89,3 +99,23 @@ func (s *Desktop) Set() {
|
|||||||
s.UploadDrop = viper.GetBool("desktop.upload_drop")
|
s.UploadDrop = viper.GetBool("desktop.upload_drop")
|
||||||
s.FileChooserDialog = viper.GetBool("desktop.file_chooser_dialog")
|
s.FileChooserDialog = viper.GetBool("desktop.file_chooser_dialog")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Desktop) SetV2() {
|
||||||
|
if viper.IsSet("screen") {
|
||||||
|
r := regexp.MustCompile(`([0-9]{1,4})x([0-9]{1,4})@([0-9]{1,3})`)
|
||||||
|
res := r.FindStringSubmatch(viper.GetString("screen"))
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
width, err1 := strconv.ParseInt(res[1], 10, 64)
|
||||||
|
height, err2 := strconv.ParseInt(res[2], 10, 64)
|
||||||
|
rate, err3 := strconv.ParseInt(res[3], 10, 64)
|
||||||
|
|
||||||
|
if err1 == nil && err2 == nil && err3 == nil {
|
||||||
|
s.ScreenSize.Width = int(width)
|
||||||
|
s.ScreenSize.Height = int(height)
|
||||||
|
s.ScreenSize.Rate = int16(rate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_SCREEN' which is deprecated, please use 'NEKO_DESKTOP_SCREEN' instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -68,6 +68,20 @@ func (Member) Init(cmd *cobra.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (Member) InitV2(cmd *cobra.Command) error {
|
||||||
|
cmd.PersistentFlags().String("password", "", "password for connecting to stream")
|
||||||
|
if err := viper.BindPFlag("password", cmd.PersistentFlags().Lookup("password")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("password_admin", "", "admin password for connecting to stream")
|
||||||
|
if err := viper.BindPFlag("password_admin", cmd.PersistentFlags().Lookup("password_admin")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Member) Set() {
|
func (s *Member) Set() {
|
||||||
s.Provider = viper.GetString("member.provider")
|
s.Provider = viper.GetString("member.provider")
|
||||||
|
|
||||||
@ -126,3 +140,20 @@ func (s *Member) Set() {
|
|||||||
log.Warn().Err(err).Msgf("unable to parse member multiuser admin profile")
|
log.Warn().Err(err).Msgf("unable to parse member multiuser admin profile")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Member) SetV2() {
|
||||||
|
if viper.IsSet("password") || viper.IsSet("password_admin") {
|
||||||
|
s.Provider = "multiuser"
|
||||||
|
if userPassword := viper.GetString("password"); userPassword != "" {
|
||||||
|
s.Multiuser.UserPassword = userPassword
|
||||||
|
} else {
|
||||||
|
s.Multiuser.UserPassword = "neko"
|
||||||
|
}
|
||||||
|
if adminPassword := viper.GetString("password_admin"); adminPassword != "" {
|
||||||
|
s.Multiuser.AdminPassword = adminPassword
|
||||||
|
} else {
|
||||||
|
s.Multiuser.AdminPassword = "admin"
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_PASSWORD' and 'NEKO_PASSWORD_ADMIN' which are deprecated, please use 'NEKO_MEMBER_MULTIUSER_USER_PASSWORD' and 'NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD' with 'NEKO_MEMBER_PROVIDER=multiuser' instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,8 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@ -59,6 +61,15 @@ func (Root) Init(cmd *cobra.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (Root) InitV2(cmd *cobra.Command) error {
|
||||||
|
cmd.PersistentFlags().BoolP("logs", "l", false, "save logs to file")
|
||||||
|
if err := viper.BindPFlag("logs", cmd.PersistentFlags().Lookup("logs")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Root) Set() {
|
func (s *Root) Set() {
|
||||||
s.Config = viper.GetString("config")
|
s.Config = viper.GetString("config")
|
||||||
|
|
||||||
@ -95,3 +106,18 @@ func (s *Root) Set() {
|
|||||||
s.LogNocolor = true
|
s.LogNocolor = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Root) SetV2() {
|
||||||
|
if viper.IsSet("logs") {
|
||||||
|
if viper.GetBool("logs") {
|
||||||
|
logs := filepath.Join(".", "logs")
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
logs = "/var/log/neko"
|
||||||
|
}
|
||||||
|
s.LogDir = logs
|
||||||
|
} else {
|
||||||
|
s.LogDir = ""
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_LOGS' which is deprecated, please use 'NEKO_LOG_DIR=/path/to/logs' instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package config
|
|||||||
import (
|
import (
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
@ -70,6 +71,45 @@ func (Server) Init(cmd *cobra.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (Server) InitV2(cmd *cobra.Command) error {
|
||||||
|
cmd.PersistentFlags().String("bind", "", "address/port/socket to serve neko")
|
||||||
|
if err := viper.BindPFlag("bind", cmd.PersistentFlags().Lookup("bind")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("cert", "", "path to the SSL cert used to secure the neko server")
|
||||||
|
if err := viper.BindPFlag("cert", cmd.PersistentFlags().Lookup("cert")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("key", "", "path to the SSL key used to secure the neko server")
|
||||||
|
if err := viper.BindPFlag("key", cmd.PersistentFlags().Lookup("key")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Bool("proxy", false, "enable reverse proxy mode")
|
||||||
|
if err := viper.BindPFlag("proxy", cmd.PersistentFlags().Lookup("proxy")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("static", "", "path to neko client files to serve")
|
||||||
|
if err := viper.BindPFlag("static", cmd.PersistentFlags().Lookup("static")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("path_prefix", "", "path prefix for HTTP requests")
|
||||||
|
if err := viper.BindPFlag("path_prefix", cmd.PersistentFlags().Lookup("path_prefix")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().StringSlice("cors", []string{}, "list of allowed origins for CORS")
|
||||||
|
if err := viper.BindPFlag("cors", cmd.PersistentFlags().Lookup("cors")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) Set() {
|
func (s *Server) Set() {
|
||||||
s.Cert = viper.GetString("server.cert")
|
s.Cert = viper.GetString("server.cert")
|
||||||
s.Key = viper.GetString("server.key")
|
s.Key = viper.GetString("server.key")
|
||||||
@ -87,6 +127,41 @@ func (s *Server) Set() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) SetV2() {
|
||||||
|
if viper.IsSet("cert") {
|
||||||
|
s.Cert = viper.GetString("cert")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_CERT' which is deprecated, please use 'NEKO_SERVER_CERT' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("key") {
|
||||||
|
s.Key = viper.GetString("key")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_KEY' which is deprecated, please use 'NEKO_SERVER_KEY' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("bind") {
|
||||||
|
s.Bind = viper.GetString("bind")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_BIND' which is deprecated, please use 'NEKO_SERVER_BIND' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("proxy") {
|
||||||
|
s.Proxy = viper.GetBool("proxy")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_PROXY' which is deprecated, please use 'NEKO_SERVER_PROXY' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("static") {
|
||||||
|
s.Static = viper.GetString("static")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_STATIC' which is deprecated, please use 'NEKO_SERVER_STATIC' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("path_prefix") {
|
||||||
|
s.PathPrefix = path.Join("/", path.Clean(viper.GetString("path_prefix")))
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_PATH_PREFIX' which is deprecated, please use 'NEKO_SERVER_PATH_PREFIX' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("cors") {
|
||||||
|
s.CORS = viper.GetStringSlice("cors")
|
||||||
|
in, _ := utils.ArrayIn("*", s.CORS)
|
||||||
|
if len(s.CORS) == 0 || in {
|
||||||
|
s.CORS = []string{"*"}
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_CORS' which is deprecated, please use 'NEKO_SERVER_CORS' instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) HasCors() bool {
|
func (s *Server) HasCors() bool {
|
||||||
return len(s.CORS) > 0
|
return len(s.CORS) > 0
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package config
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
@ -95,6 +96,25 @@ func (Session) Init(cmd *cobra.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (Session) InitV2(cmd *cobra.Command) error {
|
||||||
|
cmd.PersistentFlags().StringSlice("locks", []string{}, "resources, that will be locked when starting (control, login)")
|
||||||
|
if err := viper.BindPFlag("locks", cmd.PersistentFlags().Lookup("locks")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Bool("control_protection", false, "control protection means, users can gain control only if at least one admin is in the room")
|
||||||
|
if err := viper.BindPFlag("control_protection", cmd.PersistentFlags().Lookup("control_protection")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Bool("implicit_control", false, "if enabled members can gain control implicitly")
|
||||||
|
if err := viper.BindPFlag("implicit_control", cmd.PersistentFlags().Lookup("implicit_control")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Session) Set() {
|
func (s *Session) Set() {
|
||||||
s.File = viper.GetString("session.file")
|
s.File = viper.GetString("session.file")
|
||||||
|
|
||||||
@ -112,3 +132,28 @@ func (s *Session) Set() {
|
|||||||
s.CookieExpiration = time.Duration(viper.GetInt("session.cookie.expiration")) * time.Hour
|
s.CookieExpiration = time.Duration(viper.GetInt("session.cookie.expiration")) * time.Hour
|
||||||
s.CookieSecure = viper.GetBool("session.cookie.secure")
|
s.CookieSecure = viper.GetBool("session.cookie.secure")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Session) SetV2() {
|
||||||
|
if viper.IsSet("locks") {
|
||||||
|
locks := viper.GetStringSlice("locks")
|
||||||
|
for _, lock := range locks {
|
||||||
|
switch lock {
|
||||||
|
// TODO: file_transfer
|
||||||
|
case "control":
|
||||||
|
s.LockedControls = true
|
||||||
|
case "login":
|
||||||
|
s.LockedLogins = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_LOCKS' which is deprecated, please use 'NEKO_SESSION_LOCKED_CONTROLS' and 'NEKO_SESSION_LOCKED_LOGINS' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.IsSet("implicit_control") {
|
||||||
|
s.ImplicitHosting = viper.GetBool("implicit_control")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_IMPLICIT_CONTROL' which is deprecated, please use 'NEKO_SESSION_IMPLICIT_HOSTING' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("control_protection") {
|
||||||
|
s.ControlProtection = viper.GetBool("control_protection")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_CONTROL_PROTECTION' which is deprecated, please use 'NEKO_SESSION_CONTROL_PROTECTION' instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -166,6 +167,50 @@ func (WebRTC) Init(cmd *cobra.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (WebRTC) InitV2(cmd *cobra.Command) error {
|
||||||
|
cmd.PersistentFlags().String("epr", "", "limits the pool of ephemeral ports that ICE UDP connections can allocate from")
|
||||||
|
if err := viper.BindPFlag("epr", cmd.PersistentFlags().Lookup("epr")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().StringSlice("nat1to1", []string{}, "sets a list of external IP addresses of 1:1 (D)NAT and a candidate type for which the external IP address is used")
|
||||||
|
if err := viper.BindPFlag("nat1to1", cmd.PersistentFlags().Lookup("nat1to1")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Int("tcpmux", 0, "single TCP mux port for all peers")
|
||||||
|
if err := viper.BindPFlag("tcpmux", cmd.PersistentFlags().Lookup("tcpmux")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Int("udpmux", 0, "single UDP mux port for all peers")
|
||||||
|
if err := viper.BindPFlag("udpmux", cmd.PersistentFlags().Lookup("udpmux")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("ipfetch", "", "automatically fetch IP address from given URL when nat1to1 is not present")
|
||||||
|
if err := viper.BindPFlag("ipfetch", cmd.PersistentFlags().Lookup("ipfetch")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Bool("icelite", false, "configures whether or not the ice agent should be a lite agent")
|
||||||
|
if err := viper.BindPFlag("icelite", cmd.PersistentFlags().Lookup("icelite")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().StringSlice("iceserver", []string{}, "describes a single STUN and TURN server that can be used by the ICEAgent to establish a connection with a peer")
|
||||||
|
if err := viper.BindPFlag("iceserver", cmd.PersistentFlags().Lookup("iceserver")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("iceservers", "", "describes a single STUN and TURN server that can be used by the ICEAgent to establish a connection with a peer")
|
||||||
|
if err := viper.BindPFlag("iceservers", cmd.PersistentFlags().Lookup("iceservers")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *WebRTC) Set() {
|
func (s *WebRTC) Set() {
|
||||||
s.ICELite = viper.GetBool("webrtc.icelite")
|
s.ICELite = viper.GetBool("webrtc.icelite")
|
||||||
s.ICETrickle = viper.GetBool("webrtc.icetrickle")
|
s.ICETrickle = viper.GetBool("webrtc.icetrickle")
|
||||||
@ -271,3 +316,84 @@ func (s *WebRTC) Set() {
|
|||||||
s.Estimator.UpgradeBackoff = viper.GetDuration("webrtc.estimator.upgrade_backoff")
|
s.Estimator.UpgradeBackoff = viper.GetDuration("webrtc.estimator.upgrade_backoff")
|
||||||
s.Estimator.DiffThreshold = viper.GetFloat64("webrtc.estimator.diff_threshold")
|
s.Estimator.DiffThreshold = viper.GetFloat64("webrtc.estimator.diff_threshold")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *WebRTC) SetV2() {
|
||||||
|
if viper.IsSet("nat1to1") {
|
||||||
|
s.NAT1To1IPs = viper.GetStringSlice("nat1to1")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_NAT1TO1' which is deprecated, please use 'NEKO_WEBRTC_NAT1TO1' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("tcpmux") {
|
||||||
|
s.TCPMux = viper.GetInt("tcpmux")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_TCPMUX' which is deprecated, please use 'NEKO_WEBRTC_TCPMUX' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("udpmux") {
|
||||||
|
s.UDPMux = viper.GetInt("udpmux")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_UDPMUX' which is deprecated, please use 'NEKO_WEBRTC_UDPMUX' instead")
|
||||||
|
}
|
||||||
|
if viper.IsSet("icelite") {
|
||||||
|
s.ICELite = viper.GetBool("icelite")
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_ICELITE' which is deprecated, please use 'NEKO_WEBRTC_ICELITE' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.IsSet("iceservers") {
|
||||||
|
iceServers := []types.ICEServer{}
|
||||||
|
iceServersJson := viper.GetString("iceservers")
|
||||||
|
if iceServersJson != "" {
|
||||||
|
err := json.Unmarshal([]byte(iceServersJson), &iceServers)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic().Err(err).Msg("failed to process iceservers")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.ICEServersFrontend = iceServers
|
||||||
|
s.ICEServersBackend = iceServers
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_ICESERVERS' which is deprecated, please use 'NEKO_WEBRTC_ICESERVERS_FRONTEND' and/or 'NEKO_WEBRTC_ICESERVERS_BACKEND' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.IsSet("iceserver") {
|
||||||
|
iceServerSlice := viper.GetStringSlice("iceserver")
|
||||||
|
if len(iceServerSlice) > 0 {
|
||||||
|
s.ICEServersFrontend = append(s.ICEServersFrontend, types.ICEServer{URLs: iceServerSlice})
|
||||||
|
s.ICEServersBackend = append(s.ICEServersBackend, types.ICEServer{URLs: iceServerSlice})
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_ICESERVER' which is deprecated, please use 'NEKO_WEBRTC_ICESERVERS_FRONTEND' and/or 'NEKO_WEBRTC_ICESERVERS_BACKEND' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.IsSet("ipfetch") {
|
||||||
|
if len(s.NAT1To1IPs) == 0 {
|
||||||
|
ipfetch := viper.GetString("ipfetch")
|
||||||
|
ip, err := utils.HttpRequestGET(ipfetch)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic().Err(err).Str("ipfetch", ipfetch).Msg("failed to fetch ip address")
|
||||||
|
}
|
||||||
|
s.NAT1To1IPs = append(s.NAT1To1IPs, ip)
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_IPFETCH' which is deprecated, please use 'NEKO_WEBRTC_IP_RETRIEVAL_URL' instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.IsSet("epr") {
|
||||||
|
min := uint16(59000)
|
||||||
|
max := uint16(59100)
|
||||||
|
epr := viper.GetString("epr")
|
||||||
|
ports := strings.SplitN(epr, "-", -1)
|
||||||
|
if len(ports) > 1 {
|
||||||
|
start, err := strconv.ParseUint(ports[0], 10, 16)
|
||||||
|
if err == nil {
|
||||||
|
min = uint16(start)
|
||||||
|
}
|
||||||
|
|
||||||
|
end, err := strconv.ParseUint(ports[1], 10, 16)
|
||||||
|
if err == nil {
|
||||||
|
max = uint16(end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if min > max {
|
||||||
|
s.EphemeralMin = max
|
||||||
|
s.EphemeralMax = min
|
||||||
|
} else {
|
||||||
|
s.EphemeralMin = min
|
||||||
|
s.EphemeralMax = max
|
||||||
|
}
|
||||||
|
log.Warn().Msg("you are using v2 configuration 'NEKO_EPR' which is deprecated, please use 'NEKO_WEBRTC_EPR' instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -30,6 +30,18 @@ func (Config) Init(cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// v2 config
|
||||||
|
|
||||||
|
cmd.PersistentFlags().Bool("file_transfer_enabled", false, "enable file transfer feature")
|
||||||
|
if err := viper.BindPFlag("file_transfer_enabled", cmd.PersistentFlags().Lookup("file_transfer_enabled")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("file_transfer_path", "", "path to use for file transfer")
|
||||||
|
if err := viper.BindPFlag("file_transfer_path", cmd.PersistentFlags().Lookup("file_transfer_path")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,4 +50,14 @@ func (s *Config) Set() {
|
|||||||
rootDir := viper.GetString("filetransfer.dir")
|
rootDir := viper.GetString("filetransfer.dir")
|
||||||
s.RootDir = filepath.Clean(rootDir)
|
s.RootDir = filepath.Clean(rootDir)
|
||||||
s.RefreshInterval = viper.GetDuration("filetransfer.refresh_interval")
|
s.RefreshInterval = viper.GetDuration("filetransfer.refresh_interval")
|
||||||
|
|
||||||
|
// v2 config
|
||||||
|
|
||||||
|
if viper.IsSet("file_transfer_enabled") {
|
||||||
|
s.Enabled = viper.GetBool("file_transfer_enabled")
|
||||||
|
}
|
||||||
|
if viper.IsSet("file_transfer_path") {
|
||||||
|
rootDir = viper.GetString("file_transfer_path")
|
||||||
|
s.RootDir = filepath.Clean(rootDir)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user