Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support publishing with WebRTC (#1659) #1786

Merged
merged 6 commits into from
May 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Live streams can be published to the server with:
|RTMP servers and cameras|RTMP, RTMPS, Enhanced RTMP|H264|MPEG-4 Audio (AAC), MPEG-2 Audio (MP3)|
|HLS servers and cameras|Low-Latency HLS, MP4-based HLS, legacy HLS|H265, H264|Opus, MPEG-4 Audio (AAC)|
|UDP/MPEG-TS streams|Unicast, broadcast, multicast|H265, H264|Opus, MPEG-4 Audio (AAC)|
|WebRTC||AV1, VP9, VP8, H264|Opus, G722, G711|
|Raspberry Pi Cameras||H264||

And can be read from the server with:
Expand Down Expand Up @@ -86,6 +87,7 @@ In the next months, the repository name and the Docker image name will be change
* [From OBS Studio](#from-obs-studio)
* [From OpenCV](#from-opencv)
* [From a UDP stream](#from-a-udp-stream)
* [From the browser](#from-the-browser)
* [Read from the server](#read-from-the-server)
* [From VLC and Ubuntu](#from-vlc-and-ubuntu)
* [RTSP protocol](#rtsp-protocol)
Expand Down Expand Up @@ -800,6 +802,14 @@ paths:

After starting the server, the stream can be reached on `rtsp://localhost:8554/udp`.

### From the browser

Open the page into the browser:

```
http://localhost:8889/mystream/publish
```

## Read from the server

### From VLC and Ubuntu
Expand Down
144 changes: 19 additions & 125 deletions apidocs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -303,15 +303,7 @@ components:
conf:
$ref: '#/components/schemas/PathConf'
source:
oneOf:
- $ref: '#/components/schemas/PathSourceRTSPSession'
- $ref: '#/components/schemas/PathSourceRTSPSSession'
- $ref: '#/components/schemas/PathSourceRTMPConn'
- $ref: '#/components/schemas/PathSourceRTMPSConn'
- $ref: '#/components/schemas/PathSourceRTSPSource'
- $ref: '#/components/schemas/PathSourceRTMPSource'
- $ref: '#/components/schemas/PathSourceHLSSource'
- $ref: '#/components/schemas/PathSourceRPICameraSource'
$ref: '#/components/schemas/PathSourceOrReader'
sourceReady:
type: boolean
tracks:
Expand All @@ -324,127 +316,26 @@ components:
readers:
type: array
items:
oneOf:
- $ref: '#/components/schemas/PathReaderHLSMuxer'
- $ref: '#/components/schemas/PathReaderRTMPConn'
- $ref: '#/components/schemas/PathReaderRTMPSConn'
- $ref: '#/components/schemas/PathReaderRTSPSession'
- $ref: '#/components/schemas/PathReaderRTSPSSession'
- $ref: '#/components/schemas/PathReaderWebRTCConn'

PathSourceRTSPSession:
type: object
properties:
type:
type: string
enum: [rtspSession]
id:
type: string

PathSourceRTSPSSession:
type: object
properties:
type:
type: string
enum: [rtspsSession]
id:
type: string

PathSourceRTMPConn:
type: object
properties:
type:
type: string
enum: [rtmpConn]
id:
type: string

PathSourceRTMPSConn:
type: object
properties:
type:
type: string
enum: [rtmpsConn]
id:
type: string

PathSourceRTSPSource:
type: object
properties:
type:
type: string
enum: [rtspSource]

PathSourceRTMPSource:
type: object
properties:
type:
type: string
enum: [rtmpSource]

PathSourceHLSSource:
type: object
properties:
type:
type: string
enum: [hlsSource]

PathSourceRPICameraSource:
type: object
properties:
type:
type: string
enum: [rpiCameraSource]

PathReaderHLSMuxer:
type: object
properties:
type:
type: string
enum: [hlsMuxer]
$ref: '#/components/schemas/PathSourceOrReader'

PathReaderRTMPConn:
PathSourceOrReader:
type: object
properties:
type:
type: string
enum: [rtmpConn]
id:
type: string

PathReaderRTMPSConn:
type: object
properties:
type:
type: string
enum: [rtmpsConn]
id:
type: string

PathReaderRTSPSession:
type: object
properties:
type:
type: string
enum: [rtspSession]
id:
type: string

PathReaderRTSPSSession:
type: object
properties:
type:
type: string
enum: [rtspsSession]
id:
type: string

PathReaderWebRTCConn:
type: object
properties:
type:
type: string
enum: [webRTCConn]
enum:
- hlsMuxer
- hlsSource
- rpiCameraSource
- rtmpSession
- rtmpSource
- rtmpsSession
- rtspSession
- rtspSource
- rtspsSession
- redirect
- udpSource
- webRTCConn
id:
type: string

Expand Down Expand Up @@ -560,6 +451,9 @@ components:
type: string
remoteCandidate:
type: string
state:
type: string
enum: [read, publish]
bytesReceived:
type: integer
format: int64
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ require (
github.com/notedit/rtmp v0.0.2
github.com/pion/ice/v2 v2.3.2
github.com/pion/interceptor v0.1.16
github.com/pion/rtcp v1.2.10
github.com/pion/rtp v1.7.13
github.com/pion/sdp/v3 v3.0.6
github.com/pion/webrtc/v3 v3.2.1
github.com/stretchr/testify v1.8.2
golang.org/x/crypto v0.9.0
Expand Down Expand Up @@ -50,9 +52,7 @@ require (
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.10 // indirect
github.com/pion/sctp v1.8.7 // indirect
github.com/pion/sdp/v3 v3.0.6 // indirect
github.com/pion/srtp/v2 v2.0.12 // indirect
github.com/pion/stun v0.4.0 // indirect
github.com/pion/transport/v2 v2.2.0 // indirect
Expand Down
13 changes: 6 additions & 7 deletions internal/core/hls_muxer.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,7 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})

m.path = res.path

defer func() {
m.path.readerRemove(pathReaderRemoveReq{author: m})
}()
defer m.path.readerRemove(pathReaderRemoveReq{author: m})

m.ringBuffer, _ = ringbuffer.New(uint64(m.readBufferCount))

Expand Down Expand Up @@ -614,8 +612,9 @@ func (m *hlsMuxer) apiMuxersList(req hlsServerAPIMuxersListSubReq) {
}

// apiReaderDescribe implements reader.
func (m *hlsMuxer) apiReaderDescribe() interface{} {
return struct {
Type string `json:"type"`
}{"hlsMuxer"}
func (m *hlsMuxer) apiReaderDescribe() pathAPISourceOrReader {
return pathAPISourceOrReader{
Type: "hlsMuxer",
ID: "",
}
}
9 changes: 5 additions & 4 deletions internal/core/hls_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,9 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}

// apiSourceDescribe implements sourceStaticImpl.
func (*hlsSource) apiSourceDescribe() interface{} {
return struct {
Type string `json:"type"`
}{"hlsSource"}
func (*hlsSource) apiSourceDescribe() pathAPISourceOrReader {
return pathAPISourceOrReader{
Type: "hlsSource",
ID: "",
}
}
7 changes: 7 additions & 0 deletions internal/core/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ type pathGetPathConfRes struct {

type pathGetPathConfReq struct {
name string
publish bool
credentials authCredentials
res chan pathGetPathConfRes
}
Expand Down Expand Up @@ -130,6 +131,7 @@ type pathPublisherAnnounceRes struct {
type pathPublisherAddReq struct {
author publisher
pathName string
skipAuth bool
credentials authCredentials
res chan pathPublisherAnnounceRes
}
Expand All @@ -151,6 +153,11 @@ type pathPublisherStopReq struct {
res chan struct{}
}

type pathAPISourceOrReader struct {
Type string `json:"type"`
ID string `json:"id"`
}

type pathAPIPathsListItem struct {
ConfName string `json:"confName"`
Conf *conf.PathConf `json:"conf"`
Expand Down
13 changes: 8 additions & 5 deletions internal/core/path_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ outer:
continue
}

err = authenticate(pm.externalAuthenticationURL, pm.authMethods, req.name, pathConf, false, req.credentials)
err = authenticate(pm.externalAuthenticationURL, pm.authMethods,
req.name, pathConf, req.publish, req.credentials)
if err != nil {
req.res <- pathGetPathConfRes{err: pathErrAuth{wrapped: err}}
continue
Expand Down Expand Up @@ -266,10 +267,12 @@ outer:
continue
}

err = authenticate(pm.externalAuthenticationURL, pm.authMethods, req.pathName, pathConf, true, req.credentials)
if err != nil {
req.res <- pathPublisherAnnounceRes{err: pathErrAuth{wrapped: err}}
continue
if !req.skipAuth {
err = authenticate(pm.externalAuthenticationURL, pm.authMethods, req.pathName, pathConf, true, req.credentials)
if err != nil {
req.res <- pathPublisherAnnounceRes{err: pathErrAuth{wrapped: err}}
continue
}
}

// create path if it doesn't exist
Expand Down
2 changes: 1 addition & 1 deletion internal/core/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package core
// reader is an entity that can read a stream.
type reader interface {
close()
apiReaderDescribe() interface{}
apiReaderDescribe() pathAPISourceOrReader
}
9 changes: 5 additions & 4 deletions internal/core/rpicamera_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ func (s *rpiCameraSource) run(ctx context.Context, cnf *conf.PathConf, reloadCon
}

// apiSourceDescribe implements sourceStaticImpl.
func (*rpiCameraSource) apiSourceDescribe() interface{} {
return struct {
Type string `json:"type"`
}{"rpiCameraSource"}
func (*rpiCameraSource) apiSourceDescribe() pathAPISourceOrReader {
return pathAPISourceOrReader{
Type: "rpiCameraSource",
ID: "",
}
}
Loading