mirror of
https://github.com/pion/webrtc.git
synced 2025-11-02 03:32:48 +08:00
Update CI configs to v0.4.7
Update lint scripts and CI configs.
This commit is contained in:
@@ -3,6 +3,80 @@ linters-settings:
|
||||
check-shadowing: true
|
||||
misspell:
|
||||
locale: US
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
|
||||
- bodyclose # checks whether HTTP response body is closed successfully
|
||||
- deadcode # Finds unused code
|
||||
- depguard # Go linter that checks if package imports are in a list of acceptable packages
|
||||
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
|
||||
- dupl # Tool for code clone detection
|
||||
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
||||
- exhaustive # check exhaustiveness of enum switch statements
|
||||
- exportloopref # checks for pointers to enclosing loop variables
|
||||
- gci # Gci control golang package import order and make it always deterministic.
|
||||
- gochecknoglobals # Checks that no globals are present in Go code
|
||||
- gochecknoinits # Checks that no init functions are present in Go code
|
||||
- gocognit # Computes and checks the cognitive complexity of functions
|
||||
- goconst # Finds repeated strings that could be replaced by a constant
|
||||
- gocritic # The most opinionated Go source code linter
|
||||
- godox # Tool for detection of FIXME, TODO and other comment keywords
|
||||
- goerr113 # Golang linter to check the errors handling expressions
|
||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
- gofumpt # Gofumpt checks whether code was gofumpt-ed.
|
||||
- goheader # Checks is file header matches to pattern
|
||||
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports
|
||||
- golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
|
||||
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
|
||||
- goprintffuncname # Checks that printf-like functions are named with `f` at the end
|
||||
- gosec # Inspects source code for security problems
|
||||
- gosimple # Linter for Go source code that specializes in simplifying a code
|
||||
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
- ineffassign # Detects when assignments to existing variables are not used
|
||||
- misspell # Finds commonly misspelled English words in comments
|
||||
- nakedret # Finds naked returns in functions greater than a specified function length
|
||||
- noctx # noctx finds sending http request without context.Context
|
||||
- scopelint # Scopelint checks for unpinned variables in go programs
|
||||
- staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
|
||||
- structcheck # Finds unused struct fields
|
||||
- stylecheck # Stylecheck is a replacement for golint
|
||||
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
|
||||
- unconvert # Remove unnecessary type conversions
|
||||
- unparam # Reports unused function parameters
|
||||
- unused # Checks Go code for unused constants, variables, functions and types
|
||||
- varcheck # Finds unused global variables and constants
|
||||
- whitespace # Tool for detection of leading and trailing whitespace
|
||||
disable:
|
||||
- funlen # Tool for detection of long functions
|
||||
- gocyclo # Computes and checks the cyclomatic complexity of functions
|
||||
- godot # Check if comments end in a period
|
||||
- gomnd # An analyzer to detect magic numbers.
|
||||
- lll # Reports long lines
|
||||
- maligned # Tool to detect Go structs that would take less memory if their fields were sorted
|
||||
- nestif # Reports deeply nested if statements
|
||||
- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
|
||||
- nolintlint # Reports ill-formed or insufficient nolint directives
|
||||
- prealloc # Finds slice declarations that could potentially be preallocated
|
||||
- rowserrcheck # checks whether Err of rows is checked successfully
|
||||
- sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
|
||||
- testpackage # linter that makes you use a separate _test package
|
||||
- wsl # Whitespace Linter - Forces you to use empty lines!
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
# Allow complex tests, better to be self contained
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gocognit
|
||||
|
||||
# Allow complex main function in examples
|
||||
- path: examples
|
||||
text: "of func `main` is high"
|
||||
linters:
|
||||
- gocognit
|
||||
|
||||
run:
|
||||
skip-dirs-use-default: false
|
||||
|
||||
@@ -203,6 +203,7 @@ Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contribu
|
||||
* [Joshua Obasaju](https://github.com/obasajujoshua31)
|
||||
* [Mission Liao](https://github.com/mission-liao)
|
||||
* [Hanjun Kim](https://github.com/hallazzang)
|
||||
* [ZHENK](https://github.com/scorpionknifes)
|
||||
|
||||
### License
|
||||
MIT License - see [LICENSE](LICENSE) for full text
|
||||
|
||||
@@ -103,11 +103,11 @@ func (c Certificate) GetFingerprints() ([]DTLSFingerprint, error) {
|
||||
for _, algo := range fingerprintAlgorithms {
|
||||
name, err := fingerprint.StringFromHash(algo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create fingerprint: %v", err)
|
||||
return nil, fmt.Errorf("%w: %v", ErrFailedToGenerateCertificateFingerprint, err)
|
||||
}
|
||||
value, err := fingerprint.Fingerprint(c.x509Cert, algo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create fingerprint: %v", err)
|
||||
return nil, fmt.Errorf("%w: %v", ErrFailedToGenerateCertificateFingerprint, err)
|
||||
}
|
||||
res[i] = DTLSFingerprint{
|
||||
Algorithm: name,
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/pion/webrtc/v3/pkg/rtcerr"
|
||||
)
|
||||
|
||||
const dataChannelBufferSize = math.MaxUint16 //message size limit for Chromium
|
||||
const dataChannelBufferSize = math.MaxUint16 // message size limit for Chromium
|
||||
var errSCTPNotEstablished = errors.New("SCTP not established")
|
||||
|
||||
// DataChannel represents a WebRTC DataChannel
|
||||
@@ -372,11 +372,11 @@ func (d *DataChannel) Detach() (datachannel.ReadWriteCloser, error) {
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if !d.api.settingEngine.detach.DataChannels {
|
||||
return nil, fmt.Errorf("enable detaching by calling webrtc.DetachDataChannels()")
|
||||
return nil, errDetachNotEnabled
|
||||
}
|
||||
|
||||
if d.dataChannel == nil {
|
||||
return nil, fmt.Errorf("datachannel not opened yet, try calling Detach from OnOpen")
|
||||
return nil, errDetachBeforeOpened
|
||||
}
|
||||
|
||||
d.detachCalled = true
|
||||
|
||||
@@ -67,8 +67,7 @@ func TestDataChannel_MessagesAreOrdered(t *testing.T) {
|
||||
// math/rand a weak RNG, but this does not need to be secure. Ignore with #nosec
|
||||
/* #nosec */
|
||||
randInt, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
|
||||
/* #nosec */
|
||||
if err != nil {
|
||||
/* #nosec */ if err != nil {
|
||||
t.Fatalf("Failed to get random sleep duration: %s", err)
|
||||
}
|
||||
time.Sleep(time.Duration(randInt.Int64()) * time.Microsecond)
|
||||
@@ -117,7 +116,7 @@ func TestDataChannelParamters_Go(t *testing.T) {
|
||||
defer report()
|
||||
|
||||
t.Run("MaxPacketLifeTime exchange", func(t *testing.T) {
|
||||
var ordered = true
|
||||
ordered := true
|
||||
var maxPacketLifeTime uint16 = 3
|
||||
options := &DataChannelInit{
|
||||
Ordered: &ordered,
|
||||
@@ -218,8 +217,7 @@ func TestDataChannelBufferedAmount(t *testing.T) {
|
||||
t.Fatalf("Failed to send string on data channel")
|
||||
}
|
||||
assert.Equal(t, uint64(1500), dc.BufferedAmountLowThreshold(), "value mismatch")
|
||||
|
||||
//assert.Equal(t, (i+1)*len(buf), int(dc.BufferedAmount()), "unexpected bufferedAmount")
|
||||
// assert.Equal(t, (i+1)*len(buf), int(dc.BufferedAmount()), "unexpected bufferedAmount")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -300,8 +298,7 @@ func TestDataChannelBufferedAmount(t *testing.T) {
|
||||
t.Fatalf("Failed to send string on data channel")
|
||||
}
|
||||
assert.Equal(t, uint64(1500), dc.BufferedAmountLowThreshold(), "value mismatch")
|
||||
|
||||
//assert.Equal(t, (i+1)*len(buf), int(dc.BufferedAmount()), "unexpected bufferedAmount")
|
||||
// assert.Equal(t, (i+1)*len(buf), int(dc.BufferedAmount()), "unexpected bufferedAmount")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -436,18 +433,13 @@ func TestEOF(t *testing.T) {
|
||||
lim := test.TimeOut(time.Second * 5)
|
||||
defer lim.Stop()
|
||||
|
||||
// Use Detach data channels mode
|
||||
s := SettingEngine{}
|
||||
//s.DetachDataChannels()
|
||||
api := NewAPI(WithSettingEngine(s))
|
||||
|
||||
// Set up two peer connections.
|
||||
config := Configuration{}
|
||||
pca, err := api.NewPeerConnection(config)
|
||||
pca, err := NewPeerConnection(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pcb, err := api.NewPeerConnection(config)
|
||||
pcb, err := NewPeerConnection(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
package webrtc
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pion/transport/test"
|
||||
"github.com/pion/webrtc/v3/internal/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDataChannel_ORTCE2E(t *testing.T) {
|
||||
|
||||
@@ -203,11 +203,8 @@ func TestDataChannel_Send(t *testing.T) {
|
||||
dc.OnMessage(func(msg DataChannelMessage) {
|
||||
done <- true
|
||||
})
|
||||
// TODO: currently there is no way of properly subscribing to OnOpen with the js binding,
|
||||
// because CreateDataChannel might return an already open data channel
|
||||
//
|
||||
e := dc.SendText("Ping")
|
||||
if e != nil {
|
||||
|
||||
if e := dc.SendText("Ping"); e != nil {
|
||||
// wasm binding doesn't fire OnOpen (we probably already missed it)
|
||||
dc.OnOpen(func() {
|
||||
e = dc.SendText("Ping")
|
||||
|
||||
@@ -151,7 +151,7 @@ func (t *DTLSTransport) startSRTP() error {
|
||||
if t.srtpSession.Load() != nil && t.srtcpSession.Load() != nil {
|
||||
return nil
|
||||
} else if t.conn == nil {
|
||||
return fmt.Errorf("the DTLS transport has not started yet")
|
||||
return errDtlsTransportNotStarted
|
||||
}
|
||||
|
||||
srtpConfig := &srtp.Config{
|
||||
@@ -189,17 +189,17 @@ func (t *DTLSTransport) startSRTP() error {
|
||||
connState := t.conn.ConnectionState()
|
||||
err := srtpConfig.ExtractSessionKeysFromDTLS(&connState, t.role() == DTLSRoleClient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to extract sctp session keys: %v", err)
|
||||
return fmt.Errorf("%w: %v", errDtlsKeyExtractionFailed, err)
|
||||
}
|
||||
|
||||
srtpSession, err := srtp.NewSessionSRTP(t.srtpEndpoint, srtpConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start srtp: %v", err)
|
||||
return fmt.Errorf("%w: %v", errFailedToStartSRTP, err)
|
||||
}
|
||||
|
||||
srtcpSession, err := srtp.NewSessionSRTCP(t.srtcpEndpoint, srtpConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start srtp: %v", err)
|
||||
return fmt.Errorf("%w: %v", errFailedToStartSRTCP, err)
|
||||
}
|
||||
|
||||
t.srtpSession.Store(srtpSession)
|
||||
@@ -237,6 +237,7 @@ func (t *DTLSTransport) role() DTLSRole {
|
||||
return DTLSRoleServer
|
||||
case DTLSRoleServer:
|
||||
return DTLSRoleClient
|
||||
default:
|
||||
}
|
||||
|
||||
// If SettingEngine has an explicit role
|
||||
@@ -245,6 +246,7 @@ func (t *DTLSTransport) role() DTLSRole {
|
||||
return DTLSRoleServer
|
||||
case DTLSRoleClient:
|
||||
return DTLSRoleClient
|
||||
default:
|
||||
}
|
||||
|
||||
// Remote was auto and no explicit role was configured via SettingEngine
|
||||
@@ -267,7 +269,7 @@ func (t *DTLSTransport) Start(remoteParameters DTLSParameters) error {
|
||||
}
|
||||
|
||||
if t.state != DTLSTransportStateNew {
|
||||
return DTLSRole(0), nil, &rtcerr.InvalidStateError{Err: fmt.Errorf("attempted to start DTLSTransport that is not in new state: %s", t.state)}
|
||||
return DTLSRole(0), nil, &rtcerr.InvalidStateError{Err: fmt.Errorf("%w: %s", errInvalidDTLSStart, t.state)}
|
||||
}
|
||||
|
||||
t.srtpEndpoint = t.iceTransport.NewEndpoint(mux.MatchSRTP)
|
||||
@@ -282,7 +284,8 @@ func (t *DTLSTransport) Start(remoteParameters DTLSParameters) error {
|
||||
{
|
||||
Certificate: [][]byte{cert.x509Cert.Raw},
|
||||
PrivateKey: cert.privateKey,
|
||||
}},
|
||||
},
|
||||
},
|
||||
SRTPProtectionProfiles: []dtls.SRTPProtectionProfile{dtls.SRTP_AEAD_AES_128_GCM, dtls.SRTP_AES128_CM_HMAC_SHA1_80},
|
||||
ClientAuth: dtls.RequireAnyClientCert,
|
||||
LoggerFactory: t.api.settingEngine.LoggerFactory,
|
||||
@@ -345,7 +348,7 @@ func (t *DTLSTransport) Start(remoteParameters DTLSParameters) error {
|
||||
remoteCerts := t.conn.ConnectionState().PeerCertificates
|
||||
if len(remoteCerts) == 0 {
|
||||
t.onStateChange(DTLSTransportStateFailed)
|
||||
return fmt.Errorf("peer didn't provide certificate via DTLS")
|
||||
return errNoRemoteCertificate
|
||||
}
|
||||
t.remoteCertificate = remoteCerts[0]
|
||||
|
||||
@@ -386,7 +389,7 @@ func (t *DTLSTransport) Stop() error {
|
||||
|
||||
if t.conn != nil {
|
||||
// dtls connection may be closed on sctp close.
|
||||
if err := t.conn.Close(); err != nil && err != dtls.ErrConnClosed {
|
||||
if err := t.conn.Close(); err != nil && !errors.Is(err, dtls.ErrConnClosed) {
|
||||
closeErrs = append(closeErrs, err)
|
||||
}
|
||||
}
|
||||
@@ -411,12 +414,12 @@ func (t *DTLSTransport) validateFingerPrint(remoteCert *x509.Certificate) error
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("no matching fingerprint")
|
||||
return errNoMatchingCertificateFingerprint
|
||||
}
|
||||
|
||||
func (t *DTLSTransport) ensureICEConn() error {
|
||||
if t.iceTransport == nil || t.iceTransport.State() == ICETransportStateNew {
|
||||
return errors.New("ICE connection not started")
|
||||
return errICEConnectionNotStarted
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -16,6 +15,7 @@ import (
|
||||
|
||||
"github.com/sclevine/agouti"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/pion/webrtc/v3/pkg/media"
|
||||
)
|
||||
@@ -351,7 +351,7 @@ func createTrack(offer webrtc.SessionDescription) (*webrtc.PeerConnection, *webr
|
||||
return nil, nil, nil, errPc
|
||||
}
|
||||
|
||||
track, errTrack := pc.NewTrack(payloadType, rand.Uint32(), "video", "pion")
|
||||
track, errTrack := pc.NewTrack(payloadType, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
if errTrack != nil {
|
||||
return nil, nil, nil, errTrack
|
||||
}
|
||||
|
||||
87
errors.go
87
errors.go
@@ -88,7 +88,7 @@ var (
|
||||
ErrIncorrectSignalingState = errors.New("operation can not be run in current signaling state")
|
||||
|
||||
// ErrProtocolTooLarge indicates that value given for a DataChannelInit protocol is
|
||||
//longer then 65535 bytes
|
||||
// longer then 65535 bytes
|
||||
ErrProtocolTooLarge = errors.New("protocol is larger then 65535 bytes")
|
||||
|
||||
// ErrSenderNotCreatedByConnection indicates RemoveTrack was called with a RtpSender not created
|
||||
@@ -125,4 +125,89 @@ var (
|
||||
|
||||
// ErrNoSRTPProtectionProfile indicates that the DTLS handshake completed and no SRTP Protection Profile was chosen
|
||||
ErrNoSRTPProtectionProfile = errors.New("DTLS Handshake completed and no SRTP Protection Profile was chosen")
|
||||
|
||||
// ErrFailedToGenerateCertificateFingerprint indicates that we failed to generate the fingerprint used for comparing certificates
|
||||
ErrFailedToGenerateCertificateFingerprint = errors.New("failed to generate certificate fingerprint")
|
||||
|
||||
errDetachNotEnabled = errors.New("enable detaching by calling webrtc.DetachDataChannels()")
|
||||
errDetachBeforeOpened = errors.New("datachannel not opened yet, try calling Detach from OnOpen")
|
||||
errDtlsTransportNotStarted = errors.New("the DTLS transport has not started yet")
|
||||
errDtlsKeyExtractionFailed = errors.New("failed extracting keys from DTLS for SRTP")
|
||||
errFailedToStartSRTP = errors.New("failed to start SRTP")
|
||||
errFailedToStartSRTCP = errors.New("failed to start SRTCP")
|
||||
errInvalidDTLSStart = errors.New("attempted to start DTLSTransport that is not in new state")
|
||||
errNoRemoteCertificate = errors.New("peer didn't provide certificate via DTLS")
|
||||
errIdentityProviderNotImplemented = errors.New("identity provider is not implemented")
|
||||
errNoMatchingCertificateFingerprint = errors.New("remote certificate does not match any fingerprint")
|
||||
|
||||
errICEConnectionNotStarted = errors.New("ICE connection not started")
|
||||
errICECandidateTypeUnknown = errors.New("unknown candidate type")
|
||||
errICEInvalidConvertCandidateType = errors.New("cannot convert ice.CandidateType into webrtc.ICECandidateType, invalid type")
|
||||
errICEAgentNotExist = errors.New("ICEAgent does not exist")
|
||||
errICECandiatesCoversionFailed = errors.New("unable to convert ICE candidates to ICECandidates")
|
||||
errICERoleUnknown = errors.New("unknown ICE Role")
|
||||
errICEProtocolUnknown = errors.New("unknown protocol")
|
||||
errICEGathererNotStarted = errors.New("gatherer not started")
|
||||
|
||||
errMediaEngineParseError = errors.New("format parse error")
|
||||
errMediaEngineCodecNotFound = errors.New("could not find codec")
|
||||
errNetworkTypeUnknown = errors.New("unknown network type")
|
||||
|
||||
errSDPDoesNotMatchOffer = errors.New("new sdp does not match previous offer")
|
||||
errSDPDoesNotMatchAnswer = errors.New("new sdp does not match previous answer")
|
||||
errPeerConnSDPTypeInvalidValue = errors.New("provided value is not a valid enum value of type SDPType")
|
||||
errPeerConnStateChangeInvalid = errors.New("invalid state change op")
|
||||
errPeerConnStateChangeUnhandled = errors.New("unhandled state change op")
|
||||
errPeerConnSDPTypeInvalidValueSetLocalDescription = errors.New("invalid SDP type supplied to SetLocalDescription()")
|
||||
errPeerConnRemoteDescriptionWithoutMidValue = errors.New("remoteDescription contained media section without mid value")
|
||||
errPeerConnRemoteDescriptionNil = errors.New("remoteDescription has not been set yet")
|
||||
errPeerConnSingleMediaSectionHasExplicitSSRC = errors.New("single media section has an explicit SSRC")
|
||||
errPeerConnRemoteSSRCAddTransceiver = errors.New("could not add transceiver for remote SSRC")
|
||||
errPeerConnSimulcastMidAndRidRTPExtensionRequired = errors.New("mid and rid RTP Extensions required for Simulcast")
|
||||
errPeerConnSimulcastIncomingSSRCFailed = errors.New("incoming SSRC failed Simulcast probing")
|
||||
errPeerConnAddTransceiverFromKindOnlyAcceptsOne = errors.New("AddTransceiverFromKind only accepts one RtpTransceiverInit")
|
||||
errPeerConnAddTransceiverFromTrackOnlyAcceptsOne = errors.New("AddTransceiverFromTrack only accepts one RtpTransceiverInit")
|
||||
errPeerConnCodecsNotFound = errors.New("no codecs found")
|
||||
errPeerConnAddTransceiverFromKindSupport = errors.New("AddTransceiverFromKind currently only supports recvonly and sendrecv")
|
||||
errPeerConnAddTransceiverFromTrackOneTransceiver = errors.New("AddTransceiverFromTrack only accepts one RtpTransceiverInit")
|
||||
errPeerConnSetIdentityProviderNotImplemented = errors.New("TODO SetIdentityProvider")
|
||||
errPeerConnWriteRTCPOpenWriteStream = errors.New("WriteRTCP failed to open WriteStream")
|
||||
errPeerConnCodecPayloaderNotSet = errors.New("codec payloader not set")
|
||||
errPeerConnTranscieverMidNil = errors.New("cannot find transceiver with mid")
|
||||
|
||||
errRTPReceiverDTLSTransportNil = errors.New("DTLSTransport must not be nil")
|
||||
errRTPReceiverReceiveAlreadyCalled = errors.New("Receive has already been called")
|
||||
errRTPReceiverWithSSRCTrackStreamNotFound = errors.New("unable to find stream for Track with SSRC")
|
||||
errRTPReceiverForSSRCTrackStreamNotFound = errors.New("no trackStreams found for SSRC")
|
||||
|
||||
errRTPSenderTrackNil = errors.New("Track must not be nil")
|
||||
errRTPSenderDTLSTransportNil = errors.New("DTLSTransport must not be nil")
|
||||
errRTPSenderCannotConstructRemoteTrack = errors.New("RTPSender can not be constructed with remote track")
|
||||
errRTPSenderSendAlreadyCalled = errors.New("Send has already been called")
|
||||
errRTPSenderStopped = errors.New("RTPSender has been stopped")
|
||||
|
||||
errRTPTransceiverCannotChangeMid = errors.New("errRTPSenderTrackNil")
|
||||
errRTPTransceiverSetSendingInvalidState = errors.New("invalid state change in RTPTransceiver.setSending")
|
||||
|
||||
errSCTPTransportDTLS = errors.New("DTLS not established")
|
||||
|
||||
errSDPZeroTransceivers = errors.New("addTransceiverSDP() called with 0 transceivers")
|
||||
errSDPMediaSectionMediaDataChanInvalid = errors.New("invalid Media Section. Media + DataChannel both enabled")
|
||||
errSDPMediaSectionMultipleTrackInvalid = errors.New("invalid Media Section. Can not have multiple tracks in one MediaSection in UnifiedPlan")
|
||||
errSDPParseExtMap = errors.New("failed to parse ExtMap")
|
||||
errSDPRemoteDescriptionChangedExtMap = errors.New("RemoteDescription changed some extmaps values")
|
||||
|
||||
errSettingEngineSetAnsweringDTLSRole = errors.New("SetAnsweringDTLSRole must DTLSRoleClient or DTLSRoleServer")
|
||||
|
||||
errSignalingStateCannotRollback = errors.New("can't rollback from stable state")
|
||||
errSignalingStateProposedTransitionInvalid = errors.New("invalid proposed signaling state transition")
|
||||
|
||||
errStatsICECandidateStateInvalid = errors.New("cannot convert to StatsICECandidatePairStateSucceeded invalid ice candidate state")
|
||||
|
||||
errTrackLocalTrackRead = errors.New("this is a local track and must not be read from")
|
||||
errTrackLocalTrackWrite = errors.New("this is a remote track and must not be written to")
|
||||
errTrackSSRCNewTrackZero = errors.New("SSRC supplied to NewTrack() must be non-zero")
|
||||
|
||||
errQuickTransportFingerprintNoMatch = errors.New("no matching fingerprint")
|
||||
errQuickTransportICEConnectionNotStarted = errors.New("ICE connection not started")
|
||||
)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
@@ -15,7 +15,7 @@ const (
|
||||
rtcpPLIInterval = time.Second * 3
|
||||
)
|
||||
|
||||
func main() {
|
||||
func main() { // nolint:gocognit
|
||||
sdpChan := signal.HTTPSDPServer()
|
||||
|
||||
// Everything below is the Pion WebRTC API, thanks for using it ❤️.
|
||||
@@ -82,7 +82,7 @@ func main() {
|
||||
}
|
||||
|
||||
// ErrClosedPipe means we don't have any subscribers, this is ok if no peers have connected yet
|
||||
if _, err = localTrack.Write(rtpBuf[:i]); err != nil && err != io.ErrClosedPipe {
|
||||
if _, err = localTrack.Write(rtpBuf[:i]); err != nil && !errors.Is(err, io.ErrClosedPipe) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"html/template"
|
||||
@@ -15,6 +16,11 @@ import (
|
||||
// Examples represents the examples loaded from examples.json.
|
||||
type Examples []*Example
|
||||
|
||||
var (
|
||||
errListExamples = errors.New("failed to list examples (please run in the examples folder)")
|
||||
errParseExamples = errors.New("failed to parse examples")
|
||||
)
|
||||
|
||||
// Example represents an example loaded from examples.json.
|
||||
type Example struct {
|
||||
Title string `json:"title"`
|
||||
@@ -113,7 +119,7 @@ func serve(addr string) error {
|
||||
func getExamples() (*Examples, error) {
|
||||
file, err := os.Open("./examples.json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list examples (please run in the examples folder): %v", err)
|
||||
return nil, fmt.Errorf("%w: %v", errListExamples, err)
|
||||
}
|
||||
defer func() {
|
||||
closeErr := file.Close()
|
||||
@@ -125,7 +131,7 @@ func getExamples() (*Examples, error) {
|
||||
var examples Examples
|
||||
err = json.NewDecoder(file).Decode(&examples)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse examples: %v", err)
|
||||
return nil, fmt.Errorf("%w: %v", errParseExamples, err)
|
||||
}
|
||||
|
||||
for _, example := range examples {
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
"github.com/pion/webrtc/v3/pkg/media"
|
||||
@@ -56,7 +56,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Create a video track
|
||||
videoTrack, err := peerConnection.NewTrack(payloadType, rand.Uint32(), "video", "pion")
|
||||
videoTrack, err := peerConnection.NewTrack(payloadType, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
package signal
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
)
|
||||
import "github.com/pion/randutil"
|
||||
|
||||
// RandSeq generates a random string to serve as dummy data
|
||||
//
|
||||
// It returns a deterministic sequence of values each time a program is run.
|
||||
// Use rand.Seed() function in your real applications.
|
||||
func RandSeq(n int) string {
|
||||
letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
val, err := randutil.GenerateCryptoRandomString(n, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(b)
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/pion/quic"
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
|
||||
@@ -11,15 +11,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
func signalCandidate(addr string, c *webrtc.ICECandidate) error {
|
||||
payload := []byte(c.ToJSON().Candidate)
|
||||
resp, err := http.Post(fmt.Sprintf("http://%s/candidate", addr),
|
||||
resp, err := http.Post(fmt.Sprintf("http://%s/candidate", addr), // nolint:noctx
|
||||
"application/json; charset=utf-8", bytes.NewReader(payload))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -31,7 +29,7 @@ func signalCandidate(addr string, c *webrtc.ICECandidate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
func main() { // nolint:gocognit
|
||||
offerAddr := flag.String("offer-address", "localhost:50000", "Address that the Offer HTTP server is hosted on.")
|
||||
answerAddr := flag.String("answer-address", ":60000", "Address that the Answer HTTP server is hosted on.")
|
||||
flag.Parse()
|
||||
@@ -108,7 +106,7 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := http.Post(fmt.Sprintf("http://%s/sdp", *offerAddr), "application/json; charset=utf-8", bytes.NewReader(payload))
|
||||
resp, err := http.Post(fmt.Sprintf("http://%s/sdp", *offerAddr), "application/json; charset=utf-8", bytes.NewReader(payload)) // nolint:noctx
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else if closeErr := resp.Body.Close(); closeErr != nil {
|
||||
|
||||
@@ -11,15 +11,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
func signalCandidate(addr string, c *webrtc.ICECandidate) error {
|
||||
payload := []byte(c.ToJSON().Candidate)
|
||||
resp, err := http.Post(fmt.Sprintf("http://%s/candidate", addr),
|
||||
"application/json; charset=utf-8", bytes.NewReader(payload))
|
||||
|
||||
resp, err := http.Post(fmt.Sprintf("http://%s/candidate", addr), "application/json; charset=utf-8", bytes.NewReader(payload)) //nolint:noctx
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -31,7 +28,7 @@ func signalCandidate(addr string, c *webrtc.ICECandidate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
func main() { //nolint:gocognit
|
||||
offerAddr := flag.String("offer-address", ":50000", "Address that the Offer HTTP server is hosted on.")
|
||||
answerAddr := flag.String("answer-address", "127.0.0.1:60000", "Address that the Answer HTTP server is hosted on.")
|
||||
flag.Parse()
|
||||
@@ -160,7 +157,7 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := http.Post(fmt.Sprintf("http://%s/sdp", *answerAddr), "application/json; charset=utf-8", bytes.NewReader(payload))
|
||||
resp, err := http.Post(fmt.Sprintf("http://%s/sdp", *answerAddr), "application/json; charset=utf-8", bytes.NewReader(payload)) // nolint:noctx
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else if err := resp.Body.Close(); err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/pion/webrtc/v3/pkg/media"
|
||||
"github.com/pion/webrtc/v3/pkg/media/ivfreader"
|
||||
@@ -65,7 +66,12 @@ func createPeerConnection(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Add a single video track
|
||||
func addVideo(w http.ResponseWriter, r *http.Request) {
|
||||
videoTrack, err := peerConnection.NewTrack(webrtc.DefaultPayloadTypeVP8, rand.Uint32(), fmt.Sprintf("video-%d", rand.Uint32()), fmt.Sprintf("video-%d", rand.Uint32()))
|
||||
videoTrack, err := peerConnection.NewTrack(
|
||||
webrtc.DefaultPayloadTypeVP8,
|
||||
randutil.NewMathRandomGenerator().Uint32(),
|
||||
fmt.Sprintf("video-%d", randutil.NewMathRandomGenerator().Uint32()),
|
||||
fmt.Sprintf("video-%d", randutil.NewMathRandomGenerator().Uint32()),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
"github.com/pion/webrtc/v3/pkg/media"
|
||||
@@ -59,7 +59,7 @@ func main() {
|
||||
|
||||
if haveVideoFile {
|
||||
// Create a video track
|
||||
videoTrack, addTrackErr := peerConnection.NewTrack(getPayloadType(mediaEngine, webrtc.RTPCodecTypeVideo, "VP8"), rand.Uint32(), "video", "pion")
|
||||
videoTrack, addTrackErr := peerConnection.NewTrack(getPayloadType(mediaEngine, webrtc.RTPCodecTypeVideo, "VP8"), randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
if addTrackErr != nil {
|
||||
panic(addTrackErr)
|
||||
}
|
||||
@@ -106,7 +106,7 @@ func main() {
|
||||
|
||||
if haveAudioFile {
|
||||
// Create a audio track
|
||||
audioTrack, addTrackErr := peerConnection.NewTrack(getPayloadType(mediaEngine, webrtc.RTPCodecTypeAudio, "opus"), rand.Uint32(), "audio", "pion")
|
||||
audioTrack, addTrackErr := peerConnection.NewTrack(getPayloadType(mediaEngine, webrtc.RTPCodecTypeAudio, "opus"), randutil.NewMathRandomGenerator().Uint32(), "audio", "pion")
|
||||
if addTrackErr != nil {
|
||||
panic(addTrackErr)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
@@ -52,7 +52,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Create Track that we send video back to browser on
|
||||
outputTrack, err := peerConnection.NewTrack(videoCodecs[0].PayloadType, rand.Uint32(), "video", "pion")
|
||||
outputTrack, err := peerConnection.NewTrack(videoCodecs[0].PayloadType, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -7,11 +7,10 @@ import (
|
||||
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
"github.com/pion/webrtc/v3/pkg/media"
|
||||
"github.com/pion/webrtc/v3/pkg/media/ivfwriter"
|
||||
"github.com/pion/webrtc/v3/pkg/media/oggwriter"
|
||||
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
func saveToDisk(i media.Writer, track *webrtc.Track) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/sdp/v3"
|
||||
"github.com/pion/webrtc/v3"
|
||||
@@ -38,7 +39,7 @@ func main() {
|
||||
panic("Offer contained no video codecs")
|
||||
}
|
||||
|
||||
//Configure required extensions
|
||||
// Configure required extensions
|
||||
|
||||
sdes, _ := url.Parse(sdp.SDESRTPStreamIDURI)
|
||||
sdedMid, _ := url.Parse(sdp.SDESMidURI)
|
||||
@@ -73,19 +74,19 @@ func main() {
|
||||
outputTracks := map[string]*webrtc.Track{}
|
||||
|
||||
// Create Track that we send video back to browser on
|
||||
outputTrack, err := peerConnection.NewTrack(videoCodecs[0].PayloadType, rand.Uint32(), "video_q", "pion_q")
|
||||
outputTrack, err := peerConnection.NewTrack(videoCodecs[0].PayloadType, randutil.NewMathRandomGenerator().Uint32(), "video_q", "pion_q")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
outputTracks["q"] = outputTrack
|
||||
|
||||
outputTrack, err = peerConnection.NewTrack(videoCodecs[0].PayloadType, rand.Uint32(), "video_h", "pion_h")
|
||||
outputTrack, err = peerConnection.NewTrack(videoCodecs[0].PayloadType, randutil.NewMathRandomGenerator().Uint32(), "video_h", "pion_h")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
outputTracks["h"] = outputTrack
|
||||
|
||||
outputTrack, err = peerConnection.NewTrack(videoCodecs[0].PayloadType, rand.Uint32(), "video_f", "pion_f")
|
||||
outputTrack, err = peerConnection.NewTrack(videoCodecs[0].PayloadType, randutil.NewMathRandomGenerator().Uint32(), "video_f", "pion_f")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -135,7 +136,7 @@ func main() {
|
||||
|
||||
packet.SSRC = outputTracks[rid].SSRC()
|
||||
|
||||
if writeErr := outputTracks[rid].WriteRTP(packet); writeErr != nil && writeErr != io.ErrClosedPipe {
|
||||
if writeErr := outputTracks[rid].WriteRTP(packet); writeErr != nil && !errors.Is(writeErr, io.ErrClosedPipe) {
|
||||
panic(writeErr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/rtp"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/pion/webrtc/v3/examples/internal/signal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
func main() { // nolint:gocognit
|
||||
// Everything below is the Pion WebRTC API! Thanks for using it ❤️.
|
||||
|
||||
// Wait for the offer to be pasted
|
||||
@@ -54,7 +55,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Create Track that we send video back to browser on
|
||||
outputTrack, err := peerConnection.NewTrack(videoCodecs[0].PayloadType, rand.Uint32(), "video", "pion")
|
||||
outputTrack, err := peerConnection.NewTrack(videoCodecs[0].PayloadType, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -174,7 +175,7 @@ func main() {
|
||||
// Keep an increasing sequence number
|
||||
packet.SequenceNumber = i
|
||||
// Write out the packet, ignoring closed pipe if nobody is listening
|
||||
if err := outputTrack.WriteRTP(packet); err != nil && err != io.ErrClosedPipe {
|
||||
if err := outputTrack.WriteRTP(packet); err != nil && !errors.Is(err, io.ErrClosedPipe) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
14
go.mod
14
go.mod
@@ -4,16 +4,16 @@ go 1.12
|
||||
|
||||
require (
|
||||
github.com/pion/datachannel v1.4.21
|
||||
github.com/pion/dtls/v2 v2.0.2
|
||||
github.com/pion/ice/v2 v2.0.6
|
||||
github.com/pion/dtls/v2 v2.0.3
|
||||
github.com/pion/ice/v2 v2.0.7
|
||||
github.com/pion/logging v0.2.2
|
||||
github.com/pion/quic v0.1.4
|
||||
github.com/pion/randutil v0.1.0
|
||||
github.com/pion/rtcp v1.2.3
|
||||
github.com/pion/rtp v1.6.0
|
||||
github.com/pion/sctp v1.7.10
|
||||
github.com/pion/sdp/v3 v3.0.1
|
||||
github.com/pion/srtp v1.5.1
|
||||
github.com/pion/rtcp v1.2.4
|
||||
github.com/pion/rtp v1.6.1
|
||||
github.com/pion/sctp v1.7.11
|
||||
github.com/pion/sdp/v3 v3.0.2
|
||||
github.com/pion/srtp v1.5.2
|
||||
github.com/pion/transport v0.10.1
|
||||
github.com/sclevine/agouti v3.0.0+incompatible
|
||||
github.com/stretchr/testify v1.6.1
|
||||
|
||||
35
go.sum
35
go.sum
@@ -102,29 +102,29 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pion/datachannel v1.4.21 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0=
|
||||
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
|
||||
github.com/pion/dtls/v2 v2.0.2 h1:FHCHTiM182Y8e15aFTiORroiATUI16ryHiQh8AIOJ1E=
|
||||
github.com/pion/dtls/v2 v2.0.2/go.mod h1:27PEO3MDdaCfo21heT59/vsdmZc0zMt9wQPcSlLu/1I=
|
||||
github.com/pion/ice/v2 v2.0.6 h1:7Jf3AX6VIjgO2tGRyT0RGGxkDYOF4m5I5DQzf34IN1Y=
|
||||
github.com/pion/ice/v2 v2.0.6/go.mod h1:xOXvVRlQC/B7FPJeJYKY6IepFRAKb3t1un1K9boYaaQ=
|
||||
github.com/pion/dtls/v2 v2.0.3 h1:3qQ0s4+TXD00rsllL8g8KQcxAs+Y/Z6oz618RXX6p14=
|
||||
github.com/pion/dtls/v2 v2.0.3/go.mod h1:TUjyL8bf8LH95h81Xj7kATmzMRt29F/4lxpIPj2Xe4Y=
|
||||
github.com/pion/ice/v2 v2.0.7 h1:3Iv+EfthCdPbJCsPbhnL4xRzolR1oh9mJTuUsxyxPJI=
|
||||
github.com/pion/ice/v2 v2.0.7/go.mod h1:0C4VBZxkO3A7Qj5ZEgZut8OptbJFSbuGNyPyJMftuHA=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY=
|
||||
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
|
||||
github.com/pion/quic v0.1.4 h1:bNz9sCJjlM3GqMdq7Fne57FiWfdyiJ++yHVbuqeoD3Y=
|
||||
github.com/pion/quic v0.1.4/go.mod h1:dBhNvkLoQqRwfi6h3Vqj3IcPLgiW7rkZxBbRdp7Vzvk=
|
||||
github.com/pion/randutil v0.0.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
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.3 h1:2wrhKnqgSz91Q5nzYTO07mQXztYPtxL8a0XOss4rJqA=
|
||||
github.com/pion/rtcp v1.2.3/go.mod h1:zGhIv0RPRF0Z1Wiij22pUt5W/c9fevqSzT4jje/oK7I=
|
||||
github.com/pion/rtp v1.6.0 h1:4Ssnl/T5W2LzxHj9ssYpGVEQh3YYhQFNVmSWO88MMwk=
|
||||
github.com/pion/rtp v1.6.0/go.mod h1:QgfogHsMBVE/RFNno467U/KBqfUywEH+HK+0rtnwsdI=
|
||||
github.com/pion/sctp v1.7.10 h1:o3p3/hZB5Cx12RMGyWmItevJtZ6o2cpuxaw6GOS4x+8=
|
||||
github.com/pion/rtcp v1.2.4 h1:NT3H5LkUGgaEapvp0HGik+a+CpflRF7KTD7H+o7OWIM=
|
||||
github.com/pion/rtcp v1.2.4/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
|
||||
github.com/pion/rtp v1.6.1 h1:2Y2elcVBrahYnHKN2X7rMHX/r1R4TEBMP1LaVu/wNhk=
|
||||
github.com/pion/rtp v1.6.1/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
|
||||
github.com/pion/sdp/v3 v3.0.1 h1:we4OyeTT6s+6sxrAKy/LVywskx1dzUQlh4xu3b+iAs0=
|
||||
github.com/pion/sdp/v3 v3.0.1/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
|
||||
github.com/pion/srtp v1.5.1 h1:9Q3jAfslYZBt+C69SI/ZcONJh9049JUHZWYRRf5KEKw=
|
||||
github.com/pion/srtp v1.5.1/go.mod h1:B+QgX5xPeQTNc1CJStJPHzOlHK66ViMDWTT0HZTCkcA=
|
||||
github.com/pion/sctp v1.7.11 h1:UCnj7MsobLKLuP/Hh+JMiI/6W5Bs/VF45lWKgHFjSIE=
|
||||
github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
|
||||
github.com/pion/sdp/v3 v3.0.2 h1:UNnSPVaMM+Pdu/mR9UvAyyo6zkdYbKeuOooCwZvTl/g=
|
||||
github.com/pion/sdp/v3 v3.0.2/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
|
||||
github.com/pion/srtp v1.5.2 h1:25DmvH+fqKZDqvX64vTwnycVwL9ooJxHF/gkX16bDBY=
|
||||
github.com/pion/srtp v1.5.2/go.mod h1:NiBff/MSxUwMUwx/fRNyD/xGE+dVvf8BOCeXhjCXZ9U=
|
||||
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
||||
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
||||
github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8=
|
||||
@@ -172,7 +172,6 @@ github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYED
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@@ -190,8 +189,9 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -254,8 +254,9 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
|
||||
@@ -122,7 +122,7 @@ func (c ICECandidate) toICE() (ice.Candidate, error) {
|
||||
}
|
||||
return ice.NewCandidateRelay(&config)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown candidate type: %s", c.Typ)
|
||||
return nil, fmt.Errorf("%w: %s", errICECandidateTypeUnknown, c.Typ)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ func convertTypeFromICE(t ice.CandidateType) (ICECandidateType, error) {
|
||||
case ice.CandidateTypeRelay:
|
||||
return ICECandidateTypeRelay, nil
|
||||
default:
|
||||
return ICECandidateType(t), fmt.Errorf("unknown ICE candidate type: %s", t)
|
||||
return ICECandidateType(t), fmt.Errorf("%w: %s", errICECandidateTypeUnknown, t)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestICECandidate_Convert(t *testing.T) {
|
||||
for i, testCase := range testCases {
|
||||
var expectedICE ice.Candidate
|
||||
var err error
|
||||
switch testCase.expectedType {
|
||||
switch testCase.expectedType { // nolint:exhaustive
|
||||
case ice.CandidateTypeHost:
|
||||
config := ice.CandidateHostConfig{
|
||||
Network: testCase.expectedNetwork,
|
||||
@@ -110,7 +110,6 @@ func TestICECandidate_Convert(t *testing.T) {
|
||||
RelPort: testCase.expectedRelatedAddress.Port,
|
||||
}
|
||||
expectedICE, err = ice.NewCandidateServerReflexive(&config)
|
||||
assert.NoError(t, err)
|
||||
case ice.CandidateTypePeerReflexive:
|
||||
config := ice.CandidatePeerReflexiveConfig{
|
||||
Network: testCase.expectedNetwork,
|
||||
|
||||
@@ -57,7 +57,7 @@ func NewICECandidateType(raw string) (ICECandidateType, error) {
|
||||
case iceCandidateTypeRelayStr:
|
||||
return ICECandidateTypeRelay, nil
|
||||
default:
|
||||
return ICECandidateType(Unknown), fmt.Errorf("unknown ICE candidate type: %s", raw)
|
||||
return ICECandidateType(Unknown), fmt.Errorf("%w: %s", errICECandidateTypeUnknown, raw)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,9 +88,7 @@ func getCandidateType(candidateType ice.CandidateType) (ICECandidateType, error)
|
||||
return ICECandidateTypeRelay, nil
|
||||
default:
|
||||
// NOTE: this should never happen[tm]
|
||||
err := fmt.Errorf(
|
||||
"cannot convert ice.CandidateType into webrtc.ICECandidateType, invalid type: %s",
|
||||
candidateType.String())
|
||||
err := fmt.Errorf("%w: %s", errICEInvalidConvertCandidateType, candidateType.String())
|
||||
return ICECandidateType(Unknown), err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func NewICEProtocol(raw string) (ICEProtocol, error) {
|
||||
case strings.EqualFold(iceProtocolTCPStr, raw):
|
||||
return ICEProtocolTCP, nil
|
||||
default:
|
||||
return ICEProtocol(Unknown), fmt.Errorf("unknown protocol: %s", raw)
|
||||
return ICEProtocol(Unknown), fmt.Errorf("%w: %s", errICEProtocolUnknown, raw)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ package webrtc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -83,7 +83,7 @@ func (t *ICETransport) Start(gatherer *ICEGatherer, params ICEParameters, role *
|
||||
|
||||
agent := t.gatherer.getAgent()
|
||||
if agent == nil {
|
||||
return errors.New("ICEAgent does not exist, unable to start ICETransport")
|
||||
return fmt.Errorf("%w: unable to start ICETransport", errICEAgentNotExist)
|
||||
}
|
||||
|
||||
if err := agent.OnConnectionStateChange(func(iceState ice.ConnectionState) {
|
||||
@@ -99,7 +99,7 @@ func (t *ICETransport) Start(gatherer *ICEGatherer, params ICEParameters, role *
|
||||
if err := agent.OnSelectedCandidatePairChange(func(local, remote ice.Candidate) {
|
||||
candidates, err := newICECandidatesFromICE([]ice.Candidate{local, remote})
|
||||
if err != nil {
|
||||
t.log.Warnf("Unable to convert ICE candidates to ICECandidates: %s", err)
|
||||
t.log.Warnf("%w: %s", errICECandiatesCoversionFailed, err)
|
||||
return
|
||||
}
|
||||
t.onSelectedCandidatePairChange(NewICECandidatePair(&candidates[0], &candidates[1]))
|
||||
@@ -131,7 +131,7 @@ func (t *ICETransport) Start(gatherer *ICEGatherer, params ICEParameters, role *
|
||||
params.Password)
|
||||
|
||||
default:
|
||||
err = errors.New("unknown ICE Role")
|
||||
err = errICERoleUnknown
|
||||
}
|
||||
|
||||
// Reacquire the lock to set the connection/mux
|
||||
@@ -160,7 +160,7 @@ func (t *ICETransport) restart() error {
|
||||
|
||||
agent := t.gatherer.getAgent()
|
||||
if agent == nil {
|
||||
return errors.New("ICEAgent does not exist, unable to restart ICETransport")
|
||||
return fmt.Errorf("%w: unable to restart ICETransport", errICEAgentNotExist)
|
||||
}
|
||||
|
||||
if err := agent.Restart(t.gatherer.api.settingEngine.candidates.UsernameFragment, t.gatherer.api.settingEngine.candidates.Password); err != nil {
|
||||
@@ -227,7 +227,7 @@ func (t *ICETransport) SetRemoteCandidates(remoteCandidates []ICECandidate) erro
|
||||
|
||||
agent := t.gatherer.getAgent()
|
||||
if agent == nil {
|
||||
return errors.New("ICEAgent does not exist, unable to set remote candidates")
|
||||
return fmt.Errorf("%w: unable to set remote candidates", errICEAgentNotExist)
|
||||
}
|
||||
|
||||
for _, c := range remoteCandidates {
|
||||
@@ -260,7 +260,7 @@ func (t *ICETransport) AddRemoteCandidate(remoteCandidate ICECandidate) error {
|
||||
|
||||
agent := t.gatherer.getAgent()
|
||||
if agent == nil {
|
||||
return errors.New("ICEAgent does not exist, unable to add remote candidates")
|
||||
return fmt.Errorf("%w: unable to add remote candidates", errICEAgentNotExist)
|
||||
}
|
||||
|
||||
err = agent.AddRemoteCandidate(c)
|
||||
@@ -287,7 +287,7 @@ func (t *ICETransport) NewEndpoint(f mux.MatchFunc) *mux.Endpoint {
|
||||
|
||||
func (t *ICETransport) ensureGatherer() error {
|
||||
if t.gatherer == nil {
|
||||
return errors.New("gatherer not started")
|
||||
return errICEGathererNotStarted
|
||||
} else if t.gatherer.getAgent() == nil {
|
||||
if err := t.gatherer.createAgent(); err != nil {
|
||||
return err
|
||||
@@ -341,7 +341,7 @@ func (t *ICETransport) setRemoteCredentials(newUfrag, newPwd string) error {
|
||||
|
||||
agent := t.gatherer.getAgent()
|
||||
if agent == nil {
|
||||
return errors.New("ICEAgent does not exist, unable to SetRemoteCredentials")
|
||||
return fmt.Errorf("%w: unable to SetRemoteCredentials", errICEAgentNotExist)
|
||||
}
|
||||
|
||||
return agent.SetRemoteCredentials(newUfrag, newPwd)
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
package webrtc
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/transport/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -26,7 +26,7 @@ func TestICETransport_OnSelectedCandidatePairChange(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opusTrack, err := pcOffer.NewTrack(DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion1")
|
||||
opusTrack, err := pcOffer.NewTrack(DefaultPayloadTypeOpus, randutil.NewMathRandomGenerator().Uint32(), "audio", "pion1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -37,7 +37,7 @@ func TestICETransport_OnSelectedCandidatePairChange(t *testing.T) {
|
||||
iceComplete := make(chan bool)
|
||||
pcAnswer.OnICEConnectionStateChange(func(iceState ICEConnectionState) {
|
||||
if iceState == ICEConnectionStateConnected {
|
||||
time.Sleep(3 * time.Second) // TODO PeerConnection.Close() doesn't block for all subsystems
|
||||
time.Sleep(3 * time.Second)
|
||||
close(iceComplete)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
@@ -39,9 +40,9 @@ func (e *Endpoint) Read(p []byte) (int, error) {
|
||||
// Write writes len(p) bytes to the underlying conn
|
||||
func (e *Endpoint) Write(p []byte) (int, error) {
|
||||
n, err := e.mux.nextConn.Write(p)
|
||||
if err == ice.ErrNoCandidatePairs {
|
||||
if errors.Is(err, ice.ErrNoCandidatePairs) {
|
||||
return 0, nil
|
||||
} else if err == ice.ErrClosed {
|
||||
} else if errors.Is(err, ice.ErrClosed) {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
@@ -58,7 +59,7 @@ func (me multiError) Error() string {
|
||||
|
||||
func (me multiError) Is(err error) bool {
|
||||
for _, e := range me {
|
||||
if e == err {
|
||||
if errors.Is(e, err) {
|
||||
return true
|
||||
}
|
||||
if me2, ok := e.(multiError); ok {
|
||||
|
||||
@@ -11,7 +11,7 @@ func TestMathRandAlpha(t *testing.T) {
|
||||
t.Errorf("MathRandAlpha return invalid length")
|
||||
}
|
||||
|
||||
var isLetter = regexp.MustCompile(`^[a-zA-Z]+$`).MatchString
|
||||
isLetter := regexp.MustCompile(`^[a-zA-Z]+$`).MatchString
|
||||
if !isLetter(MathRandAlpha(10)) {
|
||||
t.Errorf("MathRandAlpha should be AlphaNumeric only")
|
||||
}
|
||||
@@ -19,10 +19,10 @@ func TestMathRandAlpha(t *testing.T) {
|
||||
|
||||
func TestMultiError(t *testing.T) {
|
||||
rawErrs := []error{
|
||||
errors.New("err1"),
|
||||
errors.New("err2"),
|
||||
errors.New("err3"),
|
||||
errors.New("err4"),
|
||||
errors.New("err1"), //nolint
|
||||
errors.New("err2"), //nolint
|
||||
errors.New("err3"), //nolint
|
||||
errors.New("err4"), //nolint
|
||||
}
|
||||
errs := FlattenErrs([]error{
|
||||
rawErrs[0],
|
||||
|
||||
@@ -40,6 +40,7 @@ type MediaEngine struct {
|
||||
// RegisterCodec adds codec to m.
|
||||
// RegisterCodec is not safe for concurrent use.
|
||||
func (m *MediaEngine) RegisterCodec(codec *RTPCodec) uint8 {
|
||||
// nolint:godox
|
||||
// TODO: dynamically generate a payload type in the range 96-127 if one wasn't provided.
|
||||
// See https://github.com/pion/webrtc/issues/43
|
||||
m.codecs = append(m.codecs, codec)
|
||||
@@ -81,13 +82,13 @@ func (m *MediaEngine) PopulateFromSDP(sd SessionDescription) error {
|
||||
for _, format := range md.MediaName.Formats {
|
||||
pt, err := strconv.Atoi(format)
|
||||
if err != nil {
|
||||
return fmt.Errorf("format parse error")
|
||||
return errMediaEngineParseError
|
||||
}
|
||||
|
||||
payloadType := uint8(pt)
|
||||
payloadCodec, err := sdp.GetCodecForPayloadType(payloadType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find codec for payload type %d", payloadType)
|
||||
return fmt.Errorf("%w: codec for payload type %d", errMediaEngineCodecNotFound, payloadType)
|
||||
}
|
||||
|
||||
var codec *RTPCodec
|
||||
@@ -158,7 +159,6 @@ func (m *MediaEngine) GetCodecsByKind(kind RTPCodecType) []*RTPCodec {
|
||||
var codecs []*RTPCodec
|
||||
for _, codec := range m.codecs {
|
||||
if codec.Type == kind {
|
||||
// TODO: clone the codec for safety?
|
||||
codecs = append(codecs, codec)
|
||||
}
|
||||
}
|
||||
@@ -217,7 +217,7 @@ func NewRTPOpusCodec(payloadType uint8, clockrate uint32) *RTPCodec {
|
||||
c := NewRTPCodec(RTPCodecTypeAudio,
|
||||
Opus,
|
||||
clockrate,
|
||||
2, //According to RFC7587, Opus RTP streams must have exactly 2 channels.
|
||||
2, // According to RFC7587, Opus RTP streams must have exactly 2 channels.
|
||||
"minptime=10;useinbandfec=1",
|
||||
payloadType,
|
||||
&codecs.OpusPayloader{})
|
||||
@@ -416,7 +416,6 @@ type RTPCapabilities struct {
|
||||
}
|
||||
|
||||
func (m *MediaEngine) collectStats(collector *statsReportCollector) {
|
||||
|
||||
for _, codec := range m.codecs {
|
||||
collector.Collecting()
|
||||
stats := CodecStats{
|
||||
|
||||
@@ -84,7 +84,7 @@ func NewNetworkType(raw string) (NetworkType, error) {
|
||||
case networkTypeTCP6Str:
|
||||
return NetworkTypeTCP6, nil
|
||||
default:
|
||||
return NetworkType(Unknown), fmt.Errorf("unknown network type: %s", raw)
|
||||
return NetworkType(Unknown), fmt.Errorf("%w: %s", errNetworkTypeUnknown, raw)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,6 @@ func getNetworkType(iceNetworkType ice.NetworkType) (NetworkType, error) {
|
||||
case ice.NetworkTypeTCP6:
|
||||
return NetworkTypeTCP6, nil
|
||||
default:
|
||||
return NetworkType(Unknown), fmt.Errorf("unknown network type: %s", iceNetworkType.String())
|
||||
return NetworkType(Unknown), fmt.Errorf("%w: %s", errNetworkTypeUnknown, iceNetworkType.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/pion/logging"
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/sdp/v3"
|
||||
|
||||
"github.com/pion/webrtc/v3/internal/util"
|
||||
"github.com/pion/webrtc/v3/pkg/rtcerr"
|
||||
)
|
||||
@@ -318,7 +317,7 @@ func (pc *PeerConnection) negotiationNeededOp() {
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *PeerConnection) checkNegotiationNeeded() bool {
|
||||
func (pc *PeerConnection) checkNegotiationNeeded() bool { //nolint:gocognit
|
||||
// To check if negotiation is needed for connection, perform the following checks:
|
||||
// Skip 1, 2 steps
|
||||
// Step 3
|
||||
@@ -378,6 +377,7 @@ func (pc *PeerConnection) checkNegotiationNeeded() bool {
|
||||
if _, ok := m.Attribute(t.Direction().String()); !ok {
|
||||
return true
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
// Step 5.4
|
||||
@@ -457,7 +457,7 @@ func (pc *PeerConnection) OnConnectionStateChange(f func(PeerConnectionState)) {
|
||||
}
|
||||
|
||||
// SetConfiguration updates the configuration of this PeerConnection object.
|
||||
func (pc *PeerConnection) SetConfiguration(configuration Configuration) error {
|
||||
func (pc *PeerConnection) SetConfiguration(configuration Configuration) error { //nolint:gocognit
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-setconfiguration (step #2)
|
||||
if pc.isClosed.get() {
|
||||
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
|
||||
@@ -560,11 +560,11 @@ func (pc *PeerConnection) hasLocalDescriptionChanged(desc *SessionDescription) b
|
||||
|
||||
// CreateOffer starts the PeerConnection and generates the localDescription
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-createoffer
|
||||
func (pc *PeerConnection) CreateOffer(options *OfferOptions) (SessionDescription, error) {
|
||||
func (pc *PeerConnection) CreateOffer(options *OfferOptions) (SessionDescription, error) { //nolint:gocognit
|
||||
useIdentity := pc.idpLoginURL != nil
|
||||
switch {
|
||||
case useIdentity:
|
||||
return SessionDescription{}, fmt.Errorf("TODO handle identity provider")
|
||||
return SessionDescription{}, errIdentityProviderNotImplemented
|
||||
case pc.isClosed.get():
|
||||
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
|
||||
}
|
||||
@@ -754,7 +754,7 @@ func (pc *PeerConnection) CreateAnswer(options *AnswerOptions) (SessionDescripti
|
||||
case pc.RemoteDescription() == nil:
|
||||
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrNoRemoteDescription}
|
||||
case useIdentity:
|
||||
return SessionDescription{}, fmt.Errorf("TODO handle identity provider")
|
||||
return SessionDescription{}, errIdentityProviderNotImplemented
|
||||
case pc.isClosed.get():
|
||||
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
|
||||
case pc.signalingState.Get() != SignalingStateHaveRemoteOffer && pc.signalingState.Get() != SignalingStateHaveLocalPranswer:
|
||||
@@ -787,12 +787,12 @@ func (pc *PeerConnection) CreateAnswer(options *AnswerOptions) (SessionDescripti
|
||||
}
|
||||
|
||||
// 4.4.1.6 Set the SessionDescription
|
||||
func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeOp) error {
|
||||
func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeOp) error { //nolint:gocognit
|
||||
switch {
|
||||
case pc.isClosed.get():
|
||||
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
|
||||
case newSDPType(sd.Type.String()) == SDPType(Unknown):
|
||||
return &rtcerr.TypeError{Err: fmt.Errorf("the provided value '%d' is not a valid enum value of type SDPType", sd.Type)}
|
||||
return &rtcerr.TypeError{Err: fmt.Errorf("%w: '%d' is not a valid enum value of type SDPType", errPeerConnSDPTypeInvalidValue, sd.Type)}
|
||||
}
|
||||
|
||||
nextState, err := func() (SignalingState, error) {
|
||||
@@ -802,8 +802,8 @@ func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeO
|
||||
cur := pc.SignalingState()
|
||||
setLocal := stateChangeOpSetLocal
|
||||
setRemote := stateChangeOpSetRemote
|
||||
newSDPDoesNotMatchOffer := &rtcerr.InvalidModificationError{Err: fmt.Errorf("new sdp does not match previous offer")}
|
||||
newSDPDoesNotMatchAnswer := &rtcerr.InvalidModificationError{Err: fmt.Errorf("new sdp does not match previous answer")}
|
||||
newSDPDoesNotMatchOffer := &rtcerr.InvalidModificationError{Err: errSDPDoesNotMatchOffer}
|
||||
newSDPDoesNotMatchAnswer := &rtcerr.InvalidModificationError{Err: errSDPDoesNotMatchAnswer}
|
||||
|
||||
var nextState SignalingState
|
||||
var err error
|
||||
@@ -847,7 +847,7 @@ func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeO
|
||||
pc.pendingLocalDescription = sd
|
||||
}
|
||||
default:
|
||||
return nextState, &rtcerr.OperationError{Err: fmt.Errorf("invalid state change op: %s(%s)", op, sd.Type)}
|
||||
return nextState, &rtcerr.OperationError{Err: fmt.Errorf("%w: %s(%s)", errPeerConnStateChangeInvalid, op, sd.Type)}
|
||||
}
|
||||
case setRemote:
|
||||
switch sd.Type {
|
||||
@@ -879,10 +879,10 @@ func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeO
|
||||
pc.pendingRemoteDescription = sd
|
||||
}
|
||||
default:
|
||||
return nextState, &rtcerr.OperationError{Err: fmt.Errorf("invalid state change op: %s(%s)", op, sd.Type)}
|
||||
return nextState, &rtcerr.OperationError{Err: fmt.Errorf("%w: %s(%s)", errPeerConnStateChangeInvalid, op, sd.Type)}
|
||||
}
|
||||
default:
|
||||
return nextState, &rtcerr.OperationError{Err: fmt.Errorf("unhandled state change op: %q", op)}
|
||||
return nextState, &rtcerr.OperationError{Err: fmt.Errorf("%w: %q", errPeerConnStateChangeUnhandled, op)}
|
||||
}
|
||||
|
||||
return nextState, nil
|
||||
@@ -916,7 +916,7 @@ func (pc *PeerConnection) SetLocalDescription(desc SessionDescription) error {
|
||||
desc.SDP = pc.lastOffer
|
||||
default:
|
||||
return &rtcerr.InvalidModificationError{
|
||||
Err: fmt.Errorf("invalid SDP type supplied to SetLocalDescription(): %s", desc.Type),
|
||||
Err: fmt.Errorf("%w: %s", errPeerConnSDPTypeInvalidValueSetLocalDescription, desc.Type),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -958,7 +958,7 @@ func (pc *PeerConnection) LocalDescription() *SessionDescription {
|
||||
|
||||
// SetRemoteDescription sets the SessionDescription of the remote peer
|
||||
// nolint: gocyclo
|
||||
func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
|
||||
func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error { //nolint:gocognit
|
||||
if pc.isClosed.get() {
|
||||
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
|
||||
}
|
||||
@@ -982,7 +982,7 @@ func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
|
||||
for _, media := range pc.RemoteDescription().parsed.MediaDescriptions {
|
||||
midValue := getMidValue(media)
|
||||
if midValue == "" {
|
||||
return fmt.Errorf("RemoteDescription contained media section without mid value")
|
||||
return errPeerConnRemoteDescriptionWithoutMidValue
|
||||
}
|
||||
|
||||
if media.MediaName.Media == mediaSectionApplication {
|
||||
@@ -1126,7 +1126,7 @@ func (pc *PeerConnection) startReceiver(incoming trackDetails, receiver *RTPRece
|
||||
}
|
||||
|
||||
// startRTPReceivers opens knows inbound SRTP streams from the RemoteDescription
|
||||
func (pc *PeerConnection) startRTPReceivers(incomingTracks []trackDetails, currentTransceivers []*RTPTransceiver) {
|
||||
func (pc *PeerConnection) startRTPReceivers(incomingTracks []trackDetails, currentTransceivers []*RTPTransceiver) { //nolint:gocognit
|
||||
localTransceivers := append([]*RTPTransceiver{}, currentTransceivers...)
|
||||
|
||||
remoteIsPlanB := false
|
||||
@@ -1135,6 +1135,8 @@ func (pc *PeerConnection) startRTPReceivers(incomingTracks []trackDetails, curre
|
||||
remoteIsPlanB = true
|
||||
case SDPSemanticsUnifiedPlanWithFallback:
|
||||
remoteIsPlanB = descriptionIsPlanB(pc.RemoteDescription())
|
||||
default:
|
||||
// none
|
||||
}
|
||||
|
||||
// Ensure we haven't already started a transceiver for this ssrc
|
||||
@@ -1198,7 +1200,6 @@ func (pc *PeerConnection) startRTPReceivers(incomingTracks []trackDetails, curre
|
||||
// startRTPSenders starts all outbound RTP streams
|
||||
func (pc *PeerConnection) startRTPSenders(currentTransceivers []*RTPTransceiver) {
|
||||
for _, transceiver := range currentTransceivers {
|
||||
// TODO(sgotti) when in future we'll avoid replacing a transceiver sender just check the transceiver negotiation status
|
||||
if transceiver.Sender() != nil && transceiver.Sender().isNegotiated() && !transceiver.Sender().hasSent() {
|
||||
err := transceiver.Sender().Send(RTPSendParameters{
|
||||
Encodings: RTPEncodingParameters{
|
||||
@@ -1206,7 +1207,8 @@ func (pc *PeerConnection) startRTPSenders(currentTransceivers []*RTPTransceiver)
|
||||
SSRC: transceiver.Sender().Track().SSRC(),
|
||||
PayloadType: transceiver.Sender().Track().PayloadType(),
|
||||
},
|
||||
}})
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
pc.log.Warnf("Failed to start Sender: %s", err)
|
||||
}
|
||||
@@ -1251,10 +1253,10 @@ func (pc *PeerConnection) startSCTP() {
|
||||
pc.sctpTransport.lock.Unlock()
|
||||
}
|
||||
|
||||
func (pc *PeerConnection) handleUndeclaredSSRC(rtpStream io.Reader, ssrc uint32) error {
|
||||
func (pc *PeerConnection) handleUndeclaredSSRC(rtpStream io.Reader, ssrc uint32) error { //nolint:gocognit
|
||||
remoteDescription := pc.RemoteDescription()
|
||||
if remoteDescription == nil {
|
||||
return fmt.Errorf("remote Description has not been set yet")
|
||||
return errPeerConnRemoteDescriptionNil
|
||||
}
|
||||
|
||||
// If the remote SDP was only one media section the ssrc doesn't have to be explicitly declared
|
||||
@@ -1262,7 +1264,7 @@ func (pc *PeerConnection) handleUndeclaredSSRC(rtpStream io.Reader, ssrc uint32)
|
||||
onlyMediaSection := remoteDescription.parsed.MediaDescriptions[0]
|
||||
for _, a := range onlyMediaSection.Attributes {
|
||||
if a.Key == ssrcStr {
|
||||
return fmt.Errorf("single media section has an explicit SSRC")
|
||||
return errPeerConnSingleMediaSectionHasExplicitSSRC
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1278,7 +1280,7 @@ func (pc *PeerConnection) handleUndeclaredSSRC(rtpStream io.Reader, ssrc uint32)
|
||||
Direction: RTPTransceiverDirectionSendrecv,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not add transceiver for remote SSRC %d: %s", ssrc, err)
|
||||
return fmt.Errorf("%w: %d: %s", errPeerConnRemoteSSRCAddTransceiver, ssrc, err)
|
||||
}
|
||||
pc.startReceiver(incoming, t.Receiver())
|
||||
return nil
|
||||
@@ -1293,7 +1295,7 @@ func (pc *PeerConnection) handleUndeclaredSSRC(rtpStream io.Reader, ssrc uint32)
|
||||
sdesMidExtMap := getExtMapByURI(matchedSDPMap, sdp.SDESMidURI)
|
||||
sdesStreamIDExtMap := getExtMapByURI(matchedSDPMap, sdp.SDESRTPStreamIDURI)
|
||||
if sdesMidExtMap == nil || sdesStreamIDExtMap == nil {
|
||||
return fmt.Errorf("mid and rid RTP Extensions required for Simulcast")
|
||||
return errPeerConnSimulcastMidAndRidRTPExtensionRequired
|
||||
}
|
||||
|
||||
b := make([]byte, receiveMTU)
|
||||
@@ -1339,7 +1341,7 @@ func (pc *PeerConnection) handleUndeclaredSSRC(rtpStream io.Reader, ssrc uint32)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("incoming SSRC failed Simulcast probing")
|
||||
return errPeerConnSimulcastIncomingSSRCFailed
|
||||
}
|
||||
|
||||
// undeclaredMediaProcessor handles RTP/RTCP packets that don't match any a:ssrc lines
|
||||
@@ -1540,7 +1542,7 @@ func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RtpT
|
||||
|
||||
direction := RTPTransceiverDirectionSendrecv
|
||||
if len(init) > 1 {
|
||||
return nil, fmt.Errorf("AddTransceiverFromKind only accepts one RtpTransceiverInit")
|
||||
return nil, errPeerConnAddTransceiverFromKindOnlyAcceptsOne
|
||||
} else if len(init) == 1 {
|
||||
direction = init[0].Direction
|
||||
}
|
||||
@@ -1549,7 +1551,7 @@ func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RtpT
|
||||
case RTPTransceiverDirectionSendrecv:
|
||||
codecs := pc.api.mediaEngine.GetCodecsByKind(kind)
|
||||
if len(codecs) == 0 {
|
||||
return nil, fmt.Errorf("no %s codecs found", kind.String())
|
||||
return nil, fmt.Errorf("%w: %s", errPeerConnCodecsNotFound, kind.String())
|
||||
}
|
||||
|
||||
track, err := pc.NewTrack(codecs[0].PayloadType, util.RandUint32(), util.MathRandAlpha(trackDefaultIDLength), util.MathRandAlpha(trackDefaultLabelLength))
|
||||
@@ -1576,7 +1578,7 @@ func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RtpT
|
||||
|
||||
return t, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("AddTransceiverFromKind currently only supports recvonly and sendrecv")
|
||||
return nil, errPeerConnAddTransceiverFromKindSupport
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1588,7 +1590,7 @@ func (pc *PeerConnection) AddTransceiverFromTrack(track *Track, init ...RtpTrans
|
||||
|
||||
direction := RTPTransceiverDirectionSendrecv
|
||||
if len(init) > 1 {
|
||||
return nil, fmt.Errorf("AddTransceiverFromTrack only accepts one RtpTransceiverInit")
|
||||
return nil, errPeerConnAddTransceiverFromTrackOnlyAcceptsOne
|
||||
} else if len(init) == 1 {
|
||||
direction = init[0].Direction
|
||||
}
|
||||
@@ -1629,7 +1631,7 @@ func (pc *PeerConnection) AddTransceiverFromTrack(track *Track, init ...RtpTrans
|
||||
pc.onNegotiationNeeded()
|
||||
return t, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("AddTransceiverFromTrack currently only supports sendonly and sendrecv")
|
||||
return nil, errPeerConnAddTransceiverFromTrackOneTransceiver
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1715,7 +1717,7 @@ func (pc *PeerConnection) CreateDataChannel(label string, options *DataChannelIn
|
||||
|
||||
// SetIdentityProvider is used to configure an identity provider to generate identity assertions
|
||||
func (pc *PeerConnection) SetIdentityProvider(provider string) error {
|
||||
return fmt.Errorf("TODO SetIdentityProvider")
|
||||
return errPeerConnSetIdentityProviderNotImplemented
|
||||
}
|
||||
|
||||
// WriteRTCP sends a user provided RTCP packet to the connected peer
|
||||
@@ -1733,7 +1735,7 @@ func (pc *PeerConnection) WriteRTCP(pkts []rtcp.Packet) error {
|
||||
|
||||
writeStream, err := srtcpSession.OpenWriteStream()
|
||||
if err != nil {
|
||||
return fmt.Errorf("WriteRTCP failed to open WriteStream: %v", err)
|
||||
return fmt.Errorf("%w: %v", errPeerConnWriteRTCPOpenWriteStream, err)
|
||||
}
|
||||
|
||||
if _, err := writeStream.Write(raw); err != nil {
|
||||
@@ -1804,7 +1806,7 @@ func (pc *PeerConnection) NewTrack(payloadType uint8, ssrc uint32, id, label str
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if codec.Payloader == nil {
|
||||
return nil, fmt.Errorf("codec payloader not set")
|
||||
return nil, errPeerConnCodecPayloaderNotSet
|
||||
}
|
||||
|
||||
return NewTrack(payloadType, ssrc, id, label, codec)
|
||||
@@ -2107,7 +2109,7 @@ func (pc *PeerConnection) generateUnmatchedSDP(transceivers []*RTPTransceiver, u
|
||||
// generateMatchedSDP generates a SDP and takes the remote state into account
|
||||
// this is used everytime we have a RemoteDescription
|
||||
// nolint: gocyclo
|
||||
func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, useIdentity bool, includeUnmatched bool, connectionRole sdp.ConnectionRole) (*sdp.SessionDescription, error) {
|
||||
func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, useIdentity bool, includeUnmatched bool, connectionRole sdp.ConnectionRole) (*sdp.SessionDescription, error) { //nolint:gocognit
|
||||
d, err := sdp.NewJSEPSessionDescription(useIdentity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -2132,7 +2134,7 @@ func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, use
|
||||
for _, media := range pc.RemoteDescription().parsed.MediaDescriptions {
|
||||
midValue := getMidValue(media)
|
||||
if midValue == "" {
|
||||
return nil, fmt.Errorf("RemoteDescription contained media section without mid value")
|
||||
return nil, errPeerConnRemoteDescriptionWithoutMidValue
|
||||
}
|
||||
|
||||
if media.MediaName.Media == mediaSectionApplication {
|
||||
@@ -2180,7 +2182,7 @@ func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, use
|
||||
}
|
||||
t, localTransceivers = findByMid(midValue, localTransceivers)
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("cannot find transceiver with mid %q", midValue)
|
||||
return nil, fmt.Errorf("%w: %q", errPeerConnTranscieverMidNil, midValue)
|
||||
}
|
||||
if t.Sender() != nil {
|
||||
t.Sender().setNegotiated()
|
||||
|
||||
@@ -654,7 +654,7 @@ func TestOnICEGatheringStateChange(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
switch s {
|
||||
switch s { // nolint:exhaustive
|
||||
case ICEGathererStateClosed:
|
||||
close(seenClosed)
|
||||
return
|
||||
|
||||
@@ -5,15 +5,16 @@ package webrtc
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/sdp/v3"
|
||||
"github.com/pion/transport/test"
|
||||
@@ -22,6 +23,12 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
errIncomingTrackIDInvalid = errors.New("incoming Track ID is invalid")
|
||||
errIncomingTrackLabelInvalid = errors.New("incoming Track Label is invalid")
|
||||
errNoTransceiverwithMid = errors.New("no transceiver with mid")
|
||||
)
|
||||
|
||||
func offerMediaHasDirection(offer SessionDescription, kind RTPCodecType, direction RTPTransceiverDirection) bool {
|
||||
for _, media := range offer.parsed.MediaDescriptions {
|
||||
if media.MediaName.Media == kind.String() {
|
||||
@@ -72,12 +79,12 @@ func TestPeerConnection_Media_Sample(t *testing.T) {
|
||||
|
||||
pcAnswer.OnTrack(func(track *Track, receiver *RTPReceiver) {
|
||||
if track.ID() != expectedTrackID {
|
||||
trackMetadataValid <- fmt.Errorf("Incoming Track ID is invalid expected(%s) actual(%s)", expectedTrackID, track.ID())
|
||||
trackMetadataValid <- fmt.Errorf("%w: expected(%s) actual(%s)", errIncomingTrackIDInvalid, expectedTrackID, track.ID())
|
||||
return
|
||||
}
|
||||
|
||||
if track.Label() != expectedTrackLabel {
|
||||
trackMetadataValid <- fmt.Errorf("Incoming Track Label is invalid expected(%s) actual(%s)", expectedTrackLabel, track.Label())
|
||||
trackMetadataValid <- fmt.Errorf("%w: expected(%s) actual(%s)", errIncomingTrackLabelInvalid, expectedTrackLabel, track.Label())
|
||||
return
|
||||
}
|
||||
close(trackMetadataValid)
|
||||
@@ -121,7 +128,7 @@ func TestPeerConnection_Media_Sample(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), expectedTrackID, expectedTrackLabel)
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), expectedTrackID, expectedTrackLabel)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -233,11 +240,11 @@ func TestPeerConnection_Media_Shutdown(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opusTrack, err := pcOffer.NewTrack(DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion1")
|
||||
opusTrack, err := pcOffer.NewTrack(DefaultPayloadTypeOpus, randutil.NewMathRandomGenerator().Uint32(), "audio", "pion1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2")
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -326,7 +333,7 @@ func TestPeerConnection_Media_Disconnected(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2")
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -406,7 +413,7 @@ func TestPeerConnection_Media_Closed(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vp8Writer, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2")
|
||||
vp8Writer, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -455,9 +462,9 @@ func TestPeerConnection_Media_Closed(t *testing.T) {
|
||||
assert.NoError(t, pcOffer.Close())
|
||||
assert.NoError(t, pcAnswer.Close())
|
||||
|
||||
if err = vp8Writer.WriteSample(media.Sample{Data: []byte{0x00}, Samples: 1}); err != io.ErrClosedPipe {
|
||||
if err = vp8Writer.WriteSample(media.Sample{Data: []byte{0x00}, Samples: 1}); !errors.Is(err, io.ErrClosedPipe) {
|
||||
t.Fatal("Write to Track with no RTPSenders did not return io.ErrClosedPipe")
|
||||
} else if err = pcAnswer.WriteRTCP([]rtcp.Packet{&rtcp.RapidResynchronizationRequest{SenderSSRC: 0, MediaSSRC: 0}}); err != io.ErrClosedPipe {
|
||||
} else if err = pcAnswer.WriteRTCP([]rtcp.Packet{&rtcp.RapidResynchronizationRequest{SenderSSRC: 0, MediaSSRC: 0}}); !errors.Is(err, io.ErrClosedPipe) {
|
||||
t.Fatal("WriteRTCP to closed PeerConnection did not return io.ErrClosedPipe")
|
||||
}
|
||||
}
|
||||
@@ -482,7 +489,7 @@ func TestUndeclaredSSRC(t *testing.T) {
|
||||
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo)
|
||||
assert.NoError(t, err)
|
||||
|
||||
vp8Writer, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2")
|
||||
vp8Writer, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion2")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = pcOffer.AddTrack(vp8Writer)
|
||||
@@ -573,7 +580,7 @@ func TestOfferRejectionMissingCodec(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
track, err := pc.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2")
|
||||
track, err := pc.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -622,7 +629,6 @@ func TestAddTransceiverFromTrackSendOnly(t *testing.T) {
|
||||
"track-id",
|
||||
"track-label",
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
@@ -680,7 +686,6 @@ func TestAddTransceiverFromTrackSendRecv(t *testing.T) {
|
||||
"track-id",
|
||||
"track-label",
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
@@ -770,7 +775,7 @@ func TestAddTransceiverAddTrack_Reuse(t *testing.T) {
|
||||
assert.Equal(t, []*RTPTransceiver{tr}, pc.GetTransceivers())
|
||||
|
||||
addTrack := func() (*Track, *RTPSender) {
|
||||
track, err := pc.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "foo", "bar")
|
||||
track, err := pc.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "foo", "bar")
|
||||
assert.NoError(t, err)
|
||||
|
||||
sender, err := pc.AddTrack(track)
|
||||
@@ -811,7 +816,7 @@ func TestAddTransceiverAddTrack_NewRTPSender_Error(t *testing.T) {
|
||||
dtlsTransport := pc.dtlsTransport
|
||||
pc.dtlsTransport = nil
|
||||
|
||||
track, err := pc.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "foo", "bar")
|
||||
track, err := pc.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "foo", "bar")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = pc.AddTrack(track)
|
||||
@@ -929,7 +934,6 @@ func TestAddTransceiverFromTrackFailsRecvOnly(t *testing.T) {
|
||||
"track-id",
|
||||
"track-label",
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
@@ -1051,7 +1055,7 @@ func TestGetRegisteredRTPCodecs(t *testing.T) {
|
||||
func TestPlanBMediaExchange(t *testing.T) {
|
||||
runTest := func(trackCount int, t *testing.T) {
|
||||
addSingleTrack := func(p *PeerConnection) *Track {
|
||||
track, err := p.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), fmt.Sprintf("video-%d", rand.Uint32()), fmt.Sprintf("video-%d", rand.Uint32()))
|
||||
track, err := p.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), fmt.Sprintf("video-%d", randutil.NewMathRandomGenerator().Uint32()), fmt.Sprintf("video-%d", randutil.NewMathRandomGenerator().Uint32()))
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = p.AddTrack(track)
|
||||
@@ -1137,7 +1141,7 @@ func TestPeerConnection_Start_Only_Negotiated_Senders(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
defer func() { assert.NoError(t, pcAnswer.Close()) }()
|
||||
|
||||
track1, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion1")
|
||||
track1, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion1")
|
||||
require.NoError(t, err)
|
||||
|
||||
sender1, err := pcOffer.AddTrack(track1)
|
||||
@@ -1158,7 +1162,7 @@ func TestPeerConnection_Start_Only_Negotiated_Senders(t *testing.T) {
|
||||
|
||||
// Add a new track between providing the offer and applying the answer
|
||||
|
||||
track2, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2")
|
||||
track2, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion2")
|
||||
require.NoError(t, err)
|
||||
|
||||
sender2, err := pcOffer.AddTrack(track2)
|
||||
@@ -1186,7 +1190,7 @@ func TestPeerConnection_Start_Right_Receiver(t *testing.T) {
|
||||
}
|
||||
return transceiver.Receiver() != nil && transceiver.Receiver().haveReceived(), nil
|
||||
}
|
||||
return false, fmt.Errorf("no transceiver with mid %q", mid)
|
||||
return false, fmt.Errorf("%w: %q", errNoTransceiverwithMid, mid)
|
||||
}
|
||||
|
||||
api := NewAPI()
|
||||
@@ -1203,7 +1207,7 @@ func TestPeerConnection_Start_Right_Receiver(t *testing.T) {
|
||||
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
assert.NoError(t, err)
|
||||
|
||||
track1, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion1")
|
||||
track1, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion1")
|
||||
require.NoError(t, err)
|
||||
|
||||
sender1, err := pcOffer.AddTrack(track1)
|
||||
|
||||
@@ -5,7 +5,6 @@ package webrtc
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -13,11 +12,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v3/pkg/rtcerr"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/transport/test"
|
||||
"github.com/pion/webrtc/v3/internal/util"
|
||||
"github.com/pion/webrtc/v3/pkg/media"
|
||||
"github.com/pion/webrtc/v3/pkg/rtcerr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -96,7 +95,7 @@ func TestPeerConnection_Renegotiation_AddTrack(t *testing.T) {
|
||||
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
assert.NoError(t, err)
|
||||
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "foo", "bar")
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "foo", "bar")
|
||||
assert.NoError(t, err)
|
||||
|
||||
sender, err := pcOffer.AddTrack(vp8Track)
|
||||
@@ -140,7 +139,7 @@ func TestPeerConnection_Renegotiation_AddTrack_Multiple(t *testing.T) {
|
||||
_, err := pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
assert.NoError(t, err)
|
||||
|
||||
track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), trackName, trackName)
|
||||
track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), trackName, trackName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = pcOffer.AddTrack(track)
|
||||
@@ -222,7 +221,7 @@ func TestPeerConnection_Renegotiation_AddTrack_Rename(t *testing.T) {
|
||||
|
||||
_, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
assert.NoError(t, err)
|
||||
vp8Track, err := pcAnswer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "foo1", "bar1")
|
||||
vp8Track, err := pcAnswer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "foo1", "bar1")
|
||||
assert.NoError(t, err)
|
||||
_, err = pcAnswer.AddTrack(vp8Track)
|
||||
assert.NoError(t, err)
|
||||
@@ -263,13 +262,13 @@ func TestPeerConnection_Transceiver_Mid(t *testing.T) {
|
||||
pcAnswer, err := NewPeerConnection(Configuration{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
track1, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion1")
|
||||
track1, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion1")
|
||||
require.NoError(t, err)
|
||||
|
||||
sender1, err := pcOffer.AddTrack(track1)
|
||||
require.NoError(t, err)
|
||||
|
||||
track2, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2")
|
||||
track2, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion2")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = pcOffer.AddTrack(track2)
|
||||
@@ -321,7 +320,7 @@ func TestPeerConnection_Transceiver_Mid(t *testing.T) {
|
||||
pcOffer.ops.Done()
|
||||
pcAnswer.ops.Done()
|
||||
|
||||
track3, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion3")
|
||||
track3, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion3")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = pcOffer.AddTrack(track3)
|
||||
@@ -454,7 +453,7 @@ func TestPeerConnection_Renegotiation_RemoveTrack(t *testing.T) {
|
||||
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
assert.NoError(t, err)
|
||||
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "foo", "bar")
|
||||
vp8Track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "foo", "bar")
|
||||
assert.NoError(t, err)
|
||||
|
||||
rtpSender, err := pcOffer.AddTrack(vp8Track)
|
||||
@@ -511,7 +510,7 @@ func TestPeerConnection_RoleSwitch(t *testing.T) {
|
||||
_, err = pcFirstOfferer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
assert.NoError(t, err)
|
||||
|
||||
vp8Track, err := pcSecondOfferer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "foo", "bar")
|
||||
vp8Track, err := pcSecondOfferer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "foo", "bar")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = pcSecondOfferer.AddTrack(vp8Track)
|
||||
@@ -622,7 +621,7 @@ func TestPeerConnection_Renegotiation_SetLocalDescription(t *testing.T) {
|
||||
_, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
|
||||
assert.NoError(t, err)
|
||||
|
||||
localTrack, err := pcAnswer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "foo", "bar")
|
||||
localTrack, err := pcAnswer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "foo", "bar")
|
||||
assert.NoError(t, err)
|
||||
|
||||
sender, err := pcAnswer.AddTrack(localTrack)
|
||||
@@ -724,7 +723,7 @@ func TestAddDataChannelDuringRenegotation(t *testing.T) {
|
||||
pcAnswer, err := NewPeerConnection(Configuration{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion")
|
||||
track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = pcOffer.AddTrack(track)
|
||||
@@ -792,7 +791,7 @@ func TestNegotiationTrackAndChannel(t *testing.T) {
|
||||
pcAnswer, err := NewPeerConnection(Configuration{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion")
|
||||
track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
assert.NoError(t, err)
|
||||
|
||||
pcAnswer.OnDataChannel(func(*DataChannel) {
|
||||
@@ -860,7 +859,7 @@ func TestNegotiationNeededRemoveTrack(t *testing.T) {
|
||||
pcAnswer, err := NewPeerConnection(Configuration{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion")
|
||||
track, err := pcOffer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
assert.NoError(t, err)
|
||||
|
||||
pcOffer.OnNegotiationNeeded(func() {
|
||||
@@ -924,7 +923,7 @@ func TestNegotiationNeededStressOneSided(t *testing.T) {
|
||||
})
|
||||
|
||||
for i := 0; i < 500; i++ {
|
||||
track, err := pcA.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion")
|
||||
track, err := pcA.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = pcA.AddTrack(track)
|
||||
|
||||
@@ -6,10 +6,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/pion/transport/test"
|
||||
"github.com/pion/webrtc/v3/pkg/rtcerr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// newPair creates two new peer connections (an offerer and an answerer)
|
||||
@@ -225,6 +224,7 @@ func TestPeerConnection_GetConfiguration(t *testing.T) {
|
||||
assert.Equal(t, expected.ICETransportPolicy, actual.ICETransportPolicy)
|
||||
assert.Equal(t, expected.BundlePolicy, actual.BundlePolicy)
|
||||
assert.Equal(t, expected.RTCPMuxPolicy, actual.RTCPMuxPolicy)
|
||||
// nolint:godox
|
||||
// TODO(albrow): Uncomment this after #513 is fixed.
|
||||
// See: https://github.com/pion/webrtc/issues/513.
|
||||
// assert.Equal(t, len(expected.Certificates), len(actual.Certificates))
|
||||
|
||||
@@ -13,8 +13,10 @@ type writerCloser struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
var errCloseErr = errors.New("close error")
|
||||
|
||||
func (w *writerCloser) Close() error {
|
||||
return errors.New("close error")
|
||||
return errCloseErr
|
||||
}
|
||||
|
||||
func TestNewWith(t *testing.T) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package ivfreader
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
@@ -13,6 +14,15 @@ const (
|
||||
ivfFrameHeaderSize = 12
|
||||
)
|
||||
|
||||
var (
|
||||
errNilStream = errors.New("stream is nil")
|
||||
errIncompleteFrameHeader = errors.New("incomplete frame header")
|
||||
errIncompleteFrameData = errors.New("incomplete frame data")
|
||||
errIncompleteFileHeader = errors.New("incomplete file header")
|
||||
errSignatureMismatch = errors.New("IVF signature mismatch")
|
||||
errUnknownIVFVersion = errors.New("IVF version unknown, parser may not parse correctly")
|
||||
)
|
||||
|
||||
// IVFFileHeader 32-byte header for IVF files
|
||||
// https://wiki.multimedia.cx/index.php/IVF
|
||||
type IVFFileHeader struct {
|
||||
@@ -45,7 +55,7 @@ type IVFReader struct {
|
||||
// with an io.Reader input
|
||||
func NewWith(in io.Reader) (*IVFReader, *IVFFileHeader, error) {
|
||||
if in == nil {
|
||||
return nil, nil, fmt.Errorf("stream is nil")
|
||||
return nil, nil, errNilStream
|
||||
}
|
||||
|
||||
reader := &IVFReader{
|
||||
@@ -76,8 +86,8 @@ func (i *IVFReader) ParseNextFrame() ([]byte, *IVFFrameHeader, error) {
|
||||
|
||||
bytesRead, err := io.ReadFull(i.stream, buffer)
|
||||
headerBytesRead := bytesRead
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return nil, nil, fmt.Errorf("incomplete frame header")
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
return nil, nil, errIncompleteFrameHeader
|
||||
} else if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -89,8 +99,8 @@ func (i *IVFReader) ParseNextFrame() ([]byte, *IVFFrameHeader, error) {
|
||||
|
||||
payload := make([]byte, header.FrameSize)
|
||||
bytesRead, err = io.ReadFull(i.stream, payload)
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return nil, nil, fmt.Errorf("incomplete frame data")
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
return nil, nil, errIncompleteFrameData
|
||||
} else if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -105,8 +115,8 @@ func (i *IVFReader) parseFileHeader() (*IVFFileHeader, error) {
|
||||
buffer := make([]byte, ivfFileHeaderSize)
|
||||
|
||||
bytesRead, err := io.ReadFull(i.stream, buffer)
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return nil, fmt.Errorf("incomplete file header")
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
return nil, errIncompleteFileHeader
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -125,11 +135,9 @@ func (i *IVFReader) parseFileHeader() (*IVFFileHeader, error) {
|
||||
}
|
||||
|
||||
if header.signature != ivfFileHeaderSignature {
|
||||
return nil, fmt.Errorf("IVF signature mismatch")
|
||||
return nil, errSignatureMismatch
|
||||
} else if header.version != uint16(0) {
|
||||
errStr := fmt.Sprintf("IVF version unknown: %d,"+
|
||||
" parser may not parse correctly", header.version)
|
||||
return nil, fmt.Errorf(errStr)
|
||||
return nil, fmt.Errorf("%w: expected(0) got(%d)", errUnknownIVFVersion, header.version)
|
||||
}
|
||||
|
||||
i.bytesReadSuccesfully += int64(bytesRead)
|
||||
|
||||
@@ -2,7 +2,7 @@ package ivfreader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -127,7 +127,7 @@ func TestIVFReader_ParseIncompleteFrameHeader(t *testing.T) {
|
||||
|
||||
assert.Nil(payload, "Payload should be nil")
|
||||
assert.Nil(header, "Incomplete header should be nil")
|
||||
assert.Equal(fmt.Errorf("incomplete frame header"), err)
|
||||
assert.Equal(errIncompleteFrameHeader, err)
|
||||
}
|
||||
|
||||
func TestIVFReader_ParseIncompleteFramePayload(t *testing.T) {
|
||||
@@ -150,7 +150,7 @@ func TestIVFReader_ParseIncompleteFramePayload(t *testing.T) {
|
||||
|
||||
assert.Nil(payload, "Incomplete payload should be nil")
|
||||
assert.Nil(header, "Header should be nil")
|
||||
assert.Equal(fmt.Errorf("incomplete frame data"), err)
|
||||
assert.Equal(errIncompleteFrameData, err)
|
||||
}
|
||||
|
||||
func TestIVFReader_EOFWhenNoFramesLeft(t *testing.T) {
|
||||
@@ -163,5 +163,5 @@ func TestIVFReader_EOFWhenNoFramesLeft(t *testing.T) {
|
||||
|
||||
_, _, err = reader.ParseNextFrame()
|
||||
|
||||
assert.Equal(fmt.Errorf("EOF"), err)
|
||||
assert.Equal(io.EOF, err)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package ivfwriter
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
@@ -11,6 +11,11 @@ import (
|
||||
"github.com/pion/rtp/codecs"
|
||||
)
|
||||
|
||||
var (
|
||||
errFileNotOpened = errors.New("file not opened")
|
||||
errInvalidNilPacket = errors.New("invalid nil packet")
|
||||
)
|
||||
|
||||
// IVFWriter is used to take RTP packets and write them to an IVF on disk
|
||||
type IVFWriter struct {
|
||||
ioWriter io.Writer
|
||||
@@ -36,7 +41,7 @@ func New(fileName string) (*IVFWriter, error) {
|
||||
// NewWith initialize a new IVF writer with an io.Writer output
|
||||
func NewWith(out io.Writer) (*IVFWriter, error) {
|
||||
if out == nil {
|
||||
return nil, fmt.Errorf("file not opened")
|
||||
return nil, errFileNotOpened
|
||||
}
|
||||
|
||||
writer := &IVFWriter{
|
||||
@@ -51,10 +56,10 @@ func NewWith(out io.Writer) (*IVFWriter, error) {
|
||||
|
||||
func (i *IVFWriter) writeHeader() error {
|
||||
header := make([]byte, 32)
|
||||
copy(header[0:], []byte("DKIF")) // DKIF
|
||||
copy(header[0:], "DKIF") // DKIF
|
||||
binary.LittleEndian.PutUint16(header[4:], 0) // Version
|
||||
binary.LittleEndian.PutUint16(header[6:], 32) // Header size
|
||||
copy(header[8:], []byte("VP80")) // FOURCC
|
||||
copy(header[8:], "VP80") // FOURCC
|
||||
binary.LittleEndian.PutUint16(header[12:], 640) // Width in pixels
|
||||
binary.LittleEndian.PutUint16(header[14:], 480) // Height in pixels
|
||||
binary.LittleEndian.PutUint32(header[16:], 30) // Framerate denominator
|
||||
@@ -69,7 +74,7 @@ func (i *IVFWriter) writeHeader() error {
|
||||
// WriteRTP adds a new packet and writes the appropriate headers for it
|
||||
func (i *IVFWriter) WriteRTP(packet *rtp.Packet) error {
|
||||
if i.ioWriter == nil {
|
||||
return fmt.Errorf("file not opened")
|
||||
return errFileNotOpened
|
||||
}
|
||||
|
||||
vp8Packet := codecs.VP8Packet{}
|
||||
|
||||
@@ -2,7 +2,6 @@ package ivfwriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
@@ -125,7 +124,7 @@ func TestIVFWriter_AddPacketAndClose(t *testing.T) {
|
||||
message: "IVFWriter shouldn't be able to write something to a closed file",
|
||||
messageClose: "IVFWriter should be able to close an already closed file",
|
||||
packet: nil,
|
||||
err: fmt.Errorf("file not opened"),
|
||||
err: errFileNotOpened,
|
||||
closeErr: nil,
|
||||
},
|
||||
{
|
||||
@@ -133,7 +132,7 @@ func TestIVFWriter_AddPacketAndClose(t *testing.T) {
|
||||
message: "IVFWriter shouldn't be able to write something an empty packet",
|
||||
messageClose: "IVFWriter should be able to close the file",
|
||||
packet: &rtp.Packet{},
|
||||
err: fmt.Errorf("invalid nil packet"),
|
||||
err: errInvalidNilPacket,
|
||||
closeErr: nil,
|
||||
},
|
||||
{
|
||||
@@ -149,7 +148,7 @@ func TestIVFWriter_AddPacketAndClose(t *testing.T) {
|
||||
message: "IVFWriter shouldn't be able to write something to a closed file",
|
||||
messageClose: "IVFWriter should be able to close an already closed file",
|
||||
packet: nil,
|
||||
err: fmt.Errorf("file not opened"),
|
||||
err: errFileNotOpened,
|
||||
closeErr: nil,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,11 +3,11 @@ package oggwriter
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"errors"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/rtp"
|
||||
"github.com/pion/rtp/codecs"
|
||||
)
|
||||
@@ -22,6 +22,11 @@ const (
|
||||
pageHeaderSignature = "OggS"
|
||||
)
|
||||
|
||||
var (
|
||||
errFileNotOpened = errors.New("file not opened")
|
||||
errInvalidNilPacket = errors.New("invalid nil packet")
|
||||
)
|
||||
|
||||
// OggWriter is used to take RTP packets and write them to an OGG on disk
|
||||
type OggWriter struct {
|
||||
stream io.Writer
|
||||
@@ -53,14 +58,14 @@ func New(fileName string, sampleRate uint32, channelCount uint16) (*OggWriter, e
|
||||
// NewWith initialize a new OGG Opus writer with an io.Writer output
|
||||
func NewWith(out io.Writer, sampleRate uint32, channelCount uint16) (*OggWriter, error) {
|
||||
if out == nil {
|
||||
return nil, fmt.Errorf("file not opened")
|
||||
return nil, errFileNotOpened
|
||||
}
|
||||
|
||||
writer := &OggWriter{
|
||||
stream: out,
|
||||
sampleRate: sampleRate,
|
||||
channelCount: channelCount,
|
||||
serial: rand.Uint32(),
|
||||
serial: randutil.NewMathRandomGenerator().Uint32(),
|
||||
checksumTable: generateChecksumTable(),
|
||||
|
||||
// Timestamp and Granule MUST start from 1
|
||||
@@ -102,7 +107,7 @@ func (i *OggWriter) writeHeaders() error {
|
||||
// ID Header
|
||||
oggIDHeader := make([]byte, 19)
|
||||
|
||||
copy(oggIDHeader[0:], []byte(idPageSignature)) // Magic Signature 'OpusHead'
|
||||
copy(oggIDHeader[0:], idPageSignature) // Magic Signature 'OpusHead'
|
||||
oggIDHeader[8] = 1 // Version
|
||||
oggIDHeader[9] = uint8(i.channelCount) // Channel count
|
||||
binary.LittleEndian.PutUint16(oggIDHeader[10:], defaultPreSkip) // pre-skip
|
||||
@@ -120,9 +125,9 @@ func (i *OggWriter) writeHeaders() error {
|
||||
|
||||
// Comment Header
|
||||
oggCommentHeader := make([]byte, 21)
|
||||
copy(oggCommentHeader[0:], []byte(commentPageSignature)) // Magic Signature 'OpusTags'
|
||||
copy(oggCommentHeader[0:], commentPageSignature) // Magic Signature 'OpusTags'
|
||||
binary.LittleEndian.PutUint32(oggCommentHeader[8:], 5) // Vendor Length
|
||||
copy(oggCommentHeader[12:], []byte("pion")) // Vendor name 'pion'
|
||||
copy(oggCommentHeader[12:], "pion") // Vendor name 'pion'
|
||||
binary.LittleEndian.PutUint32(oggCommentHeader[17:], 0) // User Comment List Length
|
||||
|
||||
// RFC specifies that the page where the CommentHeader completes should have a granule position of 0
|
||||
@@ -143,7 +148,7 @@ func (i *OggWriter) createPage(payload []uint8, headerType uint8, granulePos uin
|
||||
i.lastPayloadSize = len(payload)
|
||||
page := make([]byte, pageHeaderSize+1+i.lastPayloadSize)
|
||||
|
||||
copy(page[0:], []byte(pageHeaderSignature)) // page headers starts with 'OggS'
|
||||
copy(page[0:], pageHeaderSignature) // page headers starts with 'OggS'
|
||||
page[4] = 0 // Version
|
||||
page[5] = headerType // 1 = continuation, 2 = beginning of stream, 4 = end of stream
|
||||
binary.LittleEndian.PutUint64(page[6:], granulePos) // granule position
|
||||
@@ -165,7 +170,7 @@ func (i *OggWriter) createPage(payload []uint8, headerType uint8, granulePos uin
|
||||
// WriteRTP adds a new packet and writes the appropriate headers for it
|
||||
func (i *OggWriter) WriteRTP(packet *rtp.Packet) error {
|
||||
if packet == nil {
|
||||
return fmt.Errorf("packet must not be nil")
|
||||
return errInvalidNilPacket
|
||||
}
|
||||
|
||||
opusPacket := codecs.OpusPacket{}
|
||||
@@ -230,7 +235,7 @@ func (i *OggWriter) Close() error {
|
||||
// so we can set values for EOS
|
||||
func (i *OggWriter) writeToStream(p []byte) error {
|
||||
if i.stream == nil {
|
||||
return fmt.Errorf("file not opened")
|
||||
return errFileNotOpened
|
||||
}
|
||||
|
||||
_, err := i.stream.Write(p)
|
||||
|
||||
@@ -2,7 +2,6 @@ package oggwriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
@@ -54,7 +53,7 @@ func TestOggWriter_AddPacketAndClose(t *testing.T) {
|
||||
message: "OggWriter shouldn't be able to write something to a closed file",
|
||||
messageClose: "OggWriter should be able to close an already closed file",
|
||||
packet: validPacket,
|
||||
err: fmt.Errorf("file not opened"),
|
||||
err: errFileNotOpened,
|
||||
closeErr: nil,
|
||||
},
|
||||
{
|
||||
@@ -62,7 +61,7 @@ func TestOggWriter_AddPacketAndClose(t *testing.T) {
|
||||
message: "OggWriter shouldn't be able to write an empty packet",
|
||||
messageClose: "OggWriter should be able to close the file",
|
||||
packet: &rtp.Packet{},
|
||||
err: fmt.Errorf("invalid nil packet"),
|
||||
err: errInvalidNilPacket,
|
||||
closeErr: nil,
|
||||
},
|
||||
{
|
||||
@@ -78,7 +77,7 @@ func TestOggWriter_AddPacketAndClose(t *testing.T) {
|
||||
message: "OggWriter shouldn't be able to write something to a closed file",
|
||||
messageClose: "OggWriter should be able to close an already closed file",
|
||||
packet: nil,
|
||||
err: fmt.Errorf("file not opened"),
|
||||
err: errFileNotOpened,
|
||||
closeErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package rtpdump
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
"regexp"
|
||||
"sync"
|
||||
@@ -30,7 +31,7 @@ func NewReader(r io.Reader) (*Reader, Header, error) {
|
||||
}
|
||||
|
||||
// The file starts with #!rtpplay1.0 address/port\n
|
||||
var preambleRegexp = regexp.MustCompile(`#\!rtpplay1\.0 \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,5}\n`)
|
||||
preambleRegexp := regexp.MustCompile(`#\!rtpplay1\.0 \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,5}\n`)
|
||||
if !preambleRegexp.Match(peek) {
|
||||
return nil, hdr, errMalformed
|
||||
}
|
||||
@@ -46,7 +47,7 @@ func NewReader(r io.Reader) (*Reader, Header, error) {
|
||||
|
||||
hBuf := make([]byte, headerLen)
|
||||
_, err = io.ReadFull(bio, hBuf)
|
||||
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
|
||||
return nil, hdr, errMalformed
|
||||
}
|
||||
if err != nil {
|
||||
@@ -70,7 +71,7 @@ func (r *Reader) Next() (Packet, error) {
|
||||
hBuf := make([]byte, pktHeaderLen)
|
||||
|
||||
_, err := io.ReadFull(r.reader, hBuf)
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
return Packet{}, errMalformed
|
||||
}
|
||||
if err != nil {
|
||||
@@ -88,7 +89,7 @@ func (r *Reader) Next() (Packet, error) {
|
||||
|
||||
payload := make([]byte, h.Length-pktHeaderLen)
|
||||
_, err = io.ReadFull(r.reader, payload)
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
return Packet{}, errMalformed
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package rtpdump
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"reflect"
|
||||
@@ -247,7 +248,7 @@ func TestReader(t *testing.T) {
|
||||
} {
|
||||
r, hdr, err := NewReader(bytes.NewReader(test.Data))
|
||||
if err != nil {
|
||||
if got, want := err, test.WantErr; got != want {
|
||||
if got, want := err, test.WantErr; !errors.Is(got, want) {
|
||||
t.Fatalf("NewReader(%s) err=%v want %v", test.Name, got, want)
|
||||
}
|
||||
continue
|
||||
@@ -272,7 +273,7 @@ func TestReader(t *testing.T) {
|
||||
packets = append(packets, pkt)
|
||||
}
|
||||
|
||||
if got, want := nextErr, test.WantErr; got != want {
|
||||
if got, want := nextErr, test.WantErr; !errors.Is(got, want) {
|
||||
t.Fatalf("%s err=%v want %v", test.Name, got, want)
|
||||
}
|
||||
if got, want := packets, test.WantPackets; !reflect.DeepEqual(got, want) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package rtpdump
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
@@ -65,7 +66,7 @@ func TestMarshalHeader(t *testing.T) {
|
||||
},
|
||||
} {
|
||||
data, err := test.Header.Marshal()
|
||||
if got, want := err, test.WantErr; got != want {
|
||||
if got, want := err, test.WantErr; !errors.Is(got, want) {
|
||||
t.Fatalf("Marshal(%q) err=%v, want %v", test.Name, got, want)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -155,13 +154,13 @@ func (t *QUICTransport) validateFingerPrint(remoteParameters QUICParameters, rem
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("no matching fingerprint")
|
||||
return errQuickTransportFingerprintNoMatch
|
||||
}
|
||||
|
||||
func (t *QUICTransport) ensureICEConn() error {
|
||||
if t.iceTransport == nil ||
|
||||
t.iceTransport.State() == ICETransportStateNew {
|
||||
return errors.New("ICE connection not started")
|
||||
return errQuickTransportICEConnectionNotStarted
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package webrtc
|
||||
|
||||
const (
|
||||
//TypeRTCPFBTransportCC ..
|
||||
// TypeRTCPFBTransportCC ..
|
||||
TypeRTCPFBTransportCC = "transport-cc"
|
||||
|
||||
//TypeRTCPFBGoogREMB ..
|
||||
// TypeRTCPFBGoogREMB ..
|
||||
TypeRTCPFBGoogREMB = "goog-remb"
|
||||
|
||||
//TypeRTCPFBACK ..
|
||||
// TypeRTCPFBACK ..
|
||||
TypeRTCPFBACK = "ack"
|
||||
|
||||
//TypeRTCPFBCCM ..
|
||||
// TypeRTCPFBCCM ..
|
||||
TypeRTCPFBCCM = "ccm"
|
||||
|
||||
//TypeRTCPFBNACK ..
|
||||
// TypeRTCPFBNACK ..
|
||||
TypeRTCPFBNACK = "nack"
|
||||
)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ type RTPReceiver struct {
|
||||
// NewRTPReceiver constructs a new RTPReceiver
|
||||
func (api *API) NewRTPReceiver(kind RTPCodecType, transport *DTLSTransport) (*RTPReceiver, error) {
|
||||
if transport == nil {
|
||||
return nil, fmt.Errorf("DTLSTransport must not be nil")
|
||||
return nil, errRTPReceiverDTLSTransportNil
|
||||
}
|
||||
|
||||
return &RTPReceiver{
|
||||
@@ -87,7 +87,7 @@ func (r *RTPReceiver) Receive(parameters RTPReceiveParameters) error {
|
||||
defer r.mu.Unlock()
|
||||
select {
|
||||
case <-r.received:
|
||||
return fmt.Errorf("Receive has already been called")
|
||||
return errRTPReceiverReceiveAlreadyCalled
|
||||
default:
|
||||
}
|
||||
defer close(r.received)
|
||||
@@ -197,7 +197,7 @@ func (r *RTPReceiver) readRTP(b []byte, reader *Track) (n int, err error) {
|
||||
return t.rtpReadStream.Read(b)
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("unable to find stream for Track with SSRC(%d)", reader.SSRC())
|
||||
return 0, fmt.Errorf("%w: %d", errRTPReceiverWithSSRCTrackStreamNotFound, reader.SSRC())
|
||||
}
|
||||
|
||||
// receiveForRid is the sibling of Receive expect for RIDs instead of SSRCs
|
||||
@@ -224,7 +224,7 @@ func (r *RTPReceiver) receiveForRid(rid string, codec *RTPCodec, ssrc uint32) (*
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no trackStreams found for SSRC(%d)", ssrc)
|
||||
return nil, fmt.Errorf("%w: %d", errRTPReceiverForSSRCTrackStreamNotFound, ssrc)
|
||||
}
|
||||
|
||||
func (r *RTPReceiver) streamsForSSRC(ssrc uint32) (*srtp.ReadStreamSRTP, *srtp.ReadStreamSRTCP, error) {
|
||||
|
||||
12
rtpsender.go
12
rtpsender.go
@@ -3,7 +3,6 @@
|
||||
package webrtc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
@@ -19,6 +18,7 @@ type RTPSender struct {
|
||||
|
||||
transport *DTLSTransport
|
||||
|
||||
// nolint:godox
|
||||
// TODO(sgotti) remove this when in future we'll avoid replacing
|
||||
// a transceiver sender since we can just check the
|
||||
// transceiver negotiation status
|
||||
@@ -34,15 +34,15 @@ type RTPSender struct {
|
||||
// NewRTPSender constructs a new RTPSender
|
||||
func (api *API) NewRTPSender(track *Track, transport *DTLSTransport) (*RTPSender, error) {
|
||||
if track == nil {
|
||||
return nil, fmt.Errorf("Track must not be nil")
|
||||
return nil, errRTPSenderTrackNil
|
||||
} else if transport == nil {
|
||||
return nil, fmt.Errorf("DTLSTransport must not be nil")
|
||||
return nil, errRTPSenderDTLSTransportNil
|
||||
}
|
||||
|
||||
track.mu.Lock()
|
||||
defer track.mu.Unlock()
|
||||
if track.receiver != nil {
|
||||
return nil, fmt.Errorf("RTPSender can not be constructed with remote track")
|
||||
return nil, errRTPSenderCannotConstructRemoteTrack
|
||||
}
|
||||
track.totalSenderCount++
|
||||
|
||||
@@ -94,7 +94,7 @@ func (r *RTPSender) Send(parameters RTPSendParameters) error {
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.hasSent() {
|
||||
return fmt.Errorf("Send has already been called")
|
||||
return errRTPSenderSendAlreadyCalled
|
||||
}
|
||||
|
||||
srtcpSession, err := r.transport.getSRTCPSession()
|
||||
@@ -176,7 +176,7 @@ func (r *RTPSender) ReadRTCP() ([]rtcp.Packet, error) {
|
||||
func (r *RTPSender) SendRTP(header *rtp.Header, payload []byte) (int, error) {
|
||||
select {
|
||||
case <-r.stopCalled:
|
||||
return 0, fmt.Errorf("RTPSender has been stopped")
|
||||
return 0, errRTPSenderStopped
|
||||
case <-r.sendCalled:
|
||||
srtpSession, err := r.transport.getSRTPSession()
|
||||
if err != nil {
|
||||
|
||||
@@ -46,7 +46,7 @@ func (t *RTPTransceiver) Receiver() *RTPReceiver {
|
||||
// setMid sets the RTPTransceiver's mid. If it was already set, will return an error.
|
||||
func (t *RTPTransceiver) setMid(mid string) error {
|
||||
if currentMid := t.Mid(); currentMid != "" {
|
||||
return fmt.Errorf("cannot change transceiver mid from: %s to %s", currentMid, mid)
|
||||
return fmt.Errorf("%w: %s to %s", errRTPTransceiverCannotChangeMid, currentMid, mid)
|
||||
}
|
||||
t.mid.Store(mid)
|
||||
return nil
|
||||
@@ -111,7 +111,7 @@ func (t *RTPTransceiver) setSendingTrack(track *Track) error {
|
||||
case track == nil && t.Direction() == RTPTransceiverDirectionSendonly:
|
||||
t.setDirection(RTPTransceiverDirectionInactive)
|
||||
default:
|
||||
return fmt.Errorf("invalid state change in RTPTransceiver.setSending")
|
||||
return errRTPTransceiverSetSendingInvalidState
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -138,9 +138,10 @@ func satisfyTypeAndDirection(remoteKind RTPCodecType, remoteDirection RTPTransce
|
||||
return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendrecv}
|
||||
case RTPTransceiverDirectionRecvonly:
|
||||
return []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv}
|
||||
}
|
||||
default:
|
||||
return []RTPTransceiverDirection{}
|
||||
}
|
||||
}
|
||||
|
||||
for _, possibleDirection := range getPreferredDirections() {
|
||||
for i := range localTransceivers {
|
||||
|
||||
@@ -68,6 +68,7 @@ func (t RTPTransceiverDirection) Revers() RTPTransceiverDirection {
|
||||
return RTPTransceiverDirectionRecvonly
|
||||
case RTPTransceiverDirectionRecvonly:
|
||||
return RTPTransceiverDirectionSendonly
|
||||
}
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package webrtc
|
||||
|
||||
// RtpTransceiverInit dictionary is used when calling the WebRTC function addTransceiver() to provide configuration options for the new transceiver.
|
||||
type RtpTransceiverInit struct {
|
||||
// RTPTransceiverInit dictionary is used when calling the WebRTC function addTransceiver() to provide configuration options for the new transceiver.
|
||||
type RTPTransceiverInit struct {
|
||||
Direction RTPTransceiverDirection
|
||||
SendEncodings []RTPEncodingParameters
|
||||
// Streams []*Track
|
||||
}
|
||||
|
||||
type RtpTransceiverInit = RTPTransceiverInit //nolint: stylecheck
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
package webrtc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"sync"
|
||||
@@ -141,7 +140,7 @@ func (r *SCTPTransport) Stop() error {
|
||||
func (r *SCTPTransport) ensureDTLS() error {
|
||||
dtlsTransport := r.Transport()
|
||||
if dtlsTransport == nil || dtlsTransport.conn == nil {
|
||||
return errors.New("DTLS not established")
|
||||
return errSCTPTransportDTLS
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -160,10 +159,12 @@ func (r *SCTPTransport) acceptDataChannels(a *sctp.Association) {
|
||||
return
|
||||
}
|
||||
|
||||
var ordered = true
|
||||
var maxRetransmits *uint16
|
||||
var maxPacketLifeTime *uint16
|
||||
var val = uint16(dc.Config.ReliabilityParameter)
|
||||
var (
|
||||
maxRetransmits *uint16
|
||||
maxPacketLifeTime *uint16
|
||||
)
|
||||
val := uint16(dc.Config.ReliabilityParameter)
|
||||
ordered := true
|
||||
|
||||
switch dc.Config.ChannelType {
|
||||
case datachannel.ChannelTypeReliable:
|
||||
@@ -195,7 +196,6 @@ func (r *SCTPTransport) acceptDataChannels(a *sctp.Association) {
|
||||
MaxPacketLifeTime: maxPacketLifeTime,
|
||||
MaxRetransmits: maxRetransmits,
|
||||
}, r.api.settingEngine.LoggerFactory.NewLogger("ortc"))
|
||||
|
||||
if err != nil {
|
||||
r.log.Errorf("Failed to accept data channel: %v", err)
|
||||
r.onError(err)
|
||||
|
||||
12
sdp.go
12
sdp.go
@@ -54,7 +54,7 @@ const (
|
||||
)
|
||||
|
||||
// extract all trackDetails from an SDP.
|
||||
func trackDetailsFromSDP(log logging.LeveledLogger, s *sdp.SessionDescription) []trackDetails {
|
||||
func trackDetailsFromSDP(log logging.LeveledLogger, s *sdp.SessionDescription) []trackDetails { // nolint:gocognit
|
||||
incomingTracks := []trackDetails{}
|
||||
rtxRepairFlows := map[uint32]bool{}
|
||||
|
||||
@@ -285,7 +285,7 @@ func populateLocalCandidates(sessionDescription *SessionDescription, i *ICEGathe
|
||||
func addTransceiverSDP(d *sdp.SessionDescription, isPlanB bool, dtlsFingerprints []DTLSFingerprint, mediaEngine *MediaEngine, midValue string, iceParams ICEParameters, candidates []ICECandidate, dtlsRole sdp.ConnectionRole, iceGatheringState ICEGatheringState, extMaps map[SDPSectionType][]sdp.ExtMap, mediaSection mediaSection) (bool, error) {
|
||||
transceivers := mediaSection.transceivers
|
||||
if len(transceivers) < 1 {
|
||||
return false, fmt.Errorf("addTransceiverSDP() called with 0 transceivers")
|
||||
return false, errSDPZeroTransceivers
|
||||
}
|
||||
// Use the first transceiver to generate the section attributes
|
||||
t := transceivers[0]
|
||||
@@ -385,9 +385,9 @@ func populateSDP(d *sdp.SessionDescription, isPlanB bool, dtlsFingerprints []DTL
|
||||
|
||||
for _, m := range mediaSections {
|
||||
if m.data && len(m.transceivers) != 0 {
|
||||
return nil, fmt.Errorf("invalid Media Section. Media + DataChannel both enabled")
|
||||
return nil, errSDPMediaSectionMediaDataChanInvalid
|
||||
} else if !isPlanB && len(m.transceivers) > 1 {
|
||||
return nil, fmt.Errorf("invalid Media Section. Can not have multiple tracks in one MediaSection in UnifiedPlan")
|
||||
return nil, errSDPMediaSectionMultipleTrackInvalid
|
||||
}
|
||||
|
||||
shouldAddID := true
|
||||
@@ -593,11 +593,11 @@ func remoteExts(session *sdp.SessionDescription) (map[SDPSectionType]map[int]sdp
|
||||
}
|
||||
em := &sdp.ExtMap{}
|
||||
if err := em.Unmarshal("extmap:" + attr.Value); err != nil {
|
||||
return fmt.Errorf("failed to parse ExtMap: %v", err)
|
||||
return fmt.Errorf("%w: %v", errSDPParseExtMap, err)
|
||||
}
|
||||
if remoteExtMap, ok := remoteExtMaps[mediaType][em.Value]; ok {
|
||||
if remoteExtMap.Value != em.Value {
|
||||
return fmt.Errorf("RemoteDescription changed some extmaps values")
|
||||
return errSDPRemoteDescriptionChangedExtMap
|
||||
}
|
||||
} else {
|
||||
remoteExtMaps[mediaType][em.Value] = *em
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/pion/sdp/v3"
|
||||
"github.com/pion/transport/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
package webrtc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
@@ -166,7 +165,7 @@ func (e *SettingEngine) SetNAT1To1IPs(ips []string, candidateType ICECandidateTy
|
||||
// Act as DTLS Server, wait for ClientHello
|
||||
func (e *SettingEngine) SetAnsweringDTLSRole(role DTLSRole) error {
|
||||
if role != DTLSRoleClient && role != DTLSRoleServer {
|
||||
return errors.New("SetAnsweringDTLSRole must DTLSRoleClient or DTLSRoleServer")
|
||||
return errSettingEngineSetAnsweringDTLSRole
|
||||
}
|
||||
|
||||
e.answeringDTLSRole = role
|
||||
|
||||
@@ -114,16 +114,16 @@ func (t *SignalingState) Set(state SignalingState) {
|
||||
atomic.StoreInt32((*int32)(t), int32(state))
|
||||
}
|
||||
|
||||
func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType SDPType) (SignalingState, error) {
|
||||
func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType SDPType) (SignalingState, error) { // nolint:gocognit
|
||||
// Special case for rollbacks
|
||||
if sdpType == SDPTypeRollback && cur == SignalingStateStable {
|
||||
return cur, &rtcerr.InvalidModificationError{
|
||||
Err: fmt.Errorf("can't rollback from stable state"),
|
||||
Err: errSignalingStateCannotRollback,
|
||||
}
|
||||
}
|
||||
|
||||
// 4.3.1 valid state transitions
|
||||
switch cur {
|
||||
switch cur { // nolint:exhaustive
|
||||
case SignalingStateStable:
|
||||
switch op {
|
||||
case stateChangeOpSetLocal:
|
||||
@@ -139,7 +139,7 @@ func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType
|
||||
}
|
||||
case SignalingStateHaveLocalOffer:
|
||||
if op == stateChangeOpSetRemote {
|
||||
switch sdpType {
|
||||
switch sdpType { // nolint:exhaustive
|
||||
// have-local-offer->SetRemote(answer)->stable
|
||||
case SDPTypeAnswer:
|
||||
if next == SignalingStateStable {
|
||||
@@ -161,7 +161,7 @@ func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType
|
||||
}
|
||||
case SignalingStateHaveRemoteOffer:
|
||||
if op == stateChangeOpSetLocal {
|
||||
switch sdpType {
|
||||
switch sdpType { // nolint:exhaustive
|
||||
// have-remote-offer->SetLocal(answer)->stable
|
||||
case SDPTypeAnswer:
|
||||
if next == SignalingStateStable {
|
||||
@@ -182,8 +182,7 @@ func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cur, &rtcerr.InvalidModificationError{
|
||||
Err: fmt.Errorf("invalid proposed signaling state transition %s->%s(%s)->%s", cur, op, sdpType, next),
|
||||
Err: fmt.Errorf("%w: %s->%s(%s)->%s", errSignalingStateProposedTransitionInvalid, cur, op, sdpType, next),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/pion/webrtc/v3/pkg/rtcerr"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
4
stats.go
4
stats.go
@@ -1192,9 +1192,7 @@ func toStatsICECandidatePairState(state ice.CandidatePairState) (StatsICECandida
|
||||
return StatsICECandidatePairStateSucceeded, nil
|
||||
default:
|
||||
// NOTE: this should never happen[tm]
|
||||
err := fmt.Errorf(
|
||||
"cannot convert to StatsICECandidatePairStateSucceeded invalid ice candidate state: %s",
|
||||
state.String())
|
||||
err := fmt.Errorf("%w: %s", errStatsICECandidateStateInvalid, state.String())
|
||||
return StatsICECandidatePairState("Unknown"), err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ func (r StatsReport) GetCertificateStats(c *Certificate) (CertificateStats, bool
|
||||
return CertificateStats{}, false
|
||||
}
|
||||
return certificateStats, true
|
||||
|
||||
}
|
||||
|
||||
// GetCodecStats is a helper method to return the associated stats for a given Codec
|
||||
|
||||
@@ -5,15 +5,17 @@ package webrtc
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/require"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var errReceiveOfferTimeout = fmt.Errorf("timed out waiting to receive offer")
|
||||
|
||||
func TestStatsTimestampTime(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
Timestamp StatsTimestamp
|
||||
@@ -38,7 +40,6 @@ func TestStatsTimestampTime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(maxhawkins): replace with a more meaningful test
|
||||
func TestStatsMarshal(t *testing.T) {
|
||||
for _, test := range []Stats{
|
||||
AudioReceiverStats{},
|
||||
@@ -176,7 +177,7 @@ func signalPairForStats(pcOffer *PeerConnection, pcAnswer *PeerConnection) error
|
||||
timeout := time.After(3 * time.Second)
|
||||
select {
|
||||
case <-timeout:
|
||||
return fmt.Errorf("timed out waiting to receive offer")
|
||||
return errReceiveOfferTimeout
|
||||
case offer := <-offerChan:
|
||||
if err := pcAnswer.SetRemoteDescription(offer); err != nil {
|
||||
return err
|
||||
@@ -203,7 +204,7 @@ func TestPeerConnection_GetStats(t *testing.T) {
|
||||
offerPC, answerPC, err := newPair()
|
||||
assert.NoError(t, err)
|
||||
|
||||
track1, err := offerPC.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion1")
|
||||
track1, err := offerPC.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion1")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = offerPC.AddTrack(track1)
|
||||
@@ -324,9 +325,8 @@ func TestPeerConnection_GetStats(t *testing.T) {
|
||||
|
||||
certificates := offerPC.configuration.Certificates
|
||||
|
||||
for _, certificate := range certificates {
|
||||
certificateStats := getCertificateStats(t, reportPCOffer, &certificate)
|
||||
assert.NotEmpty(t, certificateStats)
|
||||
for i := range certificates {
|
||||
assert.NotEmpty(t, getCertificateStats(t, reportPCOffer, &certificates[i]))
|
||||
}
|
||||
|
||||
assert.NoError(t, offerPC.Close())
|
||||
|
||||
7
track.go
7
track.go
@@ -3,7 +3,6 @@
|
||||
package webrtc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
@@ -108,7 +107,7 @@ func (t *Track) Read(b []byte) (n int, err error) {
|
||||
|
||||
if t.totalSenderCount != 0 || r == nil {
|
||||
t.mu.RUnlock()
|
||||
return 0, fmt.Errorf("this is a local track and must not be read from")
|
||||
return 0, errTrackLocalTrackRead
|
||||
}
|
||||
t.mu.RUnlock()
|
||||
|
||||
@@ -164,7 +163,7 @@ func (t *Track) WriteRTP(p *rtp.Packet) error {
|
||||
t.mu.RLock()
|
||||
if t.receiver != nil {
|
||||
t.mu.RUnlock()
|
||||
return fmt.Errorf("this is a remote track and must not be written to")
|
||||
return errTrackLocalTrackWrite
|
||||
}
|
||||
senders := t.activeSenders
|
||||
totalSenderCount := t.totalSenderCount
|
||||
@@ -187,7 +186,7 @@ func (t *Track) WriteRTP(p *rtp.Packet) error {
|
||||
// NewTrack initializes a new *Track
|
||||
func NewTrack(payloadType uint8, ssrc uint32, id, label string, codec *RTPCodec) (*Track, error) {
|
||||
if ssrc == 0 {
|
||||
return nil, fmt.Errorf("SSRC supplied to NewTrack() must be non-zero")
|
||||
return nil, errTrackSSRCNewTrackZero
|
||||
}
|
||||
|
||||
packetizer := rtp.NewPacketizer(
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
package webrtc
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/pion/randutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestNewVideoTrack(t *testing.T) {
|
||||
|
||||
peer, _ := api.NewPeerConnection(peerConfig)
|
||||
|
||||
_, err := peer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion")
|
||||
_, err := peer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
if err != nil {
|
||||
t.Error("Failed to new video track")
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func TestNewAudioTrack(t *testing.T) {
|
||||
|
||||
peer, _ := api.NewPeerConnection(peerConfig)
|
||||
|
||||
_, err := peer.NewTrack(DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion")
|
||||
_, err := peer.NewTrack(DefaultPayloadTypeOpus, randutil.NewMathRandomGenerator().Uint32(), "audio", "pion")
|
||||
if err != nil {
|
||||
t.Error("Failed to new audio track")
|
||||
}
|
||||
@@ -64,12 +64,12 @@ func TestNewTracks(t *testing.T) {
|
||||
|
||||
peer, _ := api.NewPeerConnection(peerConfig)
|
||||
|
||||
_, err := peer.NewTrack(DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion")
|
||||
_, err := peer.NewTrack(DefaultPayloadTypeOpus, randutil.NewMathRandomGenerator().Uint32(), "audio", "pion")
|
||||
if err != nil {
|
||||
t.Error("Failed to new audio track")
|
||||
}
|
||||
|
||||
_, err = peer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion")
|
||||
_, err = peer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
if err != nil {
|
||||
t.Error("Failed to new video track")
|
||||
}
|
||||
@@ -90,12 +90,12 @@ func TestNewTracksWrite(t *testing.T) {
|
||||
|
||||
peer, _ := api.NewPeerConnection(peerConfig)
|
||||
|
||||
videoTrack, err := peer.NewTrack(DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion")
|
||||
videoTrack, err := peer.NewTrack(DefaultPayloadTypeOpus, randutil.NewMathRandomGenerator().Uint32(), "audio", "pion")
|
||||
if err != nil {
|
||||
t.Error("Failed to new video track")
|
||||
}
|
||||
|
||||
audioTrack, err := peer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion")
|
||||
audioTrack, err := peer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
|
||||
if err != nil {
|
||||
t.Error("Failed to new audio track")
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func TestTrackReadWhenNotAdded(t *testing.T) {
|
||||
peerConnection, err := NewPeerConnection(Configuration{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
track, err := peerConnection.NewTrack(DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion")
|
||||
track, err := peerConnection.NewTrack(DefaultPayloadTypeOpus, randutil.NewMathRandomGenerator().Uint32(), "audio", "pion")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = track.Read([]byte{})
|
||||
|
||||
Reference in New Issue
Block a user