Merge commit '6bd7fac875d9e9009915053d8a590abb372c5679' into feature/livekit-upgrade-1.13.1

This commit is contained in:
2026-06-25 23:54:33 +09:00
291 changed files with 37631 additions and 15381 deletions
+242 -104
View File
@@ -18,25 +18,30 @@ import (
"fmt"
"os"
"reflect"
"strconv"
"strings"
"time"
"github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v3"
"gopkg.in/yaml.v3"
"github.com/livekit/livekit-server/pkg/metric"
"github.com/livekit/livekit-server/pkg/sfu"
"github.com/livekit/livekit-server/pkg/sfu/bwe/remotebwe"
"github.com/livekit/livekit-server/pkg/sfu/bwe/sendsidebwe"
"github.com/livekit/livekit-server/pkg/sfu/mime"
"github.com/livekit/livekit-server/pkg/sfu/streamallocator"
"github.com/livekit/mediatransportutil/pkg/rtcconfig"
"github.com/livekit/protocol/codecs/mime"
"github.com/livekit/protocol/livekit"
"github.com/livekit/protocol/logger"
redisLiveKit "github.com/livekit/protocol/redis"
"github.com/livekit/protocol/rpc"
"github.com/livekit/protocol/webhook"
"github.com/livekit/livekit-server/pkg/agent"
"github.com/livekit/livekit-server/pkg/metric"
"github.com/livekit/livekit-server/pkg/sfu"
"github.com/livekit/livekit-server/pkg/sfu/bwe/remotebwe"
"github.com/livekit/livekit-server/pkg/sfu/bwe/sendsidebwe"
"github.com/livekit/livekit-server/pkg/sfu/pacer"
"github.com/livekit/livekit-server/pkg/sfu/streamallocator"
)
const (
@@ -44,8 +49,9 @@ const (
)
var (
ErrKeyFileIncorrectPermission = errors.New("key file others permissions must be set to 0")
ErrKeysNotSet = errors.New("one of key-file or keys must be provided")
ErrKeyFileIncorrectPermission = errors.New("key file others permissions must be set to 0")
ErrTURNSecretFileIncorrectPermission = errors.New("turn secret file others permissions must be set to 0")
ErrKeysNotSet = errors.New("one of key-file or keys must be provided")
)
type Config struct {
@@ -62,7 +68,7 @@ type Config struct {
TURN TURNConfig `yaml:"turn,omitempty"`
Ingress IngressConfig `yaml:"ingress,omitempty"`
SIP SIPConfig `yaml:"sip,omitempty"`
WebHook WebHookConfig `yaml:"webhook,omitempty"`
WebHook webhook.WebHookConfig `yaml:"webhook,omitempty"`
NodeSelector NodeSelectorConfig `yaml:"node_selector,omitempty"`
KeyFile string `yaml:"key_file,omitempty"`
Keys map[string]string `yaml:"keys,omitempty"`
@@ -73,10 +79,18 @@ type Config struct {
LogLevel string `yaml:"log_level,omitempty"`
Logging LoggingConfig `yaml:"logging,omitempty"`
Limit LimitConfig `yaml:"limit,omitempty"`
Agents agent.Config `yaml:"agents,omitempty"`
Development bool `yaml:"development,omitempty"`
Metric metric.MetricConfig `yaml:"metric,omitempty"`
Trace TracingConfig `yaml:"trace,omitempty"`
NodeStats NodeStatsConfig `yaml:"node_stats,omitempty"`
EnableDataTracks bool `yaml:"enable_data_tracks,omitempty"`
API APIConfig `yaml:"api,omitempty"`
}
type RTCConfig struct {
@@ -102,6 +116,18 @@ type RTCConfig struct {
// allow TCP and TURN/TLS fallback
AllowTCPFallback *bool `yaml:"allow_tcp_fallback,omitempty"`
// Signaling RTT threshold (in milliseconds) governing ICE/TCP fallback. On a UDP
// failure, ICE/TCP is attempted only while the measured signaling RTT is below this
// value; at or above it, supporting clients fall back directly to TURN/TLS. When 0
// (the default), the RTT check is disabled and ICE/TCP is always attempted (for
// clients that support it). A positive value also gates allow_udp_unstable_fallback.
TCPFallbackRTTThreshold int `yaml:"tcp_fallback_rtt_threshold,omitempty"`
// When enabled, an established UDP connection reporting sustained high packet loss is
// migrated to ICE/TCP or TURN/TLS. Requires tcp_fallback_rtt_threshold to be set
// (> 0). Disabled by default.
AllowUDPUnstableFallback bool `yaml:"allow_udp_unstable_fallback,omitempty"`
// force a reconnect on a publication error
ReconnectOnPublicationError *bool `yaml:"reconnect_on_publication_error,omitempty"`
@@ -118,7 +144,13 @@ type RTCConfig struct {
// be dropped for a slow data channel to avoid blocking the room.
DatachannelSlowThreshold int `yaml:"datachannel_slow_threshold,omitempty"`
// Target latency for lossy data channels, used to drop packets to reduce latency.
DatachannelLossyTargetLatency time.Duration `yaml:"datachannel_lossy_target_latency,omitempty"`
ForwardStats ForwardStatsConfig `yaml:"forward_stats,omitempty"`
// enable rtp stream restart detection for published tracks
EnableRTPStreamRestartDetection bool `yaml:"enable_rtp_stream_restart_detection,omitempty"`
}
type TURNServer struct {
@@ -127,6 +159,14 @@ type TURNServer struct {
Protocol string `yaml:"protocol,omitempty"`
Username string `yaml:"username,omitempty"`
Credential string `yaml:"credential,omitempty"`
// Secret is used for TURN static auth secrets mechanism. When provided,
// dynamic credentials are generated using HMAC-SHA1 instead of static Username/Credential
Secret string `yaml:"secret,omitempty"`
// File containing the secret
SecretFile string `yaml:"secret_file,omitempty"`
// TTL is the time-to-live in seconds for generated credentials when using Secret.
// Defaults to 14400 seconds (4 hours) if not specified
TTL int `yaml:"ttl,omitempty"`
}
type CongestionControlConfig struct {
@@ -139,8 +179,9 @@ type CongestionControlConfig struct {
UseSendSideBWEInterceptor bool `yaml:"use_send_side_bwe_interceptor,omitempty"`
UseSendSideBWE bool `yaml:"use_send_side_bwe,omitempty"`
SendSideBWE sendsidebwe.SendSideBWEConfig `yaml:"send_side_bwe,omitempty"`
UseSendSideBWE bool `yaml:"use_send_side_bwe,omitempty"`
SendSideBWEPacer string `yaml:"send_side_bwe_pacer,omitempty"`
SendSideBWE sendsidebwe.SendSideBWEConfig `yaml:"send_side_bwe,omitempty"`
}
type PlayoutDelayConfig struct {
@@ -152,6 +193,8 @@ type PlayoutDelayConfig struct {
type VideoConfig struct {
DynacastPauseDelay time.Duration `yaml:"dynacast_pause_delay,omitempty"`
StreamTrackerManager sfu.StreamTrackerManagerConfig `yaml:"stream_tracker_manager,omitempty"`
CodecRegressionThreshold int `yaml:"codec_regression_threshold,omitempty"`
}
type RoomConfig struct {
@@ -167,6 +210,8 @@ type RoomConfig struct {
CreateRoomEnabled bool `yaml:"create_room_enabled,omitempty"`
CreateRoomTimeout time.Duration `yaml:"create_room_timeout,omitempty"`
CreateRoomAttempts int `yaml:"create_room_attempts,omitempty"`
// target room participant update batch chunk size in bytes
UpdateBatchTargetSize int `yaml:"update_batch_target_size,omitempty"`
// deprecated, moved to limits
MaxMetadataSize uint32 `yaml:"max_metadata_size,omitempty"`
// deprecated, moved to limits
@@ -187,26 +232,33 @@ type LoggingConfig struct {
}
type TURNConfig struct {
Enabled bool `yaml:"enabled,omitempty"`
Domain string `yaml:"domain,omitempty"`
CertFile string `yaml:"cert_file,omitempty"`
KeyFile string `yaml:"key_file,omitempty"`
TLSPort int `yaml:"tls_port,omitempty"`
UDPPort int `yaml:"udp_port,omitempty"`
RelayPortRangeStart uint16 `yaml:"relay_range_start,omitempty"`
RelayPortRangeEnd uint16 `yaml:"relay_range_end,omitempty"`
ExternalTLS bool `yaml:"external_tls,omitempty"`
}
type WebHookConfig struct {
URLs []string `yaml:"urls,omitempty"`
// key to use for webhook
APIKey string `yaml:"api_key,omitempty"`
Enabled bool `yaml:"enabled,omitempty"`
Domain string `yaml:"domain,omitempty"`
CertFile string `yaml:"cert_file,omitempty"`
KeyFile string `yaml:"key_file,omitempty"`
TLSPort int `yaml:"tls_port,omitempty"`
UDPPort int `yaml:"udp_port,omitempty"`
RelayPortRangeStart uint16 `yaml:"relay_range_start,omitempty"`
RelayPortRangeEnd uint16 `yaml:"relay_range_end,omitempty"`
ExternalTLS bool `yaml:"external_tls,omitempty"`
BindAddresses []string `yaml:"bind_addresses,omitempty"`
// TTL of the TURN credentials in seconds - defaults to 300
TTLSeconds int `yaml:"ttl_seconds,omitempty"`
// list of restricted peer CIDRs (loopback, link-local (unicast, multicast), multicast, private, unspecified) to allow access to.
// By default (i. e. empty list), all restricted peer CIDRs are denied access.
// When not empty, only the specified CIDRs are allowed access.
// Note that this check is applied to restricted peer CIDRs only.
AllowRestrictedPeerCIDRs []string `yaml:"allow_restricted_peer_cidrs,omitempty"`
// list of peer CIDRs to deny access to
// This applies to all peer CIDRs, including restricted ones.
// Deny list takes precedence over allow list.
DenyPeerCIDRs []string `yaml:"deny_peer_cidrs,omitempty"`
}
type NodeSelectorConfig struct {
Kind string `yaml:"kind,omitempty"`
SortBy string `yaml:"sort_by,omitempty"`
Algorithm string `yaml:"algorithm,omitempty"`
CPULoadLimit float32 `yaml:"cpu_load_limit,omitempty"`
SysloadLimit float32 `yaml:"sysload_limit,omitempty"`
Regions []RegionConfig `yaml:"regions,omitempty"`
@@ -245,6 +297,10 @@ func (l LimitConfig) CheckRoomNameLength(name string) bool {
return l.MaxRoomNameLength == 0 || len(name) <= l.MaxRoomNameLength
}
func (l LimitConfig) CheckParticipantIdentityLength(identity string) bool {
return l.MaxParticipantIdentityLength == 0 || len(identity) <= l.MaxParticipantIdentityLength
}
func (l LimitConfig) CheckParticipantNameLength(name string) bool {
return l.MaxParticipantNameLength == 0 || len(name) <= l.MaxParticipantNameLength
}
@@ -281,6 +337,9 @@ type APIConfig struct {
// max amount of time to wait before checking for operation complete
MaxCheckInterval time.Duration `yaml:"max_check_interval,omitempty"`
// Backwards compatibility for room service api calls, will enable by default and remove in a future release
EnablePsrpcForGetListParticpants bool `yaml:"enable_psrpc_for_get_list_participants,omitempty"`
}
type PrometheusConfig struct {
@@ -295,6 +354,13 @@ type ForwardStatsConfig struct {
ReportWindow time.Duration `yaml:"report_window,omitempty"`
}
type TracingConfig struct {
// JaegerURL configures Jaeger as a global tracer.
//
// The following formats are supported: <hostname>, <host>:<port>, http(s)://<host>/<path>
JaegerURL string `yaml:"jaeger_url,omitempty"`
}
func DefaultAPIConfig() APIConfig {
return APIConfig{
ExecutionTimeout: 2 * time.Second,
@@ -303,6 +369,18 @@ func DefaultAPIConfig() APIConfig {
}
}
type NodeStatsConfig struct {
StatsUpdateInterval time.Duration `yaml:"stats_update_interval,omitempty"`
StatsRateMeasurementIntervals []time.Duration `yaml:"stats_rate_measurement_intervals,omitempty"`
StatsMaxDelay time.Duration `yaml:"stats_max_delay,omitempty"`
}
var DefaultNodeStatsConfig = NodeStatsConfig{
StatsUpdateInterval: 2 * time.Second,
StatsRateMeasurementIntervals: []time.Duration{10 * time.Second},
StatsMaxDelay: 30 * time.Second,
}
var DefaultConfig = Config{
Port: 7880,
RTC: RTCConfig{
@@ -324,31 +402,37 @@ var DefaultConfig = Config{
RemoteBWE: remotebwe.DefaultRemoteBWEConfig,
UseSendSideBWEInterceptor: false,
UseSendSideBWE: false,
SendSideBWEPacer: string(pacer.PacerBehaviorNoQueue),
SendSideBWE: sendsidebwe.DefaultSendSideBWEConfig,
},
},
Audio: sfu.DefaultAudioConfig,
Video: VideoConfig{
DynacastPauseDelay: 5 * time.Second,
StreamTrackerManager: sfu.DefaultStreamTrackerManagerConfig,
DynacastPauseDelay: 5 * time.Second,
StreamTrackerManager: sfu.DefaultStreamTrackerManagerConfig,
CodecRegressionThreshold: 5,
},
Redis: redisLiveKit.RedisConfig{},
Room: RoomConfig{
AutoCreate: true,
EnabledCodecs: []CodecSpec{
{Mime: mime.MimeTypePCMU.String()},
{Mime: mime.MimeTypePCMA.String()},
{Mime: mime.MimeTypeOpus.String()},
{Mime: mime.MimeTypeRED.String()},
{Mime: mime.MimeTypeVP8.String()},
{Mime: mime.MimeTypeH264.String()},
{Mime: mime.MimeTypeVP9.String()},
{Mime: mime.MimeTypeAV1.String()},
{Mime: mime.MimeTypeH265.String()},
{Mime: mime.MimeTypeRTX.String()},
},
EmptyTimeout: 5 * 60,
DepartureTimeout: 20,
CreateRoomEnabled: true,
CreateRoomTimeout: 10 * time.Second,
CreateRoomAttempts: 3,
EmptyTimeout: 5 * 60,
DepartureTimeout: 20,
CreateRoomEnabled: true,
CreateRoomTimeout: 10 * time.Second,
CreateRoomAttempts: 3,
UpdateBatchTargetSize: 128 * 1024,
},
Limit: LimitConfig{
MaxMetadataSize: 64000,
@@ -361,13 +445,16 @@ var DefaultConfig = Config{
PionLevel: "error",
},
TURN: TURNConfig{
Enabled: false,
Enabled: false,
BindAddresses: []string{"0.0.0.0"},
TTLSeconds: 300,
},
NodeSelector: NodeSelectorConfig{
Kind: "any",
SortBy: "random",
SysloadLimit: 0.9,
CPULoadLimit: 0.9,
Algorithm: "lowest",
},
SignalRelay: SignalRelayConfig{
RetryTimeout: 7500 * time.Millisecond,
@@ -376,12 +463,19 @@ var DefaultConfig = Config{
StreamBufferSize: 1000,
ConnectAttempts: 3,
},
PSRPC: rpc.DefaultPSRPCConfig,
Keys: map[string]string{},
Metric: metric.DefaultMetricConfig,
Agents: agent.Config{
TargetLoad: agent.DefaultTargetLoad,
},
PSRPC: rpc.DefaultPSRPCConfig,
Keys: map[string]string{},
Metric: metric.DefaultMetricConfig,
WebHook: webhook.DefaultWebHookConfig,
NodeStats: DefaultNodeStatsConfig,
API: DefaultAPIConfig(),
EnableDataTracks: true,
}
func NewConfig(confString string, strictMode bool, c *cli.Context, baseFlags []cli.Flag) (*Config, error) {
func NewConfig(confString string, strictMode bool, c *cli.Command, baseFlags []cli.Flag) (*Config, error) {
// start with defaults
marshalled, err := yaml.Marshal(&DefaultConfig)
if err != nil {
@@ -563,74 +657,110 @@ func (conf *Config) ValidateKeys() error {
return nil
}
func (conf *Config) LoadTURNSecrets() error {
var otherFilter os.FileMode = 0o007
for i, s := range conf.RTC.TURNServers {
if s.SecretFile == "" {
continue
}
if s.Secret != "" {
logger.Warnw("both secret and secret_file are set for TURN server, the hardcoded secret will be used", nil,
"host", s.Host, "port", s.Port)
continue
}
st, err := os.Stat(s.SecretFile)
if err != nil {
return err
}
if st.Mode().Perm()&otherFilter != 0o000 {
return ErrTURNSecretFileIncorrectPermission
}
data, err := os.ReadFile(s.SecretFile)
if err != nil {
return fmt.Errorf("reading turn secret file %q: %w", s.SecretFile, err)
}
conf.RTC.TURNServers[i].Secret = strings.TrimSpace(string(data))
}
return nil
}
func GenerateCLIFlags(existingFlags []cli.Flag, hidden bool) ([]cli.Flag, error) {
blankConfig := &Config{}
defaultConfig := &DefaultConfig
flags := make([]cli.Flag, 0)
for name, value := range blankConfig.ToCLIFlagNames(existingFlags) {
for name, value := range (defaultConfig).ToCLIFlagNames(existingFlags) {
kind := value.Kind()
if kind == reflect.Ptr {
kind = value.Type().Elem().Kind()
}
var flag cli.Flag
envVar := fmt.Sprintf("LIVEKIT_%s", strings.ToUpper(strings.Replace(name, ".", "_", -1)))
envVar := fmt.Sprintf("LIVEKIT_%s", strings.ToUpper(strings.ReplaceAll(name, ".", "_")))
defaultText := cliDefaultText(value)
switch kind {
case reflect.Bool:
flag = &cli.BoolFlag{
Name: name,
EnvVars: []string{envVar},
Usage: generatedCLIFlagUsage,
Hidden: hidden,
Name: name,
Sources: cli.EnvVars(envVar),
Usage: generatedCLIFlagUsage,
DefaultText: defaultText,
Hidden: hidden,
}
case reflect.String:
flag = &cli.StringFlag{
Name: name,
EnvVars: []string{envVar},
Usage: generatedCLIFlagUsage,
Hidden: hidden,
Name: name,
Sources: cli.EnvVars(envVar),
Usage: generatedCLIFlagUsage,
DefaultText: defaultText,
Hidden: hidden,
}
case reflect.Int, reflect.Int32:
flag = &cli.IntFlag{
Name: name,
EnvVars: []string{envVar},
Usage: generatedCLIFlagUsage,
Hidden: hidden,
Name: name,
Sources: cli.EnvVars(envVar),
Usage: generatedCLIFlagUsage,
DefaultText: defaultText,
Hidden: hidden,
}
case reflect.Int64:
flag = &cli.Int64Flag{
Name: name,
EnvVars: []string{envVar},
Usage: generatedCLIFlagUsage,
Hidden: hidden,
Name: name,
Sources: cli.EnvVars(envVar),
Usage: generatedCLIFlagUsage,
DefaultText: defaultText,
Hidden: hidden,
}
case reflect.Uint8, reflect.Uint16, reflect.Uint32:
flag = &cli.UintFlag{
Name: name,
EnvVars: []string{envVar},
Usage: generatedCLIFlagUsage,
Hidden: hidden,
Name: name,
Sources: cli.EnvVars(envVar),
Usage: generatedCLIFlagUsage,
DefaultText: defaultText,
Hidden: hidden,
}
case reflect.Uint64:
flag = &cli.Uint64Flag{
Name: name,
EnvVars: []string{envVar},
Usage: generatedCLIFlagUsage,
Hidden: hidden,
Name: name,
Sources: cli.EnvVars(envVar),
Usage: generatedCLIFlagUsage,
DefaultText: defaultText,
Hidden: hidden,
}
case reflect.Float32:
flag = &cli.Float64Flag{
Name: name,
EnvVars: []string{envVar},
Usage: generatedCLIFlagUsage,
Hidden: hidden,
Name: name,
Sources: cli.EnvVars(envVar),
Usage: generatedCLIFlagUsage,
DefaultText: defaultText,
Hidden: hidden,
}
case reflect.Float64:
flag = &cli.Float64Flag{
Name: name,
EnvVars: []string{envVar},
Usage: generatedCLIFlagUsage,
Hidden: hidden,
Name: name,
Sources: cli.EnvVars(envVar),
Usage: generatedCLIFlagUsage,
DefaultText: defaultText,
Hidden: hidden,
}
case reflect.Slice:
// TODO
@@ -651,13 +781,39 @@ func GenerateCLIFlags(existingFlags []cli.Flag, hidden bool) ([]cli.Flag, error)
return flags, nil
}
func (conf *Config) updateFromCLI(c *cli.Context, baseFlags []cli.Flag) error {
func cliDefaultText(value reflect.Value) string {
if value.Kind() == reflect.Ptr {
if value.IsNil() {
return ""
}
value = value.Elem()
}
switch value.Kind() {
case reflect.Bool:
return strconv.FormatBool(value.Bool())
case reflect.String:
return value.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if value.Type() == reflect.TypeOf(time.Duration(0)) {
return value.Interface().(time.Duration).String()
}
return strconv.FormatInt(value.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return strconv.FormatUint(value.Uint(), 10)
case reflect.Float32, reflect.Float64:
return strconv.FormatFloat(value.Float(), 'f', -1, 64)
default:
return ""
}
}
func (conf *Config) updateFromCLI(c *cli.Command, baseFlags []cli.Flag) error {
generatedFlagNames := conf.ToCLIFlagNames(baseFlags)
for _, flag := range c.App.Flags {
for _, flag := range c.Flags {
flagName := flag.Names()[0]
// the `c.App.Name != "test"` check is needed because `c.IsSet(...)` is always false in unit tests
if !c.IsSet(flagName) && c.App.Name != "test" {
if !c.IsSet(flagName) {
continue
}
@@ -666,34 +822,16 @@ func (conf *Config) updateFromCLI(c *cli.Context, baseFlags []cli.Flag) error {
continue
}
kind := configValue.Kind()
if kind == reflect.Ptr {
// instantiate value to be set
if configValue.Kind() == reflect.Ptr {
configValue.Set(reflect.New(configValue.Type().Elem()))
kind = configValue.Type().Elem().Kind()
configValue = configValue.Elem()
}
switch kind {
case reflect.Bool:
configValue.SetBool(c.Bool(flagName))
case reflect.String:
configValue.SetString(c.String(flagName))
case reflect.Int, reflect.Int32, reflect.Int64:
configValue.SetInt(c.Int64(flagName))
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
configValue.SetUint(c.Uint64(flagName))
case reflect.Float32:
configValue.SetFloat(c.Float64(flagName))
case reflect.Float64:
configValue.SetFloat(c.Float64(flagName))
// case reflect.Slice:
// // TODO
// case reflect.Map:
// // TODO
default:
return fmt.Errorf("unsupported generated cli flag type for config: %s is a %s", flagName, kind.String())
value := reflect.ValueOf(c.Value(flagName))
if value.CanConvert(configValue.Type()) {
configValue.Set(value.Convert(configValue.Type()))
} else {
return fmt.Errorf("unsupported generated cli flag type for config: %s (expected %s, got %s)", flagName, configValue.Type(), value.Type())
}
}
@@ -724,7 +862,7 @@ func (conf *Config) updateFromCLI(c *cli.Context, baseFlags []cli.Flag) error {
conf.TURN.KeyFile = c.String("turn-key")
}
if c.IsSet("node-ip") {
conf.RTC.NodeIP = c.String("node-ip")
conf.RTC.NodeIP.UnmarshalString(c.String("node-ip"))
}
if c.IsSet("udp-port") {
conf.RTC.UDPPort.UnmarshalString(c.String("udp-port"))
@@ -736,7 +874,7 @@ func (conf *Config) updateFromCLI(c *cli.Context, baseFlags []cli.Flag) error {
}
func (conf *Config) unmarshalKeys(keys string) error {
temp := make(map[string]interface{})
temp := make(map[string]any)
if err := yaml.Unmarshal([]byte(keys), temp); err != nil {
return err
}
+10 -13
View File
@@ -15,11 +15,10 @@
package config
import (
"flag"
"testing"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v3"
"github.com/livekit/livekit-server/pkg/config/configtest"
)
@@ -53,19 +52,17 @@ func TestGeneratedFlags(t *testing.T) {
generatedFlags, err := GenerateCLIFlags(nil, false)
require.NoError(t, err)
app := cli.NewApp()
app.Name = "test"
app.Flags = append(app.Flags, generatedFlags...)
c := &cli.Command{}
c.Name = "test"
c.Flags = append(c.Flags, generatedFlags...)
set := flag.NewFlagSet("test", 0)
set.Bool("rtc.use_ice_lite", true, "") // bool
set.String("redis.address", "localhost:6379", "") // string
set.Uint("prometheus.port", 9999, "") // uint32
set.Bool("rtc.allow_tcp_fallback", true, "") // pointer
set.Bool("rtc.reconnect_on_publication_error", true, "") // pointer
set.Bool("rtc.reconnect_on_subscription_error", false, "") // pointer
c.Set("rtc.use_ice_lite", "true")
c.Set("redis.address", "localhost:6379")
c.Set("prometheus.port", "9999")
c.Set("rtc.allow_tcp_fallback", "true")
c.Set("rtc.reconnect_on_publication_error", "true")
c.Set("rtc.reconnect_on_subscription_error", "false")
c := cli.NewContext(app, set, nil)
conf, err := NewConfig("", true, c, nil)
require.NoError(t, err)