diff --git a/encryption.go b/encryption.go index 93ddb56..0b288b9 100644 --- a/encryption.go +++ b/encryption.go @@ -22,11 +22,14 @@ const ( unencrypted_audio_bytes = 1 ) -var ErrIncorrectKeyLength = errors.New("incorrect key length for encryption/decryption") -var ErrUnableGenerateIV = errors.New("unable to generate iv for encryption") -var ErrIncorrectIVLength = errors.New("incorrect iv length") -var ErrIncorrectSecretLength = errors.New("input secret provided to derivation function cannot be empty or nil") -var ErrIncorrectSaltLength = errors.New("input salt provided to derivation function cannot be empty or nil") +var ( + ErrIncorrectKeyLength = errors.New("incorrect key length for encryption/decryption") + ErrUnableGenerateIV = errors.New("unable to generate iv for encryption") + ErrIncorrectIVLength = errors.New("incorrect iv length") + ErrIncorrectSecretLength = errors.New("input secret provided to derivation function cannot be empty or nil") + ErrIncorrectSaltLength = errors.New("input salt provided to derivation function cannot be empty or nil") + ErrBlockCipherRequired = errors.New("input block cipher cannot be nil") +) func DeriveKeyFromString(password string) ([]byte, error) { return DeriveKeyFromStringCustomSalt(password, LIVEKIT_SDK_SALT) @@ -77,6 +80,34 @@ func DeriveKeyFromBytesCustomSalt(secret []byte, salt string) ([]byte, error) { } // Take audio sample (body of RTP) encrypted by LiveKit client SDK, extract IV and decrypt using provided key +// If sample matches sifTrailer, it's considered to be a non-encrypted Server Injected Frame and nil is returned +// Use DecryptGCMAudioSampleCustomCipher with cached aes cipher block for better (30%) performance +func DecryptGCMAudioSample(sample, key, sifTrailer []byte) ([]byte, error) { + + if len(key) != 16 { + return nil, ErrIncorrectKeyLength + } + + if sifTrailer != nil && len(sample) >= len(sifTrailer) { + possibleTrailer := sample[len(sample)-len(sifTrailer):] + if bytes.Equal(possibleTrailer, sifTrailer) { + // this is unencrypted Server Injected Frame (SIF) that should be dropped + return nil, nil + } + + } + + cipherBlock, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + return DecryptGCMAudioSampleCustomCipher(sample, sifTrailer, cipherBlock) + +} + +// Take audio sample (body of RTP) encrypted by LiveKit client SDK, extract IV and decrypt using provided cipherBlock +// If sample matches sifTrailer, it's considered to be a non-encrypted Server Injected Frame and nil is returned // Encrypted sample format based on livekit client sdk // ---------+-------------------------+---------+---- // payload |IV...(length = IV_LENGTH)|IV_LENGTH|KID| @@ -86,10 +117,14 @@ func DeriveKeyFromBytesCustomSalt(secret []byte, salt string) ([]byte, error) { // IV - variable bytes (equal to IV_LENGTH bytes) // IV_LENGTH - 1 byte // KID (Key ID) - 1 byte - ignored here, key is provided as parameter to function -func DecryptGCMAudioSample(sample, key, sifTrailer []byte) ([]byte, error) { +func DecryptGCMAudioSampleCustomCipher(sample, sifTrailer []byte, cipherBlock cipher.Block) ([]byte, error) { - if len(key) != 16 { - return nil, ErrIncorrectKeyLength + if cipherBlock == nil { + return nil, ErrBlockCipherRequired + } + + if sample == nil { + return nil, nil } if sifTrailer != nil && len(sample) >= len(sifTrailer) { @@ -120,18 +155,11 @@ func DecryptGCMAudioSample(sample, key, sifTrailer []byte) ([]byte, error) { cipherText := make([]byte, cipherTextLength) copy(cipherText, sample[cipherTextStart:cipherTextStart+cipherTextLength]) - // setup AES - aesCipher, err := aes.NewCipher(key) + aesGCM, err := cipher.NewGCMWithNonceSize(cipherBlock, ivLength) // standard Nonce size is 12 bytes, but since it MAY be different in the sample, we use the one from the sample if err != nil { return nil, err } - aesGCM, err := cipher.NewGCMWithNonceSize(aesCipher, ivLength) // standard Nonce size is 12 bytes, but since it MAY be different in the sample, we use the one from the sample - if err != nil { - return nil, err - } - - // fmt.Println("**** DECRYPTION BEGIN ********") plainText, err := aesGCM.Open(nil, iv, cipherText, frameHeader) if err != nil { return nil, err @@ -147,6 +175,23 @@ func DecryptGCMAudioSample(sample, key, sifTrailer []byte) ([]byte, error) { } // Take audio sample (body of RTP) and encrypts it using AES-GCM 128bit with provided key +// Use EncryptGCMAudioSampleCustomCipher with cached aes cipher block for better (20%) performance +func EncryptGCMAudioSample(sample, key []byte, kid uint8) ([]byte, error) { + + if len(key) != 16 { + return nil, ErrIncorrectKeyLength + } + + cipherBlock, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + return EncryptGCMAudioSampleCustomCipher(sample, kid, cipherBlock) + +} + +// Take audio sample (body of RTP) and encrypts it using AES-GCM 128bit with provided cipher block // Encrypted sample format based on livekit client sdk // ---------+-------------------------+---------+---- // payload |IV...(length = IV_LENGTH)|IV_LENGTH|KID| @@ -156,10 +201,14 @@ func DecryptGCMAudioSample(sample, key, sifTrailer []byte) ([]byte, error) { // IV - variable bytes (equal to IV_LENGTH bytes) - 12 random bytes // IV_LENGTH - 1 byte - 12 bytes fixed // KID (Key ID) - 1 byte - taken from "kid" parameter -func EncryptGCMAudioSample(sample, key []byte, kid uint8) ([]byte, error) { +func EncryptGCMAudioSampleCustomCipher(sample []byte, kid uint8, cipherBlock cipher.Block) ([]byte, error) { - if len(key) != 16 { - return nil, ErrIncorrectKeyLength + if cipherBlock == nil { + return nil, ErrBlockCipherRequired + } + + if sample == nil { + return nil, nil } // variable naming is kept close to LiveKit client SDK decrypt function @@ -179,13 +228,7 @@ func EncryptGCMAudioSample(sample, key []byte, kid uint8) ([]byte, error) { plainText := make([]byte, plainTextLength) copy(plainText, sample[plainTextStart:plainTextStart+plainTextLength]) - // setup AES - aesCipher, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - aesGCM, err := cipher.NewGCMWithNonceSize(aesCipher, LIVEKIT_IV_LENGTH) // standard Nonce size is 12 bytes, but using one from defined constant (which matches Javascript SDK) + aesGCM, err := cipher.NewGCMWithNonceSize(cipherBlock, LIVEKIT_IV_LENGTH) // standard Nonce size is 12 bytes, but using one from defined constant (which matches Javascript SDK) if err != nil { return nil, err } diff --git a/encryption_test.go b/encryption_test.go index f9c3add..919e226 100644 --- a/encryption_test.go +++ b/encryption_test.go @@ -1,25 +1,31 @@ package lksdk import ( + "crypto/aes" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -var opusEncryptedFrame = []byte{120, 145, 24, 159, 76, 65, 130, 48, 144, 249, 17, 112, 134, 78, 250, 129, 171, 194, 16, 173, 73, 196, 5, 152, 69, 225, 28, 210, 196, 241, 226, 139, 231, 172, 51, 38, 139, 179, 245, 182, 170, 8, 122, 117, 98, 144, 123, 95, 73, 89, 119, 39, 205, 20, 191, 55, 121, 59, 239, 192, 85, 224, 228, 143, 10, 113, 195, 223, 118, 42, 2, 32, 22, 17, 77, 227, 109, 160, 245, 202, 189, 63, 162, 164, 5, 241, 24, 151, 45, 42, 165, 131, 171, 243, 141, 53, 35, 131, 141, 52, 253, 188, 12, 0} -var opusDecryptedFrame = []byte{120, 11, 109, 82, 113, 132, 189, 156, 220, 173, 30, 109, 87, 54, 173, 99, 26, 126, 166, 37, 127, 234, 110, 211, 230, 152, 181, 235, 197, 19, 140, 230, 179, 35, 131, 132, 29, 192, 97, 247, 108, 53, 183, 214, 77, 181, 173, 206, 175, 7, 228, 145, 93, 155, 155, 142, 14, 27, 111, 64, 96, 196, 229, 189, 142, 59, 149, 169, 99, 225, 216, 85, 186, 182} -var opusSilenceFrame = []byte{0xf8, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -var sifTrailer = []byte{50, 86, 10, 220, 108, 185, 57, 211} -var testPassphrase = "12345" +var ( + opusEncryptedFrame = []byte{120, 145, 24, 159, 76, 65, 130, 48, 144, 249, 17, 112, 134, 78, 250, 129, 171, 194, 16, 173, 73, 196, 5, 152, 69, 225, 28, 210, 196, 241, 226, 139, 231, 172, 51, 38, 139, 179, 245, 182, 170, 8, 122, 117, 98, 144, 123, 95, 73, 89, 119, 39, 205, 20, 191, 55, 121, 59, 239, 192, 85, 224, 228, 143, 10, 113, 195, 223, 118, 42, 2, 32, 22, 17, 77, 227, 109, 160, 245, 202, 189, 63, 162, 164, 5, 241, 24, 151, 45, 42, 165, 131, 171, 243, 141, 53, 35, 131, 141, 52, 253, 188, 12, 0} + opusDecryptedFrame = []byte{120, 11, 109, 82, 113, 132, 189, 156, 220, 173, 30, 109, 87, 54, 173, 99, 26, 126, 166, 37, 127, 234, 110, 211, 230, 152, 181, 235, 197, 19, 140, 230, 179, 35, 131, 132, 29, 192, 97, 247, 108, 53, 183, 214, 77, 181, 173, 206, 175, 7, 228, 145, 93, 155, 155, 142, 14, 27, 111, 64, 96, 196, 229, 189, 142, 59, 149, 169, 99, 225, 216, 85, 186, 182} + opusSilenceFrame = []byte{ + 0xf8, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + } + sifTrailer = []byte{50, 86, 10, 220, 108, 185, 57, 211} + testPassphrase = "12345" + keyIncorrectLength = []byte{1, 2, 3} +) func TestDeriveKeyFromString(t *testing.T) { @@ -28,8 +34,8 @@ func TestDeriveKeyFromString(t *testing.T) { key, err := DeriveKeyFromString(password) expectedKey := []byte{15, 94, 198, 66, 93, 211, 116, 46, 55, 97, 232, 121, 189, 233, 224, 22} - assert.Nil(t, err) - assert.Equal(t, key, expectedKey) + require.Nil(t, err) + require.Equal(t, key, expectedKey) } func TestDeriveKeyFromBytes(t *testing.T) { @@ -38,43 +44,101 @@ func TestDeriveKeyFromBytes(t *testing.T) { expectedKey := []byte{129, 224, 93, 62, 17, 203, 99, 136, 101, 35, 149, 128, 189, 152, 251, 76} key, err := DeriveKeyFromBytes(inputSecret) - assert.Nil(t, err) - assert.Equal(t, expectedKey, key) + require.Nil(t, err) + require.Equal(t, expectedKey, key) } func TestDecryptAudioSample(t *testing.T) { key, err := DeriveKeyFromString(testPassphrase) - assert.Nil(t, err) + require.Nil(t, err) + + _, err = DecryptGCMAudioSample(opusEncryptedFrame, keyIncorrectLength, sifTrailer) + require.ErrorIs(t, err, ErrIncorrectKeyLength) - decryptedFrame, err := DecryptGCMAudioSample(opusEncryptedFrame, key, sifTrailer) + decryptedFrame, err := DecryptGCMAudioSample(nil, key, sifTrailer) + require.Nil(t, err) + require.Nil(t, decryptedFrame) - assert.Nil(t, err) - assert.Equal(t, opusDecryptedFrame, decryptedFrame) + decryptedFrame, err = DecryptGCMAudioSample(opusEncryptedFrame, key, sifTrailer) + + require.Nil(t, err) + require.Equal(t, opusDecryptedFrame, decryptedFrame) var sifFrame []byte sifFrame = append(sifFrame, opusSilenceFrame...) sifFrame = append(sifFrame, sifTrailer...) decryptedFrame, err = DecryptGCMAudioSample(sifFrame, key, sifTrailer) - assert.Nil(t, err) - assert.Nil(t, decryptedFrame) + require.Nil(t, err) + require.Nil(t, decryptedFrame) } func TestEncryptAudioSample(t *testing.T) { key, err := DeriveKeyFromString(testPassphrase) - assert.Nil(t, err) + require.Nil(t, err) + + _, err = EncryptGCMAudioSample(opusDecryptedFrame, keyIncorrectLength, 0) + require.ErrorIs(t, err, ErrIncorrectKeyLength) - encryptedFrame, err := EncryptGCMAudioSample(opusDecryptedFrame, key, 0) + encryptedFrame, err := EncryptGCMAudioSample(nil, key, 0) + require.Nil(t, err) + require.Nil(t, encryptedFrame) - assert.Nil(t, err) + encryptedFrame, err = EncryptGCMAudioSample(opusDecryptedFrame, key, 0) + + require.Nil(t, err) // IV is generated randomly so to verify we decrypt and make sure that we got the expected plain text frame decryptedFrame, err := DecryptGCMAudioSample(encryptedFrame, key, sifTrailer) - assert.Nil(t, err) - assert.Equal(t, opusDecryptedFrame, decryptedFrame) + require.Nil(t, err) + require.Equal(t, opusDecryptedFrame, decryptedFrame) + +} + +func BenchmarkDecryptAudioNewCipher(b *testing.B) { + + key, _ := DeriveKeyFromString(testPassphrase) + for i := 0; i < b.N; i++ { + cipherBlock, _ := aes.NewCipher(key) + DecryptGCMAudioSampleCustomCipher(opusEncryptedFrame, sifTrailer, cipherBlock) + + } + +} + +func BenchmarkDecryptAudioCachedCipher(b *testing.B) { + + key, _ := DeriveKeyFromString(testPassphrase) + cipherBlock, _ := aes.NewCipher(key) + for i := 0; i < b.N; i++ { + DecryptGCMAudioSampleCustomCipher(opusEncryptedFrame, sifTrailer, cipherBlock) + + } + +} + +func BenchmarkEncryptAudioCachedCipher(b *testing.B) { + + key, _ := DeriveKeyFromString(testPassphrase) + cipherBlock, _ := aes.NewCipher(key) + for i := 0; i < b.N; i++ { + EncryptGCMAudioSampleCustomCipher(opusDecryptedFrame, 0, cipherBlock) + + } + +} + +func BenchmarkEncryptAudioNewCipher(b *testing.B) { + + key, _ := DeriveKeyFromString(testPassphrase) + for i := 0; i < b.N; i++ { + cipherBlock, _ := aes.NewCipher(key) + EncryptGCMAudioSampleCustomCipher(opusDecryptedFrame, 0, cipherBlock) + + } } diff --git a/examples/echoe2ee/main.go b/examples/echoe2ee/main.go new file mode 100644 index 0000000..8031ee3 --- /dev/null +++ b/examples/echoe2ee/main.go @@ -0,0 +1,160 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "os" + "os/signal" + "syscall" + "time" + + "github.com/pion/webrtc/v4" + "github.com/pion/webrtc/v4/pkg/media" + + "github.com/livekit/protocol/auth" + "github.com/livekit/protocol/livekit" + "github.com/livekit/protocol/logger" + lksdk "github.com/livekit/server-sdk-go/v2" +) + +var ( + host, apiKey, apiSecret, roomName, identity, passphrase string + key []byte + room *lksdk.Room + closeTrack chan struct{} = make(chan struct{}, 1) +) + +func init() { + flag.StringVar(&host, "host", "", "livekit server host") + flag.StringVar(&apiKey, "api-key", "", "livekit api key") + flag.StringVar(&apiSecret, "api-secret", "", "livekit api secret") + flag.StringVar(&roomName, "room-name", "", "room name") + flag.StringVar(&identity, "identity", "", "participant identity") + flag.StringVar(&passphrase, "passphrase", "", "participant identity") +} + +func main() { + logger.InitFromConfig(&logger.Config{Level: "debug"}, "echoe2ee") + lksdk.SetLogger(logger.GetLogger()) + flag.Parse() + if host == "" || apiKey == "" || apiSecret == "" || roomName == "" || identity == "" { + fmt.Println("invalid arguments.") + return + } + + if passphrase != "" { + var err error + key, err = lksdk.DeriveKeyFromString(passphrase) + if err != nil { + panic(err) + } + } + + echoTrack, err := lksdk.NewLocalTrack(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}) + if err != nil { + panic(err) + } + + room = lksdk.NewRoom(&lksdk.RoomCallback{ + ParticipantCallback: lksdk.ParticipantCallback{ + OnTrackSubscribed: func(track *webrtc.TrackRemote, publication *lksdk.RemoteTrackPublication, rp *lksdk.RemoteParticipant) { + // Only provide echo for the first participant + if track.Kind() == webrtc.RTPCodecTypeAudio { + onTrackSubscribed(track, publication, echoTrack) + } + }, + OnTrackUnsubscribed: func(track *webrtc.TrackRemote, publication *lksdk.RemoteTrackPublication, rp *lksdk.RemoteParticipant) { + if track.Kind() == webrtc.RTPCodecTypeAudio { + closeTrack <- struct{}{} + } + + }, + }, + }) + + token, err := newAccessToken(apiKey, apiSecret, roomName, identity) + if err != nil { + panic(err) + } + + // not required. warm up the connection for a participant that may join later. + if err := room.PrepareConnection(host, token); err != nil { + panic(err) + } + + if err := room.JoinWithToken(host, token); err != nil { + panic(err) + } + + if _, err = room.LocalParticipant.PublishTrack(echoTrack, &lksdk.TrackPublicationOptions{ + Name: "echo", + Encryption: livekit.Encryption_GCM, + }); err != nil { + panic(err) + } + + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT) + + <-sigChan + room.Disconnect() +} + +func onTrackSubscribed(track *webrtc.TrackRemote, publication *lksdk.RemoteTrackPublication, echoTrack *lksdk.LocalTrack) { + for { + + select { + case <-closeTrack: + return + default: + pkt, _, err := track.ReadRTP() + if err != nil { + continue + } + receivedSample := pkt.Payload + sendSample := pkt.Payload + encryption_type := publication.TrackInfo().GetEncryption() + + if encryption_type == livekit.Encryption_GCM && key == nil { + panic(errors.New("received encrypted track but passphrase is not provided")) + } + + if encryption_type == livekit.Encryption_GCM { + receivedSample, err = lksdk.DecryptGCMAudioSample(receivedSample, key, room.SifTrailer()) + if err != nil { + panic((err)) + } + + if receivedSample != nil { + sendSample, err = lksdk.EncryptGCMAudioSample(receivedSample, key, 0) + if err != nil { + panic((err)) + } + + } else { + sendSample = nil + } + + } + if sendSample != nil { + echoTrack.WriteSample(media.Sample{Data: sendSample, Duration: 20 * time.Millisecond}, &lksdk.SampleWriteOptions{}) + } + + } + + } +} + +func newAccessToken(apiKey, apiSecret, roomName, pID string) (string, error) { + at := auth.NewAccessToken(apiKey, apiSecret) + grant := &auth.VideoGrant{ + RoomJoin: true, + Room: roomName, + } + at.SetVideoGrant(grant). + SetIdentity(pID). + SetName(pID) + + return at.ToJWT() +} diff --git a/go.mod b/go.mod index 92e0390..8af85f0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/livekit/server-sdk-go/v2 -go 1.23 +go 1.22.7 toolchain go1.23.3 @@ -10,21 +10,21 @@ require ( github.com/go-logr/stdr v1.2.2 github.com/gorilla/websocket v1.5.3 github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 - github.com/livekit/mediatransportutil v0.0.0-20241128072814-c363618d4c98 - github.com/livekit/protocol v1.29.5-0.20241209183753-f6b5078b2244 + github.com/livekit/mediatransportutil v0.0.0-20241220010243-a2bdee945564 + github.com/livekit/protocol v1.30.0 github.com/magefile/mage v1.15.0 github.com/pion/dtls/v3 v3.0.4 github.com/pion/interceptor v0.1.37 - github.com/pion/rtcp v1.2.14 - github.com/pion/rtp v1.8.9 + github.com/pion/rtcp v1.2.15 + github.com/pion/rtp v1.8.10 github.com/pion/sdp/v3 v3.0.9 - github.com/pion/webrtc/v4 v4.0.5 + github.com/pion/webrtc/v4 v4.0.7 github.com/stretchr/testify v1.10.0 github.com/twitchtv/twirp v8.1.3+incompatible go.uber.org/atomic v1.11.0 golang.org/x/crypto v0.31.0 - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f - google.golang.org/protobuf v1.35.2 + golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 + google.golang.org/protobuf v1.36.1 ) require ( @@ -36,26 +36,26 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/frostbyte73/core v0.0.13 // indirect + github.com/frostbyte73/core v0.1.0 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/gammazero/deque v0.2.1 // indirect + github.com/gammazero/deque v1.0.0 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/google/cel-go v0.21.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/jxskiss/base62 v1.1.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/lithammer/shortuuid/v4 v4.0.0 // indirect github.com/livekit/psrpc v0.6.1-0.20241018124827-1efff3d113a8 // indirect - github.com/nats-io/nats.go v1.36.0 // indirect - github.com/nats-io/nkeys v0.4.7 // indirect + github.com/nats-io/nats.go v1.38.0 // indirect + github.com/nats-io/nkeys v0.4.9 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/pion/datachannel v1.5.9 // indirect + github.com/pion/datachannel v1.5.10 // indirect github.com/pion/ice/v4 v4.0.3 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/sctp v1.8.34 // indirect + github.com/pion/sctp v1.8.35 // indirect github.com/pion/srtp/v3 v3.0.4 // indirect github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v3 v3.0.7 // indirect @@ -73,8 +73,8 @@ require ( golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.68.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect + google.golang.org/grpc v1.69.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c677745..94facdb 100644 --- a/go.sum +++ b/go.sum @@ -23,12 +23,12 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= -github.com/frostbyte73/core v0.0.13 h1:W/NFPNiCkGTRzMWnCVptn6vX6Tr4a7LvN0RFc0xsC2k= -github.com/frostbyte73/core v0.0.13/go.mod h1:XsOGqrqe/VEV7+8vJ+3a8qnCIXNbKsoEiu/czs7nrcU= +github.com/frostbyte73/core v0.1.0 h1:KA4klxRjLbEHLv+judmlRtweyjcj1NWOJ+BQHQgNxfw= +github.com/frostbyte73/core v0.1.0/go.mod h1:mhfOtR+xWAvwXiwor7jnqPMnu4fxbv1F2MwZ0BEpzZo= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gammazero/deque v0.2.1 h1:qSdsbG6pgp6nL7A0+K/B7s12mcCY/5l5SIUpMOl+dC0= -github.com/gammazero/deque v0.2.1/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU= +github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= +github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -50,8 +50,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw= github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -62,22 +62,22 @@ github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y= github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 h1:jm09419p0lqTkDaKb5iXdynYrzB84ErPPO4LbRASk58= github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= -github.com/livekit/mediatransportutil v0.0.0-20241128072814-c363618d4c98 h1:QA7DqIC/ZSsMj8HC0+zNfMMwssHbA0alZALK68r30LQ= -github.com/livekit/mediatransportutil v0.0.0-20241128072814-c363618d4c98/go.mod h1:WIVFAGzVZ7VMjPC5+nbSfwdFjWcbuLgx97KeNSUDTEo= -github.com/livekit/protocol v1.29.5-0.20241209183753-f6b5078b2244 h1:Eg9HK+5bMCDRKhh5g5g16oyNaMbCqMrJvxFBaBuP7Vo= -github.com/livekit/protocol v1.29.5-0.20241209183753-f6b5078b2244/go.mod h1:NDg1btMpKCzr/w6QR5kDuXw/e4Y7yOBE+RUAHsc+Y/M= +github.com/livekit/mediatransportutil v0.0.0-20241220010243-a2bdee945564 h1:GX7KF/V9ExmcfT/2Bdia8aROjkxrgx7WpyH7w9MB4J4= +github.com/livekit/mediatransportutil v0.0.0-20241220010243-a2bdee945564/go.mod h1:36s+wwmU3O40IAhE+MjBWP3W71QRiEE9SfooSBvtBqY= +github.com/livekit/protocol v1.30.0 h1:yIaCrhRvfjWgAdvLkjf4VHh087yTeYrvjsNhLyXlUmE= +github.com/livekit/protocol v1.30.0/go.mod h1:08wT2rI6GecTCwh9n8OA28Gb7ZQNtIR+hX/LccP1TaY= github.com/livekit/psrpc v0.6.1-0.20241018124827-1efff3d113a8 h1:Ibh0LoFl5NW5a1KFJEE0eLxxz7dqqKmYTj/BfCb0PbY= github.com/livekit/psrpc v0.6.1-0.20241018124827-1efff3d113a8/go.mod h1:CQUBSPfYYAaevg1TNCc6/aYsa8DJH4jSRFdCeSZk5u0= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= -github.com/nats-io/nats.go v1.36.0 h1:suEUPuWzTSse/XhESwqLxXGuj8vGRuPRoG7MoRN/qyU= -github.com/nats-io/nats.go v1.36.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= -github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= -github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nats.go v1.38.0 h1:A7P+g7Wjp4/NWqDOOP/K6hfhr54DvdDQUznt5JFg9XA= +github.com/nats-io/nats.go v1.38.0/go.mod h1:IGUM++TwokGnXPs82/wCuiHS02/aKrdYUQkU8If6yjw= +github.com/nats-io/nkeys v0.4.9 h1:qe9Faq2Gxwi6RZnZMXfmGMZkg3afLLOtrU+gDZJ35b0= +github.com/nats-io/nkeys v0.4.9/go.mod h1:jcMqs+FLG+W5YO36OX6wFIFcmpdAns+w1Wm6D3I/evE= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= -github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= github.com/pion/ice/v4 v4.0.3 h1:9s5rI1WKzF5DRqhJ+Id8bls/8PzM7mau0mj1WZb4IXE= @@ -90,12 +90,12 @@ github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= -github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.34 h1:rCuD3m53i0oGxCSp7FLQKvqVx0Nf5AUAHhMRXTTQjBc= -github.com/pion/sctp v1.8.34/go.mod h1:yWkCClkXlzVW7BXfI2PjrUGBwUI0CjXJBkhLt+sdo4U= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.10 h1:puphjdbjPB+L+NFaVuZ5h6bt1g5q4kFIoI+r5q/g0CU= +github.com/pion/rtp v1.8.10/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA= +github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg= github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= @@ -106,8 +106,8 @@ github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1 github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= -github.com/pion/webrtc/v4 v4.0.5 h1:8cVPojcv3cQTwVga2vF1rzCNvkiEimnYdCCG7yF317I= -github.com/pion/webrtc/v4 v4.0.5/go.mod h1:LvP8Np5b/sM0uyJIcUPvJcCvhtjHxJwzh2H2PYzE6cQ= +github.com/pion/webrtc/v4 v4.0.7 h1:aeq78uVnFZd2umXW0O9A2VFQYuS7+BZxWetQvSp2jPo= +github.com/pion/webrtc/v4 v4.0.7/go.mod h1:oFVBBVSHU3vAEwSgnk3BuKCwAUwpDwQhko1EDwyZWbU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -154,8 +154,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -198,14 +198,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= -google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U= +google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= +google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/version.go b/version.go index 8d75535..5619465 100644 --- a/version.go +++ b/version.go @@ -14,4 +14,4 @@ package lksdk -const Version = "2.4.0" +const Version = "2.4.1"