-
Notifications
You must be signed in to change notification settings - Fork 206
/
Copy pathmain.go
195 lines (160 loc) · 5.19 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package main
import (
"log"
"sync"
"github.com/pion/rtp"
"github.com/bluenviron/gortsplib/v4"
"github.com/bluenviron/gortsplib/v4/pkg/base"
"github.com/bluenviron/gortsplib/v4/pkg/description"
"github.com/bluenviron/gortsplib/v4/pkg/format"
"github.com/bluenviron/gortsplib/v4/pkg/liberrors"
)
// This example shows how to
// 1. create a RTSP server which accepts plain connections
// 2. allow a single client to publish a stream with TCP or UDP, if it provides credentials
// 3. allow multiple clients to read that stream with TCP, UDP or UDP-multicast, if they provide credentials
const (
// credentials required to publish the stream
publishUser = "publishuser"
publishPass = "publishpass"
// credentials required to read the stream
readUser = "readuser"
readPass = "readpass"
)
type serverHandler struct {
s *gortsplib.Server
mutex sync.Mutex
stream *gortsplib.ServerStream
publisher *gortsplib.ServerSession
}
// called when a connection is opened.
func (sh *serverHandler) OnConnOpen(ctx *gortsplib.ServerHandlerOnConnOpenCtx) {
log.Printf("conn opened")
}
// called when a connection is closed.
func (sh *serverHandler) OnConnClose(ctx *gortsplib.ServerHandlerOnConnCloseCtx) {
log.Printf("conn closed (%v)", ctx.Error)
}
// called when a session is opened.
func (sh *serverHandler) OnSessionOpen(ctx *gortsplib.ServerHandlerOnSessionOpenCtx) {
log.Printf("session opened")
}
// called when a session is closed.
func (sh *serverHandler) OnSessionClose(ctx *gortsplib.ServerHandlerOnSessionCloseCtx) {
log.Printf("session closed")
sh.mutex.Lock()
defer sh.mutex.Unlock()
// if the session is the publisher,
// close the stream and disconnect any reader.
if sh.stream != nil && ctx.Session == sh.publisher {
sh.stream.Close()
sh.stream = nil
}
}
// called when receiving a DESCRIBE request.
func (sh *serverHandler) OnDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx) (*base.Response, *gortsplib.ServerStream, error) {
log.Printf("describe request")
// Verify reader credentials.
// In case of readers, credentials have to be verified during DESCRIBE and SETUP.
ok := ctx.Conn.VerifyCredentials(ctx.Request, readUser, readPass)
if !ok {
return &base.Response{
StatusCode: base.StatusUnauthorized,
}, nil, liberrors.ErrServerAuth{}
}
sh.mutex.Lock()
defer sh.mutex.Unlock()
// no one is publishing yet
if sh.stream == nil {
return &base.Response{
StatusCode: base.StatusNotFound,
}, nil, nil
}
// send medias that are being published to the client
return &base.Response{
StatusCode: base.StatusOK,
}, sh.stream, nil
}
// called when receiving an ANNOUNCE request.
func (sh *serverHandler) OnAnnounce(ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) {
log.Printf("announce request")
// Verify publisher credentials.
// In case of publishers, credentials have to be verified during ANNOUNCE.
ok := ctx.Conn.VerifyCredentials(ctx.Request, publishUser, publishPass)
if !ok {
return &base.Response{
StatusCode: base.StatusUnauthorized,
}, liberrors.ErrServerAuth{}
}
sh.mutex.Lock()
defer sh.mutex.Unlock()
// disconnect existing publisher
if sh.stream != nil {
sh.stream.Close()
sh.publisher.Close()
}
// create the stream and save the publisher
sh.stream = gortsplib.NewServerStream(sh.s, ctx.Description)
sh.publisher = ctx.Session
return &base.Response{
StatusCode: base.StatusOK,
}, nil
}
// called when receiving a SETUP request.
func (sh *serverHandler) OnSetup(ctx *gortsplib.ServerHandlerOnSetupCtx) (*base.Response, *gortsplib.ServerStream, error) {
log.Printf("setup request")
// Verify reader credentials.
// In case of readers, credentials have to be verified during DESCRIBE and SETUP.
if ctx.Session.State() == gortsplib.ServerSessionStateInitial {
ok := ctx.Conn.VerifyCredentials(ctx.Request, readUser, readPass)
if !ok {
return &base.Response{
StatusCode: base.StatusUnauthorized,
}, nil, liberrors.ErrServerAuth{}
}
}
// no one is publishing yet
if sh.stream == nil {
return &base.Response{
StatusCode: base.StatusNotFound,
}, nil, nil
}
return &base.Response{
StatusCode: base.StatusOK,
}, sh.stream, nil
}
// called when receiving a PLAY request.
func (sh *serverHandler) OnPlay(ctx *gortsplib.ServerHandlerOnPlayCtx) (*base.Response, error) {
log.Printf("play request")
return &base.Response{
StatusCode: base.StatusOK,
}, nil
}
// called when receiving a RECORD request.
func (sh *serverHandler) OnRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.Response, error) {
log.Printf("record request")
// called when receiving a RTP packet
ctx.Session.OnPacketRTPAny(func(medi *description.Media, forma format.Format, pkt *rtp.Packet) {
// route the RTP packet to all readers
sh.stream.WritePacketRTP(medi, pkt)
})
return &base.Response{
StatusCode: base.StatusOK,
}, nil
}
func main() {
// configure the server
h := &serverHandler{}
h.s = &gortsplib.Server{
Handler: h,
RTSPAddress: ":8554",
UDPRTPAddress: ":8000",
UDPRTCPAddress: ":8001",
MulticastIPRange: "224.1.0.0/16",
MulticastRTPPort: 8002,
MulticastRTCPPort: 8003,
}
// start server and wait until a fatal error
log.Printf("server is ready")
panic(h.s.StartAndWait())
}