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.
90 lines
3.3 KiB
90 lines
3.3 KiB
package live
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
type DisabledAdapter struct{}
|
|
|
|
func (DisabledAdapter) Provider() string { return "disabled" }
|
|
func (DisabledAdapter) CreateStream(StreamRequest) (StreamCredentials, error) {
|
|
return StreamCredentials{}, ErrDisabled
|
|
}
|
|
func (DisabledAdapter) CreatePlayURLs(PlayRequest) (PlayURLs, error) { return PlayURLs{}, ErrDisabled }
|
|
func (DisabledAdapter) QueryOnline(string) (OnlineStatus, error) { return OnlineStatus{}, ErrDisabled }
|
|
|
|
// FakeAdapter is a local provider that never contacts a cloud service.
|
|
type FakeAdapter struct {
|
|
PlayDomain string
|
|
PushDomain string
|
|
AppName string
|
|
}
|
|
|
|
func (f FakeAdapter) Provider() string { return "fake" }
|
|
func (f FakeAdapter) CreateStream(req StreamRequest) (StreamCredentials, error) {
|
|
return StreamCredentials{
|
|
Provider: f.Provider(),
|
|
PushURL: "fake://" + f.PushDomain + "/" + f.AppName + "/" + req.StreamName,
|
|
ExpiresAt: req.ExpiresAt,
|
|
}, nil
|
|
}
|
|
func (f FakeAdapter) CreatePlayURLs(req PlayRequest) (PlayURLs, error) {
|
|
return PlayURLs{
|
|
HLS: "fake://" + f.PlayDomain + "/" + f.AppName + "/" + req.StreamName + ".m3u8",
|
|
ExpiresAt: req.ExpiresAt,
|
|
}, nil
|
|
}
|
|
func (f FakeAdapter) QueryOnline(string) (OnlineStatus, error) {
|
|
return OnlineStatus{Online: true}, nil
|
|
}
|
|
|
|
type AliyunAdapter struct {
|
|
cfg Config
|
|
}
|
|
|
|
func NewAliyunAdapter(cfg Config) (Adapter, error) {
|
|
if !cfg.AllowRealCloud || cfg.PushDomain == "" || cfg.PlayDomain == "" || cfg.AppName == "" || cfg.AuthKey == "" || cfg.PlayAuthKey == "" {
|
|
return nil, ErrInvalidConfig
|
|
}
|
|
if cfg.Protocol == "" {
|
|
cfg.Protocol = "srt"
|
|
}
|
|
if cfg.SRTPort <= 0 {
|
|
cfg.SRTPort = 1105
|
|
}
|
|
return AliyunAdapter{cfg: cfg}, nil
|
|
}
|
|
|
|
func (a AliyunAdapter) Provider() string { return "aliyun" }
|
|
func (a AliyunAdapter) CreateStream(req StreamRequest) (StreamCredentials, error) {
|
|
return StreamCredentials{Provider: a.Provider(), PushURL: a.pushURL(req.StreamName, req.ExpiresAt), ExpiresAt: req.ExpiresAt}, nil
|
|
}
|
|
func (a AliyunAdapter) CreatePlayURLs(req PlayRequest) (PlayURLs, error) {
|
|
expires := req.ExpiresAt
|
|
path := "/" + a.cfg.AppName + "/" + req.StreamName
|
|
signature := sign(path, expires.Unix(), a.cfg.PlayAuthKey)
|
|
base := "https://" + a.cfg.PlayDomain + "/" + a.cfg.AppName + "/" + req.StreamName
|
|
return PlayURLs{HLS: base + ".m3u8?auth_key=" + signature, FLV: base + ".flv?auth_key=" + signature, RTMP: "rtmp://" + a.cfg.PlayDomain + "/" + a.cfg.AppName + "/" + req.StreamName, ExpiresAt: expires}, nil
|
|
}
|
|
func (a AliyunAdapter) QueryOnline(string) (OnlineStatus, error) {
|
|
return OnlineStatus{}, errors.New("aliyun online query is not configured")
|
|
}
|
|
func sign(path string, expiresAt int64, key string) string {
|
|
rand := strconv.FormatInt(expiresAt%10000, 10)
|
|
sum := md5.Sum([]byte(fmt.Sprintf("%s-%d-%s-%s-%s", path, expiresAt, rand, "0", key)))
|
|
return fmt.Sprintf("%d-%s-0-%s", expiresAt, rand, hex.EncodeToString(sum[:]))
|
|
}
|
|
|
|
func (a AliyunAdapter) pushURL(streamName string, expires time.Time) string {
|
|
path := "/" + a.cfg.AppName + "/" + streamName
|
|
auth := sign(path, expires.Unix(), a.cfg.AuthKey)
|
|
if a.cfg.Protocol == "srt" {
|
|
return "srt://" + a.cfg.PushDomain + ":" + strconv.Itoa(a.cfg.SRTPort) + "?streamid=#!::h=" + a.cfg.PushDomain + ",r=" + path + "?auth_key=" + auth + ",m=publish"
|
|
}
|
|
return "rtmps://" + a.cfg.PushDomain + "/" + a.cfg.AppName + "/" + streamName + "?auth_key=" + auth
|
|
}
|
|
|