diff --git a/README.md b/README.md index 5fc91791498..2937bf21576 100644 --- a/README.md +++ b/README.md @@ -271,6 +271,7 @@ Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contribu * [Nam V. Do](https://github.com/namvdo) * [Markus Tzoe](https://github.com/zyxar) * [Benny Daon](https://github.com/daonb) +* [Tomek](https://github.com/trojek) ### License MIT License - see [LICENSE](LICENSE) for full text diff --git a/peerconnection.go b/peerconnection.go index a6fc7913839..4a24fa11e7a 100644 --- a/peerconnection.go +++ b/peerconnection.go @@ -1637,7 +1637,7 @@ func (pc *PeerConnection) RemoveTrack(sender *RTPSender) (err error) { return nil } -// AddTransceiverFromKind Create a new RtpTransceiver(SendRecv or RecvOnly) and add it to the set of transceivers. +// AddTransceiverFromKind Create a new RtpTransceiver and adds it to the set of transceivers. func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RtpTransceiverInit) (*RTPTransceiver, error) { if pc.isClosed.get() { return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} @@ -1651,7 +1651,7 @@ func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RtpT } switch direction { - case RTPTransceiverDirectionSendrecv: + case RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv: codecs := pc.api.mediaEngine.getCodecsByKind(kind) if len(codecs) == 0 { return nil, ErrNoCodecsAvailable diff --git a/peerconnection_js.go b/peerconnection_js.go index c2931940779..90ce80ff75b 100644 --- a/peerconnection_js.go +++ b/peerconnection_js.go @@ -488,6 +488,40 @@ func (pc *PeerConnection) setGatherCompleteHandler(handler func()) { } } +// AddTransceiverFromKind Create a new RtpTransceiver and adds it to the set of transceivers. +func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RtpTransceiverInit) (transceiver *RTPTransceiver, err error) { + defer func() { + if e := recover(); e != nil { + err = recoveryToError(e) + } + }() + + if len(init) == 1 { + return &RTPTransceiver{ + underlying: pc.underlying.Call("addTransceiver", kind.String(), rtpTransceiverInitInitToValue(init[0])), + }, err + + } + + return &RTPTransceiver{ + underlying: pc.underlying.Call("addTransceiver", kind.String()), + }, err +} + +// GetTransceivers returns the RtpTransceiver that are currently attached to this PeerConnection +func (pc *PeerConnection) GetTransceivers() (transceivers []*RTPTransceiver) { + rawTransceivers := pc.underlying.Call("getTransceivers") + transceivers = make([]*RTPTransceiver, rawTransceivers.Length()) + + for i := 0; i < rawTransceivers.Length(); i++ { + transceivers[i] = &RTPTransceiver{ + underlying: rawTransceivers.Index(i), + } + } + + return +} + // Converts a Configuration to js.Value so it can be passed // through to the JavaScript WebRTC API. Any zero values are converted to // js.Undefined(), which will result in the default value being used. @@ -674,3 +708,9 @@ func dataChannelInitToValue(options *DataChannelInit) js.Value { "id": uint16PointerToValue(options.ID), }) } + +func rtpTransceiverInitInitToValue(init RtpTransceiverInit) js.Value { + return js.ValueOf(map[string]interface{}{ + "direction": init.Direction.String(), + }) +} diff --git a/peerconnection_media_test.go b/peerconnection_media_test.go index 0245f6b2350..6733f1486a2 100644 --- a/peerconnection_media_test.go +++ b/peerconnection_media_test.go @@ -29,16 +29,6 @@ var ( errNoTransceiverwithMid = errors.New("no transceiver with mid") ) -func offerMediaHasDirection(offer SessionDescription, kind RTPCodecType, direction RTPTransceiverDirection) bool { - for _, media := range offer.parsed.MediaDescriptions { - if media.MediaName.Media == kind.String() { - _, exists := media.Attribute(direction.String()) - return exists - } - } - return false -} - /* Integration test for bi-directional peers @@ -567,45 +557,6 @@ func TestAddTransceiverFromTrackSendRecv(t *testing.T) { assert.NoError(t, pc.Close()) } -// nolint: dupl -func TestAddTransceiver(t *testing.T) { - lim := test.TimeOut(time.Second * 30) - defer lim.Stop() - - report := test.CheckRoutines(t) - defer report() - - pc, err := NewPeerConnection(Configuration{}) - if err != nil { - t.Error(err.Error()) - } - - transceiver, err := pc.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{ - Direction: RTPTransceiverDirectionSendrecv, - }) - if err != nil { - t.Error(err.Error()) - } - - if transceiver.Receiver() == nil { - t.Errorf("Transceiver should have a receiver") - } - - if transceiver.Sender() == nil { - t.Errorf("Transceiver should have a sender") - } - - offer, err := pc.CreateOffer(nil) - if err != nil { - t.Error(err.Error()) - } - - if !offerMediaHasDirection(offer, RTPCodecTypeVideo, RTPTransceiverDirectionSendrecv) { - t.Errorf("Direction on SDP is not %s", RTPTransceiverDirectionSendrecv) - } - assert.NoError(t, pc.Close()) -} - func TestAddTransceiverAddTrack_Reuse(t *testing.T) { pc, err := NewPeerConnection(Configuration{}) assert.NoError(t, err) @@ -730,30 +681,6 @@ func TestAddTransceiverFromKind(t *testing.T) { assert.NoError(t, pc.Close()) } -func TestAddTransceiverFromKindFailsSendOnly(t *testing.T) { - lim := test.TimeOut(time.Second * 30) - defer lim.Stop() - - report := test.CheckRoutines(t) - defer report() - - pc, err := NewPeerConnection(Configuration{}) - if err != nil { - t.Error(err.Error()) - } - - transceiver, err := pc.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{ - Direction: RTPTransceiverDirectionSendonly, - }) - - if transceiver != nil { - t.Error("AddTransceiverFromKind shouldn't succeed with Direction RTPTransceiverDirectionSendonly") - } - - assert.NotNil(t, err) - assert.NoError(t, pc.Close()) -} - func TestAddTransceiverFromTrackFailsRecvOnly(t *testing.T) { lim := test.TimeOut(time.Second * 30) defer lim.Stop() diff --git a/peerconnection_test.go b/peerconnection_test.go index 9f1695a5e8c..cdcab63d26c 100644 --- a/peerconnection_test.go +++ b/peerconnection_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/pion/sdp/v3" "github.com/pion/transport/test" "github.com/pion/webrtc/v3/pkg/rtcerr" "github.com/stretchr/testify/assert" @@ -61,6 +62,21 @@ func signalPair(pcOffer *PeerConnection, pcAnswer *PeerConnection) error { return pcOffer.SetRemoteDescription(*pcAnswer.LocalDescription()) } +func offerMediaHasDirection(offer SessionDescription, kind RTPCodecType, direction RTPTransceiverDirection) bool { + parsed := &sdp.SessionDescription{} + if err := parsed.Unmarshal([]byte(offer.SDP)); err != nil { + return false + } + + for _, media := range parsed.MediaDescriptions { + if media.MediaName.Media == kind.String() { + _, exists := media.Attribute(direction.String()) + return exists + } + } + return false +} + func TestNew(t *testing.T) { pc, err := NewPeerConnection(Configuration{ ICEServers: []ICEServer{ @@ -650,3 +666,42 @@ func TestSetRemoteDescriptionInvalid(t *testing.T) { assert.NoError(t, pc.Close()) }) } + +// nolint: dupl +func TestAddTransceiver(t *testing.T) { + lim := test.TimeOut(time.Second * 30) + defer lim.Stop() + + report := test.CheckRoutines(t) + defer report() + + pc, err := NewPeerConnection(Configuration{}) + if err != nil { + t.Error(err.Error()) + } + + transceiver, err := pc.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{ + Direction: RTPTransceiverDirectionSendrecv, + }) + if err != nil { + t.Error(err.Error()) + } + + if transceiver.Receiver() == nil { + t.Errorf("Transceiver should have a receiver") + } + + if transceiver.Sender() == nil { + t.Errorf("Transceiver should have a sender") + } + + offer, err := pc.CreateOffer(nil) + if err != nil { + t.Error(err.Error()) + } + + if !offerMediaHasDirection(offer, RTPCodecTypeVideo, RTPTransceiverDirectionSendrecv) { + t.Errorf("Direction on SDP is not %s", RTPTransceiverDirectionSendrecv) + } + assert.NoError(t, pc.Close()) +} diff --git a/rtpreceiver_js.go b/rtpreceiver_js.go new file mode 100644 index 00000000000..bee5d9a4e51 --- /dev/null +++ b/rtpreceiver_js.go @@ -0,0 +1,11 @@ +// +build js,wasm + +package webrtc + +import "syscall/js" + +// RTPReceiver allows an application to inspect the receipt of a TrackRemote +type RTPReceiver struct { + // Pointer to the underlying JavaScript RTCRTPReceiver object. + underlying js.Value +} diff --git a/rtpsender_js.go b/rtpsender_js.go new file mode 100644 index 00000000000..cd22492045c --- /dev/null +++ b/rtpsender_js.go @@ -0,0 +1,11 @@ +// +build js,wasm + +package webrtc + +import "syscall/js" + +// RTPSender allows an application to control how a given Track is encoded and transmitted to a remote peer +type RTPSender struct { + // Pointer to the underlying JavaScript RTCRTPSender object. + underlying js.Value +} diff --git a/rtptransceiver_js.go b/rtptransceiver_js.go new file mode 100644 index 00000000000..70311cc03d4 --- /dev/null +++ b/rtptransceiver_js.go @@ -0,0 +1,36 @@ +// +build js,wasm + +package webrtc + +import "syscall/js" + +// RTPTransceiver represents a combination of an RTPSender and an RTPReceiver that share a common mid. +type RTPTransceiver struct { + // Pointer to the underlying JavaScript RTCRTPTransceiver object. + underlying js.Value +} + +// Direction returns the RTPTransceiver's current direction +func (r *RTPTransceiver) Direction() RTPTransceiverDirection { + return NewRTPTransceiverDirection(r.underlying.Get("direction").String()) +} + +// Sender returns the RTPTransceiver's RTPSender if it has one +func (r *RTPTransceiver) Sender() *RTPSender { + underlying := r.underlying.Get("sender") + if underlying.IsNull() { + return nil + } + + return &RTPSender{underlying: underlying} +} + +// Receiver returns the RTPTransceiver's RTPReceiver if it has one +func (r *RTPTransceiver) Receiver() *RTPReceiver { + underlying := r.underlying.Get("receiver") + if underlying.IsNull() { + return nil + } + + return &RTPReceiver{underlying: underlying} +}