golanggohlsrtmpwebrtcmedia-serverobs-studiortcprtmp-proxyrtmp-serverrtprtsprtsp-proxyrtsp-relayrtsp-serversrtstreamingwebrtc-proxy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.3 KiB
141 lines
3.3 KiB
package webrtc |
|
|
|
import ( |
|
"context" |
|
"io" |
|
"net" |
|
"net/http" |
|
"testing" |
|
"time" |
|
|
|
"github.com/bluenviron/gortsplib/v4/pkg/format" |
|
"github.com/pion/rtp" |
|
pwebrtc "github.com/pion/webrtc/v3" |
|
"github.com/stretchr/testify/require" |
|
|
|
"github.com/bluenviron/mediamtx/internal/conf" |
|
"github.com/bluenviron/mediamtx/internal/defs" |
|
"github.com/bluenviron/mediamtx/internal/protocols/webrtc" |
|
"github.com/bluenviron/mediamtx/internal/test" |
|
) |
|
|
|
func whipOffer(body []byte) *pwebrtc.SessionDescription { |
|
return &pwebrtc.SessionDescription{ |
|
Type: pwebrtc.SDPTypeOffer, |
|
SDP: string(body), |
|
} |
|
} |
|
|
|
func TestSource(t *testing.T) { |
|
api, err := webrtc.NewAPI(webrtc.APIConf{ |
|
LocalRandomUDP: true, |
|
IPsFromInterfaces: true, |
|
}) |
|
require.NoError(t, err) |
|
|
|
pc := &webrtc.PeerConnection{ |
|
API: api, |
|
Publish: true, |
|
Log: test.NilLogger{}, |
|
} |
|
err = pc.Start() |
|
require.NoError(t, err) |
|
defer pc.Close() |
|
|
|
tracks, err := pc.SetupOutgoingTracks( |
|
nil, |
|
&format.Opus{ |
|
PayloadTyp: 111, |
|
IsStereo: true, |
|
}, |
|
) |
|
require.NoError(t, err) |
|
|
|
state := 0 |
|
|
|
httpServ := &http.Server{ |
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
switch state { |
|
case 0: |
|
require.Equal(t, http.MethodOptions, r.Method) |
|
require.Equal(t, "/my/resource", r.URL.Path) |
|
|
|
w.Header().Set("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PATCH") |
|
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, If-Match") |
|
w.WriteHeader(http.StatusNoContent) |
|
|
|
case 1: |
|
require.Equal(t, http.MethodPost, r.Method) |
|
require.Equal(t, "/my/resource", r.URL.Path) |
|
require.Equal(t, "application/sdp", r.Header.Get("Content-Type")) |
|
|
|
body, err := io.ReadAll(r.Body) |
|
require.NoError(t, err) |
|
offer := whipOffer(body) |
|
|
|
answer, err := pc.CreateFullAnswer(context.Background(), offer) |
|
require.NoError(t, err) |
|
|
|
w.Header().Set("Content-Type", "application/sdp") |
|
w.Header().Set("Accept-Patch", "application/trickle-ice-sdpfrag") |
|
w.Header().Set("ETag", "test_etag") |
|
w.Header().Set("Location", "/my/resource/sessionid") |
|
w.WriteHeader(http.StatusCreated) |
|
w.Write([]byte(answer.SDP)) |
|
|
|
go func() { |
|
err = pc.WaitUntilConnected(context.Background()) |
|
require.NoError(t, err) |
|
|
|
err = tracks[0].WriteRTP(&rtp.Packet{ |
|
Header: rtp.Header{ |
|
Version: 2, |
|
Marker: true, |
|
PayloadType: 111, |
|
SequenceNumber: 1123, |
|
Timestamp: 45343, |
|
SSRC: 563424, |
|
}, |
|
Payload: []byte{5, 2}, |
|
}) |
|
require.NoError(t, err) |
|
}() |
|
|
|
default: |
|
require.Equal(t, "/my/resource/sessionid", r.URL.Path) |
|
|
|
switch r.Method { |
|
case http.MethodPatch: |
|
w.WriteHeader(http.StatusNoContent) |
|
|
|
case http.MethodDelete: |
|
w.WriteHeader(http.StatusOK) |
|
|
|
default: |
|
t.Errorf("should not happen") |
|
} |
|
} |
|
state++ |
|
}), |
|
} |
|
|
|
ln, err := net.Listen("tcp", "localhost:9003") |
|
require.NoError(t, err) |
|
|
|
go httpServ.Serve(ln) |
|
defer httpServ.Shutdown(context.Background()) |
|
|
|
te := test.NewSourceTester( |
|
func(p defs.StaticSourceParent) defs.StaticSource { |
|
return &Source{ |
|
ResolvedSource: "whep://localhost:9003/my/resource", |
|
ReadTimeout: conf.StringDuration(10 * time.Second), |
|
Parent: p, |
|
} |
|
}, |
|
&conf.Path{}, |
|
) |
|
defer te.Close() |
|
|
|
<-te.Unit |
|
}
|
|
|