From bb37a5550c9418c300e31996430cea87caa3d271 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 23 Mar 2021 12:10:40 +0800 Subject: [PATCH 1/3] Test: Update srs-bench --- trunk/3rdparty/srs-bench/LICENSE | 2 +- trunk/3rdparty/srs-bench/README.md | 6 + trunk/3rdparty/srs-bench/auto/sync_vnet.sh | 33 + trunk/3rdparty/srs-bench/main.go | 2 +- trunk/3rdparty/srs-bench/srs/ingester.go | 11 +- trunk/3rdparty/srs-bench/srs/interceptor.go | 23 +- trunk/3rdparty/srs-bench/srs/player.go | 9 +- trunk/3rdparty/srs-bench/srs/publisher.go | 9 +- trunk/3rdparty/srs-bench/srs/rtc_test.go | 527 +++++++++---- trunk/3rdparty/srs-bench/srs/stat.go | 5 +- trunk/3rdparty/srs-bench/srs/util.go | 711 ++++++++++++++++- trunk/3rdparty/srs-bench/srs/util_test.go | 723 ------------------ .../srs-bench/vnet/example_udpproxy_test.go | 2 +- trunk/3rdparty/srs-bench/vnet/udpproxy.go | 199 +++-- .../srs-bench/vnet/udpproxy_direct.go | 2 +- .../srs-bench/vnet/udpproxy_direct_test.go | 2 +- .../3rdparty/srs-bench/vnet/udpproxy_test.go | 35 +- trunk/3rdparty/srs-bench/vnet/vnet.go | 38 + trunk/3rdparty/st-srs/.gitignore | 3 + 19 files changed, 1277 insertions(+), 1065 deletions(-) create mode 100755 trunk/3rdparty/srs-bench/auto/sync_vnet.sh delete mode 100644 trunk/3rdparty/srs-bench/srs/util_test.go create mode 100644 trunk/3rdparty/srs-bench/vnet/vnet.go diff --git a/trunk/3rdparty/srs-bench/LICENSE b/trunk/3rdparty/srs-bench/LICENSE index 77ba5769d..1cdf14566 100644 --- a/trunk/3rdparty/srs-bench/LICENSE +++ b/trunk/3rdparty/srs-bench/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2021 srs-bench(ossrs) +Copyright (c) 2021 Winlin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/trunk/3rdparty/srs-bench/README.md b/trunk/3rdparty/srs-bench/README.md index 415cb195f..6b903692c 100644 --- a/trunk/3rdparty/srs-bench/README.md +++ b/trunk/3rdparty/srs-bench/README.md @@ -142,6 +142,12 @@ go test ./srs -mod=vendor -v -srs-server=127.0.0.1 make && ./objs/srs_test -test.v -srs-server=127.0.0.1 ``` +可以只运行某个用例,并打印详细日志,比如: + +```bash +make && ./objs/srs_test -test.v -srs-log -test.run TestRtcBasic_PublishPlay +``` + 支持的参数如下: * `-srs-server`,RTC服务器地址。默认值:`127.0.0.1` diff --git a/trunk/3rdparty/srs-bench/auto/sync_vnet.sh b/trunk/3rdparty/srs-bench/auto/sync_vnet.sh new file mode 100755 index 000000000..55ef15f1a --- /dev/null +++ b/trunk/3rdparty/srs-bench/auto/sync_vnet.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +FILES=(udpproxy.go udpproxy_test.go) +for file in ${FILES[@]}; do + echo "cp vnet/udpproxy.go ~/git/transport/vnet/" && + cp vnet/udpproxy.go ~/git/transport/vnet/ +done + +# https://github.com/pion/webrtc/wiki/Contributing#run-all-automated-tests-and-checks-before-submitting +cd ~/git/transport/ + +echo ".github/lint-commit-message.sh" && +.github/lint-commit-message.sh && +echo ".github/assert-contributors.sh" && +.github/assert-contributors.sh && +echo ".github/lint-disallowed-functions-in-library.sh" && +.github/lint-disallowed-functions-in-library.sh && +echo ".github/lint-filename.sh" && +.github/lint-filename.sh +if [[ $? -ne 0 ]]; then echo "fail"; exit -1; fi + +# https://github.com/pion/webrtc/wiki/Contributing#run-all-automated-tests-and-checks-before-submitting +cd ~/git/transport/vnet/ + +echo "go test -race ./..." && +go test -race ./... +if [[ $? -ne 0 ]]; then echo "fail"; exit -1; fi + +echo "golangci-lint run --skip-files conn_map_test.go" && +golangci-lint run --skip-files conn_map_test.go +if [[ $? -ne 0 ]]; then echo "fail"; exit -1; fi + +echo "OK" diff --git a/trunk/3rdparty/srs-bench/main.go b/trunk/3rdparty/srs-bench/main.go index d56fa4995..8b83c4dcb 100644 --- a/trunk/3rdparty/srs-bench/main.go +++ b/trunk/3rdparty/srs-bench/main.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in diff --git a/trunk/3rdparty/srs-bench/srs/ingester.go b/trunk/3rdparty/srs-bench/srs/ingester.go index 1e3161a89..f38409e59 100644 --- a/trunk/3rdparty/srs-bench/srs/ingester.go +++ b/trunk/3rdparty/srs-bench/srs/ingester.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -22,6 +22,11 @@ package srs import ( "context" + "io" + "os" + "strings" + "time" + "github.com/ossrs/go-oryx-lib/errors" "github.com/ossrs/go-oryx-lib/logger" "github.com/pion/interceptor" @@ -31,10 +36,6 @@ import ( "github.com/pion/webrtc/v3/pkg/media" "github.com/pion/webrtc/v3/pkg/media/h264reader" "github.com/pion/webrtc/v3/pkg/media/oggreader" - "io" - "os" - "strings" - "time" ) type videoIngester struct { diff --git a/trunk/3rdparty/srs-bench/srs/interceptor.go b/trunk/3rdparty/srs-bench/srs/interceptor.go index d853aaf7d..9757b705c 100644 --- a/trunk/3rdparty/srs-bench/srs/interceptor.go +++ b/trunk/3rdparty/srs-bench/srs/interceptor.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -31,14 +31,13 @@ type RTPInterceptorOptionFunc func(i *RTPInterceptor) // Common RTP packet interceptor for benchmark. // @remark Should never merge with RTCPInterceptor, because they has the same Write interface. type RTPInterceptor struct { - localInfo *interceptor.StreamInfo - remoteInfo *interceptor.StreamInfo // If rtpReader is nil, use the default next one to read. rtpReader interceptor.RTPReaderFunc nextRTPReader interceptor.RTPReader // If rtpWriter is nil, use the default next one to write. rtpWriter interceptor.RTPWriterFunc nextRTPWriter interceptor.RTPWriter + // Other common fields. BypassInterceptor } @@ -51,11 +50,6 @@ func NewRTPInterceptor(options ...RTPInterceptorOptionFunc) *RTPInterceptor { } func (v *RTPInterceptor) BindLocalStream(info *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter { - if v.localInfo != nil { - return writer // Only handle one stream. - } - - v.localInfo = info v.nextRTPWriter = writer return v // Handle all RTP } @@ -68,17 +62,9 @@ func (v *RTPInterceptor) Write(header *rtp.Header, payload []byte, attributes in } func (v *RTPInterceptor) UnbindLocalStream(info *interceptor.StreamInfo) { - if v.localInfo == nil || v.localInfo.ID != info.ID { - return - } - v.localInfo = nil // Reset the interceptor. } func (v *RTPInterceptor) BindRemoteStream(info *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader { - if v.remoteInfo != nil { - return reader // Only handle one stream. - } - v.nextRTPReader = reader return v // Handle all RTP } @@ -91,10 +77,6 @@ func (v *RTPInterceptor) Read(b []byte, a interceptor.Attributes) (int, intercep } func (v *RTPInterceptor) UnbindRemoteStream(info *interceptor.StreamInfo) { - if v.remoteInfo == nil || v.remoteInfo.ID != info.ID { - return - } - v.remoteInfo = nil } type RTCPInterceptorOptionFunc func(i *RTCPInterceptor) @@ -108,6 +90,7 @@ type RTCPInterceptor struct { // If rtcpWriter is nil, use the default next one to write. rtcpWriter interceptor.RTCPWriterFunc nextRTCPWriter interceptor.RTCPWriter + // Other common fields. BypassInterceptor } diff --git a/trunk/3rdparty/srs-bench/srs/player.go b/trunk/3rdparty/srs-bench/srs/player.go index 0947ad41c..8dc91d030 100644 --- a/trunk/3rdparty/srs-bench/srs/player.go +++ b/trunk/3rdparty/srs-bench/srs/player.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -23,6 +23,10 @@ package srs import ( "context" "fmt" + "strings" + "sync" + "time" + "github.com/ossrs/go-oryx-lib/errors" "github.com/ossrs/go-oryx-lib/logger" "github.com/pion/interceptor" @@ -33,9 +37,6 @@ import ( "github.com/pion/webrtc/v3/pkg/media/h264writer" "github.com/pion/webrtc/v3/pkg/media/ivfwriter" "github.com/pion/webrtc/v3/pkg/media/oggwriter" - "strings" - "sync" - "time" ) // @see https://github.com/pion/webrtc/blob/master/examples/save-to-disk/main.go diff --git a/trunk/3rdparty/srs-bench/srs/publisher.go b/trunk/3rdparty/srs-bench/srs/publisher.go index 8d38fb055..49abab72a 100644 --- a/trunk/3rdparty/srs-bench/srs/publisher.go +++ b/trunk/3rdparty/srs-bench/srs/publisher.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -22,14 +22,15 @@ package srs import ( "context" + "io" + "sync" + "time" + "github.com/ossrs/go-oryx-lib/errors" "github.com/ossrs/go-oryx-lib/logger" "github.com/pion/interceptor" "github.com/pion/sdp/v3" "github.com/pion/webrtc/v3" - "io" - "sync" - "time" ) // @see https://github.com/pion/webrtc/blob/master/examples/play-from-disk/main.go diff --git a/trunk/3rdparty/srs-bench/srs/rtc_test.go b/trunk/3rdparty/srs-bench/srs/rtc_test.go index 4ac869c42..62ad26663 100644 --- a/trunk/3rdparty/srs-bench/srs/rtc_test.go +++ b/trunk/3rdparty/srs-bench/srs/rtc_test.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -23,19 +23,39 @@ package srs import ( "context" "fmt" - "github.com/ossrs/go-oryx-lib/errors" - "github.com/ossrs/go-oryx-lib/logger" - "github.com/pion/interceptor" - "github.com/pion/rtcp" - "github.com/pion/rtp" "github.com/pion/transport/vnet" + "io" + "io/ioutil" "math/rand" "os" "sync" "testing" "time" + + "github.com/ossrs/go-oryx-lib/errors" + "github.com/ossrs/go-oryx-lib/logger" + "github.com/pion/interceptor" + "github.com/pion/rtcp" + "github.com/pion/rtp" ) +func TestMain(m *testing.M) { + if err := prepareTest(); err != nil { + logger.Ef(nil, "Prepare test fail, err %+v", err) + os.Exit(-1) + } + + // Disable the logger during all tests. + if *srsLog == false { + olw := logger.Switch(ioutil.Discard) + defer func() { + logger.Switch(olw) + }() + } + + os.Exit(m.Run()) +} + // Basic use scenario, publish a stream, then play it. func TestRtcBasic_PublishPlay(t *testing.T) { ctx := logger.WithContext(context.Background()) @@ -50,12 +70,20 @@ func TestRtcBasic_PublishPlay(t *testing.T) { } }(ctx) + var resources []io.Closer + defer func() { + for _, resource := range resources { + resource.Close() + } + }() + var wg sync.WaitGroup defer wg.Wait() // The event notify. var thePublisher *TestPublisher var thePlayer *TestPlayer + mainReady, mainReadyCancel := context.WithCancel(context.Background()) publishReady, publishReadyCancel := context.WithCancel(context.Background()) @@ -66,76 +94,110 @@ func TestRtcBasic_PublishPlay(t *testing.T) { defer cancel() doInit := func() error { - playOK := *srsPlayOKPackets - vnetClientIP := *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - + playOK, vnetClientIP := *srsPlayOKPackets, *srsVnetClientIP streamSuffix := fmt.Sprintf("basic-publish-play-%v-%v", os.Getpid(), rand.Int()) - play := NewTestPlayer(api, func(play *TestPlayer) { + + // Initialize player with private api. + if play, err := NewTestPlayer(nil, func(play *TestPlayer) error { play.streamSuffix = streamSuffix - }) - defer play.Close() + resources = append(resources, play) - pub := NewTestPublisher(api, func(pub *TestPublisher) { - pub.streamSuffix = streamSuffix - pub.iceReadyCancel = publishReadyCancel - }) - defer pub.Close() + api, err := NewTestWebRTCAPI() + if err != nil { + return err + } + resources = append(resources, api) + play.api = api - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nnWriteRTP, nnReadRTP, nnWriteRTCP, nnReadRTCP int64 - api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { - i.rtpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - nn, attr, err := i.nextRTPReader.Read(buf, attributes) - nnReadRTP++ - return nn, attr, err - } - i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - nn, err := i.nextRTPWriter.Write(header, payload, attributes) - - nnWriteRTP++ - logger.Tf(ctx, "publish rtp=(read:%v write:%v), rtcp=(read:%v write:%v) packets", - nnReadRTP, nnWriteRTP, nnReadRTCP, nnWriteRTCP) - return nn, err - } - })) - api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { - i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - nn, attr, err := i.nextRTCPReader.Read(buf, attributes) - nnReadRTCP++ - return nn, attr, err - } - i.rtcpWriter = func(pkts []rtcp.Packet, attributes interceptor.Attributes) (int, error) { - nn, err := i.nextRTCPWriter.Write(pkts, attributes) - nnWriteRTCP++ - return nn, err - } - })) - }, func(api *TestWebRTCAPI) { - var nn uint64 - api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { - i.rtpReader = func(payload []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nn++; nn >= uint64(playOK) { - cancel() // Completed. + var nnPlayWriteRTCP, nnPlayReadRTCP, nnPlayWriteRTP, nnPlayReadRTP uint64 + if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { + i.rtpReader = func(payload []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnPlayReadRTP++; nnPlayReadRTP >= uint64(playOK) { + cancel() // Completed. + } + logger.Tf(ctx, "Play rtp=(recv:%v, send:%v), rtcp=(recv:%v send:%v) packets", + nnPlayReadRTP, nnPlayWriteRTP, nnPlayReadRTCP, nnPlayWriteRTCP) + return i.nextRTPReader.Read(payload, attributes) } - logger.Tf(ctx, "play got %v packets", nn) - return i.nextRTPReader.Read(payload, attributes) - } - })) + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + nn, attr, err := i.nextRTCPReader.Read(buf, attributes) + nnPlayReadRTCP++ + return nn, attr, err + } + i.rtcpWriter = func(pkts []rtcp.Packet, attributes interceptor.Attributes) (int, error) { + nn, err := i.nextRTCPWriter.Write(pkts, attributes) + nnPlayWriteRTCP++ + return nn, err + } + })) + }); err != nil { + return err + } + + return nil }); err != nil { return err + } else { + thePlayer = play } - // Set the available objects. + // Initialize publisher with private api. + if pub, err := NewTestPublisher(nil, func(pub *TestPublisher) error { + pub.streamSuffix = streamSuffix + pub.iceReadyCancel = publishReadyCancel + resources = append(resources, pub) + + api, err := NewTestWebRTCAPI() + if err != nil { + return err + } + resources = append(resources, api) + pub.api = api + + var nnPubWriteRTCP, nnPubReadRTCP, nnPubWriteRTP, nnPubReadRTP uint64 + if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { + i.rtpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + nn, attr, err := i.nextRTPReader.Read(buf, attributes) + nnPubReadRTP++ + return nn, attr, err + } + i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { + nn, err := i.nextRTPWriter.Write(header, payload, attributes) + nnPubWriteRTP++ + logger.Tf(ctx, "Publish rtp=(recv:%v, send:%v), rtcp=(recv:%v send:%v) packets", + nnPubReadRTP, nnPubWriteRTP, nnPubReadRTCP, nnPubWriteRTCP) + return nn, err + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + nn, attr, err := i.nextRTCPReader.Read(buf, attributes) + nnPubReadRTCP++ + return nn, attr, err + } + i.rtcpWriter = func(pkts []rtcp.Packet, attributes interceptor.Attributes) (int, error) { + nn, err := i.nextRTCPWriter.Write(pkts, attributes) + nnPubWriteRTCP++ + return nn, err + } + })) + }); err != nil { + return err + } + + return nil + }); err != nil { + return err + } else { + thePublisher = pub + } + + // Init done. mainReadyCancel() - thePublisher = pub - thePlayer = play <-ctx.Done() return nil @@ -158,17 +220,10 @@ func TestRtcBasic_PublishPlay(t *testing.T) { case <-mainReady.Done(): } - doPublish := func() error { - if err := thePublisher.Run(logger.WithContext(ctx), cancel); err != nil { - return err - } - - logger.Tf(ctx, "pub done") - return nil - } - if err := doPublish(); err != nil { + if err := thePublisher.Run(logger.WithContext(ctx), cancel); err != nil { r2 = err } + logger.Tf(ctx, "pub done") }() // Run player. @@ -177,30 +232,16 @@ func TestRtcBasic_PublishPlay(t *testing.T) { defer wg.Done() defer cancel() - select { - case <-ctx.Done(): - return - case <-mainReady.Done(): - } - select { case <-ctx.Done(): return case <-publishReady.Done(): } - doPlay := func() error { - if err := thePlayer.Run(logger.WithContext(ctx), cancel); err != nil { - return err - } - - logger.Tf(ctx, "play done") - return nil - } - if err := doPlay(); err != nil { + if err := thePlayer.Run(logger.WithContext(ctx), cancel); err != nil { r3 = err } - + logger.Tf(ctx, "play done") }() } @@ -222,21 +263,31 @@ func TestRtcDTLS_ClientActive_Default(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -276,21 +327,31 @@ func TestRtcDTLS_ClientPassive_Default(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -327,21 +388,31 @@ func TestRtcDTLS_ClientActive_Duplicated_Alert(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -385,21 +456,31 @@ func TestRtcDTLS_ClientPassive_Duplicated_Alert(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -450,21 +531,31 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T defer api.Close() streamSuffix := fmt.Sprintf("dtls-active-arq-client-hello-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -527,21 +618,31 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ClientHello(t *testing. defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-arq-client-hello-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -603,21 +704,31 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T defer api.Close() streamSuffix := fmt.Sprintf("dtls-active-arq-client-hello-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -690,21 +801,31 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ServerHello(t *testing. defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-arq-client-hello-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -774,21 +895,31 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_Certificate(t *testing.T defer api.Close() streamSuffix := fmt.Sprintf("dtls-active-arq-certificate-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -850,21 +981,31 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_Certificate(t *testing. defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-arq-certificate-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -926,21 +1067,31 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *test defer api.Close() streamSuffix := fmt.Sprintf("dtls-active-arq-certificate-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -1011,21 +1162,31 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *tes defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-arq-certificate-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -1087,10 +1248,14 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ClientHello(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { @@ -1145,10 +1310,14 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ServerHello(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { @@ -1203,10 +1372,14 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_Certificate(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { @@ -1261,10 +1434,14 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ChangeCipherSpec(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { @@ -1320,21 +1497,31 @@ func TestRtcDTLS_ClientPassive_ARQ_VeryBadNetwork(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { @@ -1397,21 +1584,31 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_After_ClientHello(t *testing.T) { defer api.Close() streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p := NewTestPublisher(api, func(p *TestPublisher) { + p, err := NewTestPublisher(api, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive + return nil }) + if err != nil { + return err + } defer p.Close() if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { - var nn int64 + var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { - if nn++; nn >= int64(publishOK) { + nnRTP++ + return i.nextRTPWriter.Write(header, payload, attributes) + } + })) + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { cancel() // Send enough packets, done. } - logger.Tf(ctx, "publish write %v packets", nn) - return i.nextRTPWriter.Write(header, payload, attributes) + logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) + return i.nextRTCPReader.Read(buf, attributes) } })) }, func(api *TestWebRTCAPI) { diff --git a/trunk/3rdparty/srs-bench/srs/stat.go b/trunk/3rdparty/srs-bench/srs/stat.go index 3ca7ed79a..ef83fe78d 100644 --- a/trunk/3rdparty/srs-bench/srs/stat.go +++ b/trunk/3rdparty/srs-bench/srs/stat.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -23,9 +23,10 @@ package srs import ( "context" "encoding/json" - "github.com/ossrs/go-oryx-lib/logger" "net/http" "strings" + + "github.com/ossrs/go-oryx-lib/logger" ) type statRTC struct { diff --git a/trunk/3rdparty/srs-bench/srs/util.go b/trunk/3rdparty/srs-bench/srs/util.go index 8c5a5434d..941b0bb76 100644 --- a/trunk/3rdparty/srs-bench/srs/util.go +++ b/trunk/3rdparty/srs-bench/srs/util.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -24,21 +24,113 @@ import ( "bytes" "context" "encoding/json" + "flag" "fmt" - "github.com/ossrs/go-oryx-lib/errors" - "github.com/ossrs/go-oryx-lib/logger" - "github.com/pion/transport/vnet" - "github.com/pion/webrtc/v3" - "github.com/pion/webrtc/v3/pkg/media/h264reader" + "io" "io/ioutil" "net" "net/http" "net/url" + "os" + "path" "strconv" "strings" + "sync" + "testing" "time" + + "github.com/ossrs/go-oryx-lib/errors" + "github.com/ossrs/go-oryx-lib/logger" + vnet_proxy "github.com/ossrs/srs-bench/vnet" + "github.com/pion/interceptor" + "github.com/pion/logging" + "github.com/pion/rtcp" + "github.com/pion/transport/vnet" + "github.com/pion/webrtc/v3" + "github.com/pion/webrtc/v3/pkg/media/h264reader" ) +var srsHttps *bool +var srsLog *bool + +var srsTimeout *int +var srsPlayPLI *int +var srsPlayOKPackets *int +var srsPublishOKPackets *int +var srsPublishVideoFps *int +var srsDTLSDropPackets *int + +var srsSchema string +var srsServer *string +var srsStream *string +var srsPublishAudio *string +var srsPublishVideo *string +var srsVnetClientIP *string + +func prepareTest() error { + var err error + + srsHttps = flag.Bool("srs-https", false, "Whther connect to HTTPS-API") + srsServer = flag.String("srs-server", "127.0.0.1", "The RTC server to connect to") + srsStream = flag.String("srs-stream", "/rtc/regression", "The RTC stream to play") + srsLog = flag.Bool("srs-log", false, "Whether enable the detail log") + srsTimeout = flag.Int("srs-timeout", 5000, "For each case, the timeout in ms") + srsPlayPLI = flag.Int("srs-play-pli", 5000, "The PLI interval in seconds for player.") + srsPlayOKPackets = flag.Int("srs-play-ok-packets", 10, "If recv N RTP packets, it's ok, or fail") + srsPublishOKPackets = flag.Int("srs-publish-ok-packets", 3, "If send N RTP, recv N RTCP packets, it's ok, or fail") + srsPublishAudio = flag.String("srs-publish-audio", "avatar.ogg", "The audio file for publisher.") + srsPublishVideo = flag.String("srs-publish-video", "avatar.h264", "The video file for publisher.") + srsPublishVideoFps = flag.Int("srs-publish-video-fps", 25, "The video fps for publisher.") + srsVnetClientIP = flag.String("srs-vnet-client-ip", "192.168.168.168", "The client ip in pion/vnet.") + srsDTLSDropPackets = flag.Int("srs-dtls-drop-packets", 5, "If dropped N packets, it's ok, or fail") + + // Should parse it first. + flag.Parse() + + // The stream should starts with /, for example, /rtc/regression + if !strings.HasPrefix(*srsStream, "/") { + *srsStream = "/" + *srsStream + } + + // Generate srs protocol from whether use HTTPS. + srsSchema = "http" + if *srsHttps { + srsSchema = "https" + } + + // Check file. + tryOpenFile := func(filename string) (string, error) { + if filename == "" { + return filename, nil + } + + f, err := os.Open(filename) + if err != nil { + nfilename := path.Join("../", filename) + f2, err := os.Open(nfilename) + if err != nil { + return filename, errors.Wrapf(err, "No video file at %v or %v", filename, nfilename) + } + defer f2.Close() + + return nfilename, nil + } + defer f.Close() + + return filename, nil + } + + if *srsPublishVideo, err = tryOpenFile(*srsPublishVideo); err != nil { + return err + } + + if *srsPublishAudio, err = tryOpenFile(*srsPublishAudio); err != nil { + return err + } + + return nil +} + func apiRtcRequest(ctx context.Context, apiPath, r, offer string) (string, error) { u, err := url.Parse(r) if err != nil { @@ -367,7 +459,11 @@ type ChunkMessageType struct { func (v *ChunkMessageType) String() string { if v.chunk == ChunkTypeDTLS { - return fmt.Sprintf("%v-%v-%v", v.chunk, v.content, v.handshake) + if v.content == DTLSContentTypeHandshake { + return fmt.Sprintf("%v-%v-%v", v.chunk, v.content, v.handshake) + } else { + return fmt.Sprintf("%v-%v", v.chunk, v.content) + } } return fmt.Sprintf("%v", v.chunk) } @@ -466,3 +562,604 @@ func (v *DTLSRecord) Unmarshal(b []byte) error { v.Data = b[13:] return nil } + +type TestWebRTCAPIOptionFunc func(api *TestWebRTCAPI) + +type TestWebRTCAPI struct { + // The options to setup the api. + options []TestWebRTCAPIOptionFunc + // The api and settings. + api *webrtc.API + mediaEngine *webrtc.MediaEngine + registry *interceptor.Registry + settingEngine *webrtc.SettingEngine + // The vnet router, can be shared by different apis, but we do not share it. + router *vnet.Router + // The network for api. + network *vnet.Net + // The vnet UDP proxy bind to the router. + proxy *vnet_proxy.UDPProxy +} + +func NewTestWebRTCAPI(options ...TestWebRTCAPIOptionFunc) (*TestWebRTCAPI, error) { + v := &TestWebRTCAPI{} + + v.mediaEngine = &webrtc.MediaEngine{} + if err := v.mediaEngine.RegisterDefaultCodecs(); err != nil { + return nil, err + } + + v.registry = &interceptor.Registry{} + if err := webrtc.RegisterDefaultInterceptors(v.mediaEngine, v.registry); err != nil { + return nil, err + } + + for _, setup := range options { + setup(v) + } + + v.settingEngine = &webrtc.SettingEngine{} + + return v, nil +} + +func (v *TestWebRTCAPI) Close() error { + if v.proxy != nil { + v.proxy.Close() + } + + if v.router != nil { + v.router.Stop() + } + + return nil +} + +func (v *TestWebRTCAPI) Setup(vnetClientIP string, options ...TestWebRTCAPIOptionFunc) error { + // Setting engine for https://github.com/pion/transport/tree/master/vnet + setupVnet := func(vnetClientIP string) (err error) { + // We create a private router for a api, however, it's possible to share the + // same router between apis. + if v.router, err = vnet.NewRouter(&vnet.RouterConfig{ + CIDR: "0.0.0.0/0", // Accept all ip, no sub router. + LoggerFactory: logging.NewDefaultLoggerFactory(), + }); err != nil { + return errors.Wrapf(err, "create router for api") + } + + // Each api should bind to a network, however, it's possible to share it + // for different apis. + v.network = vnet.NewNet(&vnet.NetConfig{ + StaticIP: vnetClientIP, + }) + + if err = v.router.AddNet(v.network); err != nil { + return errors.Wrapf(err, "create network for api") + } + + v.settingEngine.SetVNet(v.network) + + // Create a proxy bind to the router. + if v.proxy, err = vnet_proxy.NewProxy(v.router); err != nil { + return errors.Wrapf(err, "create proxy for router") + } + + return v.router.Start() + } + if err := setupVnet(vnetClientIP); err != nil { + return err + } + + for _, setup := range options { + setup(v) + } + + for _, setup := range v.options { + setup(v) + } + + v.api = webrtc.NewAPI( + webrtc.WithMediaEngine(v.mediaEngine), + webrtc.WithInterceptorRegistry(v.registry), + webrtc.WithSettingEngine(*v.settingEngine), + ) + + return nil +} + +func (v *TestWebRTCAPI) NewPeerConnection(configuration webrtc.Configuration) (*webrtc.PeerConnection, error) { + return v.api.NewPeerConnection(configuration) +} + +type TestPlayerOptionFunc func(p *TestPlayer) error + +type TestPlayer struct { + pc *webrtc.PeerConnection + receivers []*webrtc.RTPReceiver + // root api object + api *TestWebRTCAPI + // Optional suffix for stream url. + streamSuffix string +} + +func NewTestPlayer(api *TestWebRTCAPI, options ...TestPlayerOptionFunc) (*TestPlayer, error) { + v := &TestPlayer{api: api} + + for _, opt := range options { + if err := opt(v); err != nil { + return nil, err + } + } + + // The api might be override by options. + api = v.api + + return v, nil +} + +func (v *TestPlayer) Close() error { + if v.pc != nil { + v.pc.Close() + } + + for _, receiver := range v.receivers { + receiver.Stop() + } + + return nil +} + +func (v *TestPlayer) Run(ctx context.Context, cancel context.CancelFunc) error { + r := fmt.Sprintf("%v://%v%v", srsSchema, *srsServer, *srsStream) + if v.streamSuffix != "" { + r = fmt.Sprintf("%v-%v", r, v.streamSuffix) + } + pli := time.Duration(*srsPlayPLI) * time.Millisecond + logger.Tf(ctx, "Start play url=%v", r) + + pc, err := v.api.NewPeerConnection(webrtc.Configuration{}) + if err != nil { + return errors.Wrapf(err, "Create PC") + } + v.pc = pc + + pc.AddTransceiverFromKind(webrtc.RTPCodecTypeAudio, webrtc.RTPTransceiverInit{ + Direction: webrtc.RTPTransceiverDirectionRecvonly, + }) + pc.AddTransceiverFromKind(webrtc.RTPCodecTypeVideo, webrtc.RTPTransceiverInit{ + Direction: webrtc.RTPTransceiverDirectionRecvonly, + }) + + offer, err := pc.CreateOffer(nil) + if err != nil { + return errors.Wrapf(err, "Create Offer") + } + + if err := pc.SetLocalDescription(offer); err != nil { + return errors.Wrapf(err, "Set offer %v", offer) + } + + answer, err := apiRtcRequest(ctx, "/rtc/v1/play", r, offer.SDP) + if err != nil { + return errors.Wrapf(err, "Api request offer=%v", offer.SDP) + } + + // Start a proxy for real server and vnet. + if address, err := parseAddressOfCandidate(answer); err != nil { + return errors.Wrapf(err, "parse address of %v", answer) + } else if err := v.api.proxy.Proxy(v.api.network, address); err != nil { + return errors.Wrapf(err, "proxy %v to %v", v.api.network, address) + } + + if err := pc.SetRemoteDescription(webrtc.SessionDescription{ + Type: webrtc.SDPTypeAnswer, SDP: answer, + }); err != nil { + return errors.Wrapf(err, "Set answer %v", answer) + } + + handleTrack := func(ctx context.Context, track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) error { + // Send a PLI on an interval so that the publisher is pushing a keyframe + go func() { + if track.Kind() == webrtc.RTPCodecTypeAudio { + return + } + + for { + select { + case <-ctx.Done(): + return + case <-time.After(pli): + _ = pc.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{ + MediaSSRC: uint32(track.SSRC()), + }}) + } + } + }() + + v.receivers = append(v.receivers, receiver) + + for ctx.Err() == nil { + _, _, err := track.ReadRTP() + if err != nil { + return errors.Wrapf(err, "Read RTP") + } + } + + return nil + } + + pc.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) { + err = handleTrack(ctx, track, receiver) + if err != nil { + codec := track.Codec() + err = errors.Wrapf(err, "Handle track %v, pt=%v", codec.MimeType, codec.PayloadType) + cancel() + } + }) + + pc.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) { + if state == webrtc.ICEConnectionStateFailed || state == webrtc.ICEConnectionStateClosed { + err = errors.Errorf("Close for ICE state %v", state) + cancel() + } + }) + + <-ctx.Done() + return err +} + +type TestPublisherOptionFunc func(p *TestPublisher) error + +type TestPublisher struct { + onOffer func(s *webrtc.SessionDescription) error + onAnswer func(s *webrtc.SessionDescription) error + iceReadyCancel context.CancelFunc + // internal objects + aIngester *audioIngester + vIngester *videoIngester + pc *webrtc.PeerConnection + // root api object + api *TestWebRTCAPI + // Optional suffix for stream url. + streamSuffix string +} + +func NewTestPublisher(api *TestWebRTCAPI, options ...TestPublisherOptionFunc) (*TestPublisher, error) { + sourceVideo, sourceAudio := *srsPublishVideo, *srsPublishAudio + + v := &TestPublisher{api: api} + + for _, opt := range options { + if err := opt(v); err != nil { + return nil, err + } + } + + // The api might be override by options. + api = v.api + + // Create ingesters. + if sourceAudio != "" { + v.aIngester = NewAudioIngester(sourceAudio) + } + if sourceVideo != "" { + v.vIngester = NewVideoIngester(sourceVideo) + } + + // Setup the interceptors for packets. + api.options = append(api.options, func(api *TestWebRTCAPI) { + // Filter for RTCP packets. + rtcpInterceptor := &RTCPInterceptor{} + rtcpInterceptor.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + return rtcpInterceptor.nextRTCPReader.Read(buf, attributes) + } + rtcpInterceptor.rtcpWriter = func(pkts []rtcp.Packet, attributes interceptor.Attributes) (int, error) { + return rtcpInterceptor.nextRTCPWriter.Write(pkts, attributes) + } + api.registry.Add(rtcpInterceptor) + + // Filter for ingesters. + if sourceAudio != "" { + api.registry.Add(v.aIngester.audioLevelInterceptor) + } + if sourceVideo != "" { + api.registry.Add(v.vIngester.markerInterceptor) + } + }) + + return v, nil +} + +func (v *TestPublisher) Close() error { + if v.vIngester != nil { + v.vIngester.Close() + } + + if v.aIngester != nil { + v.aIngester.Close() + } + + if v.pc != nil { + v.pc.Close() + } + + return nil +} + +func (v *TestPublisher) SetStreamSuffix(suffix string) *TestPublisher { + v.streamSuffix = suffix + return v +} + +func (v *TestPublisher) Run(ctx context.Context, cancel context.CancelFunc) error { + r := fmt.Sprintf("%v://%v%v", srsSchema, *srsServer, *srsStream) + if v.streamSuffix != "" { + r = fmt.Sprintf("%v-%v", r, v.streamSuffix) + } + sourceVideo, sourceAudio, fps := *srsPublishVideo, *srsPublishAudio, *srsPublishVideoFps + + logger.Tf(ctx, "Start publish url=%v, audio=%v, video=%v, fps=%v", + r, sourceAudio, sourceVideo, fps) + + pc, err := v.api.NewPeerConnection(webrtc.Configuration{}) + if err != nil { + return errors.Wrapf(err, "Create PC") + } + v.pc = pc + + if v.vIngester != nil { + if err := v.vIngester.AddTrack(pc, fps); err != nil { + return errors.Wrapf(err, "Add track") + } + } + + if v.aIngester != nil { + if err := v.aIngester.AddTrack(pc); err != nil { + return errors.Wrapf(err, "Add track") + } + } + + offer, err := pc.CreateOffer(nil) + if err != nil { + return errors.Wrapf(err, "Create Offer") + } + + if err := pc.SetLocalDescription(offer); err != nil { + return errors.Wrapf(err, "Set offer %v", offer) + } + + if v.onOffer != nil { + if err := v.onOffer(&offer); err != nil { + return errors.Wrapf(err, "sdp %v %v", offer.Type, offer.SDP) + } + } + + answerSDP, err := apiRtcRequest(ctx, "/rtc/v1/publish", r, offer.SDP) + if err != nil { + return errors.Wrapf(err, "Api request offer=%v", offer.SDP) + } + + // Start a proxy for real server and vnet. + if address, err := parseAddressOfCandidate(answerSDP); err != nil { + return errors.Wrapf(err, "parse address of %v", answerSDP) + } else if err := v.api.proxy.Proxy(v.api.network, address); err != nil { + return errors.Wrapf(err, "proxy %v to %v", v.api.network, address) + } + + answer := &webrtc.SessionDescription{ + Type: webrtc.SDPTypeAnswer, SDP: answerSDP, + } + if v.onAnswer != nil { + if err := v.onAnswer(answer); err != nil { + return errors.Wrapf(err, "on answerSDP") + } + } + + if err := pc.SetRemoteDescription(*answer); err != nil { + return errors.Wrapf(err, "Set answerSDP %v", answerSDP) + } + + logger.Tf(ctx, "State signaling=%v, ice=%v, conn=%v", pc.SignalingState(), pc.ICEConnectionState(), pc.ConnectionState()) + + // ICE state management. + pc.OnICEGatheringStateChange(func(state webrtc.ICEGathererState) { + logger.Tf(ctx, "ICE gather state %v", state) + }) + pc.OnICECandidate(func(candidate *webrtc.ICECandidate) { + logger.Tf(ctx, "ICE candidate %v %v:%v", candidate.Protocol, candidate.Address, candidate.Port) + + }) + pc.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) { + logger.Tf(ctx, "ICE state %v", state) + }) + + pc.OnSignalingStateChange(func(state webrtc.SignalingState) { + logger.Tf(ctx, "Signaling state %v", state) + }) + + if v.aIngester != nil { + v.aIngester.sAudioSender.Transport().OnStateChange(func(state webrtc.DTLSTransportState) { + logger.Tf(ctx, "DTLS state %v", state) + }) + } + + pcDone, pcDoneCancel := context.WithCancel(context.Background()) + pc.OnConnectionStateChange(func(state webrtc.PeerConnectionState) { + logger.Tf(ctx, "PC state %v", state) + + if state == webrtc.PeerConnectionStateConnected { + pcDoneCancel() + if v.iceReadyCancel != nil { + v.iceReadyCancel() + } + } + + if state == webrtc.PeerConnectionStateFailed || state == webrtc.PeerConnectionStateClosed { + err = errors.Errorf("Close for PC state %v", state) + cancel() + } + }) + + // Wait for event from context or tracks. + var wg sync.WaitGroup + var finalErr error + + wg.Add(1) + go func() { + defer wg.Done() + defer logger.Tf(ctx, "ingest notify done") + + <-ctx.Done() + + if v.aIngester != nil && v.aIngester.sAudioSender != nil { + v.aIngester.sAudioSender.Stop() + } + + if v.vIngester != nil && v.vIngester.sVideoSender != nil { + v.vIngester.sVideoSender.Stop() + } + }() + + wg.Add(1) + go func() { + defer wg.Done() + defer cancel() + + if v.aIngester == nil { + return + } + + select { + case <-ctx.Done(): + return + case <-pcDone.Done(): + } + + wg.Add(1) + go func() { + defer wg.Done() + defer logger.Tf(ctx, "aingester sender read done") + + buf := make([]byte, 1500) + for ctx.Err() == nil { + if _, _, err := v.aIngester.sAudioSender.Read(buf); err != nil { + return + } + } + }() + + for { + if err := v.aIngester.Ingest(ctx); err != nil { + if err == io.EOF { + logger.Tf(ctx, "aingester retry for %v", err) + continue + } + if err != context.Canceled { + finalErr = errors.Wrapf(err, "audio") + } + + logger.Tf(ctx, "aingester err=%v, final=%v", err, finalErr) + return + } + } + }() + + wg.Add(1) + go func() { + defer wg.Done() + defer cancel() + + if v.vIngester == nil { + return + } + + select { + case <-ctx.Done(): + return + case <-pcDone.Done(): + logger.Tf(ctx, "PC(ICE+DTLS+SRTP) done, start ingest video %v", sourceVideo) + } + + wg.Add(1) + go func() { + defer wg.Done() + defer logger.Tf(ctx, "vingester sender read done") + + buf := make([]byte, 1500) + for ctx.Err() == nil { + // The Read() might block in r.rtcpInterceptor.Read(b, a), + // so that the Stop() can not stop it. + if _, _, err := v.vIngester.sVideoSender.Read(buf); err != nil { + return + } + } + }() + + for { + if err := v.vIngester.Ingest(ctx); err != nil { + if err == io.EOF { + logger.Tf(ctx, "vingester retry for %v", err) + continue + } + if err != context.Canceled { + finalErr = errors.Wrapf(err, "video") + } + + logger.Tf(ctx, "vingester err=%v, final=%v", err, finalErr) + return + } + } + }() + + wg.Wait() + + logger.Tf(ctx, "ingester done ctx=%v, final=%v", ctx.Err(), finalErr) + if finalErr != nil { + return finalErr + } + return ctx.Err() +} + +func TestRTCServerVersion(t *testing.T) { + api := fmt.Sprintf("http://%v:1985/api/v1/versions", *srsServer) + req, err := http.NewRequest("POST", api, nil) + if err != nil { + t.Errorf("Request %v", api) + return + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("Do request %v", api) + return + } + + b, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Errorf("Read body of %v", api) + return + } + + obj := struct { + Code int `json:"code"` + Server string `json:"server"` + Data struct { + Major int `json:"major"` + Minor int `json:"minor"` + Revision int `json:"revision"` + Version string `json:"version"` + } `json:"data"` + }{} + if err := json.Unmarshal(b, &obj); err != nil { + t.Errorf("Parse %v", string(b)) + return + } + if obj.Code != 0 { + t.Errorf("Server err code=%v, server=%v", obj.Code, obj.Server) + return + } + if obj.Data.Major == 0 && obj.Data.Minor == 0 { + t.Errorf("Invalid version %v", obj.Data) + return + } +} diff --git a/trunk/3rdparty/srs-bench/srs/util_test.go b/trunk/3rdparty/srs-bench/srs/util_test.go deleted file mode 100644 index 68187c9ef..000000000 --- a/trunk/3rdparty/srs-bench/srs/util_test.go +++ /dev/null @@ -1,723 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2021 srs-bench(ossrs) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -package srs - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "github.com/ossrs/go-oryx-lib/errors" - "github.com/ossrs/go-oryx-lib/logger" - vnet_proxy "github.com/ossrs/srs-bench/vnet" - "github.com/pion/interceptor" - "github.com/pion/logging" - "github.com/pion/rtcp" - "github.com/pion/transport/vnet" - "github.com/pion/webrtc/v3" - "io" - "io/ioutil" - "net/http" - "os" - "path" - "strings" - "sync" - "testing" - "time" -) - -var srsSchema = "http" -var srsHttps = flag.Bool("srs-https", false, "Whther connect to HTTPS-API") -var srsServer = flag.String("srs-server", "127.0.0.1", "The RTC server to connect to") -var srsStream = flag.String("srs-stream", "/rtc/regression", "The RTC stream to play") -var srsLog = flag.Bool("srs-log", false, "Whether enable the detail log") -var srsTimeout = flag.Int("srs-timeout", 5000, "For each case, the timeout in ms") -var srsPlayPLI = flag.Int("srs-play-pli", 5000, "The PLI interval in seconds for player.") -var srsPlayOKPackets = flag.Int("srs-play-ok-packets", 10, "If got N packets, it's ok, or fail") -var srsPublishOKPackets = flag.Int("srs-publish-ok-packets", 10, "If send N packets, it's ok, or fail") -var srsPublishAudio = flag.String("srs-publish-audio", "avatar.ogg", "The audio file for publisher.") -var srsPublishVideo = flag.String("srs-publish-video", "avatar.h264", "The video file for publisher.") -var srsPublishVideoFps = flag.Int("srs-publish-video-fps", 25, "The video fps for publisher.") -var srsVnetClientIP = flag.String("srs-vnet-client-ip", "192.168.168.168", "The client ip in pion/vnet.") -var srsDTLSDropPackets = flag.Int("srs-dtls-drop-packets", 5, "If dropped N packets, it's ok, or fail") - -func prepareTest() error { - var err error - - // Should parse it first. - flag.Parse() - - // The stream should starts with /, for example, /rtc/regression - if !strings.HasPrefix(*srsStream, "/") { - *srsStream = "/" + *srsStream - } - - // Generate srs protocol from whether use HTTPS. - if *srsHttps { - srsSchema = "https" - } - - // Check file. - tryOpenFile := func(filename string) (string, error) { - if filename == "" { - return filename, nil - } - - f, err := os.Open(filename) - if err != nil { - nfilename := path.Join("../", filename) - f2, err := os.Open(nfilename) - if err != nil { - return filename, errors.Wrapf(err, "No video file at %v or %v", filename, nfilename) - } - defer f2.Close() - - return nfilename, nil - } - defer f.Close() - - return filename, nil - } - - if *srsPublishVideo, err = tryOpenFile(*srsPublishVideo); err != nil { - return err - } - - if *srsPublishAudio, err = tryOpenFile(*srsPublishAudio); err != nil { - return err - } - - return nil -} - -func TestMain(m *testing.M) { - if err := prepareTest(); err != nil { - logger.Ef(nil, "Prepare test fail, err %+v", err) - os.Exit(-1) - } - - // Disable the logger during all tests. - if *srsLog == false { - olw := logger.Switch(ioutil.Discard) - defer func() { - logger.Switch(olw) - }() - } - - os.Exit(m.Run()) -} - -type TestWebRTCAPIOptionFunc func(api *TestWebRTCAPI) - -type TestWebRTCAPI struct { - // The options to setup the api. - options []TestWebRTCAPIOptionFunc - // The api and settings. - api *webrtc.API - mediaEngine *webrtc.MediaEngine - registry *interceptor.Registry - settingEngine *webrtc.SettingEngine - // The vnet router, can be shared by different apis, but we do not share it. - router *vnet.Router - // The network for api. - network *vnet.Net - // The vnet UDP proxy bind to the router. - proxy *vnet_proxy.UDPProxy -} - -func NewTestWebRTCAPI(options ...TestWebRTCAPIOptionFunc) (*TestWebRTCAPI, error) { - v := &TestWebRTCAPI{} - - v.mediaEngine = &webrtc.MediaEngine{} - if err := v.mediaEngine.RegisterDefaultCodecs(); err != nil { - return nil, err - } - - v.registry = &interceptor.Registry{} - if err := webrtc.RegisterDefaultInterceptors(v.mediaEngine, v.registry); err != nil { - return nil, err - } - - for _, setup := range options { - setup(v) - } - - v.settingEngine = &webrtc.SettingEngine{} - - return v, nil -} - -func (v *TestWebRTCAPI) Close() error { - if v.proxy != nil { - v.proxy.Close() - v.proxy = nil - } - - if v.router != nil { - v.router.Stop() - v.router = nil - } - - return nil -} - -func (v *TestWebRTCAPI) Setup(vnetClientIP string, options ...TestWebRTCAPIOptionFunc) error { - // Setting engine for https://github.com/pion/transport/tree/master/vnet - setupVnet := func(vnetClientIP string) (err error) { - // We create a private router for a api, however, it's possible to share the - // same router between apis. - if v.router, err = vnet.NewRouter(&vnet.RouterConfig{ - CIDR: "0.0.0.0/0", // Accept all ip, no sub router. - LoggerFactory: logging.NewDefaultLoggerFactory(), - }); err != nil { - return errors.Wrapf(err, "create router for api") - } - - // Each api should bind to a network, however, it's possible to share it - // for different apis. - v.network = vnet.NewNet(&vnet.NetConfig{ - StaticIP: vnetClientIP, - }) - - if err = v.router.AddNet(v.network); err != nil { - return errors.Wrapf(err, "create network for api") - } - - v.settingEngine.SetVNet(v.network) - - // Create a proxy bind to the router. - if v.proxy, err = vnet_proxy.NewProxy(v.router); err != nil { - return errors.Wrapf(err, "create proxy for router") - } - - return v.router.Start() - } - if err := setupVnet(vnetClientIP); err != nil { - return err - } - - for _, setup := range options { - setup(v) - } - - for _, setup := range v.options { - setup(v) - } - - v.api = webrtc.NewAPI( - webrtc.WithMediaEngine(v.mediaEngine), - webrtc.WithInterceptorRegistry(v.registry), - webrtc.WithSettingEngine(*v.settingEngine), - ) - - return nil -} - -func (v *TestWebRTCAPI) NewPeerConnection(configuration webrtc.Configuration) (*webrtc.PeerConnection, error) { - return v.api.NewPeerConnection(configuration) -} - -type TestPlayerOptionFunc func(p *TestPlayer) - -type TestPlayer struct { - pc *webrtc.PeerConnection - receivers []*webrtc.RTPReceiver - // root api object - api *TestWebRTCAPI - // Optional suffix for stream url. - streamSuffix string -} - -func NewTestPlayer(api *TestWebRTCAPI, options ...TestPlayerOptionFunc) *TestPlayer { - v := &TestPlayer{api: api} - - for _, opt := range options { - opt(v) - } - - return v -} - -func (v *TestPlayer) Close() error { - if v.pc != nil { - v.pc.Close() - v.pc = nil - } - - for _, receiver := range v.receivers { - receiver.Stop() - } - v.receivers = nil - - return nil -} - -func (v *TestPlayer) Run(ctx context.Context, cancel context.CancelFunc) error { - r := fmt.Sprintf("%v://%v%v", srsSchema, *srsServer, *srsStream) - if v.streamSuffix != "" { - r = fmt.Sprintf("%v-%v", r, v.streamSuffix) - } - pli := time.Duration(*srsPlayPLI) * time.Millisecond - logger.Tf(ctx, "Start play url=%v", r) - - pc, err := v.api.NewPeerConnection(webrtc.Configuration{}) - if err != nil { - return errors.Wrapf(err, "Create PC") - } - v.pc = pc - - pc.AddTransceiverFromKind(webrtc.RTPCodecTypeAudio, webrtc.RTPTransceiverInit{ - Direction: webrtc.RTPTransceiverDirectionRecvonly, - }) - pc.AddTransceiverFromKind(webrtc.RTPCodecTypeVideo, webrtc.RTPTransceiverInit{ - Direction: webrtc.RTPTransceiverDirectionRecvonly, - }) - - offer, err := pc.CreateOffer(nil) - if err != nil { - return errors.Wrapf(err, "Create Offer") - } - - if err := pc.SetLocalDescription(offer); err != nil { - return errors.Wrapf(err, "Set offer %v", offer) - } - - answer, err := apiRtcRequest(ctx, "/rtc/v1/play", r, offer.SDP) - if err != nil { - return errors.Wrapf(err, "Api request offer=%v", offer.SDP) - } - - // Start a proxy for real server and vnet. - if address, err := parseAddressOfCandidate(answer); err != nil { - return errors.Wrapf(err, "parse address of %v", answer) - } else if err := v.api.proxy.Proxy(v.api.network, address); err != nil { - return errors.Wrapf(err, "proxy %v to %v", v.api.network, address) - } - - if err := pc.SetRemoteDescription(webrtc.SessionDescription{ - Type: webrtc.SDPTypeAnswer, SDP: answer, - }); err != nil { - return errors.Wrapf(err, "Set answer %v", answer) - } - - handleTrack := func(ctx context.Context, track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) error { - // Send a PLI on an interval so that the publisher is pushing a keyframe - go func() { - if track.Kind() == webrtc.RTPCodecTypeAudio { - return - } - - for { - select { - case <-ctx.Done(): - return - case <-time.After(pli): - _ = pc.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{ - MediaSSRC: uint32(track.SSRC()), - }}) - } - } - }() - - v.receivers = append(v.receivers, receiver) - - for ctx.Err() == nil { - _, _, err := track.ReadRTP() - if err != nil { - return errors.Wrapf(err, "Read RTP") - } - } - - return nil - } - - pc.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) { - err = handleTrack(ctx, track, receiver) - if err != nil { - codec := track.Codec() - err = errors.Wrapf(err, "Handle track %v, pt=%v", codec.MimeType, codec.PayloadType) - cancel() - } - }) - - pc.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) { - if state == webrtc.ICEConnectionStateFailed || state == webrtc.ICEConnectionStateClosed { - err = errors.Errorf("Close for ICE state %v", state) - cancel() - } - }) - - <-ctx.Done() - return err -} - -type TestPublisherOptionFunc func(p *TestPublisher) - -type TestPublisher struct { - onOffer func(s *webrtc.SessionDescription) error - onAnswer func(s *webrtc.SessionDescription) error - iceReadyCancel context.CancelFunc - // internal objects - aIngester *audioIngester - vIngester *videoIngester - pc *webrtc.PeerConnection - // root api object - api *TestWebRTCAPI - // Optional suffix for stream url. - streamSuffix string -} - -func NewTestPublisher(api *TestWebRTCAPI, options ...TestPublisherOptionFunc) *TestPublisher { - sourceVideo, sourceAudio := *srsPublishVideo, *srsPublishAudio - - v := &TestPublisher{api: api} - - for _, opt := range options { - opt(v) - } - - // Create ingesters. - if sourceAudio != "" { - v.aIngester = NewAudioIngester(sourceAudio) - } - if sourceVideo != "" { - v.vIngester = NewVideoIngester(sourceVideo) - } - - // Setup the interceptors for packets. - api.options = append(api.options, func(api *TestWebRTCAPI) { - // Filter for RTCP packets. - rtcpInterceptor := &RTCPInterceptor{} - rtcpInterceptor.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - return rtcpInterceptor.nextRTCPReader.Read(buf, attributes) - } - rtcpInterceptor.rtcpWriter = func(pkts []rtcp.Packet, attributes interceptor.Attributes) (int, error) { - return rtcpInterceptor.nextRTCPWriter.Write(pkts, attributes) - } - api.registry.Add(rtcpInterceptor) - - // Filter for ingesters. - if sourceAudio != "" { - api.registry.Add(v.aIngester.audioLevelInterceptor) - } - if sourceVideo != "" { - api.registry.Add(v.vIngester.markerInterceptor) - } - }) - - return v -} - -func (v *TestPublisher) Close() error { - if v.vIngester != nil { - v.vIngester.Close() - } - - if v.aIngester != nil { - v.aIngester.Close() - } - - if v.pc != nil { - v.pc.Close() - } - - return nil -} - -func (v *TestPublisher) SetStreamSuffix(suffix string) *TestPublisher { - v.streamSuffix = suffix - return v -} - -func (v *TestPublisher) Run(ctx context.Context, cancel context.CancelFunc) error { - r := fmt.Sprintf("%v://%v%v", srsSchema, *srsServer, *srsStream) - if v.streamSuffix != "" { - r = fmt.Sprintf("%v-%v", r, v.streamSuffix) - } - sourceVideo, sourceAudio, fps := *srsPublishVideo, *srsPublishAudio, *srsPublishVideoFps - - logger.Tf(ctx, "Start publish url=%v, audio=%v, video=%v, fps=%v", - r, sourceAudio, sourceVideo, fps) - - pc, err := v.api.NewPeerConnection(webrtc.Configuration{}) - if err != nil { - return errors.Wrapf(err, "Create PC") - } - v.pc = pc - - if v.vIngester != nil { - if err := v.vIngester.AddTrack(pc, fps); err != nil { - return errors.Wrapf(err, "Add track") - } - defer v.vIngester.Close() - } - - if v.aIngester != nil { - if err := v.aIngester.AddTrack(pc); err != nil { - return errors.Wrapf(err, "Add track") - } - defer v.aIngester.Close() - } - - offer, err := pc.CreateOffer(nil) - if err != nil { - return errors.Wrapf(err, "Create Offer") - } - - if err := pc.SetLocalDescription(offer); err != nil { - return errors.Wrapf(err, "Set offer %v", offer) - } - - if v.onOffer != nil { - if err := v.onOffer(&offer); err != nil { - return errors.Wrapf(err, "sdp %v %v", offer.Type, offer.SDP) - } - } - - answerSDP, err := apiRtcRequest(ctx, "/rtc/v1/publish", r, offer.SDP) - if err != nil { - return errors.Wrapf(err, "Api request offer=%v", offer.SDP) - } - - // Start a proxy for real server and vnet. - if address, err := parseAddressOfCandidate(answerSDP); err != nil { - return errors.Wrapf(err, "parse address of %v", answerSDP) - } else if err := v.api.proxy.Proxy(v.api.network, address); err != nil { - return errors.Wrapf(err, "proxy %v to %v", v.api.network, address) - } - - answer := &webrtc.SessionDescription{ - Type: webrtc.SDPTypeAnswer, SDP: answerSDP, - } - if v.onAnswer != nil { - if err := v.onAnswer(answer); err != nil { - return errors.Wrapf(err, "on answerSDP") - } - } - - if err := pc.SetRemoteDescription(*answer); err != nil { - return errors.Wrapf(err, "Set answerSDP %v", answerSDP) - } - - logger.Tf(ctx, "State signaling=%v, ice=%v, conn=%v", pc.SignalingState(), pc.ICEConnectionState(), pc.ConnectionState()) - - // ICE state management. - pc.OnICEGatheringStateChange(func(state webrtc.ICEGathererState) { - logger.Tf(ctx, "ICE gather state %v", state) - }) - pc.OnICECandidate(func(candidate *webrtc.ICECandidate) { - logger.Tf(ctx, "ICE candidate %v %v:%v", candidate.Protocol, candidate.Address, candidate.Port) - - }) - pc.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) { - logger.Tf(ctx, "ICE state %v", state) - }) - - pc.OnSignalingStateChange(func(state webrtc.SignalingState) { - logger.Tf(ctx, "Signaling state %v", state) - }) - - if v.aIngester != nil { - v.aIngester.sAudioSender.Transport().OnStateChange(func(state webrtc.DTLSTransportState) { - logger.Tf(ctx, "DTLS state %v", state) - }) - } - - pcDone, pcDoneCancel := context.WithCancel(context.Background()) - pc.OnConnectionStateChange(func(state webrtc.PeerConnectionState) { - logger.Tf(ctx, "PC state %v", state) - - if state == webrtc.PeerConnectionStateConnected { - pcDoneCancel() - if v.iceReadyCancel != nil { - v.iceReadyCancel() - } - } - - if state == webrtc.PeerConnectionStateFailed || state == webrtc.PeerConnectionStateClosed { - err = errors.Errorf("Close for PC state %v", state) - cancel() - } - }) - - // Wait for event from context or tracks. - var wg sync.WaitGroup - var finalErr error - - wg.Add(1) - go func() { - defer wg.Done() - defer logger.Tf(ctx, "ingest notify done") - - <-ctx.Done() - - if v.aIngester != nil && v.aIngester.sAudioSender != nil { - v.aIngester.sAudioSender.Stop() - } - - if v.vIngester != nil && v.vIngester.sVideoSender != nil { - v.vIngester.sVideoSender.Stop() - } - }() - - wg.Add(1) - go func() { - defer wg.Done() - defer cancel() - - if v.aIngester == nil { - return - } - - select { - case <-ctx.Done(): - return - case <-pcDone.Done(): - } - - wg.Add(1) - go func() { - defer wg.Done() - defer logger.Tf(ctx, "aingester sender read done") - - buf := make([]byte, 1500) - for ctx.Err() == nil { - if _, _, err := v.aIngester.sAudioSender.Read(buf); err != nil { - return - } - } - }() - - for { - if err := v.aIngester.Ingest(ctx); err != nil { - if err == io.EOF { - logger.Tf(ctx, "aingester retry for %v", err) - continue - } - if err != context.Canceled { - finalErr = errors.Wrapf(err, "audio") - } - - logger.Tf(ctx, "aingester err=%v, final=%v", err, finalErr) - return - } - } - }() - - wg.Add(1) - go func() { - defer wg.Done() - defer cancel() - - if v.vIngester == nil { - return - } - - select { - case <-ctx.Done(): - return - case <-pcDone.Done(): - logger.Tf(ctx, "PC(ICE+DTLS+SRTP) done, start ingest video %v", sourceVideo) - } - - wg.Add(1) - go func() { - defer wg.Done() - defer logger.Tf(ctx, "vingester sender read done") - - buf := make([]byte, 1500) - for ctx.Err() == nil { - // The Read() might block in r.rtcpInterceptor.Read(b, a), - // so that the Stop() can not stop it. - if _, _, err := v.vIngester.sVideoSender.Read(buf); err != nil { - return - } - } - }() - - for { - if err := v.vIngester.Ingest(ctx); err != nil { - if err == io.EOF { - logger.Tf(ctx, "vingester retry for %v", err) - continue - } - if err != context.Canceled { - finalErr = errors.Wrapf(err, "video") - } - - logger.Tf(ctx, "vingester err=%v, final=%v", err, finalErr) - return - } - } - }() - - wg.Wait() - - logger.Tf(ctx, "ingester done ctx=%v, final=%v", ctx.Err(), finalErr) - if finalErr != nil { - return finalErr - } - return ctx.Err() -} - -func TestRTCServerVersion(t *testing.T) { - api := fmt.Sprintf("http://%v:1985/api/v1/versions", *srsServer) - req, err := http.NewRequest("POST", api, nil) - if err != nil { - t.Errorf("Request %v", api) - return - } - - res, err := http.DefaultClient.Do(req) - if err != nil { - t.Errorf("Do request %v", api) - return - } - - b, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Errorf("Read body of %v", api) - return - } - - obj := struct { - Code int `json:"code"` - Server string `json:"server"` - Data struct { - Major int `json:"major"` - Minor int `json:"minor"` - Revision int `json:"revision"` - Version string `json:"version"` - } `json:"data"` - }{} - if err := json.Unmarshal(b, &obj); err != nil { - t.Errorf("Parse %v", string(b)) - return - } - if obj.Code != 0 { - t.Errorf("Server err code=%v, server=%v", obj.Code, obj.Server) - return - } - if obj.Data.Major == 0 && obj.Data.Minor == 0 { - t.Errorf("Invalid version %v", obj.Data) - return - } -} diff --git a/trunk/3rdparty/srs-bench/vnet/example_udpproxy_test.go b/trunk/3rdparty/srs-bench/vnet/example_udpproxy_test.go index d54e71653..0a8ebb55a 100644 --- a/trunk/3rdparty/srs-bench/vnet/example_udpproxy_test.go +++ b/trunk/3rdparty/srs-bench/vnet/example_udpproxy_test.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in diff --git a/trunk/3rdparty/srs-bench/vnet/udpproxy.go b/trunk/3rdparty/srs-bench/vnet/udpproxy.go index c21fe4603..caba86e0e 100644 --- a/trunk/3rdparty/srs-bench/vnet/udpproxy.go +++ b/trunk/3rdparty/srs-bench/vnet/udpproxy.go @@ -1,34 +1,13 @@ -// The MIT License (MIT) -// -// Copyright (c) 2021 srs-bench(ossrs) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package vnet import ( + "context" "net" "sync" "time" - - "github.com/pion/transport/vnet" ) -// A UDP proxy between real server(net.UDPConn) and vnet.UDPConn. +// UDPProxy is a proxy between real server(net.UDPConn) and vnet.UDPConn. // // High level design: // .............................................. @@ -44,32 +23,9 @@ import ( // : | | ............................: // : +--------+ : // ............................................... -// -// The whole big picture: -// ...................................... -// : Virtual Network (vnet) : -// : : -// +-------+ * 1 +----+ +--------+ : -// | :App |------------>|:Net|--o<-----|:Router | ............................. -// +-------+ +----+ | | : UDPProxy : -// +-----------+ * 1 +----+ | | +----+ +---------+ +---------+ +--------+ -// |:STUNServer|-------->|:Net|--o<-----| |--->o--|:Net|-->o-| vnet. |-->o-| net. |--->-| :Real | -// +-----------+ +----+ | | +----+ | UDPConn | | UDPConn | | Server | -// +-----------+ * 1 +----+ | | : +---------+ +---------+ +--------+ -// |:TURNServer|-------->|:Net|--o<-----| | ............................: -// +-----------+ +----+ [1] | | : -// : 1 | | 1 <> : -// : +---<>| |<>----+ [2] : -// : | +--------+ | : -// To form | *| v 0..1 : -// a subnet tree | o [3] +-----+ : -// : | ^ |:NAT | : -// : | | +-----+ : -// : +-------+ : -// ...................................... type UDPProxy struct { // The router bind to. - router *vnet.Router + router *Router // Each vnet source, bind to a real socket to server. // key is real server addr, which is net.Addr @@ -88,19 +44,22 @@ type UDPProxy struct { // NewProxy create a proxy, the router for this proxy belongs/bind to. If need to proxy for // please create a new proxy for each router. For all addresses we proxy, we will create a // vnet.Net in this router and proxy all packets. -func NewProxy(router *vnet.Router) (*UDPProxy, error) { +func NewProxy(router *Router) (*UDPProxy, error) { v := &UDPProxy{router: router, timeout: 2 * time.Minute} return v, nil } // Close the proxy, stop all workers. func (v *UDPProxy) Close() error { - // nolint:godox // TODO: FIXME: Do cleanup. + v.workers.Range(func(key, value interface{}) bool { + _ = value.(*aUDPProxyWorker).Close() + return true + }) return nil } // Proxy starts a worker for server, ignore if already started. -func (v *UDPProxy) Proxy(client *vnet.Net, server *net.UDPAddr) error { +func (v *UDPProxy) Proxy(client *Net, server *net.UDPAddr) error { // Note that even if the worker exists, it's also ok to create a same worker, // because the router will use the last one, and the real server will see a address // change event after we switch to the next worker. @@ -113,25 +72,44 @@ func (v *UDPProxy) Proxy(client *vnet.Net, server *net.UDPAddr) error { worker := &aUDPProxyWorker{ router: v.router, mockRealServerAddr: v.mockRealServerAddr, } + + // Create context for cleanup. + var ctx context.Context + ctx, worker.ctxDisposeCancel = context.WithCancel(context.Background()) + v.workers.Store(server.String(), worker) - return worker.Proxy(client, server) + return worker.Proxy(ctx, client, server) } // A proxy worker for a specified proxy server. type aUDPProxyWorker struct { - router *vnet.Router + router *Router mockRealServerAddr *net.UDPAddr // Each vnet source, bind to a real socket to server. // key is vnet client addr, which is net.Addr // value is *net.UDPConn endpoints sync.Map + + // For cleanup. + ctxDisposeCancel context.CancelFunc + wg sync.WaitGroup } -func (v *aUDPProxyWorker) Proxy(client *vnet.Net, serverAddr *net.UDPAddr) error { // nolint:gocognit +func (v *aUDPProxyWorker) Close() error { + // Notify all goroutines to dispose. + v.ctxDisposeCancel() + + // Wait for all goroutines quit. + v.wg.Wait() + + return nil +} + +func (v *aUDPProxyWorker) Proxy(ctx context.Context, client *Net, serverAddr *net.UDPAddr) error { // nolint:gocognit // Create vnet for real server by serverAddr. - nw := vnet.NewNet(&vnet.NetConfig{ + nw := NewNet(&NetConfig{ StaticIP: serverAddr.IP.String(), }) if err := v.router.AddNet(nw); err != nil { @@ -145,10 +123,71 @@ func (v *aUDPProxyWorker) Proxy(client *vnet.Net, serverAddr *net.UDPAddr) error return err } - // Start a proxy goroutine. - var findEndpointBy func(addr net.Addr) (*net.UDPConn, error) - // nolint:godox // TODO: FIXME: Do cleanup. + // User stop proxy, we should close the socket. go func() { + <-ctx.Done() + _ = vnetSocket.Close() + }() + + // Got new vnet client, start a new endpoint. + findEndpointBy := func(addr net.Addr) (*net.UDPConn, error) { + // Exists binding. + if value, ok := v.endpoints.Load(addr.String()); ok { + // Exists endpoint, reuse it. + return value.(*net.UDPConn), nil + } + + // The real server we proxy to, for utest to mock it. + realAddr := serverAddr + if v.mockRealServerAddr != nil { + realAddr = v.mockRealServerAddr + } + + // Got new vnet client, create new endpoint. + realSocket, err := net.DialUDP("udp4", nil, realAddr) + if err != nil { + return nil, err + } + + // User stop proxy, we should close the socket. + go func() { + <-ctx.Done() + _ = realSocket.Close() + }() + + // Bind address. + v.endpoints.Store(addr.String(), realSocket) + + // Got packet from real serverAddr, we should proxy it to vnet. + v.wg.Add(1) + go func(vnetClientAddr net.Addr) { + defer v.wg.Done() + + buf := make([]byte, 1500) + for { + n, _, err := realSocket.ReadFrom(buf) + if err != nil { + return + } + + if n <= 0 { + continue // Drop packet + } + + if _, err := vnetSocket.WriteTo(buf[:n], vnetClientAddr); err != nil { + return + } + } + }(addr) + + return realSocket, nil + } + + // Start a proxy goroutine. + v.wg.Add(1) + go func() { + defer v.wg.Done() + buf := make([]byte, 1500) for { @@ -172,51 +211,5 @@ func (v *aUDPProxyWorker) Proxy(client *vnet.Net, serverAddr *net.UDPAddr) error } }() - // Got new vnet client, start a new endpoint. - findEndpointBy = func(addr net.Addr) (*net.UDPConn, error) { - // Exists binding. - if value, ok := v.endpoints.Load(addr.String()); ok { - // Exists endpoint, reuse it. - return value.(*net.UDPConn), nil - } - - // The real server we proxy to, for utest to mock it. - realAddr := serverAddr - if v.mockRealServerAddr != nil { - realAddr = v.mockRealServerAddr - } - - // Got new vnet client, create new endpoint. - realSocket, err := net.DialUDP("udp4", nil, realAddr) - if err != nil { - return nil, err - } - - // Bind address. - v.endpoints.Store(addr.String(), realSocket) - - // Got packet from real serverAddr, we should proxy it to vnet. - // nolint:godox // TODO: FIXME: Do cleanup. - go func(vnetClientAddr net.Addr) { - buf := make([]byte, 1500) - for { - n, _, err := realSocket.ReadFrom(buf) - if err != nil { - return - } - - if n <= 0 { - continue // Drop packet - } - - if _, err := vnetSocket.WriteTo(buf[:n], vnetClientAddr); err != nil { - return - } - } - }(addr) - - return realSocket, nil - } - return nil } diff --git a/trunk/3rdparty/srs-bench/vnet/udpproxy_direct.go b/trunk/3rdparty/srs-bench/vnet/udpproxy_direct.go index 6d49494ed..35e4618d7 100644 --- a/trunk/3rdparty/srs-bench/vnet/udpproxy_direct.go +++ b/trunk/3rdparty/srs-bench/vnet/udpproxy_direct.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in diff --git a/trunk/3rdparty/srs-bench/vnet/udpproxy_direct_test.go b/trunk/3rdparty/srs-bench/vnet/udpproxy_direct_test.go index b347c682c..48b776957 100644 --- a/trunk/3rdparty/srs-bench/vnet/udpproxy_direct_test.go +++ b/trunk/3rdparty/srs-bench/vnet/udpproxy_direct_test.go @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2021 srs-bench(ossrs) +// Copyright (c) 2021 Winlin // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in diff --git a/trunk/3rdparty/srs-bench/vnet/udpproxy_test.go b/trunk/3rdparty/srs-bench/vnet/udpproxy_test.go index c0c1c4a2b..e5689bc18 100644 --- a/trunk/3rdparty/srs-bench/vnet/udpproxy_test.go +++ b/trunk/3rdparty/srs-bench/vnet/udpproxy_test.go @@ -1,23 +1,5 @@ -// The MIT License (MIT) -// -// Copyright (c) 2021 srs-bench(ossrs) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +build !wasm + package vnet import ( @@ -32,7 +14,6 @@ import ( "time" "github.com/pion/logging" - "github.com/pion/transport/vnet" ) type MockUDPEchoServer struct { @@ -163,7 +144,7 @@ func TestUDPProxyOne2One(t *testing.T) { } doVnetProxy := func() error { - router, err := vnet.NewRouter(&vnet.RouterConfig{ + router, err := NewRouter(&RouterConfig{ CIDR: "0.0.0.0/0", LoggerFactory: logging.NewDefaultLoggerFactory(), }) @@ -171,7 +152,7 @@ func TestUDPProxyOne2One(t *testing.T) { return err } - clientNetwork := vnet.NewNet(&vnet.NetConfig{ + clientNetwork := NewNet(&NetConfig{ StaticIP: "10.0.0.11", }) if err = router.AddNet(clientNetwork); err != nil { @@ -309,7 +290,7 @@ func TestUDPProxyTwo2One(t *testing.T) { } doVnetProxy := func() error { - router, err := vnet.NewRouter(&vnet.RouterConfig{ + router, err := NewRouter(&RouterConfig{ CIDR: "0.0.0.0/0", LoggerFactory: logging.NewDefaultLoggerFactory(), }) @@ -317,7 +298,7 @@ func TestUDPProxyTwo2One(t *testing.T) { return err } - clientNetwork := vnet.NewNet(&vnet.NetConfig{ + clientNetwork := NewNet(&NetConfig{ StaticIP: "10.0.0.11", }) if err = router.AddNet(clientNetwork); err != nil { @@ -487,7 +468,7 @@ func TestUDPProxyProxyTwice(t *testing.T) { } doVnetProxy := func() error { - router, err := vnet.NewRouter(&vnet.RouterConfig{ + router, err := NewRouter(&RouterConfig{ CIDR: "0.0.0.0/0", LoggerFactory: logging.NewDefaultLoggerFactory(), }) @@ -495,7 +476,7 @@ func TestUDPProxyProxyTwice(t *testing.T) { return err } - clientNetwork := vnet.NewNet(&vnet.NetConfig{ + clientNetwork := NewNet(&NetConfig{ StaticIP: "10.0.0.11", }) if err = router.AddNet(clientNetwork); err != nil { diff --git a/trunk/3rdparty/srs-bench/vnet/vnet.go b/trunk/3rdparty/srs-bench/vnet/vnet.go new file mode 100644 index 000000000..ceab0847f --- /dev/null +++ b/trunk/3rdparty/srs-bench/vnet/vnet.go @@ -0,0 +1,38 @@ +// The MIT License (MIT) +// +// Copyright (c) 2021 Winlin +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +package vnet + +import ( + "github.com/pion/transport/vnet" +) + +type Router = vnet.Router +type Net = vnet.Net + +type NetConfig = vnet.NetConfig +type RouterConfig = vnet.RouterConfig + +func NewNet(config *NetConfig) *Net { + return vnet.NewNet(config) +} +func NewRouter(config *RouterConfig) (*Router, error) { + return vnet.NewRouter(config) +} diff --git a/trunk/3rdparty/st-srs/.gitignore b/trunk/3rdparty/st-srs/.gitignore index 97cd5081d..18d2ab26f 100644 --- a/trunk/3rdparty/st-srs/.gitignore +++ b/trunk/3rdparty/st-srs/.gitignore @@ -2,3 +2,6 @@ DARWIN_*_DBG LINUX_*_DBG obj st.pc + +coverage +utest From 3fea5c0ec3c7d8721450cae60d0960dcb3ed4334 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 23 Mar 2021 19:32:59 +0800 Subject: [PATCH 2/3] Test: Add republish regression test, should fail --- trunk/3rdparty/srs-bench/srs/ingester.go | 31 +- trunk/3rdparty/srs-bench/srs/rtc_test.go | 576 +++++++++++------------ trunk/3rdparty/srs-bench/srs/util.go | 161 ++++--- trunk/src/app/srs_app_rtc_conn.cpp | 2 +- 4 files changed, 397 insertions(+), 373 deletions(-) diff --git a/trunk/3rdparty/srs-bench/srs/ingester.go b/trunk/3rdparty/srs-bench/srs/ingester.go index f38409e59..bcedebbb6 100644 --- a/trunk/3rdparty/srs-bench/srs/ingester.go +++ b/trunk/3rdparty/srs-bench/srs/ingester.go @@ -44,16 +44,20 @@ type videoIngester struct { markerInterceptor *RTPInterceptor sVideoTrack *webrtc.TrackLocalStaticSample sVideoSender *webrtc.RTPSender + ready context.Context + readyCancel context.CancelFunc } func NewVideoIngester(sourceVideo string) *videoIngester { - return &videoIngester{markerInterceptor: &RTPInterceptor{}, sourceVideo: sourceVideo} + v := &videoIngester{markerInterceptor: &RTPInterceptor{}, sourceVideo: sourceVideo} + v.ready, v.readyCancel = context.WithCancel(context.Background()) + return v } func (v *videoIngester) Close() error { + v.readyCancel() if v.sVideoSender != nil { - v.sVideoSender.Stop() - v.sVideoSender = nil + _ = v.sVideoSender.Stop() } return nil } @@ -102,6 +106,9 @@ func (v *videoIngester) Ingest(ctx context.Context) error { logger.Tf(ctx, "Video %v, tbn=%v, fps=%v, ssrc=%v, pt=%v, header=%v", codec.MimeType, codec.ClockRate, fps, enc.SSRC, codec.PayloadType, headers) + // OK, we are ready. + v.readyCancel() + clock := newWallClock() sampleDuration := time.Duration(uint64(time.Millisecond) * 1000 / uint64(fps)) for ctx.Err() == nil { @@ -179,16 +186,21 @@ type audioIngester struct { audioLevelInterceptor *RTPInterceptor sAudioTrack *webrtc.TrackLocalStaticSample sAudioSender *webrtc.RTPSender + ready context.Context + readyCancel context.CancelFunc } func NewAudioIngester(sourceAudio string) *audioIngester { - return &audioIngester{audioLevelInterceptor: &RTPInterceptor{}, sourceAudio: sourceAudio} + v := &audioIngester{audioLevelInterceptor: &RTPInterceptor{}, sourceAudio: sourceAudio} + v.ready, v.readyCancel = context.WithCancel(context.Background()) + return v } func (v *audioIngester) Close() error { + v.readyCancel() // OK we are closed, also ready. + if v.sAudioSender != nil { - v.sAudioSender.Stop() - v.sAudioSender = nil + _ = v.sAudioSender.Stop() } return nil } @@ -240,6 +252,9 @@ func (v *audioIngester) Ingest(ctx context.Context) error { } } + // OK, we are ready. + v.readyCancel() + clock := newWallClock() var lastGranule uint64 @@ -253,7 +268,7 @@ func (v *audioIngester) Ingest(ctx context.Context) error { } // The amount of samples is the difference between the last and current timestamp - sampleCount := uint64(pageHeader.GranulePosition - lastGranule) + sampleCount := pageHeader.GranulePosition - lastGranule lastGranule = pageHeader.GranulePosition sampleDuration := time.Duration(uint64(time.Millisecond) * 1000 * sampleCount / uint64(codec.ClockRate)) @@ -266,7 +281,7 @@ func (v *audioIngester) Ingest(ctx context.Context) error { return 0, err } - header.SetExtension(uint8(audioLevel.ID), audioLevelPayload) + _ = header.SetExtension(uint8(audioLevel.ID), audioLevelPayload) } return ri.nextRTPWriter.Write(header, payload, attributes) diff --git a/trunk/3rdparty/srs-bench/srs/rtc_test.go b/trunk/3rdparty/srs-bench/srs/rtc_test.go index 62ad26663..de5ac0ff0 100644 --- a/trunk/3rdparty/srs-bench/srs/rtc_test.go +++ b/trunk/3rdparty/srs-bench/srs/rtc_test.go @@ -22,11 +22,13 @@ package srs import ( "context" + "encoding/json" "fmt" "github.com/pion/transport/vnet" "io" "io/ioutil" "math/rand" + "net/http" "os" "sync" "testing" @@ -73,7 +75,7 @@ func TestRtcBasic_PublishPlay(t *testing.T) { var resources []io.Closer defer func() { for _, resource := range resources { - resource.Close() + _ = resource.Close() } }() @@ -93,27 +95,19 @@ func TestRtcBasic_PublishPlay(t *testing.T) { defer wg.Done() defer cancel() - doInit := func() error { - playOK, vnetClientIP := *srsPlayOKPackets, *srsVnetClientIP + doInit := func() (err error) { streamSuffix := fmt.Sprintf("basic-publish-play-%v-%v", os.Getpid(), rand.Int()) // Initialize player with private api. - if play, err := NewTestPlayer(nil, func(play *TestPlayer) error { + if thePlayer, err = NewTestPlayer(CreateApiForPlayer, func(play *TestPlayer) error { play.streamSuffix = streamSuffix resources = append(resources, play) - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - resources = append(resources, api) - play.api = api - var nnPlayWriteRTCP, nnPlayReadRTCP, nnPlayWriteRTP, nnPlayReadRTP uint64 - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + return play.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpReader = func(payload []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnPlayReadRTP++; nnPlayReadRTP >= uint64(playOK) { + if nnPlayReadRTP++; nnPlayReadRTP >= uint64(*srsPlayOKPackets) { cancel() // Completed. } logger.Tf(ctx, "Play rtp=(recv:%v, send:%v), rtcp=(recv:%v send:%v) packets", @@ -133,32 +127,19 @@ func TestRtcBasic_PublishPlay(t *testing.T) { return nn, err } })) - }); err != nil { - return err - } - - return nil + }) }); err != nil { return err - } else { - thePlayer = play } // Initialize publisher with private api. - if pub, err := NewTestPublisher(nil, func(pub *TestPublisher) error { + if thePublisher, err = NewTestPublisher(CreateApiForPublisher, func(pub *TestPublisher) error { pub.streamSuffix = streamSuffix pub.iceReadyCancel = publishReadyCancel resources = append(resources, pub) - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - resources = append(resources, api) - pub.api = api - var nnPubWriteRTCP, nnPubReadRTCP, nnPubWriteRTP, nnPubReadRTP uint64 - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + return pub.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { nn, attr, err := i.nextRTPReader.Read(buf, attributes) @@ -185,15 +166,9 @@ func TestRtcBasic_PublishPlay(t *testing.T) { return nn, err } })) - }); err != nil { - return err - } - - return nil + }) }); err != nil { return err - } else { - thePublisher = pub } // Init done. @@ -216,14 +191,10 @@ func TestRtcBasic_PublishPlay(t *testing.T) { select { case <-ctx.Done(): - return case <-mainReady.Done(): + r2 = thePublisher.Run(logger.WithContext(ctx), cancel) + logger.Tf(ctx, "pub done") } - - if err := thePublisher.Run(logger.WithContext(ctx), cancel); err != nil { - r2 = err - } - logger.Tf(ctx, "pub done") }() // Run player. @@ -234,14 +205,159 @@ func TestRtcBasic_PublishPlay(t *testing.T) { select { case <-ctx.Done(): - return case <-publishReady.Done(): + r3 = thePlayer.Run(logger.WithContext(ctx), cancel) + logger.Tf(ctx, "play done") + } + }() +} + +// When republish a stream, the player stream SHOULD be continuous. +func TestRtcBasic_Republish(t *testing.T) { + ctx := logger.WithContext(context.Background()) + ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond) + + var r0, r1, r2, r3, r4 error + defer func(ctx context.Context) { + if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4); err != nil { + t.Errorf("Fail for err %+v", err) + } else { + logger.Tf(ctx, "test done with err %+v", err) + } + }(ctx) + + var resources []io.Closer + defer func() { + for _, resource := range resources { + _ = resource.Close() + } + }() + + var wg sync.WaitGroup + defer wg.Wait() + + // The event notify. + var thePublisher, theRepublisher *TestPublisher + var thePlayer *TestPlayer + + mainReady, mainReadyCancel := context.WithCancel(context.Background()) + publishReady, publishReadyCancel := context.WithCancel(context.Background()) + republishReady, republishReadyCancel := context.WithCancel(context.Background()) + + // Objects init. + wg.Add(1) + go func() { + defer wg.Done() + defer cancel() + + doInit := func() (err error) { + streamSuffix := fmt.Sprintf("basic-publish-play-%v-%v", os.Getpid(), rand.Int()) + + // Initialize player with private api. + if thePlayer, err = NewTestPlayer(CreateApiForPlayer, func(play *TestPlayer) error { + play.streamSuffix = streamSuffix + resources = append(resources, play) + + var nnPlayReadRTP uint64 + return play.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { + api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { + i.rtpReader = func(payload []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + select { + case <-republishReady.Done(): + if nnPlayReadRTP++; nnPlayReadRTP >= uint64(*srsPlayOKPackets) { + cancel() // Completed. + } + logger.Tf(ctx, "Play recv rtp %v packets", nnPlayReadRTP) + default: + logger.Tf(ctx, "Play recv rtp packet before republish") + } + return i.nextRTPReader.Read(payload, attributes) + } + })) + }) + }); err != nil { + return err + } + + // Initialize publisher with private api. + if thePublisher, err = NewTestPublisher(CreateApiForPublisher, func(pub *TestPublisher) error { + pub.streamSuffix = streamSuffix + pub.iceReadyCancel = publishReadyCancel + resources = append(resources, pub) + + var nnPubReadRTCP uint64 + return pub.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { + api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { + i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { + nn, attr, err := i.nextRTCPReader.Read(buf, attributes) + if nnPubReadRTCP++; nnPubReadRTCP > 0 && pub.cancel != nil { + pub.cancel() // We only cancel the publisher itself. + } + logger.Tf(ctx, "Publish recv rtcp %v packets", nnPubReadRTCP) + return nn, attr, err + } + })) + }) + }); err != nil { + return err + } + + // Initialize re-publisher with private api. + if theRepublisher, err = NewTestPublisher(CreateApiForPublisher, func(pub *TestPublisher) error { + pub.streamSuffix = streamSuffix + pub.iceReadyCancel = republishReadyCancel + resources = append(resources, pub) + + return pub.Setup(*srsVnetClientIP) + }); err != nil { + return err + } + + // Init done. + mainReadyCancel() + + <-ctx.Done() + return nil } - if err := thePlayer.Run(logger.WithContext(ctx), cancel); err != nil { - r3 = err + if err := doInit(); err != nil { + r1 = err + } + }() + + // Run publisher. + wg.Add(1) + go func() { + defer wg.Done() + defer cancel() + + select { + case <-ctx.Done(): + case <-mainReady.Done(): + pubCtx, pubCancel := context.WithCancel(ctx) + r2 = thePublisher.Run(logger.WithContext(pubCtx), pubCancel) + logger.Tf(ctx, "pub done, re-publish again") + + // Dispose the stream. + _ = thePublisher.Close() + + r4 = theRepublisher.Run(logger.WithContext(ctx), cancel) + logger.Tf(ctx, "re-pub done") + } + }() + + // Run player. + wg.Add(1) + go func() { + defer wg.Done() + defer cancel() + + select { + case <-ctx.Done(): + case <-publishReady.Done(): + r3 = thePlayer.Run(logger.WithContext(ctx), cancel) + logger.Tf(ctx, "play done") } - logger.Tf(ctx, "play done") }() } @@ -252,18 +368,8 @@ func TestRtcBasic_PublishPlay(t *testing.T) { // No.4 srs-server: ChangeCipherSpec, Finished func TestRtcDTLS_ClientActive_Default(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive return nil @@ -273,7 +379,8 @@ func TestRtcDTLS_ClientActive_Default(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -283,7 +390,7 @@ func TestRtcDTLS_ClientActive_Default(t *testing.T) { })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -316,18 +423,8 @@ func TestRtcDTLS_ClientActive_Default(t *testing.T) { // No.4 srs-bench: ChangeCipherSpec, Finished func TestRtcDTLS_ClientPassive_Default(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -337,7 +434,8 @@ func TestRtcDTLS_ClientPassive_Default(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -347,7 +445,7 @@ func TestRtcDTLS_ClientPassive_Default(t *testing.T) { })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -377,18 +475,8 @@ func TestRtcDTLS_ClientPassive_Default(t *testing.T) { // When srs-bench close the PC, it will send DTLS alert and might retransmit it. func TestRtcDTLS_ClientActive_Duplicated_Alert(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive return nil @@ -398,7 +486,8 @@ func TestRtcDTLS_ClientActive_Duplicated_Alert(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -408,7 +497,7 @@ func TestRtcDTLS_ClientActive_Duplicated_Alert(t *testing.T) { })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -445,18 +534,8 @@ func TestRtcDTLS_ClientActive_Duplicated_Alert(t *testing.T) { // When srs-bench close the PC, it will send DTLS alert and might retransmit it. func TestRtcDTLS_ClientPassive_Duplicated_Alert(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -466,7 +545,8 @@ func TestRtcDTLS_ClientPassive_Duplicated_Alert(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -476,7 +556,7 @@ func TestRtcDTLS_ClientPassive_Duplicated_Alert(t *testing.T) { })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -520,18 +600,8 @@ func TestRtcDTLS_ClientPassive_Duplicated_Alert(t *testing.T) { func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T) { var r0 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-active-arq-client-hello-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive return nil @@ -541,7 +611,8 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -551,7 +622,7 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -579,7 +650,7 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T lastClientHello = record nnClientHello++ - ok = (nnClientHello > nnMaxDrop) + ok = nnClientHello > nnMaxDrop logger.Tf(ctx, "NN=%v, Chunk %v, %v, ok=%v %v bytes", nnClientHello, chunk, record, ok, len(c.UserData())) return }) @@ -607,18 +678,8 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T) { var r0 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-arq-client-hello-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -628,7 +689,8 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ClientHello(t *testing. } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -638,7 +700,7 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ClientHello(t *testing. })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -666,7 +728,7 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ClientHello(t *testing. lastClientHello = record nnClientHello++ - ok = (nnClientHello > nnMaxDrop) + ok = nnClientHello > nnMaxDrop logger.Tf(ctx, "NN=%v, Chunk %v, %v, ok=%v %v bytes", nnClientHello, chunk, record, ok, len(c.UserData())) return }) @@ -693,18 +755,8 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ClientHello(t *testing. func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T) { var r0, r1 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-active-arq-client-hello-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive return nil @@ -714,7 +766,8 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -724,7 +777,7 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -761,7 +814,7 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T lastServerHello = record nnServerHello++ - ok = (nnServerHello > nnMaxDrop) + ok = nnServerHello > nnMaxDrop logger.Tf(ctx, "NN=%v, Chunk %v, %v, ok=%v %v bytes", nnServerHello, chunk, record, ok, len(c.UserData())) return }) @@ -790,18 +843,8 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T) { var r0, r1 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-arq-client-hello-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -811,7 +854,8 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ServerHello(t *testing. } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -821,7 +865,7 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ServerHello(t *testing. })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -858,7 +902,7 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ServerHello(t *testing. lastServerHello = record nnServerHello++ - ok = (nnServerHello > nnMaxDrop) + ok = nnServerHello > nnMaxDrop logger.Tf(ctx, "NN=%v, Chunk %v, %v, ok=%v %v bytes", nnServerHello, chunk, record, ok, len(c.UserData())) return }) @@ -884,18 +928,8 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ServerHello(t *testing. func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_Certificate(t *testing.T) { var r0 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-active-arq-certificate-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive return nil @@ -905,7 +939,8 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_Certificate(t *testing.T } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -915,7 +950,7 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_Certificate(t *testing.T })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -943,7 +978,7 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_Certificate(t *testing.T lastCertificate = record nnCertificate++ - ok = (nnCertificate > nnMaxDrop) + ok = nnCertificate > nnMaxDrop logger.Tf(ctx, "NN=%v, Chunk %v, %v, ok=%v %v bytes", nnCertificate, chunk, record, ok, len(c.UserData())) return }) @@ -970,18 +1005,8 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_Certificate(t *testing.T func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_Certificate(t *testing.T) { var r0 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-arq-certificate-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -991,7 +1016,8 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_Certificate(t *testing. } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -1001,7 +1027,7 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_Certificate(t *testing. })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -1029,7 +1055,7 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_Certificate(t *testing. lastCertificate = record nnCertificate++ - ok = (nnCertificate > nnMaxDrop) + ok = nnCertificate > nnMaxDrop logger.Tf(ctx, "NN=%v, Chunk %v, %v, ok=%v %v bytes", nnCertificate, chunk, record, ok, len(c.UserData())) return }) @@ -1056,18 +1082,8 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_Certificate(t *testing. func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *testing.T) { var r0, r1 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-active-arq-certificate-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupActive return nil @@ -1077,7 +1093,8 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *test } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -1087,7 +1104,7 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *test })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -1123,7 +1140,7 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *test lastChangeCipherSepc = record nnCertificate++ - ok = (nnCertificate > nnMaxDrop) + ok = nnCertificate > nnMaxDrop logger.Tf(ctx, "NN=%v, Chunk %v, %v, ok=%v %v bytes", nnCertificate, chunk, record, ok, len(c.UserData())) return }) @@ -1151,18 +1168,8 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *test func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *testing.T) { var r0, r1 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-arq-certificate-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -1172,7 +1179,8 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *tes } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -1182,7 +1190,7 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *tes })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -1218,7 +1226,7 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *tes lastChangeCipherSepc = record nnCertificate++ - ok = (nnCertificate > nnMaxDrop) + ok = nnCertificate > nnMaxDrop logger.Tf(ctx, "NN=%v, Chunk %v, %v, ok=%v %v bytes", nnCertificate, chunk, record, ok, len(c.UserData())) return }) @@ -1237,18 +1245,8 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *tes // Drop all DTLS packets when got ClientHello, to test the server ARQ thread cleanup. func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ClientHello(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - vnetClientIP, dtlsDropPackets := *srsVnetClientIP, *srsDTLSDropPackets - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -1258,7 +1256,8 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ClientHello(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { nnDrop, dropAll := 0, false api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) { chunk, parsed := NewChunkMessageType(c) @@ -1275,7 +1274,7 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ClientHello(t *testing.T) { return true } - if nnDrop++; nnDrop >= dtlsDropPackets { + if nnDrop++; nnDrop >= *srsDTLSDropPackets { cancel() // Done, server transmit 5 Client Hello. } @@ -1299,18 +1298,8 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ClientHello(t *testing.T) { // Drop all DTLS packets when got ServerHello, to test the server ARQ thread cleanup. func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ServerHello(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - vnetClientIP, dtlsDropPackets := *srsVnetClientIP, *srsDTLSDropPackets - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -1320,7 +1309,8 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ServerHello(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { nnDrop, dropAll := 0, false api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) { chunk, parsed := NewChunkMessageType(c) @@ -1337,7 +1327,7 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ServerHello(t *testing.T) { return true } - if nnDrop++; nnDrop >= dtlsDropPackets { + if nnDrop++; nnDrop >= *srsDTLSDropPackets { cancel() // Done, server transmit 5 Client Hello. } @@ -1361,18 +1351,8 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ServerHello(t *testing.T) { // Drop all DTLS packets when got Certificate, to test the server ARQ thread cleanup. func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_Certificate(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - vnetClientIP, dtlsDropPackets := *srsVnetClientIP, *srsDTLSDropPackets - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -1382,7 +1362,8 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_Certificate(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { nnDrop, dropAll := 0, false api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) { chunk, parsed := NewChunkMessageType(c) @@ -1399,7 +1380,7 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_Certificate(t *testing.T) { return true } - if nnDrop++; nnDrop >= dtlsDropPackets { + if nnDrop++; nnDrop >= *srsDTLSDropPackets { cancel() // Done, server transmit 5 Client Hello. } @@ -1423,18 +1404,8 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_Certificate(t *testing.T) { // Drop all DTLS packets when got ChangeCipherSpec, to test the server ARQ thread cleanup. func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ChangeCipherSpec(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - vnetClientIP, dtlsDropPackets := *srsVnetClientIP, *srsDTLSDropPackets - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -1444,7 +1415,8 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ChangeCipherSpec(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { nnDrop, dropAll := 0, false api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) { chunk, parsed := NewChunkMessageType(c) @@ -1461,7 +1433,7 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ChangeCipherSpec(t *testing.T) { return true } - if nnDrop++; nnDrop >= dtlsDropPackets { + if nnDrop++; nnDrop >= *srsDTLSDropPackets { cancel() // Done, server transmit 5 Client Hello. } @@ -1486,18 +1458,8 @@ func TestRtcDTLS_ClientPassive_ARQ_DropAllAfter_ChangeCipherSpec(t *testing.T) { // which also consume about 750ms, but finally should be done successfully. func TestRtcDTLS_ClientPassive_ARQ_VeryBadNetwork(t *testing.T) { if err := filterTestError(func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP, dtlsDropPackets := *srsPublishOKPackets, *srsVnetClientIP, *srsDTLSDropPackets - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -1507,7 +1469,8 @@ func TestRtcDTLS_ClientPassive_ARQ_VeryBadNetwork(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -1517,7 +1480,7 @@ func TestRtcDTLS_ClientPassive_ARQ_VeryBadNetwork(t *testing.T) { })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -1545,7 +1508,7 @@ func TestRtcDTLS_ClientPassive_ARQ_VeryBadNetwork(t *testing.T) { } if chunk.IsCertificate() { - if nnDropCertificate >= dtlsDropPackets { + if nnDropCertificate >= *srsDTLSDropPackets { return true } nnDropCertificate++ @@ -1573,18 +1536,8 @@ func TestRtcDTLS_ClientPassive_ARQ_VeryBadNetwork(t *testing.T) { func TestRtcDTLS_ClientPassive_ARQ_Certificate_After_ClientHello(t *testing.T) { var r0 error err := func() error { - ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) - publishOK, vnetClientIP := *srsPublishOKPackets, *srsVnetClientIP - - // Create top level test object. - api, err := NewTestWebRTCAPI() - if err != nil { - return err - } - defer api.Close() - streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int()) - p, err := NewTestPublisher(api, func(p *TestPublisher) error { + p, err := NewTestPublisher(CreateApiForPublisher, func(p *TestPublisher) error { p.streamSuffix = streamSuffix p.onOffer = testUtilSetupPassive return nil @@ -1594,7 +1547,8 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_After_ClientHello(t *testing.T) { } defer p.Close() - if err := api.Setup(vnetClientIP, func(api *TestWebRTCAPI) { + ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond) + if err := p.Setup(*srsVnetClientIP, func(api *TestWebRTCAPI) { var nnRTCP, nnRTP int64 api.registry.Add(NewRTPInterceptor(func(i *RTPInterceptor) { i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) { @@ -1604,7 +1558,7 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_After_ClientHello(t *testing.T) { })) api.registry.Add(NewRTCPInterceptor(func(i *RTCPInterceptor) { i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) { - if nnRTCP++; nnRTCP >= int64(publishOK) && nnRTP >= int64(publishOK) { + if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) { cancel() // Send enough packets, done. } logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP) @@ -1662,3 +1616,47 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_After_ClientHello(t *testing.T) { t.Errorf("err %+v", err) } } + +func TestRTCServerVersion(t *testing.T) { + api := fmt.Sprintf("http://%v:1985/api/v1/versions", *srsServer) + req, err := http.NewRequest("POST", api, nil) + if err != nil { + t.Errorf("Request %v", api) + return + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("Do request %v", api) + return + } + + b, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Errorf("Read body of %v", api) + return + } + + obj := struct { + Code int `json:"code"` + Server string `json:"server"` + Data struct { + Major int `json:"major"` + Minor int `json:"minor"` + Revision int `json:"revision"` + Version string `json:"version"` + } `json:"data"` + }{} + if err := json.Unmarshal(b, &obj); err != nil { + t.Errorf("Parse %v", string(b)) + return + } + if obj.Code != 0 { + t.Errorf("Server err code=%v, server=%v", obj.Code, obj.Server) + return + } + if obj.Data.Major == 0 && obj.Data.Minor == 0 { + t.Errorf("Invalid version %v", obj.Data) + return + } +} diff --git a/trunk/3rdparty/srs-bench/srs/util.go b/trunk/3rdparty/srs-bench/srs/util.go index 941b0bb76..e8cb47dad 100644 --- a/trunk/3rdparty/srs-bench/srs/util.go +++ b/trunk/3rdparty/srs-bench/srs/util.go @@ -36,7 +36,6 @@ import ( "strconv" "strings" "sync" - "testing" "time" "github.com/ossrs/go-oryx-lib/errors" @@ -207,7 +206,7 @@ func apiRtcRequest(ctx context.Context, apiPath, r, offer string) (string, error logger.Tf(ctx, "Parse response to code=%v, session=%v, sdp=%v bytes", resBody.Code, resBody.Session, len(resBody.SDP)) - return string(resBody.SDP), nil + return resBody.SDP, nil } func escapeSDP(sdp string) string { @@ -219,7 +218,7 @@ func packageAsSTAPA(frames ...*h264reader.NAL) *h264reader.NAL { buf := bytes.Buffer{} buf.WriteByte( - byte(first.RefIdc<<5)&0x60 | byte(24), // STAP-A + first.RefIdc<<5&0x60 | byte(24), // STAP-A ) for _, frame := range frames { @@ -325,6 +324,14 @@ func filterTestError(errs ...error) error { if err == nil || errors.Cause(err) == context.Canceled { continue } + + // If url error, server maybe error, do not print the detail log. + if r0 := errors.Cause(err); r0 != nil { + if r1, ok := r0.(*url.Error); ok { + err = r1 + } + } + filteredErrors = append(filteredErrors, err) } @@ -352,13 +359,13 @@ func srsIsStun(b []byte) bool { // @see https://tools.ietf.org/html/rfc2246#section-6.2.1 // @see srs_is_dtls of https://github.com/ossrs/srs func srsIsDTLS(b []byte) bool { - return (len(b) >= 13 && (b[0] > 19 && b[0] < 64)) + return len(b) >= 13 && (b[0] > 19 && b[0] < 64) } // For RTP or RTCP, the V=2 which is in the high 2bits, 0xC0 (1100 0000) // @see srs_is_rtp_or_rtcp of https://github.com/ossrs/srs func srsIsRTPOrRTCP(b []byte) bool { - return (len(b) >= 12 && (b[0]&0xC0) == 0x80) + return len(b) >= 12 && (b[0]&0xC0) == 0x80 } // For RTCP, PT is [128, 223] (or without marker [0, 95]). @@ -554,7 +561,7 @@ func (v *DTLSRecord) Unmarshal(b []byte) error { return errors.Errorf("requires 13B only %v", len(b)) } - v.ContentType = DTLSContentType(uint8(b[0])) + v.ContentType = DTLSContentType(b[0]) v.Version = uint16(b[1])<<8 | uint16(b[2]) v.Epoch = uint16(b[3])<<8 | uint16(b[4]) v.SequenceNumber = uint64(b[5])<<40 | uint64(b[6])<<32 | uint64(b[7])<<24 | uint64(b[8])<<16 | uint64(b[9])<<8 | uint64(b[10]) @@ -605,11 +612,11 @@ func NewTestWebRTCAPI(options ...TestWebRTCAPIOptionFunc) (*TestWebRTCAPI, error func (v *TestWebRTCAPI) Close() error { if v.proxy != nil { - v.proxy.Close() + _ = v.proxy.Close() } if v.router != nil { - v.router.Stop() + _ = v.router.Stop() } return nil @@ -676,14 +683,24 @@ type TestPlayerOptionFunc func(p *TestPlayer) error type TestPlayer struct { pc *webrtc.PeerConnection receivers []*webrtc.RTPReceiver - // root api object + // We should dispose it. api *TestWebRTCAPI // Optional suffix for stream url. streamSuffix string } -func NewTestPlayer(api *TestWebRTCAPI, options ...TestPlayerOptionFunc) (*TestPlayer, error) { - v := &TestPlayer{api: api} +func CreateApiForPlayer(play *TestPlayer) error { + api, err := NewTestWebRTCAPI() + if err != nil { + return err + } + + play.api = api + return nil +} + +func NewTestPlayer(options ...TestPlayerOptionFunc) (*TestPlayer, error) { + v := &TestPlayer{} for _, opt := range options { if err := opt(v); err != nil { @@ -691,19 +708,24 @@ func NewTestPlayer(api *TestWebRTCAPI, options ...TestPlayerOptionFunc) (*TestPl } } - // The api might be override by options. - api = v.api - return v, nil } +func (v *TestPlayer) Setup(vnetClientIP string, options ...TestWebRTCAPIOptionFunc) error { + return v.api.Setup(vnetClientIP, options...) +} + func (v *TestPlayer) Close() error { if v.pc != nil { - v.pc.Close() + _ = v.pc.Close() } for _, receiver := range v.receivers { - receiver.Stop() + _ = receiver.Stop() + } + + if v.api != nil { + _ = v.api.Close() } return nil @@ -723,12 +745,16 @@ func (v *TestPlayer) Run(ctx context.Context, cancel context.CancelFunc) error { } v.pc = pc - pc.AddTransceiverFromKind(webrtc.RTPCodecTypeAudio, webrtc.RTPTransceiverInit{ + if _, err := pc.AddTransceiverFromKind(webrtc.RTPCodecTypeAudio, webrtc.RTPTransceiverInit{ Direction: webrtc.RTPTransceiverDirectionRecvonly, - }) - pc.AddTransceiverFromKind(webrtc.RTPCodecTypeVideo, webrtc.RTPTransceiverInit{ + }); err != nil { + return errors.Wrapf(err, "add track") + } + if _, err := pc.AddTransceiverFromKind(webrtc.RTPCodecTypeVideo, webrtc.RTPTransceiverInit{ Direction: webrtc.RTPTransceiverDirectionRecvonly, - }) + }); err != nil { + return errors.Wrapf(err, "add track") + } offer, err := pc.CreateOffer(nil) if err != nil { @@ -818,16 +844,28 @@ type TestPublisher struct { aIngester *audioIngester vIngester *videoIngester pc *webrtc.PeerConnection - // root api object + // We should dispose it. api *TestWebRTCAPI // Optional suffix for stream url. streamSuffix string + // To cancel the publisher, pass by Run. + cancel context.CancelFunc } -func NewTestPublisher(api *TestWebRTCAPI, options ...TestPublisherOptionFunc) (*TestPublisher, error) { +func CreateApiForPublisher(pub *TestPublisher) error { + api, err := NewTestWebRTCAPI() + if err != nil { + return err + } + + pub.api = api + return nil +} + +func NewTestPublisher(options ...TestPublisherOptionFunc) (*TestPublisher, error) { sourceVideo, sourceAudio := *srsPublishVideo, *srsPublishAudio - v := &TestPublisher{api: api} + v := &TestPublisher{} for _, opt := range options { if err := opt(v); err != nil { @@ -835,9 +873,6 @@ func NewTestPublisher(api *TestWebRTCAPI, options ...TestPublisherOptionFunc) (* } } - // The api might be override by options. - api = v.api - // Create ingesters. if sourceAudio != "" { v.aIngester = NewAudioIngester(sourceAudio) @@ -847,6 +882,7 @@ func NewTestPublisher(api *TestWebRTCAPI, options ...TestPublisherOptionFunc) (* } // Setup the interceptors for packets. + api := v.api api.options = append(api.options, func(api *TestWebRTCAPI) { // Filter for RTCP packets. rtcpInterceptor := &RTCPInterceptor{} @@ -870,17 +906,25 @@ func NewTestPublisher(api *TestWebRTCAPI, options ...TestPublisherOptionFunc) (* return v, nil } +func (v *TestPublisher) Setup(vnetClientIP string, options ...TestWebRTCAPIOptionFunc) error { + return v.api.Setup(vnetClientIP, options...) +} + func (v *TestPublisher) Close() error { if v.vIngester != nil { - v.vIngester.Close() + _ = v.vIngester.Close() } if v.aIngester != nil { - v.aIngester.Close() + _ = v.aIngester.Close() } if v.pc != nil { - v.pc.Close() + _ = v.pc.Close() + } + + if v.api != nil { + _ = v.api.Close() } return nil @@ -892,6 +936,9 @@ func (v *TestPublisher) SetStreamSuffix(suffix string) *TestPublisher { } func (v *TestPublisher) Run(ctx context.Context, cancel context.CancelFunc) error { + // Save the cancel. + v.cancel = cancel + r := fmt.Sprintf("%v://%v%v", srsSchema, *srsServer, *srsStream) if v.streamSuffix != "" { r = fmt.Sprintf("%v-%v", r, v.streamSuffix) @@ -1012,11 +1059,17 @@ func (v *TestPublisher) Run(ctx context.Context, cancel context.CancelFunc) erro <-ctx.Done() if v.aIngester != nil && v.aIngester.sAudioSender != nil { - v.aIngester.sAudioSender.Stop() + // We MUST wait for the ingester ready(or closed), because it might crash if sender is disposed. + <-v.aIngester.ready.Done() + + _ = v.aIngester.Close() } if v.vIngester != nil && v.vIngester.sVideoSender != nil { - v.vIngester.sVideoSender.Stop() + // We MUST wait for the ingester ready(or closed), because it might crash if sender is disposed. + <-v.vIngester.ready.Done() + + _ = v.vIngester.Close() } }() @@ -1028,6 +1081,7 @@ func (v *TestPublisher) Run(ctx context.Context, cancel context.CancelFunc) erro if v.aIngester == nil { return } + defer v.aIngester.readyCancel() select { case <-ctx.Done(): @@ -1072,6 +1126,7 @@ func (v *TestPublisher) Run(ctx context.Context, cancel context.CancelFunc) erro if v.vIngester == nil { return } + defer v.vIngester.readyCancel() select { case <-ctx.Done(): @@ -1119,47 +1174,3 @@ func (v *TestPublisher) Run(ctx context.Context, cancel context.CancelFunc) erro } return ctx.Err() } - -func TestRTCServerVersion(t *testing.T) { - api := fmt.Sprintf("http://%v:1985/api/v1/versions", *srsServer) - req, err := http.NewRequest("POST", api, nil) - if err != nil { - t.Errorf("Request %v", api) - return - } - - res, err := http.DefaultClient.Do(req) - if err != nil { - t.Errorf("Do request %v", api) - return - } - - b, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Errorf("Read body of %v", api) - return - } - - obj := struct { - Code int `json:"code"` - Server string `json:"server"` - Data struct { - Major int `json:"major"` - Minor int `json:"minor"` - Revision int `json:"revision"` - Version string `json:"version"` - } `json:"data"` - }{} - if err := json.Unmarshal(b, &obj); err != nil { - t.Errorf("Parse %v", string(b)) - return - } - if obj.Code != 0 { - t.Errorf("Server err code=%v, server=%v", obj.Code, obj.Server) - return - } - if obj.Data.Major == 0 && obj.Data.Minor == 0 { - t.Errorf("Invalid version %v", obj.Data) - return - } -} diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index e6afab909..8e5928a06 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -605,7 +605,7 @@ srs_error_t SrsRtcPlayStream::send_packet(SrsRtpPacket2*& pkt) // TODO: FIXME: Maybe refine for performance issue. if (!audio_tracks_.count(pkt->header.get_ssrc()) && !video_tracks_.count(pkt->header.get_ssrc())) { - srs_warn("ssrc %u not found", pkt->header.get_ssrc()); + srs_warn("RTC: Drop for ssrc %u not found", pkt->header.get_ssrc()); return err; } From f5ff28d47a37c5e77e15683ba40fbc2000d584cb Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 24 Mar 2021 10:50:13 +0800 Subject: [PATCH 3/3] RTC: Refine play stream init --- trunk/src/app/srs_app_rtc_conn.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 8e5928a06..536ab2d10 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -429,19 +429,18 @@ srs_error_t SrsRtcPlayStream::initialize(SrsRequest* req, std::map::iterator it = sub_relations.begin(); - while (it != sub_relations.end()) { - if (it->second->type_ == "audio") { - SrsRtcAudioSendTrack* track = new SrsRtcAudioSendTrack(session_, it->second); - audio_tracks_.insert(make_pair(it->first, track)); - } + for (map::iterator it = sub_relations.begin(); it != sub_relations.end(); ++it) { + uint32_t ssrc = it->first; + SrsRtcTrackDescription* desc = it->second; - if (it->second->type_ == "video") { - SrsRtcVideoSendTrack* track = new SrsRtcVideoSendTrack(session_, it->second); - video_tracks_.insert(make_pair(it->first, track)); - } - ++it; + if (desc->type_ == "audio") { + SrsRtcAudioSendTrack* track = new SrsRtcAudioSendTrack(session_, desc); + audio_tracks_.insert(make_pair(ssrc, track)); + } + + if (desc->type_ == "video") { + SrsRtcVideoSendTrack* track = new SrsRtcVideoSendTrack(session_, desc); + video_tracks_.insert(make_pair(ssrc, track)); } }