Files
plugin-jessica/subscriber.go
2021-03-06 17:24:59 +08:00

106 lines
2.5 KiB
Go

package jessica
import (
"encoding/binary"
"net/http"
"regexp"
. "github.com/Monibuca/engine/v3"
"github.com/Monibuca/utils/v3"
"github.com/Monibuca/utils/v3/codec"
"github.com/gobwas/ws"
)
var streamPathReg = regexp.MustCompile("/(jessica/)?((.+)(\\.flv)|(.+))")
func WsHandler(w http.ResponseWriter, r *http.Request) {
sign := r.URL.Query().Get("sign")
isFlv := false
// if err := AuthHooks.Trigger(sign); err != nil {
// w.WriteHeader(403)
// return
// }
parts := streamPathReg.FindStringSubmatch(r.RequestURI)
streamPath := parts[3]
if streamPath == "" {
streamPath = parts[5]
} else {
isFlv = true
}
conn, _, _, err := ws.UpgradeHTTP(r, w)
if err != nil {
return
}
baseStream := Subscriber{Sign: sign, ID: r.RemoteAddr, Type: "Jessica", Ctx2: r.Context()}
if isFlv {
baseStream.Type = "JessicaFlv"
}
defer conn.Close()
go func() {
b := []byte{0}
for _, err := conn.Read(b); err == nil; _, err = conn.Read(b) {
}
}()
if baseStream.Subscribe(streamPath) == nil {
at := baseStream.GetAudioTrack("aac")
vt := baseStream.OriginVideoTrack
var writeAV func(byte, uint32, []byte)
if isFlv {
if err := ws.WriteHeader(conn, ws.Header{
Fin: true,
OpCode: ws.OpBinary,
Length: int64(13),
}); err != nil {
return
}
if _, err = conn.Write(codec.FLVHeader); err != nil {
return
}
writeAV = func(t byte, ts uint32, payload []byte) {
ws.WriteHeader(conn, ws.Header{
Fin: true,
OpCode: ws.OpBinary,
Length: int64(len(payload) + 15),
})
codec.WriteFLVTag(conn, t, ts, payload)
}
} else {
writeAV = func(t byte, ts uint32, payload []byte) {
ws.WriteHeader(conn, ws.Header{
Fin: true,
OpCode: ws.OpBinary,
Length: int64(len(payload) + 5),
})
head := utils.GetSlice(5)
defer utils.RecycleSlice(head)
head[0] = t - 7
binary.BigEndian.PutUint32(head[1:5], ts)
if _, err = conn.Write(head); err != nil {
return
}
conn.Write(payload)
}
}
if vt != nil {
writeAV(codec.FLV_TAG_TYPE_VIDEO, 0, vt.RtmpTag)
baseStream.OnVideo = func(pack VideoPack) {
payload := pack.ToRTMPTag()
defer utils.RecycleSlice(payload)
writeAV(codec.FLV_TAG_TYPE_VIDEO, pack.Timestamp, payload)
}
}
if at != nil {
writeAV(codec.FLV_TAG_TYPE_AUDIO, 0, at.RtmpTag)
baseStream.OnAudio = func(pack AudioPack) {
payload := pack.ToRTMPTag(at.RtmpTag[0])
defer utils.RecycleSlice(payload)
writeAV(codec.FLV_TAG_TYPE_AUDIO, pack.Timestamp, payload)
}
}
baseStream.Play(at, vt)
} else {
w.WriteHeader(404)
}
}