mirror of
https://github.com/flavioribeiro/donut.git
synced 2025-10-05 23:16:53 +08:00
provides cancelation when a component stop responding it closes all resources
This commit is contained in:
13
FAQ.md
13
FAQ.md
@@ -1,5 +1,18 @@
|
|||||||
# FAQ
|
# FAQ
|
||||||
|
|
||||||
|
## I can't connect two tabs or browser at the same for the SRT
|
||||||
|
|
||||||
|
It doesn't work When I try to connect in another browser or tab, or even when I try to refresh the current page. It raises an seemingly timeout error.
|
||||||
|
|
||||||
|
```
|
||||||
|
astisrt: connecting failed: astisrt: connecting failed: astisrt: Connection setup failure: connection timed out
|
||||||
|
```
|
||||||
|
|
||||||
|
Apparently both `ffmpeg` and `srt-live-transmit` won't allow multiple persistent connections.
|
||||||
|
|
||||||
|
ref1 https://github.com/Haivision/srt/blob/master/docs/apps/srt-live-transmit.md#medium-srt
|
||||||
|
ref2 https://github.com/asticode/go-astisrt/issues/6#issuecomment-1917076767
|
||||||
|
|
||||||
## It's not working on Firefox/Chrome/Edge.
|
## It's not working on Firefox/Chrome/Edge.
|
||||||
|
|
||||||
[WebRTC establishes a baseline set of codecs which all compliant browsers are required to support. Some browsers may choose to allow other codecs as well.](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#supported_video_codecs)
|
[WebRTC establishes a baseline set of codecs which all compliant browsers are required to support. Some browsers may choose to allow other codecs as well.](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#supported_video_codecs)
|
||||||
|
@@ -51,18 +51,15 @@ func NewSRTController(c *entities.Config, l *zap.Logger, lc fx.Lifecycle) (*SRTC
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SRTController) Connect(params *entities.RequestParams) (*astisrt.Connection, error) {
|
func (c *SRTController) Connect(cancel context.CancelFunc, params entities.RequestParams) (*astisrt.Connection, error) {
|
||||||
c.l.Sugar().Infow("trying to connect srt")
|
c.l.Sugar().Infow("trying to connect srt")
|
||||||
if params == nil {
|
|
||||||
return nil, entities.ErrMissingRemoteOffer
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := params.Valid(); err != nil {
|
if err := params.Valid(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.l.Sugar().Infow("Connecting to SRT ",
|
c.l.Sugar().Infow("Connecting to SRT ",
|
||||||
"offer", params,
|
"offer", params.String(),
|
||||||
)
|
)
|
||||||
|
|
||||||
conn, err := astisrt.Dial(astisrt.DialOptions{
|
conn, err := astisrt.Dial(astisrt.DialOptions{
|
||||||
@@ -74,9 +71,10 @@ func (c *SRTController) Connect(params *entities.RequestParams) (*astisrt.Connec
|
|||||||
},
|
},
|
||||||
|
|
||||||
OnDisconnect: func(conn *astisrt.Connection, err error) {
|
OnDisconnect: func(conn *astisrt.Connection, err error) {
|
||||||
c.l.Sugar().Fatalw("Disconnected from SRT",
|
c.l.Sugar().Infow("Canceling SRT",
|
||||||
"error", err,
|
"error", err,
|
||||||
)
|
)
|
||||||
|
cancel()
|
||||||
},
|
},
|
||||||
|
|
||||||
Host: params.SRTHost,
|
Host: params.SRTHost,
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -28,23 +27,31 @@ func NewStreamingController(c *entities.Config, l *zap.Logger) *StreamingControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StreamingController) Stream(srtConnection *astisrt.Connection, videoTrack *webrtc.TrackLocalStaticSample, metadataTrack *webrtc.DataChannel) {
|
func (c *StreamingController) Stream(sp entities.StreamParameters) {
|
||||||
r, w := io.Pipe()
|
r, w := io.Pipe()
|
||||||
|
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
defer srtConnection.Close()
|
defer sp.SRTConnection.Close()
|
||||||
|
defer sp.WebRTCConn.Close()
|
||||||
|
defer sp.Cancel()
|
||||||
|
|
||||||
c.l.Sugar().Infow("start streaming")
|
c.l.Sugar().Infow("start streaming")
|
||||||
|
|
||||||
// TODO: pick the proper transport? is it possible to get rtp instead?
|
// TODO: pick the proper transport? is it possible to get rtp instead?
|
||||||
go c.readFromSRTIntoWriterPipe(srtConnection, w)
|
go c.readFromSRTIntoWriterPipe(sp.SRTConnection, w)
|
||||||
|
|
||||||
dmx := astits.NewDemuxer(context.Background(), r)
|
// reading from reader pipe into mpeg-ts demuxer
|
||||||
|
dmx := astits.NewDemuxer(sp.Ctx, r)
|
||||||
eia608Reader := eia608.NewEIA608Reader()
|
eia608Reader := eia608.NewEIA608Reader()
|
||||||
h264PID := uint16(0)
|
h264PID := uint16(0)
|
||||||
|
|
||||||
// reading from reader pipe
|
|
||||||
for {
|
for {
|
||||||
|
select {
|
||||||
|
case <-sp.Ctx.Done():
|
||||||
|
c.l.Sugar().Errorw("stream was cancelled")
|
||||||
|
return
|
||||||
|
default:
|
||||||
d, err := dmx.NextData()
|
d, err := dmx.NextData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.l.Sugar().Errorw("failed to demux mpeg ts",
|
c.l.Sugar().Errorw("failed to demux mpeg ts",
|
||||||
@@ -54,12 +61,13 @@ func (c *StreamingController) Stream(srtConnection *astisrt.Connection, videoTra
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.PMT != nil {
|
if d.PMT != nil {
|
||||||
h264PID = c.captureMediaInfoAndSendToWebRTC(d, metadataTrack, h264PID)
|
h264PID = c.captureMediaInfoAndSendToWebRTC(d, sp.MetadataTrack, h264PID)
|
||||||
c.captureBitrateAndSendToWebRTC(d, metadataTrack)
|
c.captureBitrateAndSendToWebRTC(d, sp.MetadataTrack)
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.PID == h264PID && d.PES != nil {
|
if d.PID == h264PID && d.PES != nil {
|
||||||
if err = videoTrack.WriteSample(media.Sample{Data: d.PES.Data, Duration: time.Second / 30}); err != nil {
|
// writing video from mpeg-ts into webrtc
|
||||||
|
if err = sp.VideoTrack.WriteSample(media.Sample{Data: d.PES.Data, Duration: time.Second / 30}); err != nil {
|
||||||
c.l.Sugar().Errorw("failed to write a sample mpeg ts to web rtc",
|
c.l.Sugar().Errorw("failed to write a sample mpeg ts to web rtc",
|
||||||
"error", err,
|
"error", err,
|
||||||
)
|
)
|
||||||
@@ -80,7 +88,8 @@ func (c *StreamingController) Stream(srtConnection *astisrt.Connection, videoTra
|
|||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
metadataTrack.SendText(captionsMsg)
|
sp.MetadataTrack.SendText(captionsMsg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/flavioribeiro/donut/internal/entities"
|
"github.com/flavioribeiro/donut/internal/entities"
|
||||||
@@ -27,7 +28,7 @@ func NewWebRTCController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *WebRTCController) CreatePeerConnection() (*webrtc.PeerConnection, error) {
|
func (c *WebRTCController) CreatePeerConnection(cancel context.CancelFunc) (*webrtc.PeerConnection, error) {
|
||||||
c.l.Sugar().Infow("trying to set up web rtc conn")
|
c.l.Sugar().Infow("trying to set up web rtc conn")
|
||||||
|
|
||||||
peerConnectionConfiguration := webrtc.Configuration{}
|
peerConnectionConfiguration := webrtc.Configuration{}
|
||||||
@@ -48,6 +49,18 @@ func (c *WebRTCController) CreatePeerConnection() (*webrtc.PeerConnection, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
|
peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
|
||||||
|
finished := connectionState == webrtc.ICEConnectionStateClosed ||
|
||||||
|
connectionState == webrtc.ICEConnectionStateDisconnected ||
|
||||||
|
connectionState == webrtc.ICEConnectionStateCompleted ||
|
||||||
|
connectionState == webrtc.ICEConnectionStateFailed
|
||||||
|
|
||||||
|
if finished {
|
||||||
|
c.l.Sugar().Infow("Canceling webrtc",
|
||||||
|
"status", connectionState.String(),
|
||||||
|
)
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
|
||||||
c.l.Sugar().Infow("OnICEConnectionStateChange",
|
c.l.Sugar().Infow("OnICEConnectionStateChange",
|
||||||
"status", connectionState.String(),
|
"status", connectionState.String(),
|
||||||
)
|
)
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
package entities
|
package entities
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
astisrt "github.com/asticode/go-astisrt/pkg"
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,6 +69,15 @@ type Track struct {
|
|||||||
Type TrackType
|
Type TrackType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StreamParameters struct {
|
||||||
|
WebRTCConn *webrtc.PeerConnection
|
||||||
|
Cancel context.CancelFunc
|
||||||
|
Ctx context.Context
|
||||||
|
SRTConnection *astisrt.Connection
|
||||||
|
VideoTrack *webrtc.TrackLocalStaticSample
|
||||||
|
MetadataTrack *webrtc.DataChannel
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
HTTPPort int32 `required:"true" default:"8080"`
|
HTTPPort int32 `required:"true" default:"8080"`
|
||||||
HTTPHost string `required:"true" default:"0.0.0.0"`
|
HTTPHost string `required:"true" default:"0.0.0.0"`
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@@ -53,7 +54,9 @@ func (h *SignalingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
peer, err := h.webRTCController.CreatePeerConnection()
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
peer, err := h.webRTCController.CreatePeerConnection(cancel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.l.Sugar().Errorw("error while setting up web rtc connection",
|
h.l.Sugar().Errorw("error while setting up web rtc connection",
|
||||||
"error", err,
|
"error", err,
|
||||||
@@ -99,7 +102,7 @@ func (h *SignalingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
srtConnection, err := h.srtController.Connect(¶ms)
|
srtConnection, err := h.srtController.Connect(cancel, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.l.Sugar().Errorw("error while connecting to an srt server",
|
h.l.Sugar().Errorw("error while connecting to an srt server",
|
||||||
"error", err,
|
"error", err,
|
||||||
@@ -107,7 +110,14 @@ func (h *SignalingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go h.streamingController.Stream(srtConnection, videoTrack, metadataSender)
|
go h.streamingController.Stream(entities.StreamParameters{
|
||||||
|
Cancel: cancel,
|
||||||
|
Ctx: ctx,
|
||||||
|
WebRTCConn: peer,
|
||||||
|
SRTConnection: srtConnection,
|
||||||
|
VideoTrack: videoTrack,
|
||||||
|
MetadataTrack: metadataSender,
|
||||||
|
})
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
Reference in New Issue
Block a user