Files
webrtc/rtcpeerconnection_media_test.go
rob-deutsch 95fcd7b3a0 RTCRtpReceiver now properly tears down
RTCRtpReceiver would leak routines and block if the ReadStream hadn't
given us a packet yet

Closes #387

Co-authored-by: rob-deutsch <robzyb+altgithub@gmail.com>
2019-02-05 23:26:44 -08:00

232 lines
4.5 KiB
Go

package webrtc
import (
"bytes"
"sync"
"testing"
"time"
"github.com/pions/rtcp"
"github.com/pions/transport/test"
"github.com/pions/webrtc/pkg/ice"
"github.com/pions/webrtc/pkg/media"
)
func TestRTCPeerConnection_Media_Sample(t *testing.T) {
api := NewAPI()
lim := test.TimeOut(time.Second * 30)
defer lim.Stop()
report := test.CheckRoutines(t)
defer report()
api.mediaEngine.RegisterDefaultCodecs()
pcOffer, pcAnswer, err := api.newPair()
if err != nil {
t.Fatal(err)
}
awaitRTPRecv := make(chan bool)
awaitRTPRecvClosed := make(chan bool)
awaitRTPSend := make(chan bool)
awaitRTCPSenderRecv := make(chan bool)
awaitRTCPSenderSend := make(chan error)
awaitRTCPRecieverRecv := make(chan bool)
awaitRTCPRecieverSend := make(chan error)
pcAnswer.OnTrack(func(track *RTCTrack) {
go func() {
for {
time.Sleep(time.Millisecond * 100)
if routineErr := pcAnswer.SendRTCP(&rtcp.RapidResynchronizationRequest{SenderSSRC: track.Ssrc, MediaSSRC: track.Ssrc}); routineErr != nil {
awaitRTCPRecieverSend <- routineErr
return
}
select {
case <-awaitRTCPSenderRecv:
close(awaitRTCPRecieverSend)
return
default:
}
}
}()
go func() {
<-track.RTCPPackets
close(awaitRTCPRecieverRecv)
}()
haveClosedAwaitRTPRecv := false
for {
p, ok := <-track.Packets
if !ok {
close(awaitRTPRecvClosed)
return
} else if bytes.Equal(p.Payload, []byte{0x10, 0x00}) && !haveClosedAwaitRTPRecv {
haveClosedAwaitRTPRecv = true
close(awaitRTPRecv)
}
}
})
vp8Track, err := pcOffer.NewRTCSampleTrack(DefaultPayloadTypeVP8, "video", "pion")
if err != nil {
t.Fatal(err)
}
if _, err = pcOffer.AddTrack(vp8Track); err != nil {
t.Fatal(err)
}
go func() {
for {
time.Sleep(time.Millisecond * 100)
vp8Track.Samples <- media.RTCSample{Data: []byte{0x00}, Samples: 1}
select {
case <-awaitRTPRecv:
close(awaitRTPSend)
return
default:
}
}
}()
go func() {
for {
time.Sleep(time.Millisecond * 100)
if routineErr := pcOffer.SendRTCP(&rtcp.PictureLossIndication{SenderSSRC: vp8Track.Ssrc, MediaSSRC: vp8Track.Ssrc}); routineErr != nil {
awaitRTCPSenderSend <- routineErr
}
select {
case <-awaitRTCPRecieverRecv:
close(awaitRTCPSenderSend)
return
default:
}
}
}()
go func() {
<-vp8Track.RTCPPackets
close(awaitRTCPSenderRecv)
}()
err = signalPair(pcOffer, pcAnswer)
if err != nil {
t.Fatal(err)
}
<-awaitRTPRecv
<-awaitRTPSend
<-awaitRTCPSenderRecv
err, ok := <-awaitRTCPSenderSend
if ok {
t.Fatal(err)
}
<-awaitRTCPRecieverRecv
err, ok = <-awaitRTCPRecieverSend
if ok {
t.Fatal(err)
}
err = pcOffer.Close()
if err != nil {
t.Fatal(err)
}
err = pcAnswer.Close()
if err != nil {
t.Fatal(err)
}
<-awaitRTPRecvClosed
}
/*
RTCPeerConnection should be able to be torn down at anytime
This test adds an input track and asserts
* OnTrack doesn't fire since no video packets will arrive
* No goroutine leaks
* No deadlocks on shutdown
*/
func TestRTCPeerConnection_Media_Shutdown(t *testing.T) {
iceComplete := make(chan bool)
api := NewAPI()
lim := test.TimeOut(time.Second * 30)
defer lim.Stop()
report := test.CheckRoutines(t)
defer report()
api.mediaEngine.RegisterDefaultCodecs()
pcOffer, pcAnswer, err := api.newPair()
if err != nil {
t.Fatal(err)
}
opusTrack, err := pcOffer.NewRTCSampleTrack(DefaultPayloadTypeOpus, "audio", "pion1")
if err != nil {
t.Fatal(err)
}
vp8Track, err := pcOffer.NewRTCSampleTrack(DefaultPayloadTypeVP8, "video", "pion2")
if err != nil {
t.Fatal(err)
}
if _, err = pcOffer.AddTrack(opusTrack); err != nil {
t.Fatal(err)
} else if _, err = pcOffer.AddTrack(vp8Track); err != nil {
t.Fatal(err)
}
var onTrackFiredLock sync.RWMutex
onTrackFired := false
pcAnswer.OnTrack(func(track *RTCTrack) {
onTrackFiredLock.Lock()
defer onTrackFiredLock.Unlock()
onTrackFired = true
})
pcAnswer.OnICEConnectionStateChange(func(iceState ice.ConnectionState) {
if iceState == ice.ConnectionStateConnected {
go func() {
time.Sleep(3 * time.Second) // TODO RTCPeerConnection.Close() doesn't block for all subsystems
close(iceComplete)
}()
}
})
err = signalPair(pcOffer, pcAnswer)
if err != nil {
t.Fatal(err)
}
<-iceComplete
err = pcOffer.Close()
if err != nil {
t.Fatal(err)
}
err = pcAnswer.Close()
if err != nil {
t.Fatal(err)
}
onTrackFiredLock.Lock()
if onTrackFired {
t.Fatalf("RTCPeerConnection OnTrack fired even though we got no packets")
}
onTrackFiredLock.Unlock()
}