You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.6 KiB
99 lines
2.6 KiB
package transcoder |
|
|
|
import ( |
|
"bytes" |
|
"io" |
|
"net" |
|
"os" |
|
"path/filepath" |
|
"strings" |
|
|
|
"net/http" |
|
|
|
"github.com/owncast/owncast/config" |
|
"github.com/owncast/owncast/utils" |
|
log "github.com/sirupsen/logrus" |
|
) |
|
|
|
// FileWriterReceiverServiceCallback are to be fired when transcoder responses are written to disk. |
|
type FileWriterReceiverServiceCallback interface { |
|
SegmentWritten(localFilePath string) |
|
VariantPlaylistWritten(localFilePath string) |
|
MasterPlaylistWritten(localFilePath string) |
|
} |
|
|
|
// FileWriterReceiverService accepts transcoder responses via HTTP and fires the callbacks. |
|
type FileWriterReceiverService struct { |
|
callbacks FileWriterReceiverServiceCallback |
|
} |
|
|
|
// SetupFileWriterReceiverService will start listening for transcoder responses. |
|
func (s *FileWriterReceiverService) SetupFileWriterReceiverService(callbacks FileWriterReceiverServiceCallback) { |
|
s.callbacks = callbacks |
|
|
|
httpServer := http.NewServeMux() |
|
httpServer.HandleFunc("/", s.uploadHandler) |
|
|
|
localListenerAddress := "127.0.0.1:0" |
|
|
|
// go func() { |
|
listener, err := net.Listen("tcp", localListenerAddress) |
|
if err != nil { |
|
log.Fatalln("Unable to start internal video writing service", err) |
|
} |
|
|
|
listenerPort := strings.Split(listener.Addr().String(), ":")[1] |
|
config.InternalHLSListenerPort = listenerPort |
|
log.Traceln("Transcoder response service listening on: " + listenerPort) |
|
go func() { |
|
if err := http.Serve(listener, httpServer); err != nil { |
|
log.Fatalln("Unable to start internal video writing service", err) |
|
} |
|
}() |
|
} |
|
|
|
func (s *FileWriterReceiverService) uploadHandler(w http.ResponseWriter, r *http.Request) { |
|
if r.Method != "PUT" { |
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) |
|
return |
|
} |
|
|
|
path := r.URL.Path |
|
writePath := filepath.Join(config.PrivateHLSStoragePath, path) |
|
|
|
var buf bytes.Buffer |
|
defer r.Body.Close() |
|
|
|
_, _ = io.Copy(&buf, r.Body) |
|
data := buf.Bytes() |
|
|
|
f, err := os.Create(writePath) |
|
if err != nil { |
|
returnError(err, w) |
|
return |
|
} |
|
|
|
defer f.Close() |
|
if _, err := f.Write(data); err != nil { |
|
returnError(err, w) |
|
return |
|
} |
|
|
|
s.fileWritten(writePath) |
|
w.WriteHeader(http.StatusOK) |
|
} |
|
|
|
func (s *FileWriterReceiverService) fileWritten(path string) { |
|
if utils.GetRelativePathFromAbsolutePath(path) == "hls/stream.m3u8" { |
|
s.callbacks.MasterPlaylistWritten(path) |
|
} else if strings.HasSuffix(path, ".ts") { |
|
s.callbacks.SegmentWritten(path) |
|
} else if strings.HasSuffix(path, ".m3u8") { |
|
s.callbacks.VariantPlaylistWritten(path) |
|
} |
|
} |
|
|
|
func returnError(err error, w http.ResponseWriter) { |
|
log.Debugln(err) |
|
http.Error(w, http.StatusText(http.StatusInternalServerError)+": "+err.Error(), http.StatusInternalServerError) |
|
}
|
|
|