offers and answers are now encoded in SDP in place of JSON; Location header is set by the server. This fixes compatibility with GStreamer and whipsink
This commit is contained in:
@@ -309,6 +309,7 @@ func (s *webRTCHTTPServer) onRequest(ctx *gin.Context) {
|
||||
ctx.Writer.Header().Set("E-Tag", res.sx.secret.String())
|
||||
ctx.Writer.Header().Set("Accept-Patch", "application/trickle-ice-sdpfrag")
|
||||
ctx.Writer.Header()["Link"] = iceServersToLinkHeader(s.parent.genICEServers())
|
||||
ctx.Writer.Header().Set("Location", ctx.Request.URL.String())
|
||||
ctx.Writer.WriteHeader(http.StatusCreated)
|
||||
ctx.Writer.Write(res.answer)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -38,10 +38,7 @@ func whipGetICEServers(t *testing.T, hc *http.Client, ur string) []webrtc.ICESer
|
||||
func whipPostOffer(t *testing.T, hc *http.Client, ur string,
|
||||
offer *webrtc.SessionDescription,
|
||||
) (*webrtc.SessionDescription, string) {
|
||||
enc, err := json.Marshal(offer)
|
||||
require.NoError(t, err)
|
||||
|
||||
req, err := http.NewRequest("POST", ur, bytes.NewReader(enc))
|
||||
req, err := http.NewRequest("POST", ur, bytes.NewReader([]byte(offer.SDP)))
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Content-Type", "application/sdp")
|
||||
@@ -51,22 +48,27 @@ func whipPostOffer(t *testing.T, hc *http.Client, ur string,
|
||||
defer res.Body.Close()
|
||||
|
||||
require.Equal(t, http.StatusCreated, res.StatusCode)
|
||||
require.Equal(t, "application/sdp", res.Header.Get("Content-Type"))
|
||||
require.Equal(t, "application/trickle-ice-sdpfrag", res.Header.Get("Accept-Patch"))
|
||||
require.Equal(t, req.URL.Path, res.Header.Get("Location"))
|
||||
|
||||
link, ok := res.Header["Link"]
|
||||
require.Equal(t, true, ok)
|
||||
servers := linkHeaderToIceServers(link)
|
||||
require.NotEqual(t, 0, len(servers))
|
||||
|
||||
require.Equal(t, "application/sdp", res.Header.Get("Content-Type"))
|
||||
etag := res.Header.Get("E-Tag")
|
||||
require.NotEqual(t, 0, len(etag))
|
||||
require.Equal(t, "application/trickle-ice-sdpfrag", res.Header.Get("Accept-Patch"))
|
||||
|
||||
var answer webrtc.SessionDescription
|
||||
err = json.NewDecoder(res.Body).Decode(&answer)
|
||||
sdp, err := io.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &answer, etag
|
||||
answer := &webrtc.SessionDescription{
|
||||
Type: webrtc.SDPTypeAnswer,
|
||||
SDP: string(sdp),
|
||||
}
|
||||
|
||||
return answer, etag
|
||||
}
|
||||
|
||||
func whipPostCandidate(t *testing.T, ur string, offer *webrtc.SessionDescription,
|
||||
@@ -323,10 +325,7 @@ func TestWebRTCReadNotFound(t *testing.T) {
|
||||
offer, err := pc.CreateOffer(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
enc, err := json.Marshal(offer)
|
||||
require.NoError(t, err)
|
||||
|
||||
req, err := http.NewRequest("POST", "http://localhost:8889/stream/whep", bytes.NewReader(enc))
|
||||
req, err := http.NewRequest("POST", "http://localhost:8889/stream/whep", bytes.NewReader([]byte(offer.SDP)))
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Content-Type", "application/sdp")
|
||||
|
||||
@@ -232,16 +232,19 @@ class Transmitter {
|
||||
headers: {
|
||||
'Content-Type': 'application/sdp',
|
||||
},
|
||||
body: JSON.stringify(desc),
|
||||
body: desc.sdp,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status !== 201) {
|
||||
throw new Error('bad status code');
|
||||
}
|
||||
this.eTag = res.headers.get('E-Tag');
|
||||
return res.json();
|
||||
return res.text();
|
||||
})
|
||||
.then((answer) => this.onRemoteDescription(answer))
|
||||
.then((sdp) => this.onRemoteDescription(new RTCSessionDescription({
|
||||
type: 'answer',
|
||||
sdp,
|
||||
})))
|
||||
.catch((err) => {
|
||||
console.log('error: ' + err);
|
||||
this.scheduleRestart();
|
||||
|
||||
@@ -143,16 +143,19 @@ class WHEPClient {
|
||||
headers: {
|
||||
'Content-Type': 'application/sdp',
|
||||
},
|
||||
body: JSON.stringify(desc),
|
||||
body: desc.sdp,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status !== 201) {
|
||||
throw new Error('bad status code');
|
||||
}
|
||||
this.eTag = res.headers.get('E-Tag');
|
||||
return res.json();
|
||||
return res.text();
|
||||
})
|
||||
.then((answer) => this.onRemoteDescription(answer))
|
||||
.then((sdp) => this.onRemoteDescription(new RTCSessionDescription({
|
||||
type: 'answer',
|
||||
sdp,
|
||||
})))
|
||||
.catch((err) => {
|
||||
console.log('error: ' + err);
|
||||
this.scheduleRestart();
|
||||
|
||||
@@ -3,7 +3,6 @@ package core
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -256,11 +255,6 @@ func (s *webRTCSession) runPublish() (int, error) {
|
||||
|
||||
defer res.path.publisherRemove(pathPublisherRemoveReq{author: s})
|
||||
|
||||
offer, err := s.decodeOffer()
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
pc, err := newPeerConnection(
|
||||
s.req.videoCodec,
|
||||
s.req.audioCodec,
|
||||
@@ -297,6 +291,7 @@ func (s *webRTCSession) runPublish() (int, error) {
|
||||
}
|
||||
})
|
||||
|
||||
offer := s.buildOffer()
|
||||
err = pc.SetRemoteDescription(*offer)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
@@ -390,11 +385,6 @@ func (s *webRTCSession) runRead() (int, error) {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
offer, err := s.decodeOffer()
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
pc, err := newPeerConnection(
|
||||
"",
|
||||
"",
|
||||
@@ -416,6 +406,7 @@ func (s *webRTCSession) runRead() (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
offer := s.buildOffer()
|
||||
err = pc.SetRemoteDescription(*offer)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
@@ -484,18 +475,11 @@ func (s *webRTCSession) runRead() (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *webRTCSession) decodeOffer() (*webrtc.SessionDescription, error) {
|
||||
var offer webrtc.SessionDescription
|
||||
err := json.Unmarshal(s.req.offer, &offer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *webRTCSession) buildOffer() *webrtc.SessionDescription {
|
||||
return &webrtc.SessionDescription{
|
||||
Type: webrtc.SDPTypeOffer,
|
||||
SDP: string(s.req.offer),
|
||||
}
|
||||
|
||||
if offer.Type != webrtc.SDPTypeOffer {
|
||||
return nil, fmt.Errorf("received SDP is not an offer")
|
||||
}
|
||||
|
||||
return &offer, nil
|
||||
}
|
||||
|
||||
func (s *webRTCSession) waitGatheringDone(pc *peerConnection) error {
|
||||
@@ -511,15 +495,10 @@ func (s *webRTCSession) waitGatheringDone(pc *peerConnection) error {
|
||||
}
|
||||
|
||||
func (s *webRTCSession) writeAnswer(answer *webrtc.SessionDescription) error {
|
||||
enc, err := json.Marshal(answer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
select {
|
||||
case s.req.res <- webRTCSessionNewRes{
|
||||
sx: s,
|
||||
answer: enc,
|
||||
answer: []byte(answer.SDP),
|
||||
}:
|
||||
s.answerSent = true
|
||||
case <-s.ctx.Done():
|
||||
|
||||
Reference in New Issue
Block a user