diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e72ea4d..b4967b21 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,4 +21,4 @@ jobs: release: uses: pion/.goassets/.github/workflows/release.reusable.yml@master with: - go-version: "1.22" # auto-update/latest-go-version + go-version: "1.24" # auto-update/latest-go-version diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b0242893..7713e939 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,7 +23,7 @@ jobs: uses: pion/.goassets/.github/workflows/test.reusable.yml@master strategy: matrix: - go: ["1.23", "1.22"] # auto-update/supported-go-version-list + go: ["1.24", "1.23"] # auto-update/supported-go-version-list fail-fast: false with: go-version: ${{ matrix.go }} @@ -33,7 +33,7 @@ jobs: uses: pion/.goassets/.github/workflows/test-i386.reusable.yml@master strategy: matrix: - go: ["1.23", "1.22"] # auto-update/supported-go-version-list + go: ["1.24", "1.23"] # auto-update/supported-go-version-list fail-fast: false with: go-version: ${{ matrix.go }} @@ -41,5 +41,5 @@ jobs: test-wasm: uses: pion/.goassets/.github/workflows/test-wasm.reusable.yml@master with: - go-version: "1.23" # auto-update/latest-go-version + go-version: "1.24" # auto-update/latest-go-version secrets: inherit diff --git a/.github/workflows/tidy-check.yaml b/.github/workflows/tidy-check.yaml index 417e730a..710dbc91 100644 --- a/.github/workflows/tidy-check.yaml +++ b/.github/workflows/tidy-check.yaml @@ -22,4 +22,4 @@ jobs: tidy: uses: pion/.goassets/.github/workflows/tidy-check.reusable.yml@master with: - go-version: "1.22" # auto-update/latest-go-version + go-version: "1.24" # auto-update/latest-go-version diff --git a/.golangci.yml b/.golangci.yml index a3235bec..120faf29 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,23 +19,42 @@ linters-settings: recommendations: - errors forbidigo: + analyze-types: true forbid: - ^fmt.Print(f|ln)?$ - ^log.(Panic|Fatal|Print)(f|ln)?$ - ^os.Exit$ - ^panic$ - ^print(ln)?$ + - p: ^testing.T.(Error|Errorf|Fatal|Fatalf|Fail|FailNow)$ + pkg: ^testing$ + msg: "use testify/assert instead" + varnamelen: + max-distance: 12 + min-name-length: 2 + ignore-type-assert-ok: true + ignore-map-index-ok: true + ignore-chan-recv-ok: true + ignore-decls: + - i int + - n int + - w io.Writer + - r io.Reader + - b []byte linters: enable: - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers - bidichk # Checks for dangerous unicode character sequences - bodyclose # checks whether HTTP response body is closed successfully + - containedctx # containedctx is a linter that detects struct contained context.Context field - contextcheck # check the function whether use a non-inherited context + - cyclop # checks function and package cyclomatic complexity - decorder # check declaration order and count of types, constants, variables and functions - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) - dupl # Tool for code clone detection - durationcheck # check for two durations multiplied together + - err113 # Golang linter to check the errors handling expressions - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occations, where the check for the returned error can be omitted. - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. @@ -46,18 +65,17 @@ linters: - forcetypeassert # finds forced type assertions - 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 + - gocyclo # Computes and checks the cyclomatic complexity of functions + - godot # Check if comments end in a period - godox # Tool for detection of FIXME, TODO and other comment keywords - - err113 # 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 - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. - - 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 @@ -65,9 +83,15 @@ linters: - grouper # An analyzer to analyze expression groups. - importas # Enforces consistent import aliases - ineffassign # Detects when assignments to existing variables are not used + - lll # Reports long lines + - maintidx # maintidx measures the maintainability index of each function. + - makezero # Finds slice declarations with non-zero initial length - misspell # Finds commonly misspelled English words in comments + - nakedret # Finds naked returns in functions greater than a specified function length + - nestif # Reports deeply nested if statements - nilerr # Finds the code that returns nil even if it checks that the error is not nil. - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. + - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity - noctx # noctx finds sending http request without context.Context - predeclared # find code that shadows one of Go's predeclared identifiers - revive # golint replacement, finds style mistakes @@ -75,28 +99,22 @@ linters: - stylecheck # Stylecheck is a replacement for golint - tagliatelle # Checks the struct tags. - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 - - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes + - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers - 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 + - varnamelen # checks that the length of a variable's name matches its scope - wastedassign # wastedassign finds wasted assignment statements - whitespace # Tool for detection of leading and trailing whitespace disable: - depguard # Go linter that checks if package imports are in a list of acceptable packages - - containedctx # containedctx is a linter that detects struct contained context.Context field - - cyclop # checks function and package cyclomatic complexity - 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. + - gochecknoinits # Checks that no init functions are present in Go code + - 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. + - interfacebloat # A linter that checks length of interface. - ireturn # Accept Interfaces, Return Concrete Types - - lll # Reports long lines - - maintidx # maintidx measures the maintainability index of each function. - - makezero # Finds slice declarations with non-zero initial length - - nakedret # Finds naked returns in functions greater than a specified function length - - nestif # Reports deeply nested if statements - - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity + - mnd # An analyzer to detect magic numbers - nolintlint # Reports ill-formed or insufficient nolint directives - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test - prealloc # Finds slice declarations that could potentially be preallocated @@ -104,8 +122,7 @@ linters: - 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 - - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers - - varnamelen # checks that the length of a variable's name matches its scope + - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes - wrapcheck # Checks that errors returned from external packages are wrapped - wsl # Whitespace Linter - Forces you to use empty lines! @@ -114,9 +131,12 @@ issues: exclude-dirs-use-default: false exclude-rules: # Allow complex tests and examples, better to be self contained - - path: (examples|main\.go|_test\.go) + - path: (examples|main\.go) linters: + - gocognit - forbidigo + - path: _test\.go + linters: - gocognit # Allow forbidden identifiers in CLI commands diff --git a/.reuse/dep5 b/.reuse/dep5 index eb7fac2f..4ce05694 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -6,6 +6,6 @@ Files: README.md DESIGN.md **/README.md AUTHORS.txt renovate.json go.mod go.sum Copyright: 2023 The Pion community License: MIT -Files: testdata/fuzz/* **/testdata/fuzz/* api/*.txt +Files: testdata/seed/* testdata/fuzz/* **/testdata/fuzz/* api/*.txt Copyright: 2023 The Pion community License: CC0-1.0 diff --git a/c-data-channels/main.go b/c-data-channels/main.go index 9b93a19e..be8032a2 100644 --- a/c-data-channels/main.go +++ b/c-data-channels/main.go @@ -20,7 +20,7 @@ import ( // are almost identical to the data-channel example that is written in pure Go, // https://github.com/pion/webrtc/tree/master/examples/data-channels. // The only difference is that Run lets you to define the OnDataChannel callback in C. -func Run(f func(*webrtc.DataChannel)) { +func Run(f func(*webrtc.DataChannel)) { // nolint // Everything below is the Pion WebRTC API! Thanks for using it ❤️. // Prepare the configuration @@ -86,7 +86,7 @@ func Run(f func(*webrtc.DataChannel)) { func main() {} -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -103,10 +103,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -116,7 +117,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/examples.go b/examples.go index 74771bee..7982859c 100644 --- a/examples.go +++ b/examples.go @@ -51,8 +51,8 @@ func serve(addr string) error { // Serve the required pages // DIY 'mux' to avoid additional dependencies - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - url := r.URL.Path + http.HandleFunc("/", func(httpWriter http.ResponseWriter, httpReader *http.Request) { + url := httpReader.URL.Path // Split up the URL. Expected parts: // 1: Base url // 2: "example" @@ -70,7 +70,8 @@ func serve(addr string) error { } fiddle := filepath.Join(exampleLink, "jsfiddle") if len(parts[4]) != 0 { - http.StripPrefix("/example/"+exampleType+"/"+exampleLink+"/", http.FileServer(http.Dir(fiddle))).ServeHTTP(w, r) + http.StripPrefix("/example/"+exampleType+"/"+exampleLink+"/", http.FileServer(http.Dir(fiddle))).ServeHTTP(httpWriter, httpReader) // nolint + return } @@ -88,16 +89,17 @@ func serve(addr string) error { exampleType == "js", } - err = temp.Execute(w, data) + err = temp.Execute(httpWriter, data) if err != nil { panic(err) } + return } } // Serve the main page - err = homeTemplate.Execute(w, examples) + err = homeTemplate.Execute(httpWriter, examples) if err != nil { panic(err) } diff --git a/ffmpeg-send/main.go b/ffmpeg-send/main.go index 7a319f07..24975ddb 100644 --- a/ffmpeg-send/main.go +++ b/ffmpeg-send/main.go @@ -106,7 +106,7 @@ var ( err error ) -func writeH264ToTrack(track *webrtc.TrackLocalStaticSample) { +func writeH264ToTrack(track *webrtc.TrackLocalStaticSample) { // nolint astiav.RegisterAllDevices() initTestSrc() @@ -184,7 +184,7 @@ func initTestSrc() { } // Open input - if err = inputFormatContext.OpenInput("testsrc=size=640x480:rate=30", astiav.FindInputFormat("lavfi"), nil); err != nil { + if err = inputFormatContext.OpenInput("testsrc=size=640x480:rate=30", astiav.FindInputFormat("lavfi"), nil); err != nil { // nolint panic(err) } @@ -277,7 +277,7 @@ func freeVideoCoding() { encodePacket.Free() } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -294,10 +294,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -307,7 +308,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/gstreamer-receive/main.go b/gstreamer-receive/main.go index 6e896811..c5238ee4 100644 --- a/gstreamer-receive/main.go +++ b/gstreamer-receive/main.go @@ -4,7 +4,8 @@ //go:build !js // +build !js -// gstreamer-receive is a simple application that shows how to receive media using Pion WebRTC and play live using GStreamer. +// gstreamer-receive is a simple application that shows how to +// receive media using Pion WebRTC and play live using GStreamer. package main import ( @@ -53,7 +54,7 @@ func main() { go func() { ticker := time.NewTicker(time.Second * 3) for range ticker.C { - rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(track.SSRC())}}) + rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(track.SSRC())}}) // nolint if rtcpSendErr != nil { fmt.Println(rtcpSendErr) } @@ -119,14 +120,14 @@ func main() { select {} } -// Create the appropriate GStreamer pipeline depending on what codec we are working with +// Create the appropriate GStreamer pipeline depending on what codec we are working with. func pipelineForCodec(track *webrtc.TrackRemote, codecName string) *app.Source { pipelineString := "appsrc format=time is-live=true do-timestamp=true name=src ! application/x-rtp" switch strings.ToLower(codecName) { case "vp8": - pipelineString += fmt.Sprintf(", payload=%d, encoding-name=VP8-DRAFT-IETF-01 ! rtpvp8depay ! decodebin ! autovideosink", track.PayloadType()) + pipelineString += fmt.Sprintf(", payload=%d, encoding-name=VP8-DRAFT-IETF-01 ! rtpvp8depay ! decodebin ! autovideosink", track.PayloadType()) // nolint case "opus": - pipelineString += fmt.Sprintf(", payload=%d, encoding-name=OPUS ! rtpopusdepay ! decodebin ! autoaudiosink", track.PayloadType()) + pipelineString += fmt.Sprintf(", payload=%d, encoding-name=OPUS ! rtpopusdepay ! decodebin ! autoaudiosink", track.PayloadType()) // nolint case "vp9": pipelineString += " ! rtpvp9depay ! decodebin ! autovideosink" case "h264": @@ -154,7 +155,7 @@ func pipelineForCodec(track *webrtc.TrackRemote, codecName string) *app.Source { return app.SrcFromElement(appSrc) } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -171,10 +172,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -184,7 +186,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/gstreamer-send-offer/main.go b/gstreamer-send-offer/main.go index eb58d5d8..dcb57582 100644 --- a/gstreamer-send-offer/main.go +++ b/gstreamer-send-offer/main.go @@ -112,16 +112,16 @@ func main() { select {} } -// Create the appropriate GStreamer pipeline depending on what codec we are working with -func pipelineForCodec(codecName string, tracks []*webrtc.TrackLocalStaticSample, pipelineSrc string) { +// Create the appropriate GStreamer pipeline depending on what codec we are working with. +func pipelineForCodec(codecName string, tracks []*webrtc.TrackLocalStaticSample, pipelineSrc string) { // nolint pipelineStr := "appsink name=appsink" switch codecName { case "vp8": - pipelineStr = pipelineSrc + " ! vp8enc error-resilient=partitions keyframe-max-dist=10 auto-alt-ref=true cpu-used=5 deadline=1 ! " + pipelineStr + pipelineStr = pipelineSrc + " ! vp8enc error-resilient=partitions keyframe-max-dist=10 auto-alt-ref=true cpu-used=5 deadline=1 ! " + pipelineStr // nolint case "vp9": pipelineStr = pipelineSrc + " ! vp9enc ! " + pipelineStr case "h264": - pipelineStr = pipelineSrc + " ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency key-int-max=20 ! video/x-h264,stream-format=byte-stream ! " + pipelineStr + pipelineStr = pipelineSrc + " ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency key-int-max=20 ! video/x-h264,stream-format=byte-stream ! " + pipelineStr // nolint case "opus": pipelineStr = pipelineSrc + " ! opusenc ! " + pipelineStr case "pcmu": @@ -172,7 +172,7 @@ func pipelineForCodec(codecName string, tracks []*webrtc.TrackLocalStaticSample, }) } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -182,7 +182,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { @@ -194,7 +194,7 @@ func decode(in string, obj *webrtc.SessionDescription) { } } -// httpSDPServer starts a HTTP Server that consumes SDPs +// httpSDPServer starts a HTTP Server that consumes SDPs. func httpSDPServer(port int) chan string { sdpChan := make(chan string) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { diff --git a/gstreamer-send/main.go b/gstreamer-send/main.go index 9363b347..dc3affde 100644 --- a/gstreamer-send/main.go +++ b/gstreamer-send/main.go @@ -24,7 +24,7 @@ import ( "github.com/pion/webrtc/v4/pkg/media" ) -func main() { +func main() { // nolint audioSrc := flag.String("audio-src", "audiotestsrc", "GStreamer audio src") videoSrc := flag.String("video-src", "videotestsrc", "GStreamer video src") flag.Parse() @@ -50,7 +50,7 @@ func main() { }) // Create a audio track - audioTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "audio/opus"}, "audio", "pion1") + audioTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "audio/opus"}, "audio", "pion1") // nolint if err != nil { panic(err) } @@ -60,7 +60,7 @@ func main() { } // Create a video track - firstVideoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion2") + firstVideoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion2") // nolint if err != nil { panic(err) } @@ -70,7 +70,7 @@ func main() { } // Create a second video track - secondVideoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion3") + secondVideoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion3") // nolint if err != nil { panic(err) } @@ -117,16 +117,16 @@ func main() { select {} } -// Create the appropriate GStreamer pipeline depending on what codec we are working with -func pipelineForCodec(codecName string, tracks []*webrtc.TrackLocalStaticSample, pipelineSrc string) { +// Create the appropriate GStreamer pipeline depending on what codec we are working with. +func pipelineForCodec(codecName string, tracks []*webrtc.TrackLocalStaticSample, pipelineSrc string) { // nolint pipelineStr := "appsink name=appsink" switch codecName { case "vp8": - pipelineStr = pipelineSrc + " ! vp8enc error-resilient=partitions keyframe-max-dist=10 auto-alt-ref=true cpu-used=5 deadline=1 ! " + pipelineStr + pipelineStr = pipelineSrc + " ! vp8enc error-resilient=partitions keyframe-max-dist=10 auto-alt-ref=true cpu-used=5 deadline=1 ! " + pipelineStr // nolint case "vp9": pipelineStr = pipelineSrc + " ! vp9enc ! " + pipelineStr case "h264": - pipelineStr = pipelineSrc + " ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency key-int-max=20 ! video/x-h264,stream-format=byte-stream ! " + pipelineStr + pipelineStr = pipelineSrc + " ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency key-int-max=20 ! video/x-h264,stream-format=byte-stream ! " + pipelineStr // nolint case "opus": pipelineStr = pipelineSrc + " ! opusenc ! " + pipelineStr case "pcmu": @@ -177,7 +177,7 @@ func pipelineForCodec(codecName string, tracks []*webrtc.TrackLocalStaticSample, }) } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -194,10 +194,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -207,7 +208,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/janus-gateway/streaming/main.go b/janus-gateway/streaming/main.go index d4b7b42b..6d112354 100644 --- a/janus-gateway/streaming/main.go +++ b/janus-gateway/streaming/main.go @@ -18,7 +18,7 @@ import ( "github.com/pion/webrtc/v4/pkg/media/oggwriter" ) -func saveToDisk(i media.Writer, track *webrtc.TrackRemote) { +func saveToDisk(i media.Writer, track *webrtc.TrackRemote) { // nolint defer func() { if err := i.Close(); err != nil { panic(err) @@ -56,7 +56,7 @@ func watchHandle(handle *janus.Handle) { } } -func main() { +func main() { // nolint // Everything below is the Pion WebRTC API! Thanks for using it ❤️. // Janus @@ -96,7 +96,7 @@ func main() { panic(err) } - if msg.Jsep != nil { + if msg.Jsep != nil { // nolint sdpVal, ok := msg.Jsep["sdp"].(string) if !ok { panic("failed to cast") diff --git a/janus-gateway/video-room/main.go b/janus-gateway/video-room/main.go index 569e17dc..0486420e 100644 --- a/janus-gateway/video-room/main.go +++ b/janus-gateway/video-room/main.go @@ -38,7 +38,7 @@ func watchHandle(handle *janus.Handle) { } } -func main() { +func main() { // nolint gst.Init(nil) // Everything below is the Pion WebRTC API! Thanks for using it ❤️. @@ -167,16 +167,16 @@ func main() { select {} } -// Create the appropriate GStreamer pipeline depending on what codec we are working with -func pipelineForCodec(codecName string, tracks []*webrtc.TrackLocalStaticSample, pipelineSrc string) { +// Create the appropriate GStreamer pipeline depending on what codec we are working with. +func pipelineForCodec(codecName string, tracks []*webrtc.TrackLocalStaticSample, pipelineSrc string) { // nolint pipelineStr := "appsink name=appsink" switch codecName { case "vp8": - pipelineStr = pipelineSrc + " ! vp8enc error-resilient=partitions keyframe-max-dist=10 auto-alt-ref=true cpu-used=5 deadline=1 ! " + pipelineStr + pipelineStr = pipelineSrc + " ! vp8enc error-resilient=partitions keyframe-max-dist=10 auto-alt-ref=true cpu-used=5 deadline=1 ! " + pipelineStr // nolint case "vp9": pipelineStr = pipelineSrc + " ! vp9enc ! " + pipelineStr case "h264": - pipelineStr = pipelineSrc + " ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency key-int-max=20 ! video/x-h264,stream-format=byte-stream ! " + pipelineStr + pipelineStr = pipelineSrc + " ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency key-int-max=20 ! video/x-h264,stream-format=byte-stream ! " + pipelineStr // nolint case "opus": pipelineStr = pipelineSrc + " ! opusenc ! " + pipelineStr case "pcmu": diff --git a/play-from-disk-h264/main.go b/play-from-disk-h264/main.go index 5284aaab..a8c4a1cf 100644 --- a/play-from-disk-h264/main.go +++ b/play-from-disk-h264/main.go @@ -63,9 +63,9 @@ func main() { //nolint iceConnectedCtx, iceConnectedCtxCancel := context.WithCancel(context.Background()) - if haveVideoFile { + if haveVideoFile { // nolint // Create a video track - videoTrack, videoTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264}, "video", "pion") + videoTrack, videoTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264}, "video", "pion") // nolint if videoTrackErr != nil { panic(videoTrackErr) } @@ -126,9 +126,9 @@ func main() { //nolint }() } - if haveAudioFile { + if haveAudioFile { // nolint // Create a audio track - audioTrack, audioTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}, "audio", "pion") + audioTrack, audioTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}, "audio", "pion") // nolint if audioTrackErr != nil { panic(audioTrackErr) } @@ -211,9 +211,10 @@ func main() { //nolint fmt.Printf("Peer Connection State has changed: %s\n", s.String()) if s == webrtc.PeerConnectionStateFailed { - // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. - // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. - // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. + // It may be reconnected using an ICE Restart. Use webrtc.PeerConnectionStateDisconnected + // if you are interested in detecting faster timeout. Note that the PeerConnection may come + // back from PeerConnectionStateDisconnected. fmt.Println("Peer Connection has gone to failed exiting") os.Exit(0) } @@ -254,7 +255,7 @@ func main() { //nolint select {} } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -271,10 +272,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -284,7 +286,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/play-from-disk-mkv/main.go b/play-from-disk-mkv/main.go index 54db6861..2386597e 100644 --- a/play-from-disk-mkv/main.go +++ b/play-from-disk-mkv/main.go @@ -38,7 +38,7 @@ const ( // nolint: gochecknoglobals var annexBPrefix = []byte{0x00, 0x00, 0x01} -func main() { +func main() { // nolint // Assert that the MKV exists _, err := os.Stat(mkvFileName) if os.IsNotExist(err) { @@ -63,7 +63,7 @@ func main() { }() // Create a Audio Track - audioTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}, "audio", "pion") + audioTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}, "audio", "pion") // nolint if err != nil { panic(err) } @@ -76,7 +76,7 @@ func main() { rtcpReader(rtpSender) // Create a Video Track - videoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264}, "video", "pion") + videoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264}, "video", "pion") // nolint if err != nil { panic(err) } @@ -104,9 +104,10 @@ func main() { fmt.Printf("Peer Connection State has changed: %s\n", s.String()) if s == webrtc.PeerConnectionStateFailed { - // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. - // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. - // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. + // It may be reconnected using an ICE Restart. Use webrtc.PeerConnectionStateDisconnected + // if you are interested in detecting faster timeout. Note that the PeerConnection may + // come back from PeerConnectionStateDisconnected. fmt.Println("Peer Connection has gone to failed exiting") os.Exit(0) } @@ -148,7 +149,7 @@ func main() { } // Write the audio samples to the video and audio track. Record how long we have been sleeping -// time.Sleep may sleep longer then expected +// time.Sleep may sleep longer then expected. func chanToTrack(sampleChan chan media.Sample, track *webrtc.TrackLocalStaticSample) { var ( sleepWanted time.Duration @@ -166,7 +167,7 @@ func chanToTrack(sampleChan chan media.Sample, track *webrtc.TrackLocalStaticSam } } -func sendMkv(mkvFile *os.File, audioTrack, videoTrack *webrtc.TrackLocalStaticSample) { +func sendMkv(mkvFile *os.File, audioTrack, videoTrack *webrtc.TrackLocalStaticSample) { //nolint var unmarshaled struct { Header webm.EBMLHeader `ebml:"EBML"` Segment webm.Segment `ebml:"Segment"` @@ -208,7 +209,7 @@ func sendMkv(mkvFile *os.File, audioTrack, videoTrack *webrtc.TrackLocalStaticSa // and push onto channels. These channels pace the send of audio and video for _, cluster := range unmarshaled.Segment.Cluster { for _, block := range cluster.SimpleBlock { - timecode := (cluster.Timecode + uint64(block.Timecode)) * unmarshaled.Segment.Info.TimecodeScale + timecode := (cluster.Timecode + uint64(block.Timecode)) * unmarshaled.Segment.Info.TimecodeScale // nolint if block.TrackNumber == videoTrackNumber { // Convert H264 from AVC bitstream to Annex-B @@ -235,17 +236,17 @@ func sendMkv(mkvFile *os.File, audioTrack, videoTrack *webrtc.TrackLocalStaticSa // Send to video goroutine for paced sending lastVideoTimeCode, oldTimeCode = timecode, lastVideoTimeCode - videoQueue <- media.Sample{Data: annexBSlice, Duration: time.Duration(timecode - oldTimeCode)} + videoQueue <- media.Sample{Data: annexBSlice, Duration: time.Duration(timecode - oldTimeCode)} // nolint } else { // Send to audio goroutine for paced sending lastAudioTimeCode, oldTimeCode = timecode, lastAudioTimeCode - audioQueue <- media.Sample{Data: block.Data[0], Duration: time.Duration(timecode - oldTimeCode)} + audioQueue <- media.Sample{Data: block.Data[0], Duration: time.Duration(timecode - oldTimeCode)} // nolint } } } } -// Convert AVC Extradata to Annex-B SPS and PPS +// Convert AVC Extradata to Annex-B SPS and PPS. func extractMetadata(codecData []byte) (out []byte) { spsCount := codecData[spsCountOffset] & naluTypeBitmask offset := 6 @@ -292,7 +293,7 @@ func rtcpReader(rtpSender *webrtc.RTPSender) { }() } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -309,10 +310,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -322,7 +324,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/rtmp-to-webrtc/main.go b/rtmp-to-webrtc/main.go index ca26f28f..c192741f 100644 --- a/rtmp-to-webrtc/main.go +++ b/rtmp-to-webrtc/main.go @@ -99,7 +99,7 @@ func main() { rtpToTrack(audioTrack, &codecs.OpusPacket{}, 48000, 5006) } -// Listen for incoming packets on a port and write them to a Track +// Listen for incoming packets on a port and write them to a Track. func rtpToTrack(track *webrtc.TrackLocalStaticSample, depacketizer rtp.Depacketizer, sampleRate uint32, port int) { // Open a UDP Listener for RTP Packets on port 5004 listener, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: port}) @@ -157,7 +157,7 @@ func processRTCP(rtpSender *webrtc.RTPSender) { }() } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -174,10 +174,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -187,7 +188,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/save-to-webm/main.go b/save-to-webm/main.go index 90cd116f..c8210f97 100644 --- a/save-to-webm/main.go +++ b/save-to-webm/main.go @@ -4,7 +4,8 @@ //go:build !js // +build !js -// save-to-webm is a simple application that shows how to receive audio and video using Pion and then save to WebM container. +// save-to-webm is a simple application that shows how to receive +// audio and video using Pion and then save to WebM container. package main import ( @@ -95,7 +96,7 @@ func (s *webmSaver) PushOpus(rtpPacket *rtp.Packet) { } } -func (s *webmSaver) PushH264(rtpPacket *rtp.Packet) { +func (s *webmSaver) PushH264(rtpPacket *rtp.Packet) { // nolint s.h264JitterBuffer.Push(rtpPacket) pkt, err := s.h264JitterBuffer.Peek(true) @@ -166,8 +167,8 @@ func (s *webmSaver) PushVP8(rtpPacket *rtp.Packet) { if videoKeyframe { // Keyframe has frame information. raw := uint(sample.Data[6]) | uint(sample.Data[7])<<8 | uint(sample.Data[8])<<16 | uint(sample.Data[9])<<24 - width := int(raw & 0x3FFF) - height := int((raw >> 16) & 0x3FFF) + width := int(raw & 0x3FFF) // nolint + height := int((raw >> 16) & 0x3FFF) // nolint if s.videoWriter == nil || s.audioWriter == nil { s.InitWriter(false, width, height) @@ -214,8 +215,8 @@ func (s *webmSaver) InitWriter(isH264 bool, width, height int) { TrackType: 1, DefaultDuration: 33333333, Video: &webm.Video{ - PixelWidth: uint64(width), - PixelHeight: uint64(height), + PixelWidth: uint64(width), // nolint + PixelHeight: uint64(height), // nolint }, }, }) @@ -227,7 +228,7 @@ func (s *webmSaver) InitWriter(isH264 bool, width, height int) { s.videoWriter = ws[1] } -func createWebRTCConn(saver *webmSaver) *webrtc.PeerConnection { +func createWebRTCConn(saver *webmSaver) *webrtc.PeerConnection { // nolint // Everything below is the Pion WebRTC API! Thanks for using it ❤️. // Prepare the configuration @@ -240,31 +241,31 @@ func createWebRTCConn(saver *webmSaver) *webrtc.PeerConnection { } // Create a MediaEngine object to configure the supported codec - m := &webrtc.MediaEngine{} + mediaEngine := &webrtc.MediaEngine{} // Setup the codecs you want to use. // This example supports VP8 or H264. Some browsers may only support one (or the other) - if err := m.RegisterCodec(webrtc.RTPCodecParameters{ - RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8, ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, + if err := mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8, ClockRate: 90000}, PayloadType: 96, }, webrtc.RTPCodecTypeVideo); err != nil { panic(err) } - if err := m.RegisterCodec(webrtc.RTPCodecParameters{ - RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, + if err := mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000}, PayloadType: 98, }, webrtc.RTPCodecTypeVideo); err != nil { panic(err) } - if err := m.RegisterCodec(webrtc.RTPCodecParameters{ - RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, + if err := mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus, ClockRate: 48000}, PayloadType: 111, }, webrtc.RTPCodecTypeAudio); err != nil { panic(err) } // Create the API object with the MediaEngine - api := webrtc.NewAPI(webrtc.WithMediaEngine(m)) + api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine)) // Create a new RTCPeerConnection peerConnection, err := api.NewPeerConnection(config) @@ -351,7 +352,7 @@ func createWebRTCConn(saver *webmSaver) *webrtc.PeerConnection { return peerConnection } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -368,10 +369,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -381,7 +383,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/sfu-ws/main.go b/sfu-ws/main.go index ba8140f8..732dc6a8 100644 --- a/sfu-ws/main.go +++ b/sfu-ws/main.go @@ -86,8 +86,8 @@ func main() { } } -// Add to list of tracks and fire renegotation for all PeerConnections -func addTrack(t *webrtc.TrackRemote) *webrtc.TrackLocalStaticRTP { +// Add to list of tracks and fire renegotation for all PeerConnections. +func addTrack(t *webrtc.TrackRemote) *webrtc.TrackLocalStaticRTP { // nolint listLock.Lock() defer func() { listLock.Unlock() @@ -101,10 +101,11 @@ func addTrack(t *webrtc.TrackRemote) *webrtc.TrackLocalStaticRTP { } trackLocals[t.ID()] = trackLocal + return trackLocal } -// Remove from list of tracks and fire renegotation for all PeerConnections +// Remove from list of tracks and fire renegotation for all PeerConnections. func removeTrack(t *webrtc.TrackLocalStaticRTP) { listLock.Lock() defer func() { @@ -115,8 +116,8 @@ func removeTrack(t *webrtc.TrackLocalStaticRTP) { delete(trackLocals, t.ID()) } -// signalPeerConnections updates each PeerConnection so that it is getting all the expected media tracks -func signalPeerConnections() { +// signalPeerConnections updates each PeerConnection so that it is getting all the expected media tracks. +func signalPeerConnections() { // nolint listLock.Lock() defer func() { listLock.Unlock() @@ -127,6 +128,7 @@ func signalPeerConnections() { for i := range peerConnections { if peerConnections[i].peerConnection.ConnectionState() == webrtc.PeerConnectionStateClosed { peerConnections = append(peerConnections[:i], peerConnections[i+1:]...) + return true // We modified the slice, start from the beginning } @@ -178,6 +180,7 @@ func signalPeerConnections() { offerString, err := json.Marshal(offer) if err != nil { log.Errorf("Failed to marshal offer to json: %v", err) + return true } @@ -191,7 +194,7 @@ func signalPeerConnections() { } } - return + return tryAgain } for syncAttempt := 0; ; syncAttempt++ { @@ -201,6 +204,7 @@ func signalPeerConnections() { time.Sleep(time.Second * 3) signalPeerConnections() }() + return } @@ -210,7 +214,7 @@ func signalPeerConnections() { } } -// dispatchKeyFrame sends a keyframe to all PeerConnections, used everytime a new user joins the call +// dispatchKeyFrame sends a keyframe to all PeerConnections, used everytime a new user joins the call. func dispatchKeyFrame() { listLock.Lock() defer listLock.Unlock() @@ -230,16 +234,17 @@ func dispatchKeyFrame() { } } -// Handle incoming websockets -func websocketHandler(w http.ResponseWriter, r *http.Request) { +// Handle incoming websockets. +func websocketHandler(w http.ResponseWriter, r *http.Request) { // nolint // Upgrade HTTP request to Websocket unsafeConn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Errorf("Failed to upgrade HTTP to Websocket: ", err) + return } - c := &threadSafeWriter{unsafeConn, sync.Mutex{}} + c := &threadSafeWriter{unsafeConn, sync.Mutex{}} // nolint // When this frame returns close the Websocket defer c.Close() //nolint @@ -248,6 +253,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{}) if err != nil { log.Errorf("Failed to creates a PeerConnection: %v", err) + return } @@ -260,6 +266,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { Direction: webrtc.RTPTransceiverDirectionRecvonly, }); err != nil { log.Errorf("Failed to add transceiver: %v", err) + return } } @@ -279,6 +286,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { candidateString, err := json.Marshal(i.ToJSON()) if err != nil { log.Errorf("Failed to marshal candidate to json: %v", err) + return } @@ -325,6 +333,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { if err = rtpPkt.Unmarshal(buf[:i]); err != nil { log.Errorf("Failed to unmarshal incoming RTP packet: %v", err) + return } @@ -349,6 +358,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { _, raw, err := c.ReadMessage() if err != nil { log.Errorf("Failed to read message: %v", err) + return } @@ -356,6 +366,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { if err := json.Unmarshal(raw, &message); err != nil { log.Errorf("Failed to unmarshal json to message: %v", err) + return } @@ -364,6 +375,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { candidate := webrtc.ICECandidateInit{} if err := json.Unmarshal([]byte(message.Data), &candidate); err != nil { log.Errorf("Failed to unmarshal json to candidate: %v", err) + return } @@ -371,12 +383,14 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { if err := peerConnection.AddICECandidate(candidate); err != nil { log.Errorf("Failed to add ICE candidate: %v", err) + return } case "answer": answer := webrtc.SessionDescription{} if err := json.Unmarshal([]byte(message.Data), &answer); err != nil { log.Errorf("Failed to unmarshal json to answer: %v", err) + return } @@ -384,6 +398,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { if err := peerConnection.SetRemoteDescription(answer); err != nil { log.Errorf("Failed to set remote description: %v", err) + return } default: @@ -392,7 +407,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { } } -// Helper to make Gorilla Websockets threadsafe +// Helper to make Gorilla Websockets threadsafe. type threadSafeWriter struct { *websocket.Conn sync.Mutex diff --git a/sip-over-websocket-to-webrtc/main.go b/sip-over-websocket-to-webrtc/main.go index 0671dfbb..793427d5 100644 --- a/sip-over-websocket-to-webrtc/main.go +++ b/sip-over-websocket-to-webrtc/main.go @@ -26,7 +26,7 @@ var ( port = flag.String("port", "5066", "Port that websocket is available on") ) -func main() { +func main() { // nolint flag.Parse() if *host == "" || *port == "" || *password == "" { diff --git a/sip-over-websocket-to-webrtc/softphone/inboundcall.go b/sip-over-websocket-to-webrtc/softphone/inboundcall.go index 334c4363..17f2d04a 100644 --- a/sip-over-websocket-to-webrtc/softphone/inboundcall.go +++ b/sip-over-websocket-to-webrtc/softphone/inboundcall.go @@ -29,11 +29,11 @@ func (softphone *Softphone) OpenToInvite() { sipMessage.address = msg.Hdr.From sipMessage.headers = make(map[string]string) sipMessage.headers["Via"] = fmt.Sprintf("SIP/2.0/WSS %s;branch=%s", softphone.fakeDomain, branch()) - sipMessage.headers["From"] = fmt.Sprintf(";tag=%s", softphone.sipInfo.Username, softphone.sipInfo.Domain, softphone.fromTag) + sipMessage.headers["From"] = fmt.Sprintf(";tag=%s", softphone.sipInfo.Username, softphone.sipInfo.Domain, softphone.fromTag) // nolint sipMessage.headers["To"] = fmt.Sprintf("", msg.Hdr.From) sipMessage.headers["Content-Type"] = "x-rc/agent" sipMessage.addCseq(softphone).addCallID(*softphone).addUserAgent() - sipMessage.Body = fmt.Sprintf(``, msg.Hdr.SID, msg.Hdr.Req, msg.Hdr.To, msg.Hdr.From, softphone.sipInfo.AuthorizationID) + sipMessage.Body = fmt.Sprintf(``, msg.Hdr.SID, msg.Hdr.Req, msg.Hdr.To, msg.Hdr.From, softphone.sipInfo.AuthorizationID) // nolint softphone.request(sipMessage, nil) softphone.OnInvite(inviteMessage) diff --git a/sip-over-websocket-to-webrtc/softphone/invite.go b/sip-over-websocket-to-webrtc/softphone/invite.go index 43cd34ba..2d61634f 100644 --- a/sip-over-websocket-to-webrtc/softphone/invite.go +++ b/sip-over-websocket-to-webrtc/softphone/invite.go @@ -18,7 +18,7 @@ func (softphone *Softphone) Invite(extension, offer string) { sipMessage.headers["Contact"] = fmt.Sprintf(";expires=200", softphone.FakeEmail) sipMessage.headers["To"] = fmt.Sprintf("", extension, softphone.sipInfo.Domain) sipMessage.headers["Via"] = fmt.Sprintf("SIP/2.0/WS %s;branch=%s", softphone.fakeDomain, branch()) - sipMessage.headers["From"] = fmt.Sprintf(";tag=%s", softphone.sipInfo.Username, softphone.sipInfo.Domain, softphone.fromTag) + sipMessage.headers["From"] = fmt.Sprintf(";tag=%s", softphone.sipInfo.Username, softphone.sipInfo.Domain, softphone.fromTag) // nolint sipMessage.headers["Supported"] = "replaces, outbound,ice" sipMessage.addCseq(softphone).addCallID(*softphone).addUserAgent() diff --git a/sip-over-websocket-to-webrtc/softphone/register.go b/sip-over-websocket-to-webrtc/softphone/register.go index c57c9f70..706ebd65 100644 --- a/sip-over-websocket-to-webrtc/softphone/register.go +++ b/sip-over-websocket-to-webrtc/softphone/register.go @@ -50,7 +50,7 @@ func (softphone *Softphone) register() { sipMessage.headers = make(map[string]string) sipMessage.headers["Contact"] = fmt.Sprintf(";expires=200", softphone.FakeEmail) sipMessage.headers["Via"] = fmt.Sprintf("SIP/2.0/WS %s;branch=%s", softphone.fakeDomain, branch()) - sipMessage.headers["From"] = fmt.Sprintf(";tag=%s", softphone.sipInfo.Username, softphone.sipInfo.Domain, softphone.fromTag) + sipMessage.headers["From"] = fmt.Sprintf(";tag=%s", softphone.sipInfo.Username, softphone.sipInfo.Domain, softphone.fromTag) // nolint sipMessage.headers["To"] = fmt.Sprintf("", softphone.sipInfo.Username, softphone.sipInfo.Domain) sipMessage.headers["Organization"] = "ACE MEDIAS TOOLS" sipMessage.headers["Supported"] = "path,ice" diff --git a/sip-over-websocket-to-webrtc/softphone/utils.go b/sip-over-websocket-to-webrtc/softphone/utils.go index 620543c0..c895b32f 100644 --- a/sip-over-websocket-to-webrtc/softphone/utils.go +++ b/sip-over-websocket-to-webrtc/softphone/utils.go @@ -22,7 +22,7 @@ type SIPInfoResponse struct { SwitchBackInterval int `json:"switchBackInterval"` } -func generateResponse(username, password, realm, method, uri, nonce string) string { // ONLY REGISTRATION WITH QOP=AUTH ! +func generateResponse(username, password, realm, method, uri, nonce string) string { // nolint ha1 := md5.Sum([]byte(fmt.Sprintf("%s:%s:%s", username, realm, password))) //nolint ha2 := md5.Sum([]byte(fmt.Sprintf("%s:%s", method, uri))) //nolint response := md5.Sum([]byte(fmt.Sprintf("%x:%s:00000001:%s:auth:%x", ha1, nonce, "0e6758e1adfccffbd0ad9ffdde3ef655", ha2))) //nolint @@ -32,17 +32,17 @@ func generateResponse(username, password, realm, method, uri, nonce string) stri func generateAuthorization(sipInfo SIPInfoResponse, method, nonce string) string { return fmt.Sprintf( - `Digest username="%s",realm="%s",nonce="%s",uri="sip:%s",response="%s",algorithm=MD5,cnonce="%s",qop=auth,nc=00000001`, + `Digest username="%s",realm="%s",nonce="%s",uri="sip:%s",response="%s",algorithm=MD5,cnonce="%s",qop=auth,nc=00000001`, // nolint sipInfo.Username, sipInfo.Domain, nonce, sipInfo.Domain, - generateResponse(sipInfo.Username, sipInfo.Password, sipInfo.Domain, method, "sip:"+sipInfo.Domain, nonce), "0e6758e1adfccffbd0ad9ffdde3ef655", + generateResponse(sipInfo.Username, sipInfo.Password, sipInfo.Domain, method, "sip:"+sipInfo.Domain, nonce), "0e6758e1adfccffbd0ad9ffdde3ef655", // nolint ) } func generateProxyAuthorization(sipInfo SIPInfoResponse, method, targetUser, nonce string) string { return fmt.Sprintf( - `Digest username="%s", realm="%s", nonce="%s", uri="sip:%s@%s", response="%s",algorithm=MD5,cnonce="%s",qop=auth,nc=00000001`, + `Digest username="%s", realm="%s", nonce="%s", uri="sip:%s@%s", response="%s",algorithm=MD5,cnonce="%s",qop=auth,nc=00000001`, // nolint sipInfo.AuthorizationID, sipInfo.Domain, nonce, targetUser, sipInfo.Domain, - generateResponse(sipInfo.AuthorizationID, sipInfo.Password, sipInfo.Domain, method, "sip:"+targetUser+"@"+sipInfo.Domain, nonce), "0e6758e1adfccffbd0ad9ffdde3ef655", + generateResponse(sipInfo.AuthorizationID, sipInfo.Password, sipInfo.Domain, method, "sip:"+targetUser+"@"+sipInfo.Domain, nonce), "0e6758e1adfccffbd0ad9ffdde3ef655", // nolint ) } diff --git a/sip-to-webrtc/main.go b/sip-to-webrtc/main.go index 1f683f7e..4a9e875d 100644 --- a/sip-to-webrtc/main.go +++ b/sip-to-webrtc/main.go @@ -35,7 +35,7 @@ var ( contentTypeHeaderSDP = sip.ContentTypeHeader("application/sdp") ) -func main() { +func main() { // nolint // Parse the flags passed to program flag.Parse() @@ -79,7 +79,7 @@ func main() { }) // Create a audio track - audioTrack, err = webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypePCMU}, "audio", "pion") + audioTrack, err = webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypePCMU}, "audio", "pion") // nolint if err != nil { panic(err) } @@ -242,10 +242,11 @@ func generateAnswer(offer []byte, unicastAddress string, rtpListenerPort int) [] if err != nil { panic(err) } + return answerByte } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -262,10 +263,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -275,7 +277,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/snapshot/main.go b/snapshot/main.go index 38dbcff1..77f64aac 100644 --- a/snapshot/main.go +++ b/snapshot/main.go @@ -24,11 +24,10 @@ import ( "golang.org/x/image/vp8" ) -// Channel for PeerConnection to push RTP Packets -// This is the read from HTTP Handler for generating jpeg +// This is the read from HTTP Handler for generating jpeg. var rtpChan chan *rtp.Packet // nolint:gochecknoglobals -func signaling(w http.ResponseWriter, r *http.Request) { +func signaling(w http.ResponseWriter, r *http.Request) { // nolint // Create a new PeerConnection peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{ ICEServers: []webrtc.ICEServer{ @@ -116,7 +115,7 @@ func signaling(w http.ResponseWriter, r *http.Request) { } } -func snapshot(w http.ResponseWriter, _ *http.Request) { +func snapshot(httpWriter http.ResponseWriter, _ *http.Request) { // Initialized with 20 maxLate, my samples sometimes 10-15 packets sampleBuilder := samplebuilder.New(20, &codecs.VP8Packet{}, 90000) decoder := vp8.NewDecoder() @@ -158,13 +157,14 @@ func snapshot(w http.ResponseWriter, _ *http.Request) { } // Serve image - w.Header().Set("Content-Type", "image/jpeg") - w.Header().Set("Content-Length", strconv.Itoa(len(buffer.Bytes()))) + httpWriter.Header().Set("Content-Type", "image/jpeg") + httpWriter.Header().Set("Content-Length", strconv.Itoa(len(buffer.Bytes()))) // Write jpeg as HTTP Response - if _, err = w.Write(buffer.Bytes()); err != nil { + if _, err = httpWriter.Write(buffer.Bytes()); err != nil { panic(err) } + return } } diff --git a/twitch/main.go b/twitch/main.go index d73ec34e..19101e59 100644 --- a/twitch/main.go +++ b/twitch/main.go @@ -35,7 +35,7 @@ var ( streamKey string ) -func main() { +func main() { // nolint if len(os.Args) != 2 { panic("example requires stream-key to be passed as an argument") } @@ -52,18 +52,18 @@ func main() { } // Create a MediaEngine object to configure the supported codec - m := &webrtc.MediaEngine{} + mediaEngine := &webrtc.MediaEngine{} // Setup the codecs you want to use. // Only support VP8 and OPUS, this makes our WebM muxer code simpler - if err := m.RegisterCodec(webrtc.RTPCodecParameters{ - RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, + if err := mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, PayloadType: 96, }, webrtc.RTPCodecTypeVideo); err != nil { panic(err) } - if err := m.RegisterCodec(webrtc.RTPCodecParameters{ - RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: "audio/opus", ClockRate: 48000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, + if err := mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}, PayloadType: 111, }, webrtc.RTPCodecTypeAudio); err != nil { panic(err) @@ -73,7 +73,7 @@ func main() { videoBuilder = samplebuilder.New(10, &codecs.VP8Packet{}, 90000) // Create the API object with the MediaEngine - api := webrtc.NewAPI(webrtc.WithMediaEngine(m)) + api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine)) // Create a new RTCPeerConnection peerConnection, err := api.NewPeerConnection(config) @@ -87,7 +87,9 @@ func main() { go func() { ticker := time.NewTicker(time.Second * 3) for range ticker.C { - rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(track.SSRC())}}) + rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{ + MediaSSRC: uint32(track.SSRC()), + }}) if rtcpSendErr != nil { fmt.Println(rtcpSendErr) } @@ -95,7 +97,7 @@ func main() { }() } - fmt.Printf("Track has started, of type %d: %s \n", track.PayloadType(), track.Codec().RTPCodecCapability.MimeType) + fmt.Printf("Track has started, of type %d: %s \n", track.PayloadType(), track.Codec().MimeType) for { // Read RTP packets being sent to Pion rtp, _, readErr := track.ReadRTP() @@ -185,8 +187,8 @@ func startFFmpeg(width, height int) { TrackType: 1, DefaultDuration: 33333333, Video: &webm.Video{ - PixelWidth: uint64(width), - PixelHeight: uint64(height), + PixelWidth: uint64(width), // nolint + PixelHeight: uint64(height), // nolint }, }, }) @@ -199,7 +201,7 @@ func startFFmpeg(width, height int) { videoWriter = ws[1] } -// Parse Opus audio and Write to WebM +// Parse Opus audio and Write to WebM. func pushOpus(rtpPacket *rtp.Packet) { audioBuilder.Push(rtpPacket) @@ -217,7 +219,7 @@ func pushOpus(rtpPacket *rtp.Packet) { } } -// Parse VP8 video and Write to WebM +// Parse VP8 video and Write to WebM. func pushVP8(rtpPacket *rtp.Packet) { videoBuilder.Push(rtpPacket) @@ -231,8 +233,8 @@ func pushVP8(rtpPacket *rtp.Packet) { if videoKeyframe { // Keyframe has frame information. raw := uint(sample.Data[6]) | uint(sample.Data[7])<<8 | uint(sample.Data[8])<<16 | uint(sample.Data[9])<<24 - width := int(raw & 0x3FFF) - height := int((raw >> 16) & 0x3FFF) + width := int(raw & 0x3FFF) // nolint + height := int((raw >> 16) & 0x3FFF) // nolint if videoWriter == nil || audioWriter == nil { // Initialize WebM saver using received frame size. @@ -248,7 +250,7 @@ func pushVP8(rtpPacket *rtp.Packet) { } } -// Read from stdin until we get a newline +// Read from stdin until we get a newline. func readUntilNewline() (in string) { var err error @@ -265,10 +267,11 @@ func readUntilNewline() (in string) { } fmt.Println("") + return } -// JSON encode + base64 a SessionDescription +// JSON encode + base64 a SessionDescription. func encode(obj *webrtc.SessionDescription) string { b, err := json.Marshal(obj) if err != nil { @@ -278,7 +281,7 @@ func encode(obj *webrtc.SessionDescription) string { return base64.StdEncoding.EncodeToString(b) } -// Decode a base64 and unmarshal JSON into a SessionDescription +// Decode a base64 and unmarshal JSON into a SessionDescription. func decode(in string, obj *webrtc.SessionDescription) { b, err := base64.StdEncoding.DecodeString(in) if err != nil { diff --git a/unreal-pixel-streaming/main.go b/unreal-pixel-streaming/main.go index 8fb70dae..3196be44 100644 --- a/unreal-pixel-streaming/main.go +++ b/unreal-pixel-streaming/main.go @@ -4,7 +4,8 @@ //go:build !js // +build !js -// unreal-pixel-streaming demonstrates how to connect to a Unreal Pixel Streaming instance and accept the inbound audio/video +// unreal-pixel-streaming demonstrates how to connect to a Unreal Pixel Streaming +// instance and accept the inbound audio/video package main import ( @@ -27,7 +28,7 @@ type websocketMessage struct { StreamerID string `json:"streamerId"` } -func main() { +func main() { // nolint url := flag.String("url", "ws://localhost/", "URL to UE5 Pixel Streaming WebSocket endpoint") origin := flag.String("origin", "http://localhost", "Origin that is passed in HTTP header") flag.Parse() @@ -66,7 +67,7 @@ func main() { case "offer": peerConnection = createPeerConnection(conn, peerConnectionConfig) - if err = peerConnection.SetRemoteDescription(webrtc.SessionDescription{Type: webrtc.SDPTypeOffer, SDP: jsonMessage.SDP}); err != nil { + if err = peerConnection.SetRemoteDescription(webrtc.SessionDescription{Type: webrtc.SDPTypeOffer, SDP: jsonMessage.SDP}); err != nil { // nolint panic(err) } @@ -90,7 +91,7 @@ func main() { fmt.Println("Player Count", jsonMessage.Count) case "streamerList": if len(jsonMessage.IDs) >= 1 { - if err = websocket.JSON.Send(conn, websocketMessage{Type: "subscribe", StreamerID: jsonMessage.IDs[0]}); err != nil { + if err = websocket.JSON.Send(conn, websocketMessage{Type: "subscribe", StreamerID: jsonMessage.IDs[0]}); err != nil { // nolint panic(err) } }