mirror of
https://github.com/livekit/livekit.git
synced 2026-03-30 02:39:54 +00:00
Added Xiaomi 2201117TI to devices that does not support H.264 (#1728)
This commit is contained in:
2
go.mod
2
go.mod
@@ -18,7 +18,7 @@ require (
|
||||
github.com/jxskiss/base62 v1.1.0
|
||||
github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1
|
||||
github.com/livekit/mediatransportutil v0.0.0-20230523035537-27577c4e1646
|
||||
github.com/livekit/protocol v1.5.7-0.20230522074955-efad03ffe4d0
|
||||
github.com/livekit/protocol v1.5.7
|
||||
github.com/livekit/psrpc v0.3.1-0.20230518234341-6f6847e10b09
|
||||
github.com/mackerelio/go-osstat v0.2.4
|
||||
github.com/magefile/mage v1.14.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -121,8 +121,8 @@ github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 h1:jm09419p0lqTkD
|
||||
github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ=
|
||||
github.com/livekit/mediatransportutil v0.0.0-20230523035537-27577c4e1646 h1:acGSGkWJdut7TUWozCDheHu4dwWFDqqRzv+SBbIY9Xo=
|
||||
github.com/livekit/mediatransportutil v0.0.0-20230523035537-27577c4e1646/go.mod h1:MRc0zSOSzXuFt0X218SgabzlaKevkvCckPgBEoHYc34=
|
||||
github.com/livekit/protocol v1.5.7-0.20230522074955-efad03ffe4d0 h1:s2essRiWF//fVVBhjmxgjLHetpKYQ2QJfzi5w1a8rOA=
|
||||
github.com/livekit/protocol v1.5.7-0.20230522074955-efad03ffe4d0/go.mod h1:ZaOnsvP+JS4s7vI1UO+JVdBagvvLp/lBXDAl2hkDS0I=
|
||||
github.com/livekit/protocol v1.5.7 h1:jZeFQEmLuIhFblXDGPRCBbfjVJHb+YU7AsO+SMoXF70=
|
||||
github.com/livekit/protocol v1.5.7/go.mod h1:ZaOnsvP+JS4s7vI1UO+JVdBagvvLp/lBXDAl2hkDS0I=
|
||||
github.com/livekit/psrpc v0.3.1-0.20230518234341-6f6847e10b09 h1:mb6jRcg57U0HQ4tKRsueHHKcvTqBinL6+0Aa84vTtWk=
|
||||
github.com/livekit/psrpc v0.3.1-0.20230518234341-6f6847e10b09/go.mod h1:n6JntEg+zT6Ji8InoyTpV7wusPNwGqqtxmHlkNhDN0U=
|
||||
github.com/mackerelio/go-osstat v0.2.4 h1:qxGbdPkFo65PXOb/F/nhDKpF2nGmGaCFDLXoZjJTtUs=
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package clientconfiguration
|
||||
|
||||
// configurations for livekit-client, add more configuration to StaticConfigurations as need
|
||||
import (
|
||||
"github.com/livekit/protocol/livekit"
|
||||
)
|
||||
|
||||
// StaticConfigurations list specific device-side limitations that should be disabled at a global level
|
||||
var StaticConfigurations = []ConfigurationItem{
|
||||
// {
|
||||
// Match: &ScriptMatch{Expr: `c.protocol <= 5 || c.browser == "firefox"`},
|
||||
@@ -14,4 +18,13 @@ var StaticConfigurations = []ConfigurationItem{
|
||||
// }}},
|
||||
// Merge: false,
|
||||
// },
|
||||
{
|
||||
Match: &ScriptMatch{Expr: `c.device_model == "Xiaomi 2201117TI" && c.os == "android"`},
|
||||
Configuration: &livekit.ClientConfiguration{
|
||||
DisabledCodecs: &livekit.DisabledCodecs{
|
||||
Publish: []*livekit.Codec{{Mime: "video/h264"}},
|
||||
},
|
||||
},
|
||||
Merge: false,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -95,18 +95,32 @@ func NewTransportManager(params TransportManagerParams) (*TransportManager, erro
|
||||
}
|
||||
t.mediaLossProxy.OnMediaLossUpdate(t.onMediaLossUpdate)
|
||||
|
||||
enabledCodecs := make([]*livekit.Codec, 0, len(params.EnabledCodecs))
|
||||
for _, c := range params.EnabledCodecs {
|
||||
var disabled bool
|
||||
for _, disableCodec := range params.ClientConf.GetDisabledCodecs().GetCodecs() {
|
||||
subscribeCodecs := make([]*livekit.Codec, 0, len(params.EnabledCodecs))
|
||||
publishCodecs := make([]*livekit.Codec, 0, len(params.EnabledCodecs))
|
||||
shouldDisable := func(c *livekit.Codec, disabledCodecs []*livekit.Codec) bool {
|
||||
for _, disableCodec := range disabledCodecs {
|
||||
// disable codec's fmtp is empty means disable this codec entirely
|
||||
if strings.EqualFold(c.Mime, disableCodec.Mime) && (disableCodec.FmtpLine == "" || disableCodec.FmtpLine == c.FmtpLine) {
|
||||
disabled = true
|
||||
break
|
||||
return true
|
||||
}
|
||||
}
|
||||
if !disabled {
|
||||
enabledCodecs = append(enabledCodecs, c)
|
||||
return false
|
||||
}
|
||||
for _, c := range params.EnabledCodecs {
|
||||
var publishDisabled bool
|
||||
var subscribeDisabled bool
|
||||
if shouldDisable(c, params.ClientConf.GetDisabledCodecs().GetCodecs()) {
|
||||
publishDisabled = true
|
||||
subscribeDisabled = true
|
||||
}
|
||||
if shouldDisable(c, params.ClientConf.GetDisabledCodecs().GetPublish()) {
|
||||
publishDisabled = true
|
||||
}
|
||||
if !publishDisabled {
|
||||
publishCodecs = append(publishCodecs, c)
|
||||
}
|
||||
if !subscribeDisabled {
|
||||
subscribeCodecs = append(subscribeCodecs, c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +132,7 @@ func NewTransportManager(params TransportManagerParams) (*TransportManager, erro
|
||||
DirectionConfig: params.Config.Publisher,
|
||||
CongestionControlConfig: params.CongestionControlConfig,
|
||||
Telemetry: params.Telemetry,
|
||||
EnabledCodecs: enabledCodecs,
|
||||
EnabledCodecs: publishCodecs,
|
||||
Logger: LoggerWithPCTarget(params.Logger, livekit.SignalTarget_PUBLISHER),
|
||||
SimTracks: params.SimTracks,
|
||||
ClientInfo: params.ClientInfo,
|
||||
@@ -150,7 +164,7 @@ func NewTransportManager(params TransportManagerParams) (*TransportManager, erro
|
||||
DirectionConfig: params.Config.Subscriber,
|
||||
CongestionControlConfig: params.CongestionControlConfig,
|
||||
Telemetry: params.Telemetry,
|
||||
EnabledCodecs: enabledCodecs,
|
||||
EnabledCodecs: subscribeCodecs,
|
||||
Logger: LoggerWithPCTarget(params.Logger, livekit.SignalTarget_SUBSCRIBER),
|
||||
ClientInfo: params.ClientInfo,
|
||||
IsOfferer: true,
|
||||
|
||||
@@ -48,6 +48,7 @@ type RTCClient struct {
|
||||
publisherFullyEstablished atomic.Bool
|
||||
subscriberFullyEstablished atomic.Bool
|
||||
pongReceivedAt atomic.Int64
|
||||
lastAnswer atomic.Pointer[webrtc.SessionDescription]
|
||||
|
||||
// tracks waiting to be acked, cid => trackInfo
|
||||
pendingPublishedTracks map[string]*livekit.TrackInfo
|
||||
@@ -81,6 +82,7 @@ var (
|
||||
type Options struct {
|
||||
AutoSubscribe bool
|
||||
Publish string
|
||||
ClientInfo *livekit.ClientInfo
|
||||
}
|
||||
|
||||
func NewWebSocketConn(host, token string, opts *Options) (*websocket.Conn, error) {
|
||||
@@ -93,8 +95,18 @@ func NewWebSocketConn(host, token string, opts *Options) (*websocket.Conn, error
|
||||
|
||||
connectUrl := u.String()
|
||||
if opts != nil {
|
||||
connectUrl = fmt.Sprintf("%s&auto_subscribe=%t&publish=%s",
|
||||
connectUrl, opts.AutoSubscribe, opts.Publish)
|
||||
connectUrl = fmt.Sprintf("%s&auto_subscribe=%t", connectUrl, opts.AutoSubscribe)
|
||||
if opts.Publish != "" {
|
||||
connectUrl += encodeQueryParam("publish", opts.Publish)
|
||||
}
|
||||
if opts.ClientInfo != nil {
|
||||
if opts.ClientInfo.DeviceModel != "" {
|
||||
connectUrl += encodeQueryParam("device_model", opts.ClientInfo.DeviceModel)
|
||||
}
|
||||
if opts.ClientInfo.Os != "" {
|
||||
connectUrl += encodeQueryParam("os", opts.ClientInfo.Os)
|
||||
}
|
||||
}
|
||||
}
|
||||
conn, _, err := websocket.DefaultDialer.Dial(connectUrl, requestHeader)
|
||||
return conn, err
|
||||
@@ -610,6 +622,11 @@ func (c *RTCClient) GetPublishedTrackIDs() []string {
|
||||
return trackIDs
|
||||
}
|
||||
|
||||
// LastAnswer return SDP of the last answer for the publisher connection
|
||||
func (c *RTCClient) LastAnswer() *webrtc.SessionDescription {
|
||||
return c.lastAnswer.Load()
|
||||
}
|
||||
|
||||
func (c *RTCClient) ensurePublisherConnected() error {
|
||||
if c.publisher.HasEverConnected() {
|
||||
return nil
|
||||
@@ -654,6 +671,8 @@ func (c *RTCClient) handleOffer(desc webrtc.SessionDescription) {
|
||||
// the client handles answer on the publisher PC
|
||||
func (c *RTCClient) handleAnswer(desc webrtc.SessionDescription) {
|
||||
logger.Infow("handling server answer", "participant", c.localParticipant.Identity)
|
||||
|
||||
c.lastAnswer.Store(&desc)
|
||||
// remote answered the offer, establish connection
|
||||
c.publisher.HandleRemoteDescription(desc)
|
||||
}
|
||||
@@ -744,3 +763,7 @@ func (c *RTCClient) SendNacks(count int) {
|
||||
|
||||
_ = c.subscriber.WriteRTCP(packets)
|
||||
}
|
||||
|
||||
func encodeQueryParam(key, value string) string {
|
||||
return fmt.Sprintf("&%s=%s", url.QueryEscape(key), url.QueryEscape(value))
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pion/sdp/v3"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/thoas/go-funk"
|
||||
@@ -22,6 +23,11 @@ import (
|
||||
testclient "github.com/livekit/livekit-server/test/client"
|
||||
)
|
||||
|
||||
const (
|
||||
waitTick = 10 * time.Millisecond
|
||||
waitTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
func TestClientCouldConnect(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.SkipNow()
|
||||
@@ -477,3 +483,63 @@ func TestSingleNodeUpdateSubscriptionPermissions(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestDeviceCodecOverride checks that codecs that are incompatible with a device is not
|
||||
// negotiated by the server
|
||||
func TestDeviceCodecOverride(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.SkipNow()
|
||||
return
|
||||
}
|
||||
|
||||
_, finish := setupSingleNodeTest("TestDeviceCodecOverride")
|
||||
defer finish()
|
||||
|
||||
// simulate device that isn't compatible with H.264
|
||||
c1 := createRTCClient("c1", defaultServerPort, &testclient.Options{
|
||||
ClientInfo: &livekit.ClientInfo{
|
||||
Os: "android",
|
||||
DeviceModel: "Xiaomi 2201117TI",
|
||||
},
|
||||
})
|
||||
defer c1.Stop()
|
||||
waitUntilConnected(t, c1)
|
||||
|
||||
// it doesn't really matter what the codec set here is, uses default Pion MediaEngine codecs
|
||||
tw, err := c1.AddStaticTrack("video/h264", "video", "webcam")
|
||||
require.NoError(t, err)
|
||||
defer stopWriters(tw)
|
||||
|
||||
// wait for server to receive track
|
||||
require.Eventually(t, func() bool {
|
||||
return c1.LastAnswer() != nil
|
||||
}, waitTimeout, waitTick, "did not receive answer")
|
||||
|
||||
sd := webrtc.SessionDescription{
|
||||
Type: webrtc.SDPTypeAnswer,
|
||||
SDP: c1.LastAnswer().SDP,
|
||||
}
|
||||
answer, err := sd.Unmarshal()
|
||||
require.NoError(t, err)
|
||||
|
||||
// video and data channel
|
||||
require.Len(t, answer.MediaDescriptions, 2)
|
||||
var desc *sdp.MediaDescription
|
||||
for _, md := range answer.MediaDescriptions {
|
||||
if md.MediaName.Media == "video" {
|
||||
desc = md
|
||||
break
|
||||
}
|
||||
}
|
||||
require.NotNil(t, desc)
|
||||
hasSeenVP8 := false
|
||||
for _, a := range desc.Attributes {
|
||||
if a.Key == "rtpmap" {
|
||||
require.NotContains(t, a.Value, "H264", "should not contain H264 codec")
|
||||
if strings.Contains(a.Value, "VP8") {
|
||||
hasSeenVP8 = true
|
||||
}
|
||||
}
|
||||
}
|
||||
require.True(t, hasSeenVP8, "should have seen VP8 codec in SDP")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user