Add web HTTP-FLV playback path

This commit is contained in:
2026-04-01 11:30:52 +08:00
parent 01b25883e1
commit 48dc6c7b26
11 changed files with 455 additions and 93 deletions

View File

@@ -3,12 +3,15 @@ package stream
import (
"fmt"
"io"
"net/http"
"strings"
"sync"
"github.com/gin-gonic/gin"
"github.com/nareix/joy4/av/avutil"
"github.com/nareix/joy4/av/pubsub"
"github.com/nareix/joy4/format"
"github.com/nareix/joy4/format/flv"
"github.com/nareix/joy4/format/rtmp"
"hightube/internal/chat"
@@ -28,6 +31,16 @@ type RTMPServer struct {
mutex sync.RWMutex
}
type writeFlusher struct {
httpFlusher http.Flusher
io.Writer
}
func (w writeFlusher) Flush() error {
w.httpFlusher.Flush()
return nil
}
// NewRTMPServer creates and initializes a new media server
func NewRTMPServer() *RTMPServer {
s := &RTMPServer{
@@ -140,3 +153,46 @@ func (s *RTMPServer) Start(addr string) error {
fmt.Printf("[INFO] RTMP Server is listening on %s...\n", addr)
return s.server.ListenAndServe()
}
// HandleHTTPFLV serves browser-compatible HTTP-FLV playback for web clients.
func (s *RTMPServer) HandleHTTPFLV(c *gin.Context) {
streamPath := fmt.Sprintf("/live/%s", c.Param("room_id"))
s.mutex.RLock()
q, ok := s.channels[streamPath]
s.mutex.RUnlock()
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "Stream not found or inactive"})
return
}
flusher, ok := c.Writer.(http.Flusher)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Streaming is not supported by the current server"})
return
}
c.Header("Content-Type", "video/x-flv")
c.Header("Transfer-Encoding", "chunked")
c.Header("Cache-Control", "no-cache")
c.Header("Connection", "keep-alive")
c.Header("Access-Control-Allow-Origin", "*")
c.Status(http.StatusOK)
flusher.Flush()
muxer := flv.NewMuxerWriteFlusher(writeFlusher{
httpFlusher: flusher,
Writer: c.Writer,
})
cursor := q.Latest()
if err := avutil.CopyFile(muxer, cursor); err != nil && err != io.EOF {
errStr := err.Error()
if strings.Contains(errStr, "broken pipe") || strings.Contains(errStr, "connection reset by peer") {
fmt.Printf("[INFO] HTTP-FLV viewer disconnected normally: %s\n", streamPath)
return
}
fmt.Printf("[ERROR] HTTP-FLV playback error on %s: %v\n", streamPath, err)
}
}