|
|
@ -4,51 +4,129 @@ import ( |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"io" |
|
|
|
"io" |
|
|
|
"net" |
|
|
|
"net" |
|
|
|
|
|
|
|
"os" |
|
|
|
|
|
|
|
"strings" |
|
|
|
|
|
|
|
"syscall" |
|
|
|
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gabek/owncast/config" |
|
|
|
|
|
|
|
"github.com/gabek/owncast/core" |
|
|
|
|
|
|
|
"github.com/gabek/owncast/core/ffmpeg" |
|
|
|
|
|
|
|
"github.com/gabek/owncast/utils" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/nareix/joy5/format/flv" |
|
|
|
|
|
|
|
"github.com/nareix/joy5/format/rtmp" |
|
|
|
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus" |
|
|
|
log "github.com/sirupsen/logrus" |
|
|
|
yutmp "github.com/yutopp/go-rtmp" |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
//IsConnected whether there is a connection or not
|
|
|
|
//IsConnected whether there is a connection or not
|
|
|
|
_isConnected = false |
|
|
|
_isConnected = false |
|
|
|
|
|
|
|
pipePath = utils.GetTemporaryPipePath() |
|
|
|
|
|
|
|
filePipe *os.File |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
//Start starts the rtmp service, listening on port 1935
|
|
|
|
//Start starts the rtmp service, listening on port 1935
|
|
|
|
func Start() { |
|
|
|
func Start() { |
|
|
|
port := 1935 |
|
|
|
port := 1935 |
|
|
|
|
|
|
|
|
|
|
|
tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf(":%d", port)) |
|
|
|
server := rtmp.NewServer() |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Panicf("Failed to resolve the tcp address for the rtmp service: %+v", err) |
|
|
|
server.LogEvent = func(conn *rtmp.Conn, nc net.Conn, e int) { |
|
|
|
|
|
|
|
log.Errorln("RTMP status:", rtmp.EventString[e]) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
listener, err := net.ListenTCP("tcp", tcpAddr) |
|
|
|
server.OnNewConn = func(conn *rtmp.Conn) { |
|
|
|
if err != nil { |
|
|
|
log.Println("OnNewConn!", conn.FlashVer) |
|
|
|
log.Panicf("Failed to acquire the tcp listener: %+v", err) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
srv := yutmp.NewServer(&yutmp.ServerConfig{ |
|
|
|
server.HandleConn = func(conn *rtmp.Conn, nc net.Conn) { |
|
|
|
OnConnect: func(conn net.Conn) (io.ReadWriteCloser, *yutmp.ConnConfig) { |
|
|
|
if _isConnected { |
|
|
|
l := log.StandardLogger() |
|
|
|
log.Errorln("stream already running; can not overtake an existing stream") |
|
|
|
l.SetLevel(log.WarnLevel) |
|
|
|
nc.Close() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
streamingKeyComponents := strings.Split(conn.URL.Path, "/") |
|
|
|
|
|
|
|
streamingKey := streamingKeyComponents[len(streamingKeyComponents)-1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if streamingKey != config.Config.VideoSettings.StreamingKey { |
|
|
|
|
|
|
|
log.Errorln("invalid streaming key; rejecting incoming stream") |
|
|
|
|
|
|
|
nc.Close() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Record streams as FLV
|
|
|
|
|
|
|
|
syscall.Mkfifo(pipePath, 0666) |
|
|
|
|
|
|
|
file, err := os.OpenFile(pipePath, os.O_RDWR, os.ModeNamedPipe) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Panicln(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filePipe = file |
|
|
|
|
|
|
|
fmt.Println(pipePath) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
muxer := flv.NewMuxer(filePipe) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_isConnected = true |
|
|
|
|
|
|
|
core.SetStreamAsConnected() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
defer filePipe.Close() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return conn, &yutmp.ConnConfig{ |
|
|
|
defer nc.Close() |
|
|
|
Handler: &Handler{}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ControlState: yutmp.StreamControlStateConfig{ |
|
|
|
transcoder := ffmpeg.NewTranscoder() |
|
|
|
DefaultBandwidthWindowSize: 6 * 1024 * 1024 / 8, |
|
|
|
go transcoder.Start() |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Logger: l, |
|
|
|
for { |
|
|
|
|
|
|
|
pkt, err := conn.ReadPacket() |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Errorln(err) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err == io.EOF { |
|
|
|
|
|
|
|
_isConnected = false |
|
|
|
|
|
|
|
core.SetStreamAsDisconnected() |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// err = muxer.WriteFileHeader()
|
|
|
|
|
|
|
|
// if err != nil {
|
|
|
|
|
|
|
|
// log.Errorln(err)
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = muxer.WritePacket(pkt) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Errorln(err) |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.Infof("RTMP server is listening for incoming stream on port: %d", port) |
|
|
|
} |
|
|
|
if err := srv.Serve(listener); err != nil { |
|
|
|
|
|
|
|
log.Panicf("Failed to serve the rtmp service: %+v", err) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var lis net.Listener |
|
|
|
|
|
|
|
var err error |
|
|
|
|
|
|
|
if lis, err = net.Listen("tcp", fmt.Sprintf(":%d", port)); err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
log.Printf("RTMP server is listening for incoming stream on port: %d", port) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
go func() { |
|
|
|
|
|
|
|
for { |
|
|
|
|
|
|
|
nc, err := lis.Accept() |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
time.Sleep(time.Second) |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
go server.HandleNetConn(nc) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}() |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//IsConnected gets whether there is an rtmp connection or not
|
|
|
|
//IsConnected gets whether there is an rtmp connection or not
|
|
|
|