Update CI configs to v0.4.7

Update lint scripts and CI configs.
This commit is contained in:
Sean DuBois
2020-09-29 13:14:15 -07:00
committed by Sean DuBois
parent 0786371c1e
commit 804a12fed3
74 changed files with 518 additions and 346 deletions

View File

@@ -3,6 +3,80 @@ linters-settings:
check-shadowing: true check-shadowing: true
misspell: misspell:
locale: US 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: run:
skip-dirs-use-default: false skip-dirs-use-default: false

View File

@@ -203,6 +203,7 @@ Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contribu
* [Joshua Obasaju](https://github.com/obasajujoshua31) * [Joshua Obasaju](https://github.com/obasajujoshua31)
* [Mission Liao](https://github.com/mission-liao) * [Mission Liao](https://github.com/mission-liao)
* [Hanjun Kim](https://github.com/hallazzang) * [Hanjun Kim](https://github.com/hallazzang)
* [ZHENK](https://github.com/scorpionknifes)
### License ### License
MIT License - see [LICENSE](LICENSE) for full text MIT License - see [LICENSE](LICENSE) for full text

View File

@@ -103,11 +103,11 @@ func (c Certificate) GetFingerprints() ([]DTLSFingerprint, error) {
for _, algo := range fingerprintAlgorithms { for _, algo := range fingerprintAlgorithms {
name, err := fingerprint.StringFromHash(algo) name, err := fingerprint.StringFromHash(algo)
if err != nil { 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) value, err := fingerprint.Fingerprint(c.x509Cert, algo)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create fingerprint: %v", err) return nil, fmt.Errorf("%w: %v", ErrFailedToGenerateCertificateFingerprint, err)
} }
res[i] = DTLSFingerprint{ res[i] = DTLSFingerprint{
Algorithm: name, Algorithm: name,

View File

@@ -15,7 +15,7 @@ import (
"github.com/pion/webrtc/v3/pkg/rtcerr" "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") var errSCTPNotEstablished = errors.New("SCTP not established")
// DataChannel represents a WebRTC DataChannel // DataChannel represents a WebRTC DataChannel
@@ -372,11 +372,11 @@ func (d *DataChannel) Detach() (datachannel.ReadWriteCloser, error) {
defer d.mu.Unlock() defer d.mu.Unlock()
if !d.api.settingEngine.detach.DataChannels { if !d.api.settingEngine.detach.DataChannels {
return nil, fmt.Errorf("enable detaching by calling webrtc.DetachDataChannels()") return nil, errDetachNotEnabled
} }
if d.dataChannel == nil { if d.dataChannel == nil {
return nil, fmt.Errorf("datachannel not opened yet, try calling Detach from OnOpen") return nil, errDetachBeforeOpened
} }
d.detachCalled = true d.detachCalled = true

View File

@@ -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 // math/rand a weak RNG, but this does not need to be secure. Ignore with #nosec
/* #nosec */ /* #nosec */
randInt, err := rand.Int(rand.Reader, big.NewInt(int64(max))) randInt, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
/* #nosec */ /* #nosec */ if err != nil {
if err != nil {
t.Fatalf("Failed to get random sleep duration: %s", err) t.Fatalf("Failed to get random sleep duration: %s", err)
} }
time.Sleep(time.Duration(randInt.Int64()) * time.Microsecond) time.Sleep(time.Duration(randInt.Int64()) * time.Microsecond)
@@ -117,7 +116,7 @@ func TestDataChannelParamters_Go(t *testing.T) {
defer report() defer report()
t.Run("MaxPacketLifeTime exchange", func(t *testing.T) { t.Run("MaxPacketLifeTime exchange", func(t *testing.T) {
var ordered = true ordered := true
var maxPacketLifeTime uint16 = 3 var maxPacketLifeTime uint16 = 3
options := &DataChannelInit{ options := &DataChannelInit{
Ordered: &ordered, Ordered: &ordered,
@@ -218,8 +217,7 @@ func TestDataChannelBufferedAmount(t *testing.T) {
t.Fatalf("Failed to send string on data channel") t.Fatalf("Failed to send string on data channel")
} }
assert.Equal(t, uint64(1500), dc.BufferedAmountLowThreshold(), "value mismatch") 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") t.Fatalf("Failed to send string on data channel")
} }
assert.Equal(t, uint64(1500), dc.BufferedAmountLowThreshold(), "value mismatch") 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) lim := test.TimeOut(time.Second * 5)
defer lim.Stop() defer lim.Stop()
// Use Detach data channels mode
s := SettingEngine{}
//s.DetachDataChannels()
api := NewAPI(WithSettingEngine(s))
// Set up two peer connections. // Set up two peer connections.
config := Configuration{} config := Configuration{}
pca, err := api.NewPeerConnection(config) pca, err := NewPeerConnection(config)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
pcb, err := api.NewPeerConnection(config) pcb, err := NewPeerConnection(config)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -3,13 +3,13 @@
package webrtc package webrtc
import ( import (
"github.com/stretchr/testify/assert"
"io" "io"
"testing" "testing"
"time" "time"
"github.com/pion/transport/test" "github.com/pion/transport/test"
"github.com/pion/webrtc/v3/internal/util" "github.com/pion/webrtc/v3/internal/util"
"github.com/stretchr/testify/assert"
) )
func TestDataChannel_ORTCE2E(t *testing.T) { func TestDataChannel_ORTCE2E(t *testing.T) {

View File

@@ -203,11 +203,8 @@ func TestDataChannel_Send(t *testing.T) {
dc.OnMessage(func(msg DataChannelMessage) { dc.OnMessage(func(msg DataChannelMessage) {
done <- true 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 if e := dc.SendText("Ping"); e != nil {
//
e := dc.SendText("Ping")
if e != nil {
// wasm binding doesn't fire OnOpen (we probably already missed it) // wasm binding doesn't fire OnOpen (we probably already missed it)
dc.OnOpen(func() { dc.OnOpen(func() {
e = dc.SendText("Ping") e = dc.SendText("Ping")

View File

@@ -151,7 +151,7 @@ func (t *DTLSTransport) startSRTP() error {
if t.srtpSession.Load() != nil && t.srtcpSession.Load() != nil { if t.srtpSession.Load() != nil && t.srtcpSession.Load() != nil {
return nil return nil
} else if t.conn == nil { } else if t.conn == nil {
return fmt.Errorf("the DTLS transport has not started yet") return errDtlsTransportNotStarted
} }
srtpConfig := &srtp.Config{ srtpConfig := &srtp.Config{
@@ -189,17 +189,17 @@ func (t *DTLSTransport) startSRTP() error {
connState := t.conn.ConnectionState() connState := t.conn.ConnectionState()
err := srtpConfig.ExtractSessionKeysFromDTLS(&connState, t.role() == DTLSRoleClient) err := srtpConfig.ExtractSessionKeysFromDTLS(&connState, t.role() == DTLSRoleClient)
if err != nil { 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) srtpSession, err := srtp.NewSessionSRTP(t.srtpEndpoint, srtpConfig)
if err != nil { 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) srtcpSession, err := srtp.NewSessionSRTCP(t.srtcpEndpoint, srtpConfig)
if err != nil { if err != nil {
return fmt.Errorf("failed to start srtp: %v", err) return fmt.Errorf("%w: %v", errFailedToStartSRTCP, err)
} }
t.srtpSession.Store(srtpSession) t.srtpSession.Store(srtpSession)
@@ -237,6 +237,7 @@ func (t *DTLSTransport) role() DTLSRole {
return DTLSRoleServer return DTLSRoleServer
case DTLSRoleServer: case DTLSRoleServer:
return DTLSRoleClient return DTLSRoleClient
default:
} }
// If SettingEngine has an explicit role // If SettingEngine has an explicit role
@@ -245,6 +246,7 @@ func (t *DTLSTransport) role() DTLSRole {
return DTLSRoleServer return DTLSRoleServer
case DTLSRoleClient: case DTLSRoleClient:
return DTLSRoleClient return DTLSRoleClient
default:
} }
// Remote was auto and no explicit role was configured via SettingEngine // 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 { 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) t.srtpEndpoint = t.iceTransport.NewEndpoint(mux.MatchSRTP)
@@ -282,7 +284,8 @@ func (t *DTLSTransport) Start(remoteParameters DTLSParameters) error {
{ {
Certificate: [][]byte{cert.x509Cert.Raw}, Certificate: [][]byte{cert.x509Cert.Raw},
PrivateKey: cert.privateKey, PrivateKey: cert.privateKey,
}}, },
},
SRTPProtectionProfiles: []dtls.SRTPProtectionProfile{dtls.SRTP_AEAD_AES_128_GCM, dtls.SRTP_AES128_CM_HMAC_SHA1_80}, SRTPProtectionProfiles: []dtls.SRTPProtectionProfile{dtls.SRTP_AEAD_AES_128_GCM, dtls.SRTP_AES128_CM_HMAC_SHA1_80},
ClientAuth: dtls.RequireAnyClientCert, ClientAuth: dtls.RequireAnyClientCert,
LoggerFactory: t.api.settingEngine.LoggerFactory, LoggerFactory: t.api.settingEngine.LoggerFactory,
@@ -345,7 +348,7 @@ func (t *DTLSTransport) Start(remoteParameters DTLSParameters) error {
remoteCerts := t.conn.ConnectionState().PeerCertificates remoteCerts := t.conn.ConnectionState().PeerCertificates
if len(remoteCerts) == 0 { if len(remoteCerts) == 0 {
t.onStateChange(DTLSTransportStateFailed) t.onStateChange(DTLSTransportStateFailed)
return fmt.Errorf("peer didn't provide certificate via DTLS") return errNoRemoteCertificate
} }
t.remoteCertificate = remoteCerts[0] t.remoteCertificate = remoteCerts[0]
@@ -386,7 +389,7 @@ func (t *DTLSTransport) Stop() error {
if t.conn != nil { if t.conn != nil {
// dtls connection may be closed on sctp close. // 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) 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 { func (t *DTLSTransport) ensureICEConn() error {
if t.iceTransport == nil || t.iceTransport.State() == ICETransportStateNew { if t.iceTransport == nil || t.iceTransport.State() == ICETransportStateNew {
return errors.New("ICE connection not started") return errICEConnectionNotStarted
} }
return nil return nil

View File

@@ -7,7 +7,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"math/rand"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@@ -16,6 +15,7 @@ import (
"github.com/sclevine/agouti" "github.com/sclevine/agouti"
"github.com/pion/randutil"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/pkg/media" "github.com/pion/webrtc/v3/pkg/media"
) )
@@ -351,7 +351,7 @@ func createTrack(offer webrtc.SessionDescription) (*webrtc.PeerConnection, *webr
return nil, nil, nil, errPc 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 { if errTrack != nil {
return nil, nil, nil, errTrack return nil, nil, nil, errTrack
} }

View File

@@ -88,7 +88,7 @@ var (
ErrIncorrectSignalingState = errors.New("operation can not be run in current signaling state") ErrIncorrectSignalingState = errors.New("operation can not be run in current signaling state")
// ErrProtocolTooLarge indicates that value given for a DataChannelInit protocol is // 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") ErrProtocolTooLarge = errors.New("protocol is larger then 65535 bytes")
// ErrSenderNotCreatedByConnection indicates RemoveTrack was called with a RtpSender not created // 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 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") 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")
) )

View File

@@ -1,13 +1,13 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"time" "time"
"github.com/pion/rtcp" "github.com/pion/rtcp"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )
@@ -15,7 +15,7 @@ const (
rtcpPLIInterval = time.Second * 3 rtcpPLIInterval = time.Second * 3
) )
func main() { func main() { // nolint:gocognit
sdpChan := signal.HTTPSDPServer() sdpChan := signal.HTTPSDPServer()
// Everything below is the Pion WebRTC API, thanks for using it ❤️. // 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 // 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) panic(err)
} }
} }

View File

@@ -6,7 +6,6 @@ import (
"time" "time"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )

View File

@@ -5,7 +5,6 @@ import (
"time" "time"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )

View File

@@ -6,7 +6,6 @@ import (
"time" "time"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )

View File

@@ -6,7 +6,6 @@ import (
"time" "time"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors"
"flag" "flag"
"fmt" "fmt"
"html/template" "html/template"
@@ -15,6 +16,11 @@ import (
// Examples represents the examples loaded from examples.json. // Examples represents the examples loaded from examples.json.
type Examples []*Example 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. // Example represents an example loaded from examples.json.
type Example struct { type Example struct {
Title string `json:"title"` Title string `json:"title"`
@@ -113,7 +119,7 @@ func serve(addr string) error {
func getExamples() (*Examples, error) { func getExamples() (*Examples, error) {
file, err := os.Open("./examples.json") file, err := os.Open("./examples.json")
if err != nil { 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() { defer func() {
closeErr := file.Close() closeErr := file.Close()
@@ -125,7 +131,7 @@ func getExamples() (*Examples, error) {
var examples Examples var examples Examples
err = json.NewDecoder(file).Decode(&examples) err = json.NewDecoder(file).Decode(&examples)
if err != nil { 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 { for _, example := range examples {

View File

@@ -4,10 +4,10 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"math/rand"
"os" "os"
"time" "time"
"github.com/pion/randutil"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
"github.com/pion/webrtc/v3/pkg/media" "github.com/pion/webrtc/v3/pkg/media"
@@ -56,7 +56,7 @@ func main() {
} }
// Create a video track // 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 { if err != nil {
panic(err) panic(err)
} }

View File

@@ -1,18 +1,16 @@
package signal package signal
import ( import "github.com/pion/randutil"
"math/rand"
)
// RandSeq generates a random string to serve as dummy data // RandSeq generates a random string to serve as dummy data
// //
// It returns a deterministic sequence of values each time a program is run. // It returns a deterministic sequence of values each time a program is run.
// Use rand.Seed() function in your real applications. // Use rand.Seed() function in your real applications.
func RandSeq(n int) string { func RandSeq(n int) string {
letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") val, err := randutil.GenerateCryptoRandomString(n, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
b := make([]rune, n) if err != nil {
for i := range b { panic(err)
b[i] = letters[rand.Intn(len(letters))]
} }
return string(b)
return val
} }

View File

@@ -9,7 +9,6 @@ import (
"github.com/pion/quic" "github.com/pion/quic"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )

View File

@@ -6,7 +6,6 @@ import (
"time" "time"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )

View File

@@ -11,15 +11,13 @@ import (
"time" "time"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )
func signalCandidate(addr string, c *webrtc.ICECandidate) error { func signalCandidate(addr string, c *webrtc.ICECandidate) error {
payload := []byte(c.ToJSON().Candidate) 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)) "application/json; charset=utf-8", bytes.NewReader(payload))
if err != nil { if err != nil {
return err return err
} }
@@ -31,7 +29,7 @@ func signalCandidate(addr string, c *webrtc.ICECandidate) error {
return nil return nil
} }
func main() { func main() { // nolint:gocognit
offerAddr := flag.String("offer-address", "localhost:50000", "Address that the Offer HTTP server is hosted on.") 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.") answerAddr := flag.String("answer-address", ":60000", "Address that the Answer HTTP server is hosted on.")
flag.Parse() flag.Parse()
@@ -108,7 +106,7 @@ func main() {
if err != nil { if err != nil {
panic(err) 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 { if err != nil {
panic(err) panic(err)
} else if closeErr := resp.Body.Close(); closeErr != nil { } else if closeErr := resp.Body.Close(); closeErr != nil {

View File

@@ -11,15 +11,12 @@ import (
"time" "time"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
) )
func signalCandidate(addr string, c *webrtc.ICECandidate) error { func signalCandidate(addr string, c *webrtc.ICECandidate) error {
payload := []byte(c.ToJSON().Candidate) 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), "application/json; charset=utf-8", bytes.NewReader(payload)) //nolint:noctx
"application/json; charset=utf-8", bytes.NewReader(payload))
if err != nil { if err != nil {
return err return err
} }
@@ -31,7 +28,7 @@ func signalCandidate(addr string, c *webrtc.ICECandidate) error {
return nil return nil
} }
func main() { func main() { //nolint:gocognit
offerAddr := flag.String("offer-address", ":50000", "Address that the Offer HTTP server is hosted on.") 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.") answerAddr := flag.String("answer-address", "127.0.0.1:60000", "Address that the Answer HTTP server is hosted on.")
flag.Parse() flag.Parse()
@@ -160,7 +157,7 @@ func main() {
if err != nil { if err != nil {
panic(err) 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 { if err != nil {
panic(err) panic(err)
} else if err := resp.Body.Close(); err != nil { } else if err := resp.Body.Close(); err != nil {

View File

@@ -8,6 +8,7 @@ import (
"os" "os"
"time" "time"
"github.com/pion/randutil"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/pkg/media" "github.com/pion/webrtc/v3/pkg/media"
"github.com/pion/webrtc/v3/pkg/media/ivfreader" "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 // Add a single video track
func addVideo(w http.ResponseWriter, r *http.Request) { 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 { if err != nil {
panic(err) panic(err)
} }

View File

@@ -4,10 +4,10 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"math/rand"
"os" "os"
"time" "time"
"github.com/pion/randutil"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
"github.com/pion/webrtc/v3/pkg/media" "github.com/pion/webrtc/v3/pkg/media"
@@ -59,7 +59,7 @@ func main() {
if haveVideoFile { if haveVideoFile {
// Create a video track // 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 { if addTrackErr != nil {
panic(addTrackErr) panic(addTrackErr)
} }
@@ -106,7 +106,7 @@ func main() {
if haveAudioFile { if haveAudioFile {
// Create a audio track // 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 { if addTrackErr != nil {
panic(addTrackErr) panic(addTrackErr)
} }

View File

@@ -2,9 +2,9 @@ package main
import ( import (
"fmt" "fmt"
"math/rand"
"time" "time"
"github.com/pion/randutil"
"github.com/pion/rtcp" "github.com/pion/rtcp"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "github.com/pion/webrtc/v3/examples/internal/signal"
@@ -52,7 +52,7 @@ func main() {
} }
// Create Track that we send video back to browser on // 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 { if err != nil {
panic(err) panic(err)
} }

View File

@@ -7,11 +7,10 @@ import (
"github.com/pion/rtcp" "github.com/pion/rtcp"
"github.com/pion/webrtc/v3" "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"
"github.com/pion/webrtc/v3/pkg/media/ivfwriter" "github.com/pion/webrtc/v3/pkg/media/ivfwriter"
"github.com/pion/webrtc/v3/pkg/media/oggwriter" "github.com/pion/webrtc/v3/pkg/media/oggwriter"
"github.com/pion/webrtc/v3/examples/internal/signal"
) )
func saveToDisk(i media.Writer, track *webrtc.Track) { func saveToDisk(i media.Writer, track *webrtc.Track) {

View File

@@ -1,12 +1,13 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"math/rand"
"net/url" "net/url"
"time" "time"
"github.com/pion/randutil"
"github.com/pion/rtcp" "github.com/pion/rtcp"
"github.com/pion/sdp/v3" "github.com/pion/sdp/v3"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
@@ -38,7 +39,7 @@ func main() {
panic("Offer contained no video codecs") panic("Offer contained no video codecs")
} }
//Configure required extensions // Configure required extensions
sdes, _ := url.Parse(sdp.SDESRTPStreamIDURI) sdes, _ := url.Parse(sdp.SDESRTPStreamIDURI)
sdedMid, _ := url.Parse(sdp.SDESMidURI) sdedMid, _ := url.Parse(sdp.SDESMidURI)
@@ -73,19 +74,19 @@ func main() {
outputTracks := map[string]*webrtc.Track{} outputTracks := map[string]*webrtc.Track{}
// Create Track that we send video back to browser on // 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 { if err != nil {
panic(err) panic(err)
} }
outputTracks["q"] = outputTrack 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 { if err != nil {
panic(err) panic(err)
} }
outputTracks["h"] = outputTrack 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 { if err != nil {
panic(err) panic(err)
} }
@@ -135,7 +136,7 @@ func main() {
packet.SSRC = outputTracks[rid].SSRC() 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) panic(writeErr)
} }
} }

View File

@@ -1,18 +1,19 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"math/rand"
"time" "time"
"github.com/pion/randutil"
"github.com/pion/rtcp" "github.com/pion/rtcp"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/examples/internal/signal" "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 ❤️. // Everything below is the Pion WebRTC API! Thanks for using it ❤️.
// Wait for the offer to be pasted // Wait for the offer to be pasted
@@ -54,7 +55,7 @@ func main() {
} }
// Create Track that we send video back to browser on // 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 { if err != nil {
panic(err) panic(err)
} }
@@ -174,7 +175,7 @@ func main() {
// Keep an increasing sequence number // Keep an increasing sequence number
packet.SequenceNumber = i packet.SequenceNumber = i
// Write out the packet, ignoring closed pipe if nobody is listening // 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) panic(err)
} }
} }

14
go.mod
View File

@@ -4,16 +4,16 @@ go 1.12
require ( require (
github.com/pion/datachannel v1.4.21 github.com/pion/datachannel v1.4.21
github.com/pion/dtls/v2 v2.0.2 github.com/pion/dtls/v2 v2.0.3
github.com/pion/ice/v2 v2.0.6 github.com/pion/ice/v2 v2.0.7
github.com/pion/logging v0.2.2 github.com/pion/logging v0.2.2
github.com/pion/quic v0.1.4 github.com/pion/quic v0.1.4
github.com/pion/randutil v0.1.0 github.com/pion/randutil v0.1.0
github.com/pion/rtcp v1.2.3 github.com/pion/rtcp v1.2.4
github.com/pion/rtp v1.6.0 github.com/pion/rtp v1.6.1
github.com/pion/sctp v1.7.10 github.com/pion/sctp v1.7.11
github.com/pion/sdp/v3 v3.0.1 github.com/pion/sdp/v3 v3.0.2
github.com/pion/srtp v1.5.1 github.com/pion/srtp v1.5.2
github.com/pion/transport v0.10.1 github.com/pion/transport v0.10.1
github.com/sclevine/agouti v3.0.0+incompatible github.com/sclevine/agouti v3.0.0+incompatible
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1

35
go.sum
View File

@@ -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/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 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0=
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg= 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.3 h1:3qQ0s4+TXD00rsllL8g8KQcxAs+Y/Z6oz618RXX6p14=
github.com/pion/dtls/v2 v2.0.2/go.mod h1:27PEO3MDdaCfo21heT59/vsdmZc0zMt9wQPcSlLu/1I= github.com/pion/dtls/v2 v2.0.3/go.mod h1:TUjyL8bf8LH95h81Xj7kATmzMRt29F/4lxpIPj2Xe4Y=
github.com/pion/ice/v2 v2.0.6 h1:7Jf3AX6VIjgO2tGRyT0RGGxkDYOF4m5I5DQzf34IN1Y= github.com/pion/ice/v2 v2.0.7 h1:3Iv+EfthCdPbJCsPbhnL4xRzolR1oh9mJTuUsxyxPJI=
github.com/pion/ice/v2 v2.0.6/go.mod h1:xOXvVRlQC/B7FPJeJYKY6IepFRAKb3t1un1K9boYaaQ= 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 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= 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 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY=
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0= 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 h1:bNz9sCJjlM3GqMdq7Fne57FiWfdyiJ++yHVbuqeoD3Y=
github.com/pion/quic v0.1.4/go.mod h1:dBhNvkLoQqRwfi6h3Vqj3IcPLgiW7rkZxBbRdp7Vzvk= 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 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= 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.4 h1:NT3H5LkUGgaEapvp0HGik+a+CpflRF7KTD7H+o7OWIM=
github.com/pion/rtcp v1.2.3/go.mod h1:zGhIv0RPRF0Z1Wiij22pUt5W/c9fevqSzT4jje/oK7I= github.com/pion/rtcp v1.2.4/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtp v1.6.0 h1:4Ssnl/T5W2LzxHj9ssYpGVEQh3YYhQFNVmSWO88MMwk= github.com/pion/rtp v1.6.1 h1:2Y2elcVBrahYnHKN2X7rMHX/r1R4TEBMP1LaVu/wNhk=
github.com/pion/rtp v1.6.0/go.mod h1:QgfogHsMBVE/RFNno467U/KBqfUywEH+HK+0rtnwsdI= github.com/pion/rtp v1.6.1/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.7.10 h1:o3p3/hZB5Cx12RMGyWmItevJtZ6o2cpuxaw6GOS4x+8=
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0= 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/sctp v1.7.11 h1:UCnj7MsobLKLuP/Hh+JMiI/6W5Bs/VF45lWKgHFjSIE=
github.com/pion/sdp/v3 v3.0.1/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk= github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/srtp v1.5.1 h1:9Q3jAfslYZBt+C69SI/ZcONJh9049JUHZWYRRf5KEKw= github.com/pion/sdp/v3 v3.0.2 h1:UNnSPVaMM+Pdu/mR9UvAyyo6zkdYbKeuOooCwZvTl/g=
github.com/pion/srtp v1.5.1/go.mod h1:B+QgX5xPeQTNc1CJStJPHzOlHK66ViMDWTT0HZTCkcA= 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 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= 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= 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/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/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/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/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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 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-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-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-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-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/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-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/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-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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 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-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-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.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=

View File

@@ -122,7 +122,7 @@ func (c ICECandidate) toICE() (ice.Candidate, error) {
} }
return ice.NewCandidateRelay(&config) return ice.NewCandidateRelay(&config)
default: 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: case ice.CandidateTypeRelay:
return ICECandidateTypeRelay, nil return ICECandidateTypeRelay, nil
default: default:
return ICECandidateType(t), fmt.Errorf("unknown ICE candidate type: %s", t) return ICECandidateType(t), fmt.Errorf("%w: %s", errICECandidateTypeUnknown, t)
} }
} }

View File

@@ -87,7 +87,7 @@ func TestICECandidate_Convert(t *testing.T) {
for i, testCase := range testCases { for i, testCase := range testCases {
var expectedICE ice.Candidate var expectedICE ice.Candidate
var err error var err error
switch testCase.expectedType { switch testCase.expectedType { // nolint:exhaustive
case ice.CandidateTypeHost: case ice.CandidateTypeHost:
config := ice.CandidateHostConfig{ config := ice.CandidateHostConfig{
Network: testCase.expectedNetwork, Network: testCase.expectedNetwork,
@@ -110,7 +110,6 @@ func TestICECandidate_Convert(t *testing.T) {
RelPort: testCase.expectedRelatedAddress.Port, RelPort: testCase.expectedRelatedAddress.Port,
} }
expectedICE, err = ice.NewCandidateServerReflexive(&config) expectedICE, err = ice.NewCandidateServerReflexive(&config)
assert.NoError(t, err)
case ice.CandidateTypePeerReflexive: case ice.CandidateTypePeerReflexive:
config := ice.CandidatePeerReflexiveConfig{ config := ice.CandidatePeerReflexiveConfig{
Network: testCase.expectedNetwork, Network: testCase.expectedNetwork,

View File

@@ -57,7 +57,7 @@ func NewICECandidateType(raw string) (ICECandidateType, error) {
case iceCandidateTypeRelayStr: case iceCandidateTypeRelayStr:
return ICECandidateTypeRelay, nil return ICECandidateTypeRelay, nil
default: 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 return ICECandidateTypeRelay, nil
default: default:
// NOTE: this should never happen[tm] // NOTE: this should never happen[tm]
err := fmt.Errorf( err := fmt.Errorf("%w: %s", errICEInvalidConvertCandidateType, candidateType.String())
"cannot convert ice.CandidateType into webrtc.ICECandidateType, invalid type: %s",
candidateType.String())
return ICECandidateType(Unknown), err return ICECandidateType(Unknown), err
} }
} }

View File

@@ -31,7 +31,7 @@ func NewICEProtocol(raw string) (ICEProtocol, error) {
case strings.EqualFold(iceProtocolTCPStr, raw): case strings.EqualFold(iceProtocolTCPStr, raw):
return ICEProtocolTCP, nil return ICEProtocolTCP, nil
default: default:
return ICEProtocol(Unknown), fmt.Errorf("unknown protocol: %s", raw) return ICEProtocol(Unknown), fmt.Errorf("%w: %s", errICEProtocolUnknown, raw)
} }
} }

View File

@@ -4,7 +4,7 @@ package webrtc
import ( import (
"context" "context"
"errors" "fmt"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -83,7 +83,7 @@ func (t *ICETransport) Start(gatherer *ICEGatherer, params ICEParameters, role *
agent := t.gatherer.getAgent() agent := t.gatherer.getAgent()
if agent == nil { 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) { 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) { if err := agent.OnSelectedCandidatePairChange(func(local, remote ice.Candidate) {
candidates, err := newICECandidatesFromICE([]ice.Candidate{local, remote}) candidates, err := newICECandidatesFromICE([]ice.Candidate{local, remote})
if err != nil { if err != nil {
t.log.Warnf("Unable to convert ICE candidates to ICECandidates: %s", err) t.log.Warnf("%w: %s", errICECandiatesCoversionFailed, err)
return return
} }
t.onSelectedCandidatePairChange(NewICECandidatePair(&candidates[0], &candidates[1])) t.onSelectedCandidatePairChange(NewICECandidatePair(&candidates[0], &candidates[1]))
@@ -131,7 +131,7 @@ func (t *ICETransport) Start(gatherer *ICEGatherer, params ICEParameters, role *
params.Password) params.Password)
default: default:
err = errors.New("unknown ICE Role") err = errICERoleUnknown
} }
// Reacquire the lock to set the connection/mux // Reacquire the lock to set the connection/mux
@@ -160,7 +160,7 @@ func (t *ICETransport) restart() error {
agent := t.gatherer.getAgent() agent := t.gatherer.getAgent()
if agent == nil { 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 { 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() agent := t.gatherer.getAgent()
if agent == nil { 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 { for _, c := range remoteCandidates {
@@ -260,7 +260,7 @@ func (t *ICETransport) AddRemoteCandidate(remoteCandidate ICECandidate) error {
agent := t.gatherer.getAgent() agent := t.gatherer.getAgent()
if agent == nil { 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) err = agent.AddRemoteCandidate(c)
@@ -287,7 +287,7 @@ func (t *ICETransport) NewEndpoint(f mux.MatchFunc) *mux.Endpoint {
func (t *ICETransport) ensureGatherer() error { func (t *ICETransport) ensureGatherer() error {
if t.gatherer == nil { if t.gatherer == nil {
return errors.New("gatherer not started") return errICEGathererNotStarted
} else if t.gatherer.getAgent() == nil { } else if t.gatherer.getAgent() == nil {
if err := t.gatherer.createAgent(); err != nil { if err := t.gatherer.createAgent(); err != nil {
return err return err
@@ -341,7 +341,7 @@ func (t *ICETransport) setRemoteCredentials(newUfrag, newPwd string) error {
agent := t.gatherer.getAgent() agent := t.gatherer.getAgent()
if agent == nil { 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) return agent.SetRemoteCredentials(newUfrag, newPwd)

View File

@@ -3,11 +3,11 @@
package webrtc package webrtc
import ( import (
"math/rand"
"sync/atomic" "sync/atomic"
"testing" "testing"
"time" "time"
"github.com/pion/randutil"
"github.com/pion/transport/test" "github.com/pion/transport/test"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -26,7 +26,7 @@ func TestICETransport_OnSelectedCandidatePairChange(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -37,7 +37,7 @@ func TestICETransport_OnSelectedCandidatePairChange(t *testing.T) {
iceComplete := make(chan bool) iceComplete := make(chan bool)
pcAnswer.OnICEConnectionStateChange(func(iceState ICEConnectionState) { pcAnswer.OnICEConnectionStateChange(func(iceState ICEConnectionState) {
if iceState == ICEConnectionStateConnected { if iceState == ICEConnectionStateConnected {
time.Sleep(3 * time.Second) // TODO PeerConnection.Close() doesn't block for all subsystems time.Sleep(3 * time.Second)
close(iceComplete) close(iceComplete)
} }
}) })

View File

@@ -1,6 +1,7 @@
package mux package mux
import ( import (
"errors"
"io" "io"
"net" "net"
"time" "time"
@@ -39,9 +40,9 @@ func (e *Endpoint) Read(p []byte) (int, error) {
// Write writes len(p) bytes to the underlying conn // Write writes len(p) bytes to the underlying conn
func (e *Endpoint) Write(p []byte) (int, error) { func (e *Endpoint) Write(p []byte) (int, error) {
n, err := e.mux.nextConn.Write(p) n, err := e.mux.nextConn.Write(p)
if err == ice.ErrNoCandidatePairs { if errors.Is(err, ice.ErrNoCandidatePairs) {
return 0, nil return 0, nil
} else if err == ice.ErrClosed { } else if errors.Is(err, ice.ErrClosed) {
return 0, io.ErrClosedPipe return 0, io.ErrClosedPipe
} }

View File

@@ -2,6 +2,7 @@
package util package util
import ( import (
"errors"
"strings" "strings"
"github.com/pion/randutil" "github.com/pion/randutil"
@@ -58,7 +59,7 @@ func (me multiError) Error() string {
func (me multiError) Is(err error) bool { func (me multiError) Is(err error) bool {
for _, e := range me { for _, e := range me {
if e == err { if errors.Is(e, err) {
return true return true
} }
if me2, ok := e.(multiError); ok { if me2, ok := e.(multiError); ok {

View File

@@ -11,7 +11,7 @@ func TestMathRandAlpha(t *testing.T) {
t.Errorf("MathRandAlpha return invalid length") 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)) { if !isLetter(MathRandAlpha(10)) {
t.Errorf("MathRandAlpha should be AlphaNumeric only") t.Errorf("MathRandAlpha should be AlphaNumeric only")
} }
@@ -19,10 +19,10 @@ func TestMathRandAlpha(t *testing.T) {
func TestMultiError(t *testing.T) { func TestMultiError(t *testing.T) {
rawErrs := []error{ rawErrs := []error{
errors.New("err1"), errors.New("err1"), //nolint
errors.New("err2"), errors.New("err2"), //nolint
errors.New("err3"), errors.New("err3"), //nolint
errors.New("err4"), errors.New("err4"), //nolint
} }
errs := FlattenErrs([]error{ errs := FlattenErrs([]error{
rawErrs[0], rawErrs[0],

View File

@@ -40,6 +40,7 @@ type MediaEngine struct {
// RegisterCodec adds codec to m. // RegisterCodec adds codec to m.
// RegisterCodec is not safe for concurrent use. // RegisterCodec is not safe for concurrent use.
func (m *MediaEngine) RegisterCodec(codec *RTPCodec) uint8 { 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. // TODO: dynamically generate a payload type in the range 96-127 if one wasn't provided.
// See https://github.com/pion/webrtc/issues/43 // See https://github.com/pion/webrtc/issues/43
m.codecs = append(m.codecs, codec) m.codecs = append(m.codecs, codec)
@@ -81,13 +82,13 @@ func (m *MediaEngine) PopulateFromSDP(sd SessionDescription) error {
for _, format := range md.MediaName.Formats { for _, format := range md.MediaName.Formats {
pt, err := strconv.Atoi(format) pt, err := strconv.Atoi(format)
if err != nil { if err != nil {
return fmt.Errorf("format parse error") return errMediaEngineParseError
} }
payloadType := uint8(pt) payloadType := uint8(pt)
payloadCodec, err := sdp.GetCodecForPayloadType(payloadType) payloadCodec, err := sdp.GetCodecForPayloadType(payloadType)
if err != nil { 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 var codec *RTPCodec
@@ -158,7 +159,6 @@ func (m *MediaEngine) GetCodecsByKind(kind RTPCodecType) []*RTPCodec {
var codecs []*RTPCodec var codecs []*RTPCodec
for _, codec := range m.codecs { for _, codec := range m.codecs {
if codec.Type == kind { if codec.Type == kind {
// TODO: clone the codec for safety?
codecs = append(codecs, codec) codecs = append(codecs, codec)
} }
} }
@@ -217,7 +217,7 @@ func NewRTPOpusCodec(payloadType uint8, clockrate uint32) *RTPCodec {
c := NewRTPCodec(RTPCodecTypeAudio, c := NewRTPCodec(RTPCodecTypeAudio,
Opus, Opus,
clockrate, 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", "minptime=10;useinbandfec=1",
payloadType, payloadType,
&codecs.OpusPayloader{}) &codecs.OpusPayloader{})
@@ -416,7 +416,6 @@ type RTPCapabilities struct {
} }
func (m *MediaEngine) collectStats(collector *statsReportCollector) { func (m *MediaEngine) collectStats(collector *statsReportCollector) {
for _, codec := range m.codecs { for _, codec := range m.codecs {
collector.Collecting() collector.Collecting()
stats := CodecStats{ stats := CodecStats{

View File

@@ -84,7 +84,7 @@ func NewNetworkType(raw string) (NetworkType, error) {
case networkTypeTCP6Str: case networkTypeTCP6Str:
return NetworkTypeTCP6, nil return NetworkTypeTCP6, nil
default: 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: case ice.NetworkTypeTCP6:
return NetworkTypeTCP6, nil return NetworkTypeTCP6, nil
default: default:
return NetworkType(Unknown), fmt.Errorf("unknown network type: %s", iceNetworkType.String()) return NetworkType(Unknown), fmt.Errorf("%w: %s", errNetworkTypeUnknown, iceNetworkType.String())
} }
} }

View File

@@ -18,7 +18,6 @@ import (
"github.com/pion/logging" "github.com/pion/logging"
"github.com/pion/rtcp" "github.com/pion/rtcp"
"github.com/pion/sdp/v3" "github.com/pion/sdp/v3"
"github.com/pion/webrtc/v3/internal/util" "github.com/pion/webrtc/v3/internal/util"
"github.com/pion/webrtc/v3/pkg/rtcerr" "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: // To check if negotiation is needed for connection, perform the following checks:
// Skip 1, 2 steps // Skip 1, 2 steps
// Step 3 // Step 3
@@ -378,6 +377,7 @@ func (pc *PeerConnection) checkNegotiationNeeded() bool {
if _, ok := m.Attribute(t.Direction().String()); !ok { if _, ok := m.Attribute(t.Direction().String()); !ok {
return true return true
} }
default:
} }
} }
// Step 5.4 // Step 5.4
@@ -457,7 +457,7 @@ func (pc *PeerConnection) OnConnectionStateChange(f func(PeerConnectionState)) {
} }
// SetConfiguration updates the configuration of this PeerConnection object. // 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) // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-setconfiguration (step #2)
if pc.isClosed.get() { if pc.isClosed.get() {
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed} return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
@@ -560,11 +560,11 @@ func (pc *PeerConnection) hasLocalDescriptionChanged(desc *SessionDescription) b
// CreateOffer starts the PeerConnection and generates the localDescription // CreateOffer starts the PeerConnection and generates the localDescription
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-createoffer // 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 useIdentity := pc.idpLoginURL != nil
switch { switch {
case useIdentity: case useIdentity:
return SessionDescription{}, fmt.Errorf("TODO handle identity provider") return SessionDescription{}, errIdentityProviderNotImplemented
case pc.isClosed.get(): case pc.isClosed.get():
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
} }
@@ -754,7 +754,7 @@ func (pc *PeerConnection) CreateAnswer(options *AnswerOptions) (SessionDescripti
case pc.RemoteDescription() == nil: case pc.RemoteDescription() == nil:
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrNoRemoteDescription} return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrNoRemoteDescription}
case useIdentity: case useIdentity:
return SessionDescription{}, fmt.Errorf("TODO handle identity provider") return SessionDescription{}, errIdentityProviderNotImplemented
case pc.isClosed.get(): case pc.isClosed.get():
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
case pc.signalingState.Get() != SignalingStateHaveRemoteOffer && pc.signalingState.Get() != SignalingStateHaveLocalPranswer: 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 // 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 { switch {
case pc.isClosed.get(): case pc.isClosed.get():
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed} return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
case newSDPType(sd.Type.String()) == SDPType(Unknown): 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) { nextState, err := func() (SignalingState, error) {
@@ -802,8 +802,8 @@ func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeO
cur := pc.SignalingState() cur := pc.SignalingState()
setLocal := stateChangeOpSetLocal setLocal := stateChangeOpSetLocal
setRemote := stateChangeOpSetRemote setRemote := stateChangeOpSetRemote
newSDPDoesNotMatchOffer := &rtcerr.InvalidModificationError{Err: fmt.Errorf("new sdp does not match previous offer")} newSDPDoesNotMatchOffer := &rtcerr.InvalidModificationError{Err: errSDPDoesNotMatchOffer}
newSDPDoesNotMatchAnswer := &rtcerr.InvalidModificationError{Err: fmt.Errorf("new sdp does not match previous answer")} newSDPDoesNotMatchAnswer := &rtcerr.InvalidModificationError{Err: errSDPDoesNotMatchAnswer}
var nextState SignalingState var nextState SignalingState
var err error var err error
@@ -847,7 +847,7 @@ func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeO
pc.pendingLocalDescription = sd pc.pendingLocalDescription = sd
} }
default: 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: case setRemote:
switch sd.Type { switch sd.Type {
@@ -879,10 +879,10 @@ func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeO
pc.pendingRemoteDescription = sd pc.pendingRemoteDescription = sd
} }
default: 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: 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 return nextState, nil
@@ -916,7 +916,7 @@ func (pc *PeerConnection) SetLocalDescription(desc SessionDescription) error {
desc.SDP = pc.lastOffer desc.SDP = pc.lastOffer
default: default:
return &rtcerr.InvalidModificationError{ 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 // SetRemoteDescription sets the SessionDescription of the remote peer
// nolint: gocyclo // nolint: gocyclo
func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error { func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error { //nolint:gocognit
if pc.isClosed.get() { if pc.isClosed.get() {
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed} return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
} }
@@ -982,7 +982,7 @@ func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
for _, media := range pc.RemoteDescription().parsed.MediaDescriptions { for _, media := range pc.RemoteDescription().parsed.MediaDescriptions {
midValue := getMidValue(media) midValue := getMidValue(media)
if midValue == "" { if midValue == "" {
return fmt.Errorf("RemoteDescription contained media section without mid value") return errPeerConnRemoteDescriptionWithoutMidValue
} }
if media.MediaName.Media == mediaSectionApplication { 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 // 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...) localTransceivers := append([]*RTPTransceiver{}, currentTransceivers...)
remoteIsPlanB := false remoteIsPlanB := false
@@ -1135,6 +1135,8 @@ func (pc *PeerConnection) startRTPReceivers(incomingTracks []trackDetails, curre
remoteIsPlanB = true remoteIsPlanB = true
case SDPSemanticsUnifiedPlanWithFallback: case SDPSemanticsUnifiedPlanWithFallback:
remoteIsPlanB = descriptionIsPlanB(pc.RemoteDescription()) remoteIsPlanB = descriptionIsPlanB(pc.RemoteDescription())
default:
// none
} }
// Ensure we haven't already started a transceiver for this ssrc // 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 // startRTPSenders starts all outbound RTP streams
func (pc *PeerConnection) startRTPSenders(currentTransceivers []*RTPTransceiver) { func (pc *PeerConnection) startRTPSenders(currentTransceivers []*RTPTransceiver) {
for _, transceiver := range currentTransceivers { 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() { if transceiver.Sender() != nil && transceiver.Sender().isNegotiated() && !transceiver.Sender().hasSent() {
err := transceiver.Sender().Send(RTPSendParameters{ err := transceiver.Sender().Send(RTPSendParameters{
Encodings: RTPEncodingParameters{ Encodings: RTPEncodingParameters{
@@ -1206,7 +1207,8 @@ func (pc *PeerConnection) startRTPSenders(currentTransceivers []*RTPTransceiver)
SSRC: transceiver.Sender().Track().SSRC(), SSRC: transceiver.Sender().Track().SSRC(),
PayloadType: transceiver.Sender().Track().PayloadType(), PayloadType: transceiver.Sender().Track().PayloadType(),
}, },
}}) },
})
if err != nil { if err != nil {
pc.log.Warnf("Failed to start Sender: %s", err) pc.log.Warnf("Failed to start Sender: %s", err)
} }
@@ -1251,10 +1253,10 @@ func (pc *PeerConnection) startSCTP() {
pc.sctpTransport.lock.Unlock() 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() remoteDescription := pc.RemoteDescription()
if remoteDescription == nil { 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 // 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] onlyMediaSection := remoteDescription.parsed.MediaDescriptions[0]
for _, a := range onlyMediaSection.Attributes { for _, a := range onlyMediaSection.Attributes {
if a.Key == ssrcStr { 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, Direction: RTPTransceiverDirectionSendrecv,
}) })
if err != nil { 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()) pc.startReceiver(incoming, t.Receiver())
return nil return nil
@@ -1293,7 +1295,7 @@ func (pc *PeerConnection) handleUndeclaredSSRC(rtpStream io.Reader, ssrc uint32)
sdesMidExtMap := getExtMapByURI(matchedSDPMap, sdp.SDESMidURI) sdesMidExtMap := getExtMapByURI(matchedSDPMap, sdp.SDESMidURI)
sdesStreamIDExtMap := getExtMapByURI(matchedSDPMap, sdp.SDESRTPStreamIDURI) sdesStreamIDExtMap := getExtMapByURI(matchedSDPMap, sdp.SDESRTPStreamIDURI)
if sdesMidExtMap == nil || sdesStreamIDExtMap == nil { if sdesMidExtMap == nil || sdesStreamIDExtMap == nil {
return fmt.Errorf("mid and rid RTP Extensions required for Simulcast") return errPeerConnSimulcastMidAndRidRTPExtensionRequired
} }
b := make([]byte, receiveMTU) 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 // 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 direction := RTPTransceiverDirectionSendrecv
if len(init) > 1 { if len(init) > 1 {
return nil, fmt.Errorf("AddTransceiverFromKind only accepts one RtpTransceiverInit") return nil, errPeerConnAddTransceiverFromKindOnlyAcceptsOne
} else if len(init) == 1 { } else if len(init) == 1 {
direction = init[0].Direction direction = init[0].Direction
} }
@@ -1549,7 +1551,7 @@ func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RtpT
case RTPTransceiverDirectionSendrecv: case RTPTransceiverDirectionSendrecv:
codecs := pc.api.mediaEngine.GetCodecsByKind(kind) codecs := pc.api.mediaEngine.GetCodecsByKind(kind)
if len(codecs) == 0 { 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)) 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 return t, nil
default: 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 direction := RTPTransceiverDirectionSendrecv
if len(init) > 1 { if len(init) > 1 {
return nil, fmt.Errorf("AddTransceiverFromTrack only accepts one RtpTransceiverInit") return nil, errPeerConnAddTransceiverFromTrackOnlyAcceptsOne
} else if len(init) == 1 { } else if len(init) == 1 {
direction = init[0].Direction direction = init[0].Direction
} }
@@ -1629,7 +1631,7 @@ func (pc *PeerConnection) AddTransceiverFromTrack(track *Track, init ...RtpTrans
pc.onNegotiationNeeded() pc.onNegotiationNeeded()
return t, nil return t, nil
default: 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 // SetIdentityProvider is used to configure an identity provider to generate identity assertions
func (pc *PeerConnection) SetIdentityProvider(provider string) error { 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 // 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() writeStream, err := srtcpSession.OpenWriteStream()
if err != nil { 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 { 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 { if err != nil {
return nil, err return nil, err
} else if codec.Payloader == nil { } else if codec.Payloader == nil {
return nil, fmt.Errorf("codec payloader not set") return nil, errPeerConnCodecPayloaderNotSet
} }
return NewTrack(payloadType, ssrc, id, label, codec) 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 // generateMatchedSDP generates a SDP and takes the remote state into account
// this is used everytime we have a RemoteDescription // this is used everytime we have a RemoteDescription
// nolint: gocyclo // 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) d, err := sdp.NewJSEPSessionDescription(useIdentity)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -2132,7 +2134,7 @@ func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, use
for _, media := range pc.RemoteDescription().parsed.MediaDescriptions { for _, media := range pc.RemoteDescription().parsed.MediaDescriptions {
midValue := getMidValue(media) midValue := getMidValue(media)
if midValue == "" { if midValue == "" {
return nil, fmt.Errorf("RemoteDescription contained media section without mid value") return nil, errPeerConnRemoteDescriptionWithoutMidValue
} }
if media.MediaName.Media == mediaSectionApplication { if media.MediaName.Media == mediaSectionApplication {
@@ -2180,7 +2182,7 @@ func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, use
} }
t, localTransceivers = findByMid(midValue, localTransceivers) t, localTransceivers = findByMid(midValue, localTransceivers)
if t == nil { 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 { if t.Sender() != nil {
t.Sender().setNegotiated() t.Sender().setNegotiated()

View File

@@ -654,7 +654,7 @@ func TestOnICEGatheringStateChange(t *testing.T) {
) )
} }
switch s { switch s { // nolint:exhaustive
case ICEGathererStateClosed: case ICEGathererStateClosed:
close(seenClosed) close(seenClosed)
return return

View File

@@ -5,15 +5,16 @@ package webrtc
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io" "io"
"math/rand"
"reflect" "reflect"
"strings" "strings"
"sync" "sync"
"testing" "testing"
"time" "time"
"github.com/pion/randutil"
"github.com/pion/rtcp" "github.com/pion/rtcp"
"github.com/pion/sdp/v3" "github.com/pion/sdp/v3"
"github.com/pion/transport/test" "github.com/pion/transport/test"
@@ -22,6 +23,12 @@ import (
"github.com/stretchr/testify/require" "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 { func offerMediaHasDirection(offer SessionDescription, kind RTPCodecType, direction RTPTransceiverDirection) bool {
for _, media := range offer.parsed.MediaDescriptions { for _, media := range offer.parsed.MediaDescriptions {
if media.MediaName.Media == kind.String() { if media.MediaName.Media == kind.String() {
@@ -72,12 +79,12 @@ func TestPeerConnection_Media_Sample(t *testing.T) {
pcAnswer.OnTrack(func(track *Track, receiver *RTPReceiver) { pcAnswer.OnTrack(func(track *Track, receiver *RTPReceiver) {
if track.ID() != expectedTrackID { 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 return
} }
if track.Label() != expectedTrackLabel { 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 return
} }
close(trackMetadataValid) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -233,11 +240,11 @@ func TestPeerConnection_Media_Shutdown(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -326,7 +333,7 @@ func TestPeerConnection_Media_Disconnected(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -406,7 +413,7 @@ func TestPeerConnection_Media_Closed(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -455,9 +462,9 @@ func TestPeerConnection_Media_Closed(t *testing.T) {
assert.NoError(t, pcOffer.Close()) assert.NoError(t, pcOffer.Close())
assert.NoError(t, pcAnswer.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") 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") t.Fatal("WriteRTCP to closed PeerConnection did not return io.ErrClosedPipe")
} }
} }
@@ -482,7 +489,7 @@ func TestUndeclaredSSRC(t *testing.T) {
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo) _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo)
assert.NoError(t, err) 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) assert.NoError(t, err)
_, err = pcOffer.AddTrack(vp8Writer) _, err = pcOffer.AddTrack(vp8Writer)
@@ -573,7 +580,7 @@ func TestOfferRejectionMissingCodec(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -622,7 +629,6 @@ func TestAddTransceiverFromTrackSendOnly(t *testing.T) {
"track-id", "track-id",
"track-label", "track-label",
) )
if err != nil { if err != nil {
t.Error(err.Error()) t.Error(err.Error())
} }
@@ -680,7 +686,6 @@ func TestAddTransceiverFromTrackSendRecv(t *testing.T) {
"track-id", "track-id",
"track-label", "track-label",
) )
if err != nil { if err != nil {
t.Error(err.Error()) t.Error(err.Error())
} }
@@ -770,7 +775,7 @@ func TestAddTransceiverAddTrack_Reuse(t *testing.T) {
assert.Equal(t, []*RTPTransceiver{tr}, pc.GetTransceivers()) assert.Equal(t, []*RTPTransceiver{tr}, pc.GetTransceivers())
addTrack := func() (*Track, *RTPSender) { 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) assert.NoError(t, err)
sender, err := pc.AddTrack(track) sender, err := pc.AddTrack(track)
@@ -811,7 +816,7 @@ func TestAddTransceiverAddTrack_NewRTPSender_Error(t *testing.T) {
dtlsTransport := pc.dtlsTransport dtlsTransport := pc.dtlsTransport
pc.dtlsTransport = nil 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) assert.NoError(t, err)
_, err = pc.AddTrack(track) _, err = pc.AddTrack(track)
@@ -929,7 +934,6 @@ func TestAddTransceiverFromTrackFailsRecvOnly(t *testing.T) {
"track-id", "track-id",
"track-label", "track-label",
) )
if err != nil { if err != nil {
t.Error(err.Error()) t.Error(err.Error())
} }
@@ -1051,7 +1055,7 @@ func TestGetRegisteredRTPCodecs(t *testing.T) {
func TestPlanBMediaExchange(t *testing.T) { func TestPlanBMediaExchange(t *testing.T) {
runTest := func(trackCount int, t *testing.T) { runTest := func(trackCount int, t *testing.T) {
addSingleTrack := func(p *PeerConnection) *Track { 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) assert.NoError(t, err)
_, err = p.AddTrack(track) _, err = p.AddTrack(track)
@@ -1137,7 +1141,7 @@ func TestPeerConnection_Start_Only_Negotiated_Senders(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
defer func() { assert.NoError(t, pcAnswer.Close()) }() 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) require.NoError(t, err)
sender1, err := pcOffer.AddTrack(track1) 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 // 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) require.NoError(t, err)
sender2, err := pcOffer.AddTrack(track2) 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 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() api := NewAPI()
@@ -1203,7 +1207,7 @@ func TestPeerConnection_Start_Right_Receiver(t *testing.T) {
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly}) _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
assert.NoError(t, err) 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) require.NoError(t, err)
sender1, err := pcOffer.AddTrack(track1) sender1, err := pcOffer.AddTrack(track1)

View File

@@ -5,7 +5,6 @@ package webrtc
import ( import (
"context" "context"
"io" "io"
"math/rand"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@@ -13,11 +12,11 @@ import (
"testing" "testing"
"time" "time"
"github.com/pion/webrtc/v3/pkg/rtcerr" "github.com/pion/randutil"
"github.com/pion/transport/test" "github.com/pion/transport/test"
"github.com/pion/webrtc/v3/internal/util" "github.com/pion/webrtc/v3/internal/util"
"github.com/pion/webrtc/v3/pkg/media" "github.com/pion/webrtc/v3/pkg/media"
"github.com/pion/webrtc/v3/pkg/rtcerr"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -96,7 +95,7 @@ func TestPeerConnection_Renegotiation_AddTrack(t *testing.T) {
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly}) _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
assert.NoError(t, err) 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) assert.NoError(t, err)
sender, err := pcOffer.AddTrack(vp8Track) sender, err := pcOffer.AddTrack(vp8Track)
@@ -140,7 +139,7 @@ func TestPeerConnection_Renegotiation_AddTrack_Multiple(t *testing.T) {
_, err := pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly}) _, err := pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
assert.NoError(t, err) 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) assert.NoError(t, err)
_, err = pcOffer.AddTrack(track) _, err = pcOffer.AddTrack(track)
@@ -222,7 +221,7 @@ func TestPeerConnection_Renegotiation_AddTrack_Rename(t *testing.T) {
_, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly}) _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
assert.NoError(t, err) 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) assert.NoError(t, err)
_, err = pcAnswer.AddTrack(vp8Track) _, err = pcAnswer.AddTrack(vp8Track)
assert.NoError(t, err) assert.NoError(t, err)
@@ -263,13 +262,13 @@ func TestPeerConnection_Transceiver_Mid(t *testing.T) {
pcAnswer, err := NewPeerConnection(Configuration{}) pcAnswer, err := NewPeerConnection(Configuration{})
assert.NoError(t, err) 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) require.NoError(t, err)
sender1, err := pcOffer.AddTrack(track1) sender1, err := pcOffer.AddTrack(track1)
require.NoError(t, err) 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) require.NoError(t, err)
_, err = pcOffer.AddTrack(track2) _, err = pcOffer.AddTrack(track2)
@@ -321,7 +320,7 @@ func TestPeerConnection_Transceiver_Mid(t *testing.T) {
pcOffer.ops.Done() pcOffer.ops.Done()
pcAnswer.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) require.NoError(t, err)
_, err = pcOffer.AddTrack(track3) _, err = pcOffer.AddTrack(track3)
@@ -454,7 +453,7 @@ func TestPeerConnection_Renegotiation_RemoveTrack(t *testing.T) {
_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly}) _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
assert.NoError(t, err) 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) assert.NoError(t, err)
rtpSender, err := pcOffer.AddTrack(vp8Track) rtpSender, err := pcOffer.AddTrack(vp8Track)
@@ -511,7 +510,7 @@ func TestPeerConnection_RoleSwitch(t *testing.T) {
_, err = pcFirstOfferer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly}) _, err = pcFirstOfferer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
assert.NoError(t, err) 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) assert.NoError(t, err)
_, err = pcSecondOfferer.AddTrack(vp8Track) _, err = pcSecondOfferer.AddTrack(vp8Track)
@@ -622,7 +621,7 @@ func TestPeerConnection_Renegotiation_SetLocalDescription(t *testing.T) {
_, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly}) _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
assert.NoError(t, err) 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) assert.NoError(t, err)
sender, err := pcAnswer.AddTrack(localTrack) sender, err := pcAnswer.AddTrack(localTrack)
@@ -724,7 +723,7 @@ func TestAddDataChannelDuringRenegotation(t *testing.T) {
pcAnswer, err := NewPeerConnection(Configuration{}) pcAnswer, err := NewPeerConnection(Configuration{})
assert.NoError(t, err) 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) assert.NoError(t, err)
_, err = pcOffer.AddTrack(track) _, err = pcOffer.AddTrack(track)
@@ -792,7 +791,7 @@ func TestNegotiationTrackAndChannel(t *testing.T) {
pcAnswer, err := NewPeerConnection(Configuration{}) pcAnswer, err := NewPeerConnection(Configuration{})
assert.NoError(t, err) 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) assert.NoError(t, err)
pcAnswer.OnDataChannel(func(*DataChannel) { pcAnswer.OnDataChannel(func(*DataChannel) {
@@ -860,7 +859,7 @@ func TestNegotiationNeededRemoveTrack(t *testing.T) {
pcAnswer, err := NewPeerConnection(Configuration{}) pcAnswer, err := NewPeerConnection(Configuration{})
assert.NoError(t, err) 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) assert.NoError(t, err)
pcOffer.OnNegotiationNeeded(func() { pcOffer.OnNegotiationNeeded(func() {
@@ -924,7 +923,7 @@ func TestNegotiationNeededStressOneSided(t *testing.T) {
}) })
for i := 0; i < 500; i++ { 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) assert.NoError(t, err)
_, err = pcA.AddTrack(track) _, err = pcA.AddTrack(track)

View File

@@ -6,10 +6,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
"github.com/pion/transport/test" "github.com/pion/transport/test"
"github.com/pion/webrtc/v3/pkg/rtcerr" "github.com/pion/webrtc/v3/pkg/rtcerr"
"github.com/stretchr/testify/assert"
) )
// newPair creates two new peer connections (an offerer and an answerer) // 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.ICETransportPolicy, actual.ICETransportPolicy)
assert.Equal(t, expected.BundlePolicy, actual.BundlePolicy) assert.Equal(t, expected.BundlePolicy, actual.BundlePolicy)
assert.Equal(t, expected.RTCPMuxPolicy, actual.RTCPMuxPolicy) assert.Equal(t, expected.RTCPMuxPolicy, actual.RTCPMuxPolicy)
// nolint:godox
// TODO(albrow): Uncomment this after #513 is fixed. // TODO(albrow): Uncomment this after #513 is fixed.
// See: https://github.com/pion/webrtc/issues/513. // See: https://github.com/pion/webrtc/issues/513.
// assert.Equal(t, len(expected.Certificates), len(actual.Certificates)) // assert.Equal(t, len(expected.Certificates), len(actual.Certificates))

View File

@@ -13,8 +13,10 @@ type writerCloser struct {
bytes.Buffer bytes.Buffer
} }
var errCloseErr = errors.New("close error")
func (w *writerCloser) Close() error { func (w *writerCloser) Close() error {
return errors.New("close error") return errCloseErr
} }
func TestNewWith(t *testing.T) { func TestNewWith(t *testing.T) {

View File

@@ -3,6 +3,7 @@ package ivfreader
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
) )
@@ -13,6 +14,15 @@ const (
ivfFrameHeaderSize = 12 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 // IVFFileHeader 32-byte header for IVF files
// https://wiki.multimedia.cx/index.php/IVF // https://wiki.multimedia.cx/index.php/IVF
type IVFFileHeader struct { type IVFFileHeader struct {
@@ -45,7 +55,7 @@ type IVFReader struct {
// with an io.Reader input // with an io.Reader input
func NewWith(in io.Reader) (*IVFReader, *IVFFileHeader, error) { func NewWith(in io.Reader) (*IVFReader, *IVFFileHeader, error) {
if in == nil { if in == nil {
return nil, nil, fmt.Errorf("stream is nil") return nil, nil, errNilStream
} }
reader := &IVFReader{ reader := &IVFReader{
@@ -76,8 +86,8 @@ func (i *IVFReader) ParseNextFrame() ([]byte, *IVFFrameHeader, error) {
bytesRead, err := io.ReadFull(i.stream, buffer) bytesRead, err := io.ReadFull(i.stream, buffer)
headerBytesRead := bytesRead headerBytesRead := bytesRead
if err == io.ErrUnexpectedEOF { if errors.Is(err, io.ErrUnexpectedEOF) {
return nil, nil, fmt.Errorf("incomplete frame header") return nil, nil, errIncompleteFrameHeader
} else if err != nil { } else if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -89,8 +99,8 @@ func (i *IVFReader) ParseNextFrame() ([]byte, *IVFFrameHeader, error) {
payload := make([]byte, header.FrameSize) payload := make([]byte, header.FrameSize)
bytesRead, err = io.ReadFull(i.stream, payload) bytesRead, err = io.ReadFull(i.stream, payload)
if err == io.ErrUnexpectedEOF { if errors.Is(err, io.ErrUnexpectedEOF) {
return nil, nil, fmt.Errorf("incomplete frame data") return nil, nil, errIncompleteFrameData
} else if err != nil { } else if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -105,8 +115,8 @@ func (i *IVFReader) parseFileHeader() (*IVFFileHeader, error) {
buffer := make([]byte, ivfFileHeaderSize) buffer := make([]byte, ivfFileHeaderSize)
bytesRead, err := io.ReadFull(i.stream, buffer) bytesRead, err := io.ReadFull(i.stream, buffer)
if err == io.ErrUnexpectedEOF { if errors.Is(err, io.ErrUnexpectedEOF) {
return nil, fmt.Errorf("incomplete file header") return nil, errIncompleteFileHeader
} else if err != nil { } else if err != nil {
return nil, err return nil, err
} }
@@ -125,11 +135,9 @@ func (i *IVFReader) parseFileHeader() (*IVFFileHeader, error) {
} }
if header.signature != ivfFileHeaderSignature { if header.signature != ivfFileHeaderSignature {
return nil, fmt.Errorf("IVF signature mismatch") return nil, errSignatureMismatch
} else if header.version != uint16(0) { } else if header.version != uint16(0) {
errStr := fmt.Sprintf("IVF version unknown: %d,"+ return nil, fmt.Errorf("%w: expected(0) got(%d)", errUnknownIVFVersion, header.version)
" parser may not parse correctly", header.version)
return nil, fmt.Errorf(errStr)
} }
i.bytesReadSuccesfully += int64(bytesRead) i.bytesReadSuccesfully += int64(bytesRead)

View File

@@ -2,7 +2,7 @@ package ivfreader
import ( import (
"bytes" "bytes"
"fmt" "io"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -127,7 +127,7 @@ func TestIVFReader_ParseIncompleteFrameHeader(t *testing.T) {
assert.Nil(payload, "Payload should be nil") assert.Nil(payload, "Payload should be nil")
assert.Nil(header, "Incomplete header 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) { 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(payload, "Incomplete payload should be nil")
assert.Nil(header, "Header 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) { func TestIVFReader_EOFWhenNoFramesLeft(t *testing.T) {
@@ -163,5 +163,5 @@ func TestIVFReader_EOFWhenNoFramesLeft(t *testing.T) {
_, _, err = reader.ParseNextFrame() _, _, err = reader.ParseNextFrame()
assert.Equal(fmt.Errorf("EOF"), err) assert.Equal(io.EOF, err)
} }

View File

@@ -3,7 +3,7 @@ package ivfwriter
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "errors"
"io" "io"
"os" "os"
@@ -11,6 +11,11 @@ import (
"github.com/pion/rtp/codecs" "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 // IVFWriter is used to take RTP packets and write them to an IVF on disk
type IVFWriter struct { type IVFWriter struct {
ioWriter io.Writer ioWriter io.Writer
@@ -36,7 +41,7 @@ func New(fileName string) (*IVFWriter, error) {
// NewWith initialize a new IVF writer with an io.Writer output // NewWith initialize a new IVF writer with an io.Writer output
func NewWith(out io.Writer) (*IVFWriter, error) { func NewWith(out io.Writer) (*IVFWriter, error) {
if out == nil { if out == nil {
return nil, fmt.Errorf("file not opened") return nil, errFileNotOpened
} }
writer := &IVFWriter{ writer := &IVFWriter{
@@ -51,10 +56,10 @@ func NewWith(out io.Writer) (*IVFWriter, error) {
func (i *IVFWriter) writeHeader() error { func (i *IVFWriter) writeHeader() error {
header := make([]byte, 32) 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[4:], 0) // Version
binary.LittleEndian.PutUint16(header[6:], 32) // Header size 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[12:], 640) // Width in pixels
binary.LittleEndian.PutUint16(header[14:], 480) // Height in pixels binary.LittleEndian.PutUint16(header[14:], 480) // Height in pixels
binary.LittleEndian.PutUint32(header[16:], 30) // Framerate denominator 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 // WriteRTP adds a new packet and writes the appropriate headers for it
func (i *IVFWriter) WriteRTP(packet *rtp.Packet) error { func (i *IVFWriter) WriteRTP(packet *rtp.Packet) error {
if i.ioWriter == nil { if i.ioWriter == nil {
return fmt.Errorf("file not opened") return errFileNotOpened
} }
vp8Packet := codecs.VP8Packet{} vp8Packet := codecs.VP8Packet{}

View File

@@ -2,7 +2,6 @@ package ivfwriter
import ( import (
"bytes" "bytes"
"fmt"
"io" "io"
"testing" "testing"
@@ -125,7 +124,7 @@ func TestIVFWriter_AddPacketAndClose(t *testing.T) {
message: "IVFWriter shouldn't be able to write something to a closed file", message: "IVFWriter shouldn't be able to write something to a closed file",
messageClose: "IVFWriter should be able to close an already closed file", messageClose: "IVFWriter should be able to close an already closed file",
packet: nil, packet: nil,
err: fmt.Errorf("file not opened"), err: errFileNotOpened,
closeErr: nil, closeErr: nil,
}, },
{ {
@@ -133,7 +132,7 @@ func TestIVFWriter_AddPacketAndClose(t *testing.T) {
message: "IVFWriter shouldn't be able to write something an empty packet", message: "IVFWriter shouldn't be able to write something an empty packet",
messageClose: "IVFWriter should be able to close the file", messageClose: "IVFWriter should be able to close the file",
packet: &rtp.Packet{}, packet: &rtp.Packet{},
err: fmt.Errorf("invalid nil packet"), err: errInvalidNilPacket,
closeErr: nil, 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", message: "IVFWriter shouldn't be able to write something to a closed file",
messageClose: "IVFWriter should be able to close an already closed file", messageClose: "IVFWriter should be able to close an already closed file",
packet: nil, packet: nil,
err: fmt.Errorf("file not opened"), err: errFileNotOpened,
closeErr: nil, closeErr: nil,
}, },
{ {

View File

@@ -3,11 +3,11 @@ package oggwriter
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "errors"
"io" "io"
"math/rand"
"os" "os"
"github.com/pion/randutil"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/pion/rtp/codecs" "github.com/pion/rtp/codecs"
) )
@@ -22,6 +22,11 @@ const (
pageHeaderSignature = "OggS" 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 // OggWriter is used to take RTP packets and write them to an OGG on disk
type OggWriter struct { type OggWriter struct {
stream io.Writer 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 // NewWith initialize a new OGG Opus writer with an io.Writer output
func NewWith(out io.Writer, sampleRate uint32, channelCount uint16) (*OggWriter, error) { func NewWith(out io.Writer, sampleRate uint32, channelCount uint16) (*OggWriter, error) {
if out == nil { if out == nil {
return nil, fmt.Errorf("file not opened") return nil, errFileNotOpened
} }
writer := &OggWriter{ writer := &OggWriter{
stream: out, stream: out,
sampleRate: sampleRate, sampleRate: sampleRate,
channelCount: channelCount, channelCount: channelCount,
serial: rand.Uint32(), serial: randutil.NewMathRandomGenerator().Uint32(),
checksumTable: generateChecksumTable(), checksumTable: generateChecksumTable(),
// Timestamp and Granule MUST start from 1 // Timestamp and Granule MUST start from 1
@@ -102,7 +107,7 @@ func (i *OggWriter) writeHeaders() error {
// ID Header // ID Header
oggIDHeader := make([]byte, 19) oggIDHeader := make([]byte, 19)
copy(oggIDHeader[0:], []byte(idPageSignature)) // Magic Signature 'OpusHead' copy(oggIDHeader[0:], idPageSignature) // Magic Signature 'OpusHead'
oggIDHeader[8] = 1 // Version oggIDHeader[8] = 1 // Version
oggIDHeader[9] = uint8(i.channelCount) // Channel count oggIDHeader[9] = uint8(i.channelCount) // Channel count
binary.LittleEndian.PutUint16(oggIDHeader[10:], defaultPreSkip) // pre-skip binary.LittleEndian.PutUint16(oggIDHeader[10:], defaultPreSkip) // pre-skip
@@ -120,9 +125,9 @@ func (i *OggWriter) writeHeaders() error {
// Comment Header // Comment Header
oggCommentHeader := make([]byte, 21) 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 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 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 // 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) i.lastPayloadSize = len(payload)
page := make([]byte, pageHeaderSize+1+i.lastPayloadSize) 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[4] = 0 // Version
page[5] = headerType // 1 = continuation, 2 = beginning of stream, 4 = end of stream page[5] = headerType // 1 = continuation, 2 = beginning of stream, 4 = end of stream
binary.LittleEndian.PutUint64(page[6:], granulePos) // granule position 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 // WriteRTP adds a new packet and writes the appropriate headers for it
func (i *OggWriter) WriteRTP(packet *rtp.Packet) error { func (i *OggWriter) WriteRTP(packet *rtp.Packet) error {
if packet == nil { if packet == nil {
return fmt.Errorf("packet must not be nil") return errInvalidNilPacket
} }
opusPacket := codecs.OpusPacket{} opusPacket := codecs.OpusPacket{}
@@ -230,7 +235,7 @@ func (i *OggWriter) Close() error {
// so we can set values for EOS // so we can set values for EOS
func (i *OggWriter) writeToStream(p []byte) error { func (i *OggWriter) writeToStream(p []byte) error {
if i.stream == nil { if i.stream == nil {
return fmt.Errorf("file not opened") return errFileNotOpened
} }
_, err := i.stream.Write(p) _, err := i.stream.Write(p)

View File

@@ -2,7 +2,6 @@ package oggwriter
import ( import (
"bytes" "bytes"
"fmt"
"io" "io"
"testing" "testing"
@@ -54,7 +53,7 @@ func TestOggWriter_AddPacketAndClose(t *testing.T) {
message: "OggWriter shouldn't be able to write something to a closed file", message: "OggWriter shouldn't be able to write something to a closed file",
messageClose: "OggWriter should be able to close an already closed file", messageClose: "OggWriter should be able to close an already closed file",
packet: validPacket, packet: validPacket,
err: fmt.Errorf("file not opened"), err: errFileNotOpened,
closeErr: nil, closeErr: nil,
}, },
{ {
@@ -62,7 +61,7 @@ func TestOggWriter_AddPacketAndClose(t *testing.T) {
message: "OggWriter shouldn't be able to write an empty packet", message: "OggWriter shouldn't be able to write an empty packet",
messageClose: "OggWriter should be able to close the file", messageClose: "OggWriter should be able to close the file",
packet: &rtp.Packet{}, packet: &rtp.Packet{},
err: fmt.Errorf("invalid nil packet"), err: errInvalidNilPacket,
closeErr: nil, 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", message: "OggWriter shouldn't be able to write something to a closed file",
messageClose: "OggWriter should be able to close an already closed file", messageClose: "OggWriter should be able to close an already closed file",
packet: nil, packet: nil,
err: fmt.Errorf("file not opened"), err: errFileNotOpened,
closeErr: nil, closeErr: nil,
}, },
} }

View File

@@ -2,6 +2,7 @@ package rtpdump
import ( import (
"bufio" "bufio"
"errors"
"io" "io"
"regexp" "regexp"
"sync" "sync"
@@ -30,7 +31,7 @@ func NewReader(r io.Reader) (*Reader, Header, error) {
} }
// The file starts with #!rtpplay1.0 address/port\n // 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) { if !preambleRegexp.Match(peek) {
return nil, hdr, errMalformed return nil, hdr, errMalformed
} }
@@ -46,7 +47,7 @@ func NewReader(r io.Reader) (*Reader, Header, error) {
hBuf := make([]byte, headerLen) hBuf := make([]byte, headerLen)
_, err = io.ReadFull(bio, hBuf) _, 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 return nil, hdr, errMalformed
} }
if err != nil { if err != nil {
@@ -70,7 +71,7 @@ func (r *Reader) Next() (Packet, error) {
hBuf := make([]byte, pktHeaderLen) hBuf := make([]byte, pktHeaderLen)
_, err := io.ReadFull(r.reader, hBuf) _, err := io.ReadFull(r.reader, hBuf)
if err == io.ErrUnexpectedEOF { if errors.Is(err, io.ErrUnexpectedEOF) {
return Packet{}, errMalformed return Packet{}, errMalformed
} }
if err != nil { if err != nil {
@@ -88,7 +89,7 @@ func (r *Reader) Next() (Packet, error) {
payload := make([]byte, h.Length-pktHeaderLen) payload := make([]byte, h.Length-pktHeaderLen)
_, err = io.ReadFull(r.reader, payload) _, err = io.ReadFull(r.reader, payload)
if err == io.ErrUnexpectedEOF { if errors.Is(err, io.ErrUnexpectedEOF) {
return Packet{}, errMalformed return Packet{}, errMalformed
} }
if err != nil { if err != nil {

View File

@@ -2,6 +2,7 @@ package rtpdump
import ( import (
"bytes" "bytes"
"errors"
"io" "io"
"net" "net"
"reflect" "reflect"
@@ -247,7 +248,7 @@ func TestReader(t *testing.T) {
} { } {
r, hdr, err := NewReader(bytes.NewReader(test.Data)) r, hdr, err := NewReader(bytes.NewReader(test.Data))
if err != nil { 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) t.Fatalf("NewReader(%s) err=%v want %v", test.Name, got, want)
} }
continue continue
@@ -272,7 +273,7 @@ func TestReader(t *testing.T) {
packets = append(packets, pkt) 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) t.Fatalf("%s err=%v want %v", test.Name, got, want)
} }
if got, want := packets, test.WantPackets; !reflect.DeepEqual(got, want) { if got, want := packets, test.WantPackets; !reflect.DeepEqual(got, want) {

View File

@@ -1,6 +1,7 @@
package rtpdump package rtpdump
import ( import (
"errors"
"net" "net"
"reflect" "reflect"
"testing" "testing"
@@ -65,7 +66,7 @@ func TestMarshalHeader(t *testing.T) {
}, },
} { } {
data, err := test.Header.Marshal() 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) t.Fatalf("Marshal(%q) err=%v, want %v", test.Name, got, want)
} }

View File

@@ -8,7 +8,6 @@ import (
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/x509" "crypto/x509"
"errors"
"strings" "strings"
"sync" "sync"
"time" "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 { func (t *QUICTransport) ensureICEConn() error {
if t.iceTransport == nil || if t.iceTransport == nil ||
t.iceTransport.State() == ICETransportStateNew { t.iceTransport.State() == ICETransportStateNew {
return errors.New("ICE connection not started") return errQuickTransportICEConnectionNotStarted
} }
return nil return nil

View File

@@ -1,19 +1,19 @@
package webrtc package webrtc
const ( const (
//TypeRTCPFBTransportCC .. // TypeRTCPFBTransportCC ..
TypeRTCPFBTransportCC = "transport-cc" TypeRTCPFBTransportCC = "transport-cc"
//TypeRTCPFBGoogREMB .. // TypeRTCPFBGoogREMB ..
TypeRTCPFBGoogREMB = "goog-remb" TypeRTCPFBGoogREMB = "goog-remb"
//TypeRTCPFBACK .. // TypeRTCPFBACK ..
TypeRTCPFBACK = "ack" TypeRTCPFBACK = "ack"
//TypeRTCPFBCCM .. // TypeRTCPFBCCM ..
TypeRTCPFBCCM = "ccm" TypeRTCPFBCCM = "ccm"
//TypeRTCPFBNACK .. // TypeRTCPFBNACK ..
TypeRTCPFBNACK = "nack" TypeRTCPFBNACK = "nack"
) )

View File

@@ -36,7 +36,7 @@ type RTPReceiver struct {
// NewRTPReceiver constructs a new RTPReceiver // NewRTPReceiver constructs a new RTPReceiver
func (api *API) NewRTPReceiver(kind RTPCodecType, transport *DTLSTransport) (*RTPReceiver, error) { func (api *API) NewRTPReceiver(kind RTPCodecType, transport *DTLSTransport) (*RTPReceiver, error) {
if transport == nil { if transport == nil {
return nil, fmt.Errorf("DTLSTransport must not be nil") return nil, errRTPReceiverDTLSTransportNil
} }
return &RTPReceiver{ return &RTPReceiver{
@@ -87,7 +87,7 @@ func (r *RTPReceiver) Receive(parameters RTPReceiveParameters) error {
defer r.mu.Unlock() defer r.mu.Unlock()
select { select {
case <-r.received: case <-r.received:
return fmt.Errorf("Receive has already been called") return errRTPReceiverReceiveAlreadyCalled
default: default:
} }
defer close(r.received) 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 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 // 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) { func (r *RTPReceiver) streamsForSSRC(ssrc uint32) (*srtp.ReadStreamSRTP, *srtp.ReadStreamSRTCP, error) {

View File

@@ -3,7 +3,6 @@
package webrtc package webrtc
import ( import (
"fmt"
"io" "io"
"sync" "sync"
@@ -19,6 +18,7 @@ type RTPSender struct {
transport *DTLSTransport transport *DTLSTransport
// nolint:godox
// TODO(sgotti) remove this when in future we'll avoid replacing // TODO(sgotti) remove this when in future we'll avoid replacing
// a transceiver sender since we can just check the // a transceiver sender since we can just check the
// transceiver negotiation status // transceiver negotiation status
@@ -34,15 +34,15 @@ type RTPSender struct {
// NewRTPSender constructs a new RTPSender // NewRTPSender constructs a new RTPSender
func (api *API) NewRTPSender(track *Track, transport *DTLSTransport) (*RTPSender, error) { func (api *API) NewRTPSender(track *Track, transport *DTLSTransport) (*RTPSender, error) {
if track == nil { if track == nil {
return nil, fmt.Errorf("Track must not be nil") return nil, errRTPSenderTrackNil
} else if transport == nil { } else if transport == nil {
return nil, fmt.Errorf("DTLSTransport must not be nil") return nil, errRTPSenderDTLSTransportNil
} }
track.mu.Lock() track.mu.Lock()
defer track.mu.Unlock() defer track.mu.Unlock()
if track.receiver != nil { if track.receiver != nil {
return nil, fmt.Errorf("RTPSender can not be constructed with remote track") return nil, errRTPSenderCannotConstructRemoteTrack
} }
track.totalSenderCount++ track.totalSenderCount++
@@ -94,7 +94,7 @@ func (r *RTPSender) Send(parameters RTPSendParameters) error {
defer r.mu.Unlock() defer r.mu.Unlock()
if r.hasSent() { if r.hasSent() {
return fmt.Errorf("Send has already been called") return errRTPSenderSendAlreadyCalled
} }
srtcpSession, err := r.transport.getSRTCPSession() 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) { func (r *RTPSender) SendRTP(header *rtp.Header, payload []byte) (int, error) {
select { select {
case <-r.stopCalled: case <-r.stopCalled:
return 0, fmt.Errorf("RTPSender has been stopped") return 0, errRTPSenderStopped
case <-r.sendCalled: case <-r.sendCalled:
srtpSession, err := r.transport.getSRTPSession() srtpSession, err := r.transport.getSRTPSession()
if err != nil { if err != nil {

View File

@@ -46,7 +46,7 @@ func (t *RTPTransceiver) Receiver() *RTPReceiver {
// setMid sets the RTPTransceiver's mid. If it was already set, will return an error. // setMid sets the RTPTransceiver's mid. If it was already set, will return an error.
func (t *RTPTransceiver) setMid(mid string) error { func (t *RTPTransceiver) setMid(mid string) error {
if currentMid := t.Mid(); currentMid != "" { 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) t.mid.Store(mid)
return nil return nil
@@ -111,7 +111,7 @@ func (t *RTPTransceiver) setSendingTrack(track *Track) error {
case track == nil && t.Direction() == RTPTransceiverDirectionSendonly: case track == nil && t.Direction() == RTPTransceiverDirectionSendonly:
t.setDirection(RTPTransceiverDirectionInactive) t.setDirection(RTPTransceiverDirectionInactive)
default: default:
return fmt.Errorf("invalid state change in RTPTransceiver.setSending") return errRTPTransceiverSetSendingInvalidState
} }
return nil return nil
} }
@@ -138,9 +138,10 @@ func satisfyTypeAndDirection(remoteKind RTPCodecType, remoteDirection RTPTransce
return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendrecv} return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendrecv}
case RTPTransceiverDirectionRecvonly: case RTPTransceiverDirectionRecvonly:
return []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv} return []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv}
} default:
return []RTPTransceiverDirection{} return []RTPTransceiverDirection{}
} }
}
for _, possibleDirection := range getPreferredDirections() { for _, possibleDirection := range getPreferredDirections() {
for i := range localTransceivers { for i := range localTransceivers {

View File

@@ -68,6 +68,7 @@ func (t RTPTransceiverDirection) Revers() RTPTransceiverDirection {
return RTPTransceiverDirectionRecvonly return RTPTransceiverDirectionRecvonly
case RTPTransceiverDirectionRecvonly: case RTPTransceiverDirectionRecvonly:
return RTPTransceiverDirectionSendonly return RTPTransceiverDirectionSendonly
} default:
return t return t
}
} }

View File

@@ -1,8 +1,10 @@
package webrtc package webrtc
// RtpTransceiverInit dictionary is used when calling the WebRTC function addTransceiver() to provide configuration options for the new transceiver. // RTPTransceiverInit dictionary is used when calling the WebRTC function addTransceiver() to provide configuration options for the new transceiver.
type RtpTransceiverInit struct { type RTPTransceiverInit struct {
Direction RTPTransceiverDirection Direction RTPTransceiverDirection
SendEncodings []RTPEncodingParameters SendEncodings []RTPEncodingParameters
// Streams []*Track // Streams []*Track
} }
type RtpTransceiverInit = RTPTransceiverInit //nolint: stylecheck

View File

@@ -3,7 +3,6 @@
package webrtc package webrtc
import ( import (
"errors"
"io" "io"
"math" "math"
"sync" "sync"
@@ -141,7 +140,7 @@ func (r *SCTPTransport) Stop() error {
func (r *SCTPTransport) ensureDTLS() error { func (r *SCTPTransport) ensureDTLS() error {
dtlsTransport := r.Transport() dtlsTransport := r.Transport()
if dtlsTransport == nil || dtlsTransport.conn == nil { if dtlsTransport == nil || dtlsTransport.conn == nil {
return errors.New("DTLS not established") return errSCTPTransportDTLS
} }
return nil return nil
@@ -160,10 +159,12 @@ func (r *SCTPTransport) acceptDataChannels(a *sctp.Association) {
return return
} }
var ordered = true var (
var maxRetransmits *uint16 maxRetransmits *uint16
var maxPacketLifeTime *uint16 maxPacketLifeTime *uint16
var val = uint16(dc.Config.ReliabilityParameter) )
val := uint16(dc.Config.ReliabilityParameter)
ordered := true
switch dc.Config.ChannelType { switch dc.Config.ChannelType {
case datachannel.ChannelTypeReliable: case datachannel.ChannelTypeReliable:
@@ -195,7 +196,6 @@ func (r *SCTPTransport) acceptDataChannels(a *sctp.Association) {
MaxPacketLifeTime: maxPacketLifeTime, MaxPacketLifeTime: maxPacketLifeTime,
MaxRetransmits: maxRetransmits, MaxRetransmits: maxRetransmits,
}, r.api.settingEngine.LoggerFactory.NewLogger("ortc")) }, r.api.settingEngine.LoggerFactory.NewLogger("ortc"))
if err != nil { if err != nil {
r.log.Errorf("Failed to accept data channel: %v", err) r.log.Errorf("Failed to accept data channel: %v", err)
r.onError(err) r.onError(err)

12
sdp.go
View File

@@ -54,7 +54,7 @@ const (
) )
// extract all trackDetails from an SDP. // 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{} incomingTracks := []trackDetails{}
rtxRepairFlows := map[uint32]bool{} 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) { 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 transceivers := mediaSection.transceivers
if len(transceivers) < 1 { 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 // Use the first transceiver to generate the section attributes
t := transceivers[0] t := transceivers[0]
@@ -385,9 +385,9 @@ func populateSDP(d *sdp.SessionDescription, isPlanB bool, dtlsFingerprints []DTL
for _, m := range mediaSections { for _, m := range mediaSections {
if m.data && len(m.transceivers) != 0 { 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 { } 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 shouldAddID := true
@@ -593,11 +593,11 @@ func remoteExts(session *sdp.SessionDescription) (map[SDPSectionType]map[int]sdp
} }
em := &sdp.ExtMap{} em := &sdp.ExtMap{}
if err := em.Unmarshal("extmap:" + attr.Value); err != nil { 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, ok := remoteExtMaps[mediaType][em.Value]; ok {
if remoteExtMap.Value != em.Value { if remoteExtMap.Value != em.Value {
return fmt.Errorf("RemoteDescription changed some extmaps values") return errSDPRemoteDescriptionChangedExtMap
} }
} else { } else {
remoteExtMaps[mediaType][em.Value] = *em remoteExtMaps[mediaType][em.Value] = *em

View File

@@ -9,7 +9,6 @@ import (
"github.com/pion/sdp/v3" "github.com/pion/sdp/v3"
"github.com/pion/transport/test" "github.com/pion/transport/test"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@@ -3,7 +3,6 @@
package webrtc package webrtc
import ( import (
"errors"
"time" "time"
"github.com/pion/ice/v2" "github.com/pion/ice/v2"
@@ -166,7 +165,7 @@ func (e *SettingEngine) SetNAT1To1IPs(ips []string, candidateType ICECandidateTy
// Act as DTLS Server, wait for ClientHello // Act as DTLS Server, wait for ClientHello
func (e *SettingEngine) SetAnsweringDTLSRole(role DTLSRole) error { func (e *SettingEngine) SetAnsweringDTLSRole(role DTLSRole) error {
if role != DTLSRoleClient && role != DTLSRoleServer { if role != DTLSRoleClient && role != DTLSRoleServer {
return errors.New("SetAnsweringDTLSRole must DTLSRoleClient or DTLSRoleServer") return errSettingEngineSetAnsweringDTLSRole
} }
e.answeringDTLSRole = role e.answeringDTLSRole = role

View File

@@ -114,16 +114,16 @@ func (t *SignalingState) Set(state SignalingState) {
atomic.StoreInt32((*int32)(t), int32(state)) 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 // Special case for rollbacks
if sdpType == SDPTypeRollback && cur == SignalingStateStable { if sdpType == SDPTypeRollback && cur == SignalingStateStable {
return cur, &rtcerr.InvalidModificationError{ return cur, &rtcerr.InvalidModificationError{
Err: fmt.Errorf("can't rollback from stable state"), Err: errSignalingStateCannotRollback,
} }
} }
// 4.3.1 valid state transitions // 4.3.1 valid state transitions
switch cur { switch cur { // nolint:exhaustive
case SignalingStateStable: case SignalingStateStable:
switch op { switch op {
case stateChangeOpSetLocal: case stateChangeOpSetLocal:
@@ -139,7 +139,7 @@ func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType
} }
case SignalingStateHaveLocalOffer: case SignalingStateHaveLocalOffer:
if op == stateChangeOpSetRemote { if op == stateChangeOpSetRemote {
switch sdpType { switch sdpType { // nolint:exhaustive
// have-local-offer->SetRemote(answer)->stable // have-local-offer->SetRemote(answer)->stable
case SDPTypeAnswer: case SDPTypeAnswer:
if next == SignalingStateStable { if next == SignalingStateStable {
@@ -161,7 +161,7 @@ func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType
} }
case SignalingStateHaveRemoteOffer: case SignalingStateHaveRemoteOffer:
if op == stateChangeOpSetLocal { if op == stateChangeOpSetLocal {
switch sdpType { switch sdpType { // nolint:exhaustive
// have-remote-offer->SetLocal(answer)->stable // have-remote-offer->SetLocal(answer)->stable
case SDPTypeAnswer: case SDPTypeAnswer:
if next == SignalingStateStable { if next == SignalingStateStable {
@@ -182,8 +182,7 @@ func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType
} }
} }
} }
return cur, &rtcerr.InvalidModificationError{ 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),
} }
} }

View File

@@ -4,7 +4,6 @@ import (
"testing" "testing"
"github.com/pion/webrtc/v3/pkg/rtcerr" "github.com/pion/webrtc/v3/pkg/rtcerr"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@@ -1192,9 +1192,7 @@ func toStatsICECandidatePairState(state ice.CandidatePairState) (StatsICECandida
return StatsICECandidatePairStateSucceeded, nil return StatsICECandidatePairStateSucceeded, nil
default: default:
// NOTE: this should never happen[tm] // NOTE: this should never happen[tm]
err := fmt.Errorf( err := fmt.Errorf("%w: %s", errStatsICECandidateStateInvalid, state.String())
"cannot convert to StatsICECandidatePairStateSucceeded invalid ice candidate state: %s",
state.String())
return StatsICECandidatePairState("Unknown"), err return StatsICECandidatePairState("Unknown"), err
} }
} }

View File

@@ -75,7 +75,6 @@ func (r StatsReport) GetCertificateStats(c *Certificate) (CertificateStats, bool
return CertificateStats{}, false return CertificateStats{}, false
} }
return certificateStats, true return certificateStats, true
} }
// GetCodecStats is a helper method to return the associated stats for a given Codec // GetCodecStats is a helper method to return the associated stats for a given Codec

View File

@@ -5,15 +5,17 @@ package webrtc
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/stretchr/testify/require"
"math/rand"
"sync" "sync"
"testing" "testing"
"time" "time"
"github.com/pion/randutil"
"github.com/stretchr/testify/assert" "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) { func TestStatsTimestampTime(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
Timestamp StatsTimestamp Timestamp StatsTimestamp
@@ -38,7 +40,6 @@ func TestStatsTimestampTime(t *testing.T) {
} }
} }
// TODO(maxhawkins): replace with a more meaningful test
func TestStatsMarshal(t *testing.T) { func TestStatsMarshal(t *testing.T) {
for _, test := range []Stats{ for _, test := range []Stats{
AudioReceiverStats{}, AudioReceiverStats{},
@@ -176,7 +177,7 @@ func signalPairForStats(pcOffer *PeerConnection, pcAnswer *PeerConnection) error
timeout := time.After(3 * time.Second) timeout := time.After(3 * time.Second)
select { select {
case <-timeout: case <-timeout:
return fmt.Errorf("timed out waiting to receive offer") return errReceiveOfferTimeout
case offer := <-offerChan: case offer := <-offerChan:
if err := pcAnswer.SetRemoteDescription(offer); err != nil { if err := pcAnswer.SetRemoteDescription(offer); err != nil {
return err return err
@@ -203,7 +204,7 @@ func TestPeerConnection_GetStats(t *testing.T) {
offerPC, answerPC, err := newPair() offerPC, answerPC, err := newPair()
assert.NoError(t, err) 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) require.NoError(t, err)
_, err = offerPC.AddTrack(track1) _, err = offerPC.AddTrack(track1)
@@ -324,9 +325,8 @@ func TestPeerConnection_GetStats(t *testing.T) {
certificates := offerPC.configuration.Certificates certificates := offerPC.configuration.Certificates
for _, certificate := range certificates { for i := range certificates {
certificateStats := getCertificateStats(t, reportPCOffer, &certificate) assert.NotEmpty(t, getCertificateStats(t, reportPCOffer, &certificates[i]))
assert.NotEmpty(t, certificateStats)
} }
assert.NoError(t, offerPC.Close()) assert.NoError(t, offerPC.Close())

View File

@@ -3,7 +3,6 @@
package webrtc package webrtc
import ( import (
"fmt"
"io" "io"
"sync" "sync"
@@ -108,7 +107,7 @@ func (t *Track) Read(b []byte) (n int, err error) {
if t.totalSenderCount != 0 || r == nil { if t.totalSenderCount != 0 || r == nil {
t.mu.RUnlock() t.mu.RUnlock()
return 0, fmt.Errorf("this is a local track and must not be read from") return 0, errTrackLocalTrackRead
} }
t.mu.RUnlock() t.mu.RUnlock()
@@ -164,7 +163,7 @@ func (t *Track) WriteRTP(p *rtp.Packet) error {
t.mu.RLock() t.mu.RLock()
if t.receiver != nil { if t.receiver != nil {
t.mu.RUnlock() t.mu.RUnlock()
return fmt.Errorf("this is a remote track and must not be written to") return errTrackLocalTrackWrite
} }
senders := t.activeSenders senders := t.activeSenders
totalSenderCount := t.totalSenderCount totalSenderCount := t.totalSenderCount
@@ -187,7 +186,7 @@ func (t *Track) WriteRTP(p *rtp.Packet) error {
// NewTrack initializes a new *Track // NewTrack initializes a new *Track
func NewTrack(payloadType uint8, ssrc uint32, id, label string, codec *RTPCodec) (*Track, error) { func NewTrack(payloadType uint8, ssrc uint32, id, label string, codec *RTPCodec) (*Track, error) {
if ssrc == 0 { if ssrc == 0 {
return nil, fmt.Errorf("SSRC supplied to NewTrack() must be non-zero") return nil, errTrackSSRCNewTrackZero
} }
packetizer := rtp.NewPacketizer( packetizer := rtp.NewPacketizer(

View File

@@ -3,9 +3,9 @@
package webrtc package webrtc
import ( import (
"math/rand"
"testing" "testing"
"github.com/pion/randutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -23,7 +23,7 @@ func TestNewVideoTrack(t *testing.T) {
peer, _ := api.NewPeerConnection(peerConfig) peer, _ := api.NewPeerConnection(peerConfig)
_, err := peer.NewTrack(DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion") _, err := peer.NewTrack(DefaultPayloadTypeVP8, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
if err != nil { if err != nil {
t.Error("Failed to new video track") t.Error("Failed to new video track")
} }
@@ -43,7 +43,7 @@ func TestNewAudioTrack(t *testing.T) {
peer, _ := api.NewPeerConnection(peerConfig) peer, _ := api.NewPeerConnection(peerConfig)
_, err := peer.NewTrack(DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion") _, err := peer.NewTrack(DefaultPayloadTypeOpus, randutil.NewMathRandomGenerator().Uint32(), "audio", "pion")
if err != nil { if err != nil {
t.Error("Failed to new audio track") t.Error("Failed to new audio track")
} }
@@ -64,12 +64,12 @@ func TestNewTracks(t *testing.T) {
peer, _ := api.NewPeerConnection(peerConfig) peer, _ := api.NewPeerConnection(peerConfig)
_, err := peer.NewTrack(DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion") _, err := peer.NewTrack(DefaultPayloadTypeOpus, randutil.NewMathRandomGenerator().Uint32(), "audio", "pion")
if err != nil { if err != nil {
t.Error("Failed to new audio track") 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 { if err != nil {
t.Error("Failed to new video track") t.Error("Failed to new video track")
} }
@@ -90,12 +90,12 @@ func TestNewTracksWrite(t *testing.T) {
peer, _ := api.NewPeerConnection(peerConfig) 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 { if err != nil {
t.Error("Failed to new video track") 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 { if err != nil {
t.Error("Failed to new audio track") t.Error("Failed to new audio track")
} }
@@ -122,7 +122,7 @@ func TestTrackReadWhenNotAdded(t *testing.T) {
peerConnection, err := NewPeerConnection(Configuration{}) peerConnection, err := NewPeerConnection(Configuration{})
assert.NoError(t, err) 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) assert.NoError(t, err)
_, err = track.Read([]byte{}) _, err = track.Read([]byte{})