将amf迁入engine中方便服用

This commit is contained in:
dexter
2023-01-16 09:27:14 +08:00
parent 7f00f32cb7
commit a0b55d5e1b
6 changed files with 84 additions and 427 deletions

286
amf.go
View File

@@ -1,286 +0,0 @@
package rtmp
import (
"go.uber.org/zap"
"m7s.live/engine/v4/util"
)
// Action Message Format -- AMF 0
// Action Message Format -- AMF 3
// http://download.macromedia.com/pub/labs/amf/amf0_spec_121207.pdf
// http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/amf/pdf/amf-file-format-spec.pdf
// AMF Object == AMF Object Type(1 byte) + AMF Object Value
//
// AMF Object Value :
// AMF0_STRING : 2 bytes(datasize,记录string的长度) + data(string)
// AMF0_OBJECT : AMF0_STRING + AMF Object
// AMF0_NULL : 0 byte
// AMF0_NUMBER : 8 bytes
// AMF0_DATE : 10 bytes
// AMF0_BOOLEAN : 1 byte
// AMF0_ECMA_ARRAY : 4 bytes(arraysize,记录数组的长度) + AMF0_OBJECT
// AMF0_STRICT_ARRAY : 4 bytes(arraysize,记录数组的长度) + AMF Object
// 实际测试时,AMF0_ECMA_ARRAY数据如下:
// 8 0 0 0 13 0 8 100 117 114 97 116 105 111 110 0 0 0 0 0 0 0 0 0 0 5 119 105 100 116 104 0 64 158 0 0 0 0 0 0 0 6 104 101 105 103 104 116 0 64 144 224 0 0 0 0 0
// 8 0 0 0 13 | { 0 8 100 117 114 97 116 105 111 110 --- 0 0 0 0 0 0 0 0 0 } | { 0 5 119 105 100 116 104 --- 0 64 158 0 0 0 0 0 0 } | { 0 6 104 101 105 103 104 116 --- 0 64 144 224 0 0 0 0 0 } |...
// 13 | {AMF0_STRING --- AMF0_NUMBER} | {AMF0_STRING --- AMF0_NUMBER} | {AMF0_STRING --- AMF0_NUMBER} | ...
// 13 | {AMF0_OBJECT} | {AMF0_OBJECT} | {AMF0_OBJECT} | ...
// 13 | {duration --- 0} | {width --- 1920} | {height --- 1080} | ...
const (
AMF0_NUMBER = 0x00 // 浮点数
AMF0_BOOLEAN = 0x01 // 布尔型
AMF0_STRING = 0x02 // 字符串
AMF0_OBJECT = 0x03 // 对象,开始
AMF0_MOVIECLIP = 0x04
AMF0_NULL = 0x05 // null
AMF0_UNDEFINED = 0x06
AMF0_REFERENCE = 0x07
AMF0_ECMA_ARRAY = 0x08
AMF0_END_OBJECT = 0x09 // 对象,结束
AMF0_STRICT_ARRAY = 0x0A
AMF0_DATE = 0x0B // 日期
AMF0_LONG_STRING = 0x0C // 字符串
AMF0_UNSUPPORTED = 0x0D
AMF0_RECORDSET = 0x0E
AMF0_XML_DOCUMENT = 0x0F
AMF0_TYPED_OBJECT = 0x10
AMF0_AVMPLUS_OBJECT = 0x11
AMF3_UNDEFINED = 0x00
AMF3_NULL = 0x01
AMF3_FALSE = 0x02
AMF3_TRUE = 0x03
AMF3_INTEGER = 0x04
AMF3_DOUBLE = 0x05
AMF3_STRING = 0x06
AMF3_XML_DOC = 0x07
AMF3_DATE = 0x08
AMF3_ARRAY = 0x09
AMF3_OBJECT = 0x0A
AMF3_XML = 0x0B
AMF3_BYTE_ARRAY = 0x0C
AMF3_VECTOR_INT = 0x0D
AMF3_VECTOR_UINT = 0x0E
AMF3_VECTOR_DOUBLE = 0x0F
AMF3_VECTOR_OBJECT = 0x10
AMF3_DICTIONARY = 0x11
)
var END_OBJ = []byte{0, 0, AMF0_END_OBJECT}
type AMFValue any
type AMFObject map[string]AMFValue
type AMF struct {
util.Buffer
}
var ObjectEnd = &struct{}{}
var Undefined = &struct{}{}
func (amf *AMF) decodeObject() (obj AMFValue) {
if !amf.CanRead() {
return nil
}
t := amf.Buffer[0]
switch t {
case AMF0_NUMBER:
return amf.readNumber()
case AMF0_BOOLEAN:
return amf.readBool()
case AMF0_STRING:
return amf.readString()
case AMF0_OBJECT:
return amf.readObject()
case AMF0_MOVIECLIP:
RTMPPlugin.Error("This type is not supported and is reserved for future use.(AMF0_MOVIECLIP)")
case AMF0_NULL:
return amf.readNull()
case AMF0_UNDEFINED:
amf.ReadByte()
return Undefined
case AMF0_REFERENCE:
RTMPPlugin.Error("reference-type.(AMF0_REFERENCE)")
case AMF0_ECMA_ARRAY:
return amf.readECMAArray()
case AMF0_END_OBJECT:
amf.ReadByte()
return ObjectEnd
case AMF0_STRICT_ARRAY:
return amf.readStrictArray()
case AMF0_DATE:
return amf.readDate()
case AMF0_LONG_STRING,
AMF0_XML_DOCUMENT:
return amf.readLongString()
case AMF0_UNSUPPORTED:
RTMPPlugin.Error("If a type cannot be serialized a special unsupported marker can be used in place of the type.(AMF0_UNSUPPORTED)")
case AMF0_RECORDSET:
RTMPPlugin.Error("This type is not supported and is reserved for future use.(AMF0_RECORDSET)")
case AMF0_TYPED_OBJECT:
RTMPPlugin.Error("If a strongly typed object has an alias registered for its class then the type name will also be serialized. Typed objects are considered complex types and reoccurring instances can be sent by reference.(AMF0_TYPED_OBJECT)")
case AMF0_AVMPLUS_OBJECT:
RTMPPlugin.Error("AMF0_AVMPLUS_OBJECT")
default:
RTMPPlugin.Error("Unsupported type", zap.Uint8("type", t))
}
return nil
}
func (amf *AMF) writeObject(t AMFObject) {
if t == nil {
amf.writeNull()
return
}
amf.Malloc(1)[0] = AMF0_OBJECT
defer amf.Write(END_OBJ)
for k, vv := range t {
switch vvv := vv.(type) {
case string:
amf.writeObjectString(k, vvv)
case float64, uint, float32, int, int16, int32, int64, uint16, uint32, uint64, uint8, int8:
amf.writeObjectNumber(k, util.ToFloat64(vv))
case bool:
amf.writeObjectBool(k, vvv)
}
}
return
}
func (amf *AMF) readDate() uint64 {
amf.ReadByte()
ret := amf.ReadUint64()
amf.ReadN(2) // timezone
return ret
}
func (amf *AMF) readStrictArray() (list []AMFValue) {
amf.ReadByte()
size := amf.ReadUint32()
for i := uint32(0); i < size; i++ {
list = append(list, amf.decodeObject())
}
return
}
func (amf *AMF) readECMAArray() (m AMFObject) {
m = make(AMFObject, 0)
amf.ReadByte()
size := amf.ReadUint32()
for i := uint32(0); i < size; i++ {
k := amf.readString1()
v := amf.decodeObject()
if k == "" && v == ObjectEnd {
return
}
m[k] = v
}
return
}
func (amf *AMF) readString() string {
if amf.Len() == 0 {
return ""
}
amf.ReadByte()
return amf.readString1()
}
func (amf *AMF) readString1() string {
return string(amf.ReadN(int(amf.ReadUint16())))
}
func (amf *AMF) readLongString() string {
amf.ReadByte()
return string(amf.ReadN(int(amf.ReadUint32())))
}
func (amf *AMF) readNull() any {
amf.ReadByte()
return nil
}
func (amf *AMF) readNumber() (num float64) {
if amf.Len() == 0 {
return 0
}
amf.ReadByte()
return amf.ReadFloat64()
}
func (amf *AMF) readBool() bool {
if amf.Len() == 0 {
return false
}
amf.ReadByte()
return amf.ReadByte() == 1
}
func (amf *AMF) readObject() (m AMFObject) {
if amf.Len() == 0 {
return nil
}
if amf.ReadByte() == AMF0_NULL {
return nil
}
m = make(AMFObject, 0)
for {
k := amf.readString1()
v := amf.decodeObject()
if k == "" && v == ObjectEnd {
return
}
m[k] = v
}
}
func (amf *AMF) writeSize16(l int) {
util.PutBE(amf.Malloc(2), l)
}
func (amf *AMF) writeString(value string) {
amf.WriteByte(AMF0_STRING)
amf.writeSize16(len(value))
amf.WriteString(value)
}
func (amf *AMF) writeNull() {
amf.WriteByte(AMF0_NULL)
}
func (amf *AMF) writeBool(b bool) {
amf.WriteByte(AMF0_BOOLEAN)
if b {
amf.WriteByte(1)
}
amf.WriteByte(0)
}
func (amf *AMF) writeNumber(b float64) {
amf.WriteByte(AMF0_NUMBER)
amf.WriteFloat64(b)
}
func (amf *AMF) writeKey(key string) {
amf.writeSize16(len(key))
amf.WriteString(key)
}
func (amf *AMF) writeObjectString(key, value string) {
amf.writeKey(key)
amf.writeString(value)
}
func (amf *AMF) writeObjectBool(key string, f bool) {
amf.writeKey(key)
amf.writeBool(f)
}
func (amf *AMF) writeObjectNumber(key string, value float64) {
amf.writeKey(key)
amf.writeNumber(value)
}

View File

@@ -19,6 +19,11 @@ func NewRTMPClient(addr string) (client *NetConnection, err error) {
RTMPPlugin.Error("connect url parse", zap.Error(err))
return nil, err
}
ps := strings.Split(u.Path, "/")
if len(ps) < 3 {
RTMPPlugin.Error("illegal rtmp url", zap.String("url", addr))
return nil, errors.New("illegal rtmp url")
}
isRtmps := u.Scheme == "rtmps"
if strings.Count(u.Host, ":") == 0 {
if isRtmps {
@@ -54,12 +59,11 @@ func NewRTMPClient(addr string) (client *NetConnection, err error) {
RTMPPlugin.Error("handshake", zap.Error(err))
return nil, err
}
ps := strings.Split(u.Path, "/")
client.appName = ps[1]
err = client.SendMessage(RTMP_MSG_CHUNK_SIZE, Uint32Message(conf.ChunkSize))
client.SendMessage(RTMP_MSG_AMF0_COMMAND, &CallMessage{
CommandMessage{"connect", 1},
AMFObject{
map[string]any{
"app": client.appName,
"flashVer": "monibuca/" + engine.Engine.Version,
"swfUrl": addr,

View File

@@ -85,7 +85,7 @@ func (r *RTMPSender) Response(tid uint64, code, level string) error {
m := new(ResponsePlayMessage)
m.CommandName = Response_OnStatus
m.TransactionId = tid
m.Object = AMFObject{
m.Object = map[string]any{
"code": code,
"level": level,
"description": "",
@@ -104,7 +104,7 @@ func (r *RTMPReceiver) Response(tid uint64, code, level string) error {
m := new(ResponsePublishMessage)
m.CommandName = Response_OnStatus
m.TransactionId = tid
m.Infomation = AMFObject{
m.Infomation = map[string]any{
"code": code,
"level": level,
"description": "",

197
msg.go
View File

@@ -6,6 +6,7 @@ import (
"strings"
"go.uber.org/zap"
"m7s.live/engine/v4/codec"
"m7s.live/engine/v4/util"
)
@@ -198,36 +199,36 @@ func GetRtmpMessage(chunk *Chunk) error {
// object类型要复杂点.
// 第一个byte是03表示object,其后跟的是N个(key+value).最后以00 00 09表示object结束
func decodeCommandAMF0(chunk *Chunk) {
amf := AMF{chunk.Body} // rtmp_amf.go, amf 是 bytes类型, 将rtmp body(payload)放到bytes.Buffer(amf)中去.
cmd := amf.readString() // rtmp_amf.go, 将payload的bytes类型转换成string类型.
amf := codec.AMF{chunk.Body} // rtmp_amf.go, amf 是 bytes类型, 将rtmp body(payload)放到bytes.Buffer(amf)中去.
cmd := amf.ReadShortString() // rtmp_amf.go, 将payload的bytes类型转换成string类型.
cmdMsg := CommandMessage{
cmd,
uint64(amf.readNumber()),
uint64(amf.ReadNumber()),
}
switch cmd {
case "connect", "call":
chunk.MsgData = &CallMessage{
cmdMsg,
amf.readObject(),
amf.readObject(),
amf.ReadObject(),
amf.ReadObject(),
}
case "createStream":
amf.readNull()
amf.Unmarshal()
chunk.MsgData = &cmdMsg
case "play":
amf.readNull()
amf.Unmarshal()
m := &PlayMessage{
CURDStreamMessage{
cmdMsg,
chunk.MessageStreamID,
},
amf.readString(),
amf.ReadShortString(),
float64(-2),
float64(-1),
true,
}
for i := 0; i < 3; i++ {
if v := amf.decodeObject(); v != nil {
if v, _ := amf.Unmarshal(); v != nil {
switch vv := v.(type) {
case float64:
if i == 0 {
@@ -245,67 +246,67 @@ func decodeCommandAMF0(chunk *Chunk) {
}
chunk.MsgData = m
case "play2":
amf.readNull()
amf.Unmarshal()
chunk.MsgData = &Play2Message{
cmdMsg,
uint64(amf.readNumber()),
amf.readString(),
amf.readString(),
uint64(amf.readNumber()),
amf.readString(),
uint64(amf.ReadNumber()),
amf.ReadShortString(),
amf.ReadShortString(),
uint64(amf.ReadNumber()),
amf.ReadShortString(),
}
case "publish":
amf.readNull()
amf.Unmarshal()
chunk.MsgData = &PublishMessage{
CURDStreamMessage{
cmdMsg,
chunk.MessageStreamID,
},
amf.readString(),
amf.readString(),
amf.ReadShortString(),
amf.ReadShortString(),
}
case "pause":
amf.readNull()
amf.Unmarshal()
chunk.MsgData = &PauseMessage{
cmdMsg,
amf.readBool(),
uint64(amf.readNumber()),
amf.ReadBool(),
uint64(amf.ReadNumber()),
}
case "seek":
amf.readNull()
amf.Unmarshal()
chunk.MsgData = &SeekMessage{
cmdMsg,
uint64(amf.readNumber()),
uint64(amf.ReadNumber()),
}
case "deleteStream", "closeStream":
amf.readNull()
amf.Unmarshal()
chunk.MsgData = &CURDStreamMessage{
cmdMsg,
uint32(amf.readNumber()),
uint32(amf.ReadNumber()),
}
case "releaseStream":
amf.readNull()
amf.Unmarshal()
chunk.MsgData = &ReleaseStreamMessage{
cmdMsg,
amf.readString(),
amf.ReadShortString(),
}
case "receiveAudio", "receiveVideo":
amf.readNull()
amf.Unmarshal()
chunk.MsgData = &ReceiveAVMessage{
cmdMsg,
amf.readBool(),
amf.ReadBool(),
}
case Response_Result, Response_Error, Response_OnStatus:
if cmdMsg.TransactionId == 2 {
chunk.MsgData = &ResponseCreateStreamMessage{
cmdMsg, amf.readObject(), uint32(amf.readNumber()),
cmdMsg, amf.ReadObject(), uint32(amf.ReadNumber()),
}
return
}
response := &ResponseMessage{
cmdMsg,
amf.readObject(),
amf.readObject(), "",
amf.ReadObject(),
amf.ReadObject(), "",
}
codef := zap.String("code", response.Infomation["code"].(string))
switch response.Infomation["level"] {
@@ -360,11 +361,7 @@ func (cmd *CommandMessage) GetCommand() *CommandMessage {
}
func (msg *CommandMessage) Encode() (b []byte) {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeNull()
return amf.Buffer
return codec.MarshalAMFs(msg.CommandName, msg.TransactionId, nil)
}
// Protocol control message 1.
@@ -430,29 +427,23 @@ type MetadataMessage struct {
// The called RPC name is passed as a parameter to the call command.
type CallMessage struct {
CommandMessage
Object AMFObject `json:",omitempty"`
Optional AMFObject `json:",omitempty"`
Object map[string]any `json:",omitempty"`
Optional map[string]any `json:",omitempty"`
}
func (msg *CallMessage) Encode() []byte {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeObject(msg.Object)
var amf codec.AMF
amf.Marshals(msg.CommandName, msg.TransactionId, msg.Object)
if msg.Optional != nil {
amf.writeObject(msg.Optional)
amf.Marshal(msg.Optional)
}
return amf.Buffer
}
func (msg *CallMessage) Encode3() []byte {
var amf AMF
var amf codec.AMF
amf.WriteByte(0)
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeObject(msg.Object)
amf.writeObject(msg.Optional)
return amf.Buffer
return amf.Marshals(msg.CommandName, msg.TransactionId, msg.Object, msg.Optional)
}
// Create Stream Message.
@@ -502,12 +493,7 @@ type PlayMessage struct {
// Reset -> 可选的布尔值或者数字定义了是否对以前的播放列表进行 flush
func (msg *PlayMessage) Encode() []byte {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeNull()
amf.writeString(msg.StreamName)
amf.writeNumber(-2000)
var amf codec.AMF
// if msg.Start > 0 {
// amf.writeNumber(msg.Start)
// }
@@ -517,7 +503,7 @@ func (msg *PlayMessage) Encode() []byte {
// }
// amf.writeBool(msg.Reset)
return amf.Buffer
return amf.Marshals(msg.CommandName, msg.TransactionId, nil, msg.StreamName, -2000)
}
/*
@@ -591,13 +577,7 @@ type PublishMessage struct {
// “live”:发布直播数据而不录制到文件
func (msg *PublishMessage) Encode() []byte {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeNull()
amf.writeString(msg.PublishingName)
amf.writeString(msg.PublishingType)
return amf.Buffer
return codec.MarshalAMFs(msg.CommandName, msg.TransactionId, nil, msg.PublishingName, msg.PublishingType)
}
// Seek Message
@@ -631,22 +611,15 @@ func (msg *PauseMessage) Encode0() {
// Response Message. Server -> Response -> Client
//
//
// Response Connect Message
//
type ResponseConnectMessage struct {
CommandMessage
Properties AMFObject `json:",omitempty"`
Infomation AMFObject `json:",omitempty"`
Properties map[string]any `json:",omitempty"`
Infomation map[string]any `json:",omitempty"`
}
func (msg *ResponseConnectMessage) Encode() []byte {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeObject(msg.Properties)
amf.writeObject(msg.Infomation)
return amf.Buffer
return codec.MarshalAMFs(msg.CommandName, msg.TransactionId, msg.Properties, msg.Infomation)
}
/*
@@ -654,38 +627,25 @@ func (msg *ResponseConnectMessage) Encode3() {
}*/
// Response Call Message
//
type ResponseCallMessage struct {
CommandMessage
Object AMFObject
Response AMFObject
Object map[string]any
Response map[string]any
}
func (msg *ResponseCallMessage) Encode0() []byte {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeObject(msg.Object)
amf.writeObject(msg.Response)
return amf.Buffer
return codec.MarshalAMFs(msg.CommandName, msg.TransactionId, msg.Object, msg.Response)
}
//
// Response Create Stream Message
//
type ResponseCreateStreamMessage struct {
CommandMessage
Object interface{} `json:",omitempty"`
Object any `json:",omitempty"`
StreamId uint32
}
func (msg *ResponseCreateStreamMessage) Encode() []byte {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeNull()
amf.writeNumber(float64(msg.StreamId))
return amf.Buffer
return codec.MarshalAMFs(msg.CommandName, msg.TransactionId, nil, msg.StreamId)
}
/*
@@ -693,23 +653,21 @@ func (msg *ResponseCreateStreamMessage) Encode3() {
}*/
func (msg *ResponseCreateStreamMessage) Decode0(chunk *Chunk) {
amf := AMF{chunk.Body}
msg.CommandName = amf.decodeObject().(string)
msg.TransactionId = uint64(amf.decodeObject().(float64))
amf.decodeObject()
msg.StreamId = uint32(amf.decodeObject().(float64))
amf := codec.AMF{chunk.Body}
msg.CommandName = amf.ReadShortString()
msg.TransactionId = uint64(amf.ReadNumber())
amf.Unmarshal()
msg.StreamId = uint32(amf.ReadNumber())
}
func (msg *ResponseCreateStreamMessage) Decode3(chunk *Chunk) {
chunk.Body = chunk.Body[1:]
msg.Decode0(chunk)
}
//
// Response Play Message
//
type ResponsePlayMessage struct {
CommandMessage
Object AMFObject `json:",omitempty"`
Object map[string]any `json:",omitempty"`
Description string
StreamID uint32
}
@@ -718,13 +676,7 @@ func (msg *ResponsePlayMessage) GetStreamID() uint32 {
return msg.StreamID
}
func (msg *ResponsePlayMessage) Encode() []byte {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeNull()
amf.writeObject(msg.Object)
amf.writeString(msg.Description)
return amf.Buffer
return codec.MarshalAMFs(msg.CommandName, msg.TransactionId, nil, msg.Object, msg.Description)
}
/*
@@ -732,23 +684,21 @@ func (msg *ResponsePlayMessage) Encode3() {
}*/
func (msg *ResponsePlayMessage) Decode0(chunk *Chunk) {
amf := AMF{chunk.Body}
msg.CommandName = amf.decodeObject().(string)
msg.TransactionId = uint64(amf.decodeObject().(float64))
msg.Object = amf.decodeObject().(AMFObject)
amf := codec.AMF{chunk.Body}
msg.CommandName = amf.ReadShortString()
msg.TransactionId = uint64(amf.ReadNumber())
msg.Object = amf.ReadObject()
}
func (msg *ResponsePlayMessage) Decode3(chunk *Chunk) {
chunk.Body = chunk.Body[1:]
msg.Decode0(chunk)
}
//
// Response Publish Message
//
type ResponsePublishMessage struct {
CommandMessage
Properties AMFObject `json:",omitempty"`
Infomation AMFObject `json:",omitempty"`
Properties map[string]any `json:",omitempty"`
Infomation map[string]any `json:",omitempty"`
StreamID uint32
}
@@ -762,21 +712,14 @@ func (msg *ResponsePublishMessage) GetStreamID() uint32 {
// 信息 -> level, code, description
func (msg *ResponsePublishMessage) Encode() []byte {
var amf AMF
amf.writeString(msg.CommandName)
amf.writeNumber(float64(msg.TransactionId))
amf.writeObject(msg.Properties)
amf.writeObject(msg.Infomation)
return amf.Buffer
return codec.MarshalAMFs(msg.CommandName, msg.TransactionId, msg.Properties, msg.Infomation)
}
/*
func (msg *ResponsePublishMessage) Encode3() {
}*/
//
// Response Seek Message
//
type ResponseSeekMessage struct {
CommandMessage
Description string
@@ -788,9 +731,7 @@ func (msg *ResponseSeekMessage) Encode0() {
//func (msg *ResponseSeekMessage) Encode3() {
//}
//
// Response Pause Message
//
type ResponsePauseMessage struct {
CommandMessage
Description string
@@ -806,13 +747,11 @@ func (msg *ResponsePauseMessage) Encode0() {
//func (msg *ResponsePauseMessage) Encode3() {
//}
//
// Response Message
//
type ResponseMessage struct {
CommandMessage
Properties AMFObject `json:",omitempty"`
Infomation AMFObject `json:",omitempty"`
Properties map[string]any `json:",omitempty"`
Infomation map[string]any `json:",omitempty"`
Description string
}

View File

@@ -43,8 +43,8 @@ const (
SEND_FULL_VDIEO_MESSAGE = "Send Full Video Message"
)
func newConnectResponseMessageData(objectEncoding float64) (amfobj AMFObject) {
amfobj = make(AMFObject)
func newConnectResponseMessageData(objectEncoding float64) (amfobj map[string]any) {
amfobj = make(map[string]any)
amfobj["fmsVer"] = "monibuca/" + Engine.Version
amfobj["capabilities"] = 31
amfobj["mode"] = 1
@@ -56,8 +56,8 @@ func newConnectResponseMessageData(objectEncoding float64) (amfobj AMFObject) {
return
}
func newPublishResponseMessageData(streamid uint32, code, level string) (amfobj AMFObject) {
amfobj = make(AMFObject)
func newPublishResponseMessageData(streamid uint32, code, level string) (amfobj map[string]any) {
amfobj = make(map[string]any)
amfobj["code"] = code
amfobj["level"] = level
amfobj["streamid"] = streamid
@@ -65,8 +65,8 @@ func newPublishResponseMessageData(streamid uint32, code, level string) (amfobj
return
}
func newPlayResponseMessageData(streamid uint32, code, level string) (amfobj AMFObject) {
amfobj = make(AMFObject)
func newPlayResponseMessageData(streamid uint32, code, level string) (amfobj map[string]any) {
amfobj = make(map[string]any)
amfobj["code"] = code
amfobj["level"] = level
amfobj["streamid"] = streamid

View File

@@ -90,13 +90,13 @@ func (config *RTMPConfig) ServeTCP(conn *net.TCPConn) {
m := new(ResponseConnectMessage)
m.CommandName = Response_Result
m.TransactionId = 1
m.Properties = AMFObject{
m.Properties = map[string]any{
"fmsVer": "monibuca/" + engine.Engine.Version,
"capabilities": 31,
"mode": 1,
"Author": "dexter",
}
m.Infomation = AMFObject{
m.Infomation = map[string]any{
"level": Level_Status,
"code": NetConnection_Connect_Success,
"objectEncoding": nc.objectEncoding,