func (handler *DefaultServerStreamHandler) OnPlayStart(stream rtmp.ServerStream, name string, peerName string, start float64, duration float64, flushPrevPlaylist bool) { log.Printf("OnPlayStart requested by client for name=%q, start=%f, duration=%f, flush=%t", name, start, duration, flushPrevPlaylist) info, exists := rtmp.FindNetStream(name) if !exists { // TODO return appropriate answer to client log.Printf("net stream %q not found for play", name) return } channel := make(chan *rtmp.Message, 1000) handler.Lock() handler.channelsToClose = append(handler.channelsToClose, channel) handler.Unlock() downstreamer := downstreamer{peerName, info, channel} go func() { quitChan := make(chan error) defer close(quitChan) var downstreamedMessages int go func() { for { select { case <-quitChan: log.Printf("stopped relaying messages to downstream %s", downstreamer.peerName) rtmp.UnregisterDownstream(name, &downstreamer) return case <-time.After(5 * time.Second): log.Printf("downstream relay for %q to %q: processed %d messages", name, downstreamer.peerName, downstreamedMessages) } } }() for { select { case msg := <-channel: if msg == nil { // trigger close of quitChan return } msgCopy := rtmp.CopyToStream(stream, msg) stream.Conn().Send(msgCopy) downstreamedMessages++ case <-time.After(10 * time.Minute): log.Printf("no messages after 10 mins, downstreaming %q", name) } } }() err := rtmp.RegisterDownstream(name, &downstreamer) if err != nil { channel <- nil log.Printf("error registering downstream for NetStream %q", name) } }
func (handler *DefaultServerStreamHandler) OnPublishStart(stream rtmp.ServerStream, publishingName string, publishingType string) { log.Printf("OnPublishStart requested by client for name = %q, type = %q", publishingName, publishingType) // TODO: decide if this request will be accepted at all netStreamUpstream, dispatcherHandler, err := rtmp.RegisterNewNetStream(publishingName, publishingType, stream) if err != nil { // TODO return different, appropriate status message log.Printf("error creating registering new net stream %q/%s - upstream: %s", publishingName, publishingType, err.Error()) return } _ = netStreamUpstream if publishingType != "live" { recorderDownstream, err := rtmp.CreateRollingFileRecorder(netStreamUpstream.Info()) if err != nil { log.Printf("error creating flv file for writing: %s", err.Error()) return } err = rtmp.RegisterDownstream(netStreamUpstream.Info().Name, recorderDownstream) if err != nil { log.Printf("error creating registering new net stream - downstream") return } } stream.Attach(dispatcherHandler) message := rtmp.NewMessage(stream.ChunkStreamID(), rtmp.COMMAND_AMF0, stream.ID(), 0, nil) amf.WriteString(message.Buf, "onStatus") amf.WriteDouble(message.Buf, 0) amf.WriteNull(message.Buf) amf.WriteObject(message.Buf, amf.Object{ "level": "status", "code": rtmp.NETSTREAM_PUBLISH_START, "description": "start publishing!", }) message.LogDump("onpublishstart accept:") stream.Conn().Conn().Send(message) }