Skip to content

Commit

Permalink
Implement WASM Media methods
Browse files Browse the repository at this point in the history
Add AddTransceiverFromKind and GetTransceivers. This doesn't support
everything, but enough to at least build a recvonly experience.

Resolves #500
  • Loading branch information
Tomek authored and Sean-Der committed Apr 13, 2021
1 parent 4358bb9 commit 907d070
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 75 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions peerconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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
Expand Down
40 changes: 40 additions & 0 deletions peerconnection_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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(),
})
}
73 changes: 0 additions & 73 deletions peerconnection_media_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
60 changes: 60 additions & 0 deletions peerconnection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -650,3 +666,47 @@ func TestSetRemoteDescriptionInvalid(t *testing.T) {
assert.NoError(t, pc.Close())
})
}

func TestAddTransceiver(t *testing.T) {
lim := test.TimeOut(time.Second * 30)
defer lim.Stop()

report := test.CheckRoutines(t)
defer report()

for _, testCase := range []struct {
expectSender, expectReceiver bool
direction RTPTransceiverDirection
}{
{true, true, RTPTransceiverDirectionSendrecv},
// Go and WASM diverge
// {true, false, RTPTransceiverDirectionSendonly},
// {false, true, RTPTransceiverDirectionRecvonly},
} {
pc, err := NewPeerConnection(Configuration{})
assert.NoError(t, err)

transceiver, err := pc.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{
Direction: testCase.direction,
})
assert.NoError(t, err)

if testCase.expectReceiver {
assert.NotNil(t, transceiver.Receiver())
} else {
assert.Nil(t, transceiver.Receiver())
}

if testCase.expectSender {
assert.NotNil(t, transceiver.Sender())
} else {
assert.Nil(t, transceiver.Sender())
}

offer, err := pc.CreateOffer(nil)
assert.NoError(t, err)

assert.True(t, offerMediaHasDirection(offer, RTPCodecTypeVideo, testCase.direction))
assert.NoError(t, pc.Close())
}
}
11 changes: 11 additions & 0 deletions rtpreceiver_js.go
Original file line number Diff line number Diff line change
@@ -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
}
11 changes: 11 additions & 0 deletions rtpsender_js.go
Original file line number Diff line number Diff line change
@@ -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
}
40 changes: 40 additions & 0 deletions rtptransceiver_js.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// +build js,wasm

package webrtc

import (
"fmt"
"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() {
fmt.Println("nil")
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}
}

0 comments on commit 907d070

Please sign in to comment.