diff --git a/codec.go b/codec.go index a01b6bc0..5b648f5e 100644 --- a/codec.go +++ b/codec.go @@ -9,7 +9,7 @@ import ( "github.com/pion/mediadevices/pkg/io/audio" "github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/prop" - "github.com/pion/webrtc/v2" + "github.com/pion/webrtc/v3" ) // CodecSelector is a container of video and audio encoder builders, which later will be used @@ -50,14 +50,15 @@ func NewCodecSelector(opts ...CodecSelectorOption) *CodecSelector { // Populate lets the webrtc engine be aware of supported codecs that are contained in CodecSelector func (selector *CodecSelector) Populate(setting *webrtc.MediaEngine) { for _, encoder := range selector.videoEncoders { - setting.RegisterCodec(encoder.RTPCodec().RTPCodec) + setting.RegisterCodec(encoder.RTPCodec().RTPCodecParameters, webrtc.RTPCodecTypeVideo) } for _, encoder := range selector.audioEncoders { - setting.RegisterCodec(encoder.RTPCodec().RTPCodec) + setting.RegisterCodec(encoder.RTPCodec().RTPCodecParameters, webrtc.RTPCodecTypeAudio) } } +// selectVideoCodecByNames selects a single codec that can be built and matched. codecNames can be formatted as "video/" or "" func (selector *CodecSelector) selectVideoCodecByNames(reader video.Reader, inputProp prop.Media, codecNames ...string) (codec.ReadCloser, *codec.RTPCodec, error) { var selectedEncoder codec.VideoEncoderBuilder var encodedReader codec.ReadCloser @@ -66,8 +67,10 @@ func (selector *CodecSelector) selectVideoCodecByNames(reader video.Reader, inpu outer: for _, wantCodec := range codecNames { + wantCodecLower := strings.ToLower(wantCodec) for _, encoder := range selector.videoEncoders { - if encoder.RTPCodec().Name == wantCodec { + // MimeType is formated as "video/" + if strings.HasSuffix(strings.ToLower(encoder.RTPCodec().MimeType), wantCodecLower) { encodedReader, err = encoder.BuildVideoEncoder(reader, inputProp) if err == nil { selectedEncoder = encoder @@ -75,7 +78,7 @@ outer: } } - errReasons = append(errReasons, fmt.Sprintf("%s: %s", encoder.RTPCodec().Name, err)) + errReasons = append(errReasons, fmt.Sprintf("%s: %s", encoder.RTPCodec().MimeType, err)) } } @@ -86,16 +89,17 @@ outer: return encodedReader, selectedEncoder.RTPCodec(), nil } -func (selector *CodecSelector) selectVideoCodec(reader video.Reader, inputProp prop.Media, codecs ...*webrtc.RTPCodec) (codec.ReadCloser, *codec.RTPCodec, error) { +func (selector *CodecSelector) selectVideoCodec(reader video.Reader, inputProp prop.Media, codecs ...webrtc.RTPCodecParameters) (codec.ReadCloser, *codec.RTPCodec, error) { var codecNames []string for _, codec := range codecs { - codecNames = append(codecNames, codec.Name) + codecNames = append(codecNames, codec.MimeType) } return selector.selectVideoCodecByNames(reader, inputProp, codecNames...) } +// selectAudioCodecByNames selects a single codec that can be built and matched. codecNames can be formatted as "audio/" or "" func (selector *CodecSelector) selectAudioCodecByNames(reader audio.Reader, inputProp prop.Media, codecNames ...string) (codec.ReadCloser, *codec.RTPCodec, error) { var selectedEncoder codec.AudioEncoderBuilder var encodedReader codec.ReadCloser @@ -104,8 +108,10 @@ func (selector *CodecSelector) selectAudioCodecByNames(reader audio.Reader, inpu outer: for _, wantCodec := range codecNames { + wantCodecLower := strings.ToLower(wantCodec) for _, encoder := range selector.audioEncoders { - if encoder.RTPCodec().Name == wantCodec { + // MimeType is formated as "audio/" + if strings.HasSuffix(strings.ToLower(encoder.RTPCodec().MimeType), wantCodecLower) { encodedReader, err = encoder.BuildAudioEncoder(reader, inputProp) if err == nil { selectedEncoder = encoder @@ -113,7 +119,7 @@ outer: } } - errReasons = append(errReasons, fmt.Sprintf("%s: %s", encoder.RTPCodec().Name, err)) + errReasons = append(errReasons, fmt.Sprintf("%s: %s", encoder.RTPCodec().MimeType, err)) } } @@ -124,11 +130,11 @@ outer: return encodedReader, selectedEncoder.RTPCodec(), nil } -func (selector *CodecSelector) selectAudioCodec(reader audio.Reader, inputProp prop.Media, codecs ...*webrtc.RTPCodec) (codec.ReadCloser, *codec.RTPCodec, error) { +func (selector *CodecSelector) selectAudioCodec(reader audio.Reader, inputProp prop.Media, codecs ...webrtc.RTPCodecParameters) (codec.ReadCloser, *codec.RTPCodec, error) { var codecNames []string for _, codec := range codecs { - codecNames = append(codecNames, codec.Name) + codecNames = append(codecNames, codec.MimeType) } return selector.selectAudioCodecByNames(reader, inputProp, codecNames...) diff --git a/examples/archive/archive b/examples/archive/archive deleted file mode 100755 index ea99e8e9..00000000 Binary files a/examples/archive/archive and /dev/null differ diff --git a/examples/archive/main.go b/examples/archive/main.go index 152c0cfa..967d4c28 100644 --- a/examples/archive/main.go +++ b/examples/archive/main.go @@ -68,7 +68,7 @@ func main() { }) })) - reader, err := videoTrack.NewEncodedReader(x264Params.RTPCodec().Name) + reader, err := videoTrack.NewEncodedIOReader(x264Params.RTPCodec().MimeType) must(err) defer reader.Close() diff --git a/examples/rtp/main.go b/examples/rtp/main.go index 0f838859..ca0c2fa7 100644 --- a/examples/rtp/main.go +++ b/examples/rtp/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "math/rand" "net" "os" @@ -51,7 +52,7 @@ func main() { videoTrack := mediaStream.GetVideoTracks()[0] defer videoTrack.Close() - rtpReader, err := videoTrack.NewRTPReader(x264Params.RTPCodec().Name, mtu) + rtpReader, err := videoTrack.NewRTPReader(x264Params.RTPCodec().MimeType, rand.Uint32(), mtu) must(err) addr, err := net.ResolveUDPAddr("udp", dest) diff --git a/examples/webrtc/main.go b/examples/webrtc/main.go index 0df32fc2..f36402d7 100644 --- a/examples/webrtc/main.go +++ b/examples/webrtc/main.go @@ -7,7 +7,7 @@ import ( "github.com/pion/mediadevices/examples/internal/signal" "github.com/pion/mediadevices/pkg/frame" "github.com/pion/mediadevices/pkg/prop" - "github.com/pion/webrtc/v2" + "github.com/pion/webrtc/v3" // If you don't like x264, you can also use vpx by importing as below // "github.com/pion/mediadevices/pkg/codec/vpx" // This is required to use VP8/VP9 video encoder @@ -57,10 +57,7 @@ func main() { mediaEngine := webrtc.MediaEngine{} codecSelector.Populate(&mediaEngine) - if err := mediaEngine.PopulateFromSDP(offer); err != nil { - panic(err) - } - api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine)) + api := webrtc.NewAPI(webrtc.WithMediaEngine(&mediaEngine)) peerConnection, err := api.NewPeerConnection(config) if err != nil { panic(err) @@ -86,19 +83,13 @@ func main() { panic(err) } - for _, tracker := range s.GetTracks() { - tracker.OnEnded(func(err error) { + for _, track := range s.GetTracks() { + track.OnEnded(func(err error) { fmt.Printf("Track (ID: %s) ended with error: %v\n", - tracker.ID(), err) + track.ID(), err) }) - // In Pion/webrtc v3, bind will be called automatically after SDP negotiation - webrtcTrack, err := tracker.Bind(peerConnection) - if err != nil { - panic(err) - } - - _, err = peerConnection.AddTransceiverFromTrack(webrtcTrack, + _, err = peerConnection.AddTransceiverFromTrack(track, webrtc.RtpTransceiverInit{ Direction: webrtc.RTPTransceiverDirectionSendonly, }, diff --git a/go.mod b/go.mod index f7bd93a1..e582b62a 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,14 @@ require ( github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539 github.com/gen2brain/malgo v0.10.27 github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect + github.com/google/uuid v1.1.2 github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f github.com/lxn/win v0.0.0-20201111105847-2a20daff6a55 // indirect github.com/pion/logging v0.2.2 github.com/pion/rtp v1.6.2 - github.com/pion/webrtc/v2 v2.2.26 + github.com/pion/webrtc/v3 v3.0.0 github.com/satori/go.uuid v1.2.0 golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) diff --git a/go.sum b/go.sum index 4afad564..2c396307 100644 --- a/go.sum +++ b/go.sum @@ -2,84 +2,85 @@ github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd h1:u7K2oMFMd8APDV3f github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539 h1:1aIqYfg9s9RETAJHGfVKZW4ok0b22p4QTwk8MsdRtPs= github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539/go.mod h1:G0X+rEqYPWSq0dG8OMf8M446MtKytzpPjgS3HbdOJZ4= -github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= -github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gen2brain/malgo v0.10.27 h1:KlNitZIO8V4W2VnjtTM8AGMy/XBb2pN+fnIB5bEps8E= github.com/gen2brain/malgo v0.10.27/go.mod h1:zHSUNZAXfCeNsZou0RtQ6Zk7gDYLIcKOrUWtAdksnEs= github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY= github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo= -github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f h1:5hWo+DzJQSOBl6X+TDac0SPWffRonuRJ2///OYtYRT8= github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f/go.mod h1:f8GY5V3lRzakvEyr49P7hHRYoHtPr8zvj/7JodCoRzw= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lucas-clemente/quic-go v0.7.1-0.20190401152353-907071221cf9 h1:tbuodUh2vuhOVZAdW3NEUvosFHUMJwUNl7jk/VSEiwc= -github.com/lucas-clemente/quic-go v0.7.1-0.20190401152353-907071221cf9/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/lxn/win v0.0.0-20201111105847-2a20daff6a55 h1:4BxFx5XCtXc+nFtXDGDW+Uu5sPtsAbvPh6RObj3fG9o= github.com/lxn/win v0.0.0-20201111105847-2a20daff6a55/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= -github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA= -github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/pion/datachannel v1.4.21 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0= github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg= -github.com/pion/dtls/v2 v2.0.1/go.mod h1:uMQkz2W0cSqY00xav7WByQ4Hb+18xeQh2oH2fRezr5U= -github.com/pion/dtls/v2 v2.0.2 h1:FHCHTiM182Y8e15aFTiORroiATUI16ryHiQh8AIOJ1E= -github.com/pion/dtls/v2 v2.0.2/go.mod h1:27PEO3MDdaCfo21heT59/vsdmZc0zMt9wQPcSlLu/1I= -github.com/pion/ice v0.7.18 h1:KbAWlzWRUdX9SmehBh3gYpIFsirjhSQsCw6K2MjYMK0= -github.com/pion/ice v0.7.18/go.mod h1:+Bvnm3nYC6Nnp7VV6glUkuOfToB/AtMRZpOU8ihuf4c= +github.com/pion/dtls/v2 v2.0.4 h1:WuUcqi6oYMu/noNTz92QrF1DaFj4eXbhQ6dzaaAwOiI= +github.com/pion/dtls/v2 v2.0.4/go.mod h1:qAkFscX0ZHoI1E07RfYPoRw3manThveu+mlTDdOxoGI= +github.com/pion/ice/v2 v2.0.14 h1:FxXxauyykf89SWAtkQCfnHkno6G8+bhRkNguSh9zU+4= +github.com/pion/ice/v2 v2.0.14/go.mod h1:wqaUbOq5ObDNU5ox1hRsEst0rWfsKuH1zXjQFEWiZwM= +github.com/pion/interceptor v0.0.8 h1:qsVJv9RF7mPq/RUnUV5iZCzxwGizO880FuiFKkEGQaE= +github.com/pion/interceptor v0.0.8/go.mod h1:dHgEP5dtxOTf21MObuBAjJeAayPxLUAZjerGH8Xr07c= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY= github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0= -github.com/pion/quic v0.1.1 h1:D951FV+TOqI9A0rTF7tHx0Loooqz+nyzjEyj8o3PuMA= -github.com/pion/quic v0.1.1/go.mod h1:zEU51v7ru8Mp4AUBJvj6psrSth5eEFNnVQK5K48oV3k= -github.com/pion/randutil v0.0.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.3 h1:2wrhKnqgSz91Q5nzYTO07mQXztYPtxL8a0XOss4rJqA= -github.com/pion/rtcp v1.2.3/go.mod h1:zGhIv0RPRF0Z1Wiij22pUt5W/c9fevqSzT4jje/oK7I= -github.com/pion/rtp v1.6.0 h1:4Ssnl/T5W2LzxHj9ssYpGVEQh3YYhQFNVmSWO88MMwk= -github.com/pion/rtp v1.6.0/go.mod h1:QgfogHsMBVE/RFNno467U/KBqfUywEH+HK+0rtnwsdI= +github.com/pion/rtcp v1.2.4/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0= +github.com/pion/rtcp v1.2.6 h1:1zvwBbyd0TeEuuWftrd/4d++m+/kZSeiguxU61LFWpo= +github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0= +github.com/pion/rtp v1.6.1/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U= github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= -github.com/pion/sctp v1.7.10 h1:o3p3/hZB5Cx12RMGyWmItevJtZ6o2cpuxaw6GOS4x+8= github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0= -github.com/pion/sdp/v2 v2.4.0 h1:luUtaETR5x2KNNpvEMv/r4Y+/kzImzbz4Lm1z8eQNQI= -github.com/pion/sdp/v2 v2.4.0/go.mod h1:L2LxrOpSTJbAns244vfPChbciR/ReU1KWfG04OpkR7E= -github.com/pion/srtp v1.5.1 h1:9Q3jAfslYZBt+C69SI/ZcONJh9049JUHZWYRRf5KEKw= -github.com/pion/srtp v1.5.1/go.mod h1:B+QgX5xPeQTNc1CJStJPHzOlHK66ViMDWTT0HZTCkcA= +github.com/pion/sctp v1.7.11 h1:UCnj7MsobLKLuP/Hh+JMiI/6W5Bs/VF45lWKgHFjSIE= +github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0= +github.com/pion/sdp/v3 v3.0.3 h1:gJK9hk+JFD2NGIM1nXmqNCq1DkVaIZ9dlA3u3otnkaw= +github.com/pion/sdp/v3 v3.0.3/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk= +github.com/pion/srtp/v2 v2.0.0-rc.3 h1:1fPiK1nJlNyh235tSGgBnXrPc99wK1/D707f6ntb3qY= +github.com/pion/srtp/v2 v2.0.0-rc.3/go.mod h1:S6J9oY6ahAXdU3ni4nUwhWTJuBfssFjPxoB0u41TBpY= github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg= github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= -github.com/pion/transport v0.6.0/go.mod h1:iWZ07doqOosSLMhZ+FXUTq+TamDoXSllxpbGcfkCmbE= github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8= github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE= -github.com/pion/transport v0.10.1 h1:2W+yJT+0mOQ160ThZYUx5Zp2skzshiNgxrNE9GUfhJM= github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A= -github.com/pion/turn/v2 v2.0.4 h1:oDguhEv2L/4rxwbL9clGLgtzQPjtuZwCdoM7Te8vQVk= -github.com/pion/turn/v2 v2.0.4/go.mod h1:1812p4DcGVbYVBTiraUmP50XoKye++AMkbfp+N27mog= +github.com/pion/transport v0.12.0 h1:UFmOBBZkTZ3LgvLRf/NGrfWdZEubcU6zkLU3PsA9YvU= +github.com/pion/transport v0.12.0/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= +github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA= +github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw= github.com/pion/udp v0.1.0 h1:uGxQsNyrqG3GLINv36Ff60covYmfrLoxzwnCsIYspXI= github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths= -github.com/pion/webrtc/v2 v2.2.26 h1:01hWE26pL3LgqfxvQ1fr6O4ZtyRFFJmQEZK39pHWfFc= -github.com/pion/webrtc/v2 v2.2.26/go.mod h1:XMZbZRNHyPDe1gzTIHFcQu02283YO45CbiwFgKvXnmc= +github.com/pion/webrtc/v3 v3.0.0 h1:/eTiY3NbfpKj5op8cqtCZlpTv9/yumd17YRinDNOUX0= +github.com/pion/webrtc/v3 v3.0.0/go.mod h1:/xwKHOAk1Y8dspJcxMwuTtxpi8t/Gzks37iB3W6hNuM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -88,51 +89,60 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7 h1:3uJsdck53FDIpWwLeAXlia9p4C8j0BO2xZrqzKpL0D8= +golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM= golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/mediastream.go b/mediastream.go index 5ddb62d1..f6cbc63b 100644 --- a/mediastream.go +++ b/mediastream.go @@ -2,6 +2,8 @@ package mediadevices import ( "sync" + + "github.com/pion/webrtc/v3" ) // MediaStream is an interface that represents a collection of existing tracks. @@ -23,7 +25,7 @@ type mediaStream struct { l sync.RWMutex } -const trackTypeDefault MediaDeviceType = 0 +const trackTypeDefault webrtc.RTPCodecType = 0 // NewMediaStream creates a MediaStream interface that's defined in // https://w3c.github.io/mediacapture-main/#dom-mediastream @@ -40,11 +42,11 @@ func NewMediaStream(tracks ...Track) (MediaStream, error) { } func (m *mediaStream) GetAudioTracks() []Track { - return m.queryTracks(AudioInput) + return m.queryTracks(webrtc.RTPCodecTypeAudio) } func (m *mediaStream) GetVideoTracks() []Track { - return m.queryTracks(VideoInput) + return m.queryTracks(webrtc.RTPCodecTypeVideo) } func (m *mediaStream) GetTracks() []Track { @@ -53,7 +55,7 @@ func (m *mediaStream) GetTracks() []Track { // queryTracks returns all tracks that are the same kind as t. // If t is 0, which is the default, queryTracks will return all the tracks. -func (m *mediaStream) queryTracks(t MediaDeviceType) []Track { +func (m *mediaStream) queryTracks(t webrtc.RTPCodecType) []Track { m.l.RLock() defer m.l.RUnlock() diff --git a/mediastream_test.go b/mediastream_test.go index 609f1cbe..4d432b58 100644 --- a/mediastream_test.go +++ b/mediastream_test.go @@ -4,7 +4,7 @@ import ( "io" "testing" - "github.com/pion/webrtc/v2" + "github.com/pion/webrtc/v3" ) type mockMediaStreamTrack struct { @@ -15,26 +15,37 @@ func (track *mockMediaStreamTrack) ID() string { return "" } +func (track *mockMediaStreamTrack) StreamID() string { + return "" +} + func (track *mockMediaStreamTrack) Close() error { return nil } -func (track *mockMediaStreamTrack) Kind() MediaDeviceType { - return track.kind +func (track *mockMediaStreamTrack) Kind() webrtc.RTPCodecType { + switch track.kind { + case AudioInput: + return webrtc.RTPCodecTypeAudio + case VideoInput: + return webrtc.RTPCodecTypeVideo + default: + panic("invalid track kind") + } } func (track *mockMediaStreamTrack) OnEnded(handler func(error)) { } -func (track *mockMediaStreamTrack) Bind(pc *webrtc.PeerConnection) (*webrtc.Track, error) { - return nil, nil +func (track *mockMediaStreamTrack) Bind(ctx webrtc.TrackLocalContext) (webrtc.RTPCodecParameters, error) { + return webrtc.RTPCodecParameters{}, nil } -func (track *mockMediaStreamTrack) Unbind(pc *webrtc.PeerConnection) error { +func (track *mockMediaStreamTrack) Unbind(ctx webrtc.TrackLocalContext) error { return nil } -func (track *mockMediaStreamTrack) NewRTPReader(codecName string, mtu int) (RTPReadCloser, error) { +func (track *mockMediaStreamTrack) NewRTPReader(codecName string, ssrc uint32, mtu int) (RTPReadCloser, error) { return nil, nil } diff --git a/pkg/codec/codec.go b/pkg/codec/codec.go index 322d9bca..fc64395d 100644 --- a/pkg/codec/codec.go +++ b/pkg/codec/codec.go @@ -4,32 +4,83 @@ import ( "github.com/pion/mediadevices/pkg/io/audio" "github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/prop" - "github.com/pion/webrtc/v2" + "github.com/pion/rtp" + "github.com/pion/rtp/codecs" + "github.com/pion/webrtc/v3" ) // RTPCodec wraps webrtc.RTPCodec. RTPCodec might extend webrtc.RTPCodec in the future. type RTPCodec struct { - *webrtc.RTPCodec + webrtc.RTPCodecParameters + rtp.Payloader } // NewRTPH264Codec is a helper to create an H264 codec func NewRTPH264Codec(clockrate uint32) *RTPCodec { - return &RTPCodec{webrtc.NewRTPH264Codec(webrtc.DefaultPayloadTypeH264, clockrate)} + return &RTPCodec{ + RTPCodecParameters: webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: webrtc.MimeTypeH264, + ClockRate: 90000, + Channels: 0, + SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", + RTCPFeedback: nil, + }, + PayloadType: 125, + }, + Payloader: &codecs.H264Payloader{}, + } } // NewRTPVP8Codec is a helper to create an VP8 codec func NewRTPVP8Codec(clockrate uint32) *RTPCodec { - return &RTPCodec{webrtc.NewRTPVP8Codec(webrtc.DefaultPayloadTypeVP8, clockrate)} + return &RTPCodec{ + RTPCodecParameters: webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: webrtc.MimeTypeVP8, + ClockRate: 90000, + Channels: 0, + SDPFmtpLine: "", + RTCPFeedback: nil, + }, + PayloadType: 96, + }, + Payloader: &codecs.VP8Payloader{}, + } } // NewRTPVP9Codec is a helper to create an VP9 codec func NewRTPVP9Codec(clockrate uint32) *RTPCodec { - return &RTPCodec{webrtc.NewRTPVP9Codec(webrtc.DefaultPayloadTypeVP9, clockrate)} + return &RTPCodec{ + RTPCodecParameters: webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: webrtc.MimeTypeVP9, + ClockRate: 90000, + Channels: 0, + SDPFmtpLine: "", + RTCPFeedback: nil, + }, + PayloadType: 98, + }, + Payloader: &codecs.VP9Payloader{}, + } } // NewRTPOpusCodec is a helper to create an Opus codec func NewRTPOpusCodec(clockrate uint32) *RTPCodec { - return &RTPCodec{webrtc.NewRTPOpusCodec(webrtc.DefaultPayloadTypeOpus, clockrate)} + return &RTPCodec{ + RTPCodecParameters: webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: webrtc.MimeTypeOpus, + ClockRate: 48000, + Channels: 2, + SDPFmtpLine: "minptime=10;useinbandfec=1", + RTCPFeedback: nil, + }, + PayloadType: 111, + }, + Payloader: &codecs.OpusPayloader{}, + } } // AudioEncoderBuilder is the interface that wraps basic operations that are diff --git a/track.go b/track.go index 56263d3b..fd19b5f7 100644 --- a/track.go +++ b/track.go @@ -2,19 +2,24 @@ package mediadevices import ( "errors" + "fmt" "image" "io" - "math/rand" + "strings" "sync" + "github.com/google/uuid" "github.com/pion/mediadevices/pkg/codec" "github.com/pion/mediadevices/pkg/driver" "github.com/pion/mediadevices/pkg/io/audio" "github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/wave" "github.com/pion/rtp" - "github.com/pion/webrtc/v2" - "github.com/pion/webrtc/v2/pkg/media" + "github.com/pion/webrtc/v3" +) + +const ( + rtpOutboundMTU = 1200 ) var ( @@ -48,16 +53,18 @@ type Track interface { // If the error is already occured before registering, the handler will be // immediately called. OnEnded(func(error)) - Kind() MediaDeviceType + Kind() webrtc.RTPCodecType + // StreamID is the group this track belongs too. This must be unique + StreamID() string // Bind binds the current track source to the given peer connection. In Pion/webrtc v3, the bind // call will happen automatically after the SDP negotiation. Users won't need to call this manually. - Bind(*webrtc.PeerConnection) (*webrtc.Track, error) + Bind(webrtc.TrackLocalContext) (webrtc.RTPCodecParameters, error) // Unbind is the clean up operation that should be called after Bind. Similar to Bind, unbind will - // be called automatically in the future. - Unbind(*webrtc.PeerConnection) error + // be called automatically in Pion/webrtc v3. + Unbind(webrtc.TrackLocalContext) error // NewRTPReader creates a new reader from the source. The reader will encode the source, and packetize // the encoded data in RTP format with given mtu size. - NewRTPReader(codecName string, mtu int) (RTPReadCloser, error) + NewRTPReader(codecName string, ssrc uint32, mtu int) (RTPReadCloser, error) // NewEncodedReader creates a EncodedReadCloser that reads the encoded data in codecName format NewEncodedReader(codecName string) (EncodedReadCloser, error) // NewEncodedReader creates a new Go standard io.ReadCloser that reads the encoded data in codecName format @@ -72,7 +79,7 @@ type baseTrack struct { endOnce sync.Once kind MediaDeviceType selector *CodecSelector - activePeerConnections map[*webrtc.PeerConnection]chan<- chan<- struct{} + activePeerConnections map[string]chan<- chan<- struct{} } func newBaseTrack(source Source, kind MediaDeviceType, selector *CodecSelector) *baseTrack { @@ -80,13 +87,30 @@ func newBaseTrack(source Source, kind MediaDeviceType, selector *CodecSelector) Source: source, kind: kind, selector: selector, - activePeerConnections: make(map[*webrtc.PeerConnection]chan<- chan<- struct{}), + activePeerConnections: make(map[string]chan<- chan<- struct{}), } } // Kind returns track's kind -func (track *baseTrack) Kind() MediaDeviceType { - return track.kind +func (track *baseTrack) Kind() webrtc.RTPCodecType { + switch track.kind { + case VideoInput: + return webrtc.RTPCodecTypeVideo + case AudioInput: + return webrtc.RTPCodecTypeAudio + default: + panic("invalid track kind: only support VideoInput and AudioInput") + } +} + +func (track *baseTrack) StreamID() string { + // TODO: StreamID should be used to group multiple tracks. Should get this information from mediastream instead. + generator, err := uuid.NewRandom() + if err != nil { + panic(err) + } + + return generator.String() } // OnEnded sets an error handler. When a track has been created and started, if an @@ -119,20 +143,35 @@ func (track *baseTrack) onError(err error) { } } -func (track *baseTrack) bind(pc *webrtc.PeerConnection, encodedReader codec.ReadCloser, selectedCodec *codec.RTPCodec, sample samplerFunc) (*webrtc.Track, error) { +func (track *baseTrack) bind(ctx webrtc.TrackLocalContext, specializedTrack Track) (webrtc.RTPCodecParameters, error) { track.mu.Lock() defer track.mu.Unlock() - webrtcTrack, err := pc.NewTrack(selectedCodec.PayloadType, rand.Uint32(), track.ID(), selectedCodec.MimeType) - if err != nil { - return nil, err + signalCh := make(chan chan<- struct{}) + track.activePeerConnections[ctx.ID()] = signalCh + + var encodedReader RTPReadCloser + var selectedCodec webrtc.RTPCodecParameters + var err error + var errReasons []string + for _, wantedCodec := range ctx.CodecParameters() { + logger.Debugf("trying to build %s rtp reader", wantedCodec.MimeType) + encodedReader, err = specializedTrack.NewRTPReader(wantedCodec.MimeType, uint32(ctx.SSRC()), rtpOutboundMTU) + if err == nil { + selectedCodec = wantedCodec + break + } + + errReasons = append(errReasons, fmt.Sprintf("%s: %s", wantedCodec.MimeType, err)) } - signalCh := make(chan chan<- struct{}) - track.activePeerConnections[pc] = signalCh + if encodedReader == nil { + return webrtc.RTPCodecParameters{}, errors.New(strings.Join(errReasons, "\n\n")) + } go func() { var doneCh chan<- struct{} + writer := ctx.WriteStream() defer func() { encodedReader.Close() @@ -150,32 +189,30 @@ func (track *baseTrack) bind(pc *webrtc.PeerConnection, encodedReader codec.Read default: } - buff, _, err := encodedReader.Read() + pkts, _, err := encodedReader.Read() if err != nil { - track.onError(err) + // explicitly ignore this error since the higher level should've reported this return } - sampleCount := sample() - err = webrtcTrack.WriteSample(media.Sample{ - Data: buff, - Samples: sampleCount, - }) - if err != nil { - track.onError(err) - return + for _, pkt := range pkts { + _, err = writer.WriteRTP(&pkt.Header, pkt.Payload) + if err != nil { + track.onError(err) + return + } } } }() - return webrtcTrack, nil + return selectedCodec, nil } -func (track *baseTrack) unbind(pc *webrtc.PeerConnection) error { +func (track *baseTrack) unbind(ctx webrtc.TrackLocalContext) error { track.mu.Lock() defer track.mu.Unlock() - ch, ok := track.activePeerConnections[pc] + ch, ok := track.activePeerConnections[ctx.ID()] if !ok { return errNotFoundPeerConnection } @@ -183,7 +220,7 @@ func (track *baseTrack) unbind(pc *webrtc.PeerConnection) error { doneCh := make(chan struct{}) ch <- doneCh <-doneCh - delete(track.activePeerConnections, pc) + delete(track.activePeerConnections, ctx.ID()) return nil } @@ -248,24 +285,12 @@ func (track *VideoTrack) Transform(fns ...video.TransformFunc) { track.Broadcaster.ReplaceSource(video.Merge(fns...)(src)) } -func (track *VideoTrack) Bind(pc *webrtc.PeerConnection) (*webrtc.Track, error) { - reader := track.NewReader(false) - inputProp, err := detectCurrentVideoProp(track.Broadcaster) - if err != nil { - return nil, err - } - - wantCodecs := pc.GetRegisteredRTPCodecs(webrtc.RTPCodecTypeVideo) - encodedReader, selectedCodec, err := track.selector.selectVideoCodec(reader, inputProp, wantCodecs...) - if err != nil { - return nil, err - } - - return track.bind(pc, encodedReader, selectedCodec, newVideoSampler(selectedCodec.ClockRate)) +func (track *VideoTrack) Bind(ctx webrtc.TrackLocalContext) (webrtc.RTPCodecParameters, error) { + return track.bind(ctx, track) } -func (track *VideoTrack) Unbind(pc *webrtc.PeerConnection) error { - return track.unbind(pc) +func (track *VideoTrack) Unbind(ctx webrtc.TrackLocalContext) error { + return track.unbind(ctx) } func (track *VideoTrack) newEncodedReader(codecNames ...string) (EncodedReadCloser, *codec.RTPCodec, error) { @@ -308,14 +333,13 @@ func (track *VideoTrack) NewEncodedIOReader(codecName string) (io.ReadCloser, er return newEncodedIOReadCloserImpl(encodedReader), nil } -func (track *VideoTrack) NewRTPReader(codecName string, mtu int) (RTPReadCloser, error) { +func (track *VideoTrack) NewRTPReader(codecName string, ssrc uint32, mtu int) (RTPReadCloser, error) { encodedReader, selectedCodec, err := track.newEncodedReader(codecName) if err != nil { return nil, err } - // FIXME: not sure the best way to get unique ssrc. We probably should have a global keeper that can generate a random ID and does book keeping? - packetizer := rtp.NewPacketizer(mtu, selectedCodec.PayloadType, rand.Uint32(), selectedCodec.Payloader, rtp.NewRandomSequencer(), selectedCodec.ClockRate) + packetizer := rtp.NewPacketizer(mtu, uint8(selectedCodec.PayloadType), ssrc, selectedCodec.Payloader, rtp.NewRandomSequencer(), selectedCodec.ClockRate) return &rtpReadCloserImpl{ readFn: func() ([]*rtp.Packet, func(), error) { @@ -381,24 +405,12 @@ func (track *AudioTrack) Transform(fns ...audio.TransformFunc) { track.Broadcaster.ReplaceSource(audio.Merge(fns...)(src)) } -func (track *AudioTrack) Bind(pc *webrtc.PeerConnection) (*webrtc.Track, error) { - reader := track.NewReader(false) - inputProp, err := detectCurrentAudioProp(track.Broadcaster) - if err != nil { - return nil, err - } - - wantCodecs := pc.GetRegisteredRTPCodecs(webrtc.RTPCodecTypeAudio) - encodedReader, selectedCodec, err := track.selector.selectAudioCodec(reader, inputProp, wantCodecs...) - if err != nil { - return nil, err - } - - return track.bind(pc, encodedReader, selectedCodec, newAudioSampler(selectedCodec.ClockRate, inputProp.Latency)) +func (track *AudioTrack) Bind(ctx webrtc.TrackLocalContext) (webrtc.RTPCodecParameters, error) { + return track.bind(ctx, track) } -func (track *AudioTrack) Unbind(pc *webrtc.PeerConnection) error { - return track.unbind(pc) +func (track *AudioTrack) Unbind(ctx webrtc.TrackLocalContext) error { + return track.unbind(ctx) } func (track *AudioTrack) newEncodedReader(codecNames ...string) (EncodedReadCloser, *codec.RTPCodec, error) { @@ -441,14 +453,13 @@ func (track *AudioTrack) NewEncodedIOReader(codecName string) (io.ReadCloser, er return newEncodedIOReadCloserImpl(encodedReader), nil } -func (track *AudioTrack) NewRTPReader(codecName string, mtu int) (RTPReadCloser, error) { +func (track *AudioTrack) NewRTPReader(codecName string, ssrc uint32, mtu int) (RTPReadCloser, error) { encodedReader, selectedCodec, err := track.newEncodedReader(codecName) if err != nil { return nil, err } - // FIXME: not sure the best way to get unique ssrc. We probably should have a global keeper that can generate a random ID and does book keeping? - packetizer := rtp.NewPacketizer(mtu, selectedCodec.PayloadType, rand.Uint32(), selectedCodec.Payloader, rtp.NewRandomSequencer(), selectedCodec.ClockRate) + packetizer := rtp.NewPacketizer(mtu, uint8(selectedCodec.PayloadType), ssrc, selectedCodec.Payloader, rtp.NewRandomSequencer(), selectedCodec.ClockRate) return &rtpReadCloserImpl{ readFn: func() ([]*rtp.Packet, func(), error) {