Add various features

* HTTP Server
* Config files
This commit is contained in:
2021-09-02 02:49:11 +02:00
parent 1d6e4270ba
commit 80acc281b9
10 changed files with 153 additions and 55 deletions

View File

@@ -9,8 +9,10 @@ import (
"sync"
"time"
"github.com/dustin/go-humanize"
"github.com/nareix/joy5/av"
"github.com/nareix/joy5/format/rtmp"
"go.uber.org/atomic"
"go.uber.org/zap"
)
@@ -21,9 +23,12 @@ type RTMPClient struct {
stream *Stream
ctx context.Context
ctxCancel context.CancelFunc
timestamp time.Time
keyframeSent bool
bytesSent atomic.Uint64
packetsChan chan av.Packet
}
@@ -34,22 +39,25 @@ func NewRTMPClient(rs *RTMPServer, stream *Stream, c *rtmp.Conn, nc net.Conn) *R
nc: nc,
server: rs,
stream: stream,
packetsChan: make(chan av.Packet, 10),
packetsChan: make(chan av.Packet, 100),
ctx: ctx,
ctxCancel: cancel,
timestamp: time.Now(),
}
}
type Stream struct {
Name string
Clients []*RTMPClient
clientsLock sync.Mutex
server *RTMPServer
nc net.Conn
c *rtmp.Conn
ctx context.Context
ctxCancel context.CancelFunc
startTime time.Time
Name string
Clients []*RTMPClient
clientsLock sync.Mutex
server *RTMPServer
nc net.Conn
c *rtmp.Conn
ctx context.Context
ctxCancel context.CancelFunc
startTime time.Time
bytesReceived atomic.Uint64
bytesSent atomic.Uint64
metadataPacket *av.Packet
h264DecoderConfigPacket *av.Packet
@@ -91,7 +99,10 @@ func (s *Stream) handleBroadcaster(c *rtmp.Conn, nc net.Conn) {
}
// Once all clients have been removed, remove stream from server
s.server.RemoveStream(s)
s.server.Logger.Infow("Stream has been successfully stopped.", "stream_name", s.Name, "duration_seconds", time.Since(s.startTime))
s.server.Logger.Infow("Stream has been successfully stopped.",
"stream_name", s.Name,
"stream_duration", time.Since(s.startTime),
"bytes_received", humanize.Bytes(s.bytesReceived.Load()))
}()
for {
@@ -119,6 +130,10 @@ func (s *Stream) handleBroadcaster(c *rtmp.Conn, nc net.Conn) {
}
nc.Close()
}
// Increase received counter
s.bytesReceived.Add(uint64(len(pkt.Data)))
switch pkt.Type {
case av.Metadata:
s.server.Logger.Debugw("Got metadata packet for stream.", "stream_name", s.Name)
@@ -138,9 +153,10 @@ func (s *Stream) handleBroadcaster(c *rtmp.Conn, nc net.Conn) {
for _, client := range s.Clients {
select {
case client.packetsChan <- pkt:
s.bytesSent.Add(uint64(len(pkt.Data)))
continue
default:
logger.Info("Client channel is blocking.")
logger.Info("Client channel is blocking.", zap.String("client_addr", client.nc.RemoteAddr().String()))
}
}
}
@@ -154,10 +170,14 @@ func (client *RTMPClient) handleClient() {
defer func() {
client.nc.Close()
stream.RemoveClient(client)
server.Logger.Infow("Disconnected viewer.", "client_addr", client.nc.RemoteAddr().String(), "stream_name", stream.Name)
server.Logger.Infow("Disconnected viewer.",
"client_addr", client.nc.RemoteAddr().String(),
"stream_name", stream.Name,
"watch_duration", time.Since(client.timestamp),
"bytes_sent", humanize.Bytes(client.bytesSent.Load()))
}()
server.Logger.Infow("Viewer connected.", "stream", stream.Name, "remote_addr", client.nc.RemoteAddr().String())
server.Logger.Infow("Viewer connected.", "stream", stream.Name, "client_addr", client.nc.RemoteAddr().String())
// First ensure that metadata, and decoder configs are set
// TODO: Ensure stream isnt cancelled before sending metadata and decoder configs
for stream.aacDecoderConfigPacket == nil || stream.metadataPacket == nil || stream.h264DecoderConfigPacket == nil {
@@ -189,11 +209,11 @@ func (client *RTMPClient) handleClient() {
// Wait for keyframe before sending video
if !pkt.IsKeyFrame && !client.keyframeSent {
continue
} else {
} else if !client.keyframeSent {
// Assume that the packet will get sent
client.keyframeSent = true
server.Logger.Debugw("Got keyframe. Sending video.", "client_addr", client.nc.RemoteAddr().String(), "stream_name", stream.Name)
}
server.Logger.Debugw("Got keyframe. Sending video.", "client_addr", client.nc.RemoteAddr().String(), "stream_name", stream.Name)
client.nc.SetWriteDeadline(time.Now().Add(1 * time.Second))
if err := client.c.WritePacket(pkt); err != nil {
@@ -212,6 +232,7 @@ func (client *RTMPClient) handleClient() {
server.Logger.Debugw("Error while writing packet to viewer.", "client_addr", client.nc.RemoteAddr().String(), "error_message", err)
return
}
client.bytesSent.Add(uint64(len(pkt.Data)))
}
}
@@ -274,7 +295,7 @@ func (rs *RTMPServer) Listen() error {
for len(rs.streams) > 0 {
time.Sleep(200 * time.Millisecond)
}
rs.Logger.Infow("Server stopped.")
rs.Logger.Infow("RTMP server stopped.")
return nil
}
// Connection not closed, wait and try again

View File

@@ -12,6 +12,7 @@ import (
type WebServer struct {
Logger *zap.SugaredLogger
ListenAddr string
ctx context.Context
rtmpServer *RTMPServer
httpServer *http.Server
@@ -22,23 +23,32 @@ func NewWebServer(ctx context.Context, rs *RTMPServer) *WebServer {
ctx: ctx,
rtmpServer: rs,
Logger: zap.NewNop().Sugar(),
ListenAddr: ":8077",
}
}
func (ws *WebServer) Serve() error {
ws.httpServer = &http.Server{
Addr: ":8077",
Addr: ws.ListenAddr,
Handler: http.HandlerFunc(ws.IndexHandler),
}
go func() {
<-ws.ctx.Done()
ws.Logger.Debugw("HTTP shutdown signal received.")
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = ws.httpServer.Shutdown(shutdownCtx)
}()
return ws.httpServer.ListenAndServe()
err := ws.httpServer.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
ws.Logger.Warnw("HTTP Server stopped with error.", "error", err)
return err
}
ws.Logger.Info("HTTP server stopped.")
return nil
}
func (ws *WebServer) IndexHandler(w http.ResponseWriter, r *http.Request) {