First cut at AMF refactoring; use idiomatic names.

This commit is contained in:
scruzin 2019-01-12 06:42:34 +10:30
parent e78cc93432
commit 19f245ae76
5 changed files with 270 additions and 348 deletions

View File

@ -3,15 +3,16 @@ NAME
amf.go amf.go
DESCRIPTION DESCRIPTION
See Readme.md RMTP encoding/decoding functions.
AUTHORS AUTHORS
Saxon Nelson-Milton <saxon@ausocean.org> Saxon Nelson-Milton <saxon@ausocean.org>
Dan Kortschak <dan@ausocean.org> Dan Kortschak <dan@ausocean.org>
Jake Lane <jake@ausocean.org> Jake Lane <jake@ausocean.org>
Alan Noble <alan@ausocean.org>
LICENSE LICENSE
amf.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) amf.go is Copyright (C) 2017-2019 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the under the terms of the GNU General Public License as published by the
@ -35,71 +36,90 @@ package rtmp
import ( import (
"encoding/binary" "encoding/binary"
"log"
"math" "math"
) )
var (
AMFObj_Invalid C_AMFObject
AMFProp_Invalid = C_AMFObjectProperty{p_type: AMF_INVALID}
)
const ( const (
AMF3_INTEGER_MAX = 268435455 amfNumber = iota
AMF3_INTEGER_MIN = -268435456 amfBoolean
amfString
amfObject
amfMovieClip // reserved, not implemented
amfNull
amfUndefined
amfReference
amfEcmaArray
amfObjectEnd
amfStrictArray
amfDate
amfLongSring
amfUnsupported
amfRecordset // reserved, not implemented
amfXmlDoc
amfTypedObject
amfAvmplus // reserved, not implemented
amfInvalid = 0xff
) )
// unsigned short AMF_DecodeInt16(const char* data); type AMF struct {
// amf.c +41 props []AMFProperty
func C_AMF_DecodeInt16(data []byte) uint16 {
return uint16(data[0])<<8 | uint16(data[1])
} }
// unsigned int AMF_DecodeInt24(const char* data); type AMFProperty struct {
// amf.c +50 name string
func C_AMF_DecodeInt24(data []byte) uint32 { atype AMFDataType
vu vu
UTCoffset int16
}
type vu struct {
number float64
aval string
obj AMF
}
type AMFDataType int32
var (
amfObjInvalid AMF
amfPropInvalid = AMFProperty{atype: amfInvalid}
)
func amfDecodeInt16(data []byte) uint16 {
return uint16(binary.BigEndian.Uint16(data))
}
func amfDecodeInt24(data []byte) uint32 {
return uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2]) return uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
// return uint16(data[0])<<8 | uint16(data[1])
} }
// unsigned int AMF_DeocdeInt32(const char* data); func amfDecodeInt32(data []byte) uint32 {
// amf.c +59 return uint32(binary.BigEndian.Uint32(data))
func C_AMF_DecodeInt32(data []byte) uint32 {
return uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
} }
// void AMF_DecodeString(const char* data, C_AVal* bv); func amfDecodeString(data []byte) string {
// amf.c +68 n := amfDecodeInt16(data)
func C_AMF_DecodeString(data []byte) string {
n := C_AMF_DecodeInt16(data)
return string(data[2 : 2+n]) return string(data[2 : 2+n])
} }
// void AMF_DecodeLongString(const char *data, AVal *bv); func amfDecodeLongString(data []byte) string {
// amf.c +75 n := amfDecodeInt32(data)
func C_AMF_DecodeLongString(data []byte) string {
n := C_AMF_DecodeInt32(data)
return string(data[2 : 2+n]) return string(data[2 : 2+n])
} }
// double AMF_DecodeNumber(const char* data); func amfDecodeNumber(data []byte) float64 {
// amf.c +82
func C_AMF_DecodeNumber(data []byte) float64 {
return math.Float64frombits(binary.BigEndian.Uint64(data)) return math.Float64frombits(binary.BigEndian.Uint64(data))
} }
// int AMF_DecodeBoolean(const char *data); func amfDecodeBoolean(data []byte) bool {
// amf.c +132
func C_AMF_DecodeBoolean(data []byte) bool {
return data[0] != 0 return data[0] != 0
} }
// char* AMF_EncodeInt24(char* output, char* outend, int nVal); func amfEncodeInt24(dst []byte, val int32) []byte {
// amf.c +149
func C_AMF_EncodeInt24(dst []byte, val int32) []byte {
if len(dst) < 3 { if len(dst) < 3 {
return nil return nil
} }
_ = dst[2]
dst[0] = byte(val >> 16) dst[0] = byte(val >> 16)
dst[1] = byte(val >> 8) dst[1] = byte(val >> 8)
dst[2] = byte(val) dst[2] = byte(val)
@ -109,9 +129,7 @@ func C_AMF_EncodeInt24(dst []byte, val int32) []byte {
return dst[3:] return dst[3:]
} }
// char* AMF_EncodeInt32(char* output, char* outend, int nVal); func amfEncodeInt32(dst []byte, val int32) []byte {
// amf.c +160
func C_AMF_EncodeInt32(dst []byte, val int32) []byte {
if len(dst) < 4 { if len(dst) < 4 {
return nil return nil
} }
@ -122,9 +140,7 @@ func C_AMF_EncodeInt32(dst []byte, val int32) []byte {
return dst[4:] return dst[4:]
} }
// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv); func amfEncodeString(dst []byte, val string) []byte {
// amf.c +173
func C_AMF_EncodeString(dst []byte, val string) []byte {
const typeSize = 1 const typeSize = 1
if len(val) < 65536 && len(val)+typeSize+binary.Size(int16(0)) > len(dst) { if len(val) < 65536 && len(val)+typeSize+binary.Size(int16(0)) > len(dst) {
return nil return nil
@ -134,7 +150,7 @@ func C_AMF_EncodeString(dst []byte, val string) []byte {
} }
if len(val) < 65536 { if len(val) < 65536 {
dst[0] = AMF_STRING dst[0] = amfString
dst = dst[1:] dst = dst[1:]
binary.BigEndian.PutUint16(dst[:2], uint16(len(val))) binary.BigEndian.PutUint16(dst[:2], uint16(len(val)))
dst = dst[2:] dst = dst[2:]
@ -144,7 +160,7 @@ func C_AMF_EncodeString(dst []byte, val string) []byte {
} }
return dst[len(val):] return dst[len(val):]
} }
dst[0] = AMF_LONG_STRING dst[0] = amfLongSring
dst = dst[1:] dst = dst[1:]
binary.BigEndian.PutUint32(dst[:4], uint32(len(val))) binary.BigEndian.PutUint32(dst[:4], uint32(len(val)))
dst = dst[4:] dst = dst[4:]
@ -155,25 +171,21 @@ func C_AMF_EncodeString(dst []byte, val string) []byte {
return dst[len(val):] return dst[len(val):]
} }
// char* AMF_EncodeNumber(char* output, char* outend, double dVal); func amfEncodeNumber(dst []byte, val float64) []byte {
// amf.c +199
func C_AMF_EncodeNumber(dst []byte, val float64) []byte {
if len(dst) < 9 { if len(dst) < 9 {
return nil return nil
} }
dst[0] = AMF_NUMBER dst[0] = amfNumber
dst = dst[1:] dst = dst[1:]
binary.BigEndian.PutUint64(dst, math.Float64bits(val)) binary.BigEndian.PutUint64(dst, math.Float64bits(val))
return dst[8:] return dst[8:]
} }
// char* AMF_EncodeBoolean(char* output, char* outend, int bVal); func amfEncodeBoolean(dst []byte, val bool) []byte {
// amf.c +260
func C_AMF_EncodeBoolean(dst []byte, val bool) []byte {
if len(dst) < 2 { if len(dst) < 2 {
return nil return nil
} }
dst[0] = AMF_BOOLEAN dst[0] = amfBoolean
if val { if val {
dst[1] = 1 dst[1] = 1
} }
@ -184,9 +196,7 @@ func C_AMF_EncodeBoolean(dst []byte, val bool) []byte {
} }
// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue); func amfEncodeNamedString(dst []byte, key, val string) []byte {
// amf.c +273
func C_AMF_EncodeNamedString(dst []byte, key, val string) []byte {
if 2+len(key) > len(dst) { if 2+len(key) > len(dst) {
return nil return nil
} }
@ -196,12 +206,10 @@ func C_AMF_EncodeNamedString(dst []byte, key, val string) []byte {
if len(key) == len(dst) { if len(key) == len(dst) {
return nil return nil
} }
return C_AMF_EncodeString(dst[len(key):], val) return amfEncodeString(dst[len(key):], val)
} }
// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal); func amfEncodeNamedNumber(dst []byte, key string, val float64) []byte {
// amf.c +286
func C_AMF_EncodeNamedNumber(dst []byte, key string, val float64) []byte {
if 2+len(key) > len(dst) { if 2+len(key) > len(dst) {
return nil return nil
} }
@ -211,12 +219,10 @@ func C_AMF_EncodeNamedNumber(dst []byte, key string, val float64) []byte {
if len(key) == len(dst) { if len(key) == len(dst) {
return nil return nil
} }
return C_AMF_EncodeNumber(dst[len(key):], val) return amfEncodeNumber(dst[len(key):], val)
} }
// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal); func amfEncodeNamedBoolean(dst []byte, key string, val bool) []byte {
// amf.c +299
func C_AMF_EncodeNamedBoolean(dst []byte, key string, val bool) []byte {
if 2+len(key) > len(dst) { if 2+len(key) > len(dst) {
return nil return nil
} }
@ -226,112 +232,100 @@ func C_AMF_EncodeNamedBoolean(dst []byte, key string, val bool) []byte {
if len(key) == len(dst) { if len(key) == len(dst) {
return nil return nil
} }
return C_AMF_EncodeBoolean(dst[len(key):], val) return amfEncodeBoolean(dst[len(key):], val)
} }
// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name); func amfPropSetName(prop *AMFProperty, name string) {
// amf.c +318 prop.name = name
func C_AMFProp_SetName(prop *C_AMFObjectProperty, name string) {
prop.p_name = name
} }
// double AMFProp_GetNumber(AMFObjectProperty* prop); func amfPropGetNumber(prop *AMFProperty) float64 {
// amf.c +330 return prop.vu.number
func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 {
return prop.p_vu.p_number
} }
// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str); func amfPropGetString(prop *AMFProperty) string {
// amf.c +341 if prop.atype == amfString {
func C_AMFProp_GetString(prop *C_AMFObjectProperty) string { return prop.vu.aval
if prop.p_type == AMF_STRING {
return prop.p_vu.p_aval
} }
return "" return ""
} }
// void AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj); func amfPropGetObject(prop *AMFProperty, a *AMF) {
// amf.c +351 if prop.atype == amfObject {
func C_AMFProp_GetObject(prop *C_AMFObjectProperty, obj *C_AMFObject) { *a = prop.vu.obj
if prop.p_type == AMF_OBJECT {
*obj = prop.p_vu.p_object
} else { } else {
*obj = AMFObj_Invalid *a = amfObjInvalid
} }
} }
// char* AMFPropEncode(AMFOBjectProperty* prop, char* pBufer, char* pBufEnd); func amfPropEncode(p *AMFProperty, dst []byte) []byte {
// amf.c +366 if p.atype == amfInvalid {
func C_AMF_PropEncode(p *C_AMFObjectProperty, dst []byte) []byte {
if p.p_type == AMF_INVALID {
return nil return nil
} }
if p.p_type != AMF_NULL && len(p.p_name)+2+1 >= len(dst) { if p.atype != amfNull && len(p.name)+2+1 >= len(dst) {
return nil return nil
} }
if p.p_type != AMF_NULL && len(p.p_name) != 0 { if p.atype != amfNull && len(p.name) != 0 {
binary.BigEndian.PutUint16(dst[:2], uint16(len(p.p_name))) binary.BigEndian.PutUint16(dst[:2], uint16(len(p.name)))
dst = dst[2:] dst = dst[2:]
copy(dst, p.p_name) copy(dst, p.name)
dst = dst[len(p.p_name):] dst = dst[len(p.name):]
} }
switch p.p_type { switch p.atype {
case AMF_NUMBER: case amfNumber:
dst = C_AMF_EncodeNumber(dst, p.p_vu.p_number) dst = amfEncodeNumber(dst, p.vu.number)
case AMF_BOOLEAN: case amfBoolean:
dst = C_AMF_EncodeBoolean(dst, p.p_vu.p_number != 0) dst = amfEncodeBoolean(dst, p.vu.number != 0)
case AMF_STRING: case amfString:
dst = C_AMF_EncodeString(dst, p.p_vu.p_aval) dst = amfEncodeString(dst, p.vu.aval)
case AMF_NULL: case amfNull:
if len(dst) < 2 { if len(dst) < 2 {
return nil return nil
} }
dst[0] = AMF_NULL dst[0] = amfNull
dst = dst[1:] dst = dst[1:]
case AMF_OBJECT: case amfObject:
dst = C_AMF_Encode(&p.p_vu.p_object, dst) dst = amfEncode(&p.vu.obj, dst)
case AMF_ECMA_ARRAY: case amfEcmaArray:
dst = C_AMF_EncodeEcmaArray(&p.p_vu.p_object, dst) dst = amfEncodeEcmaArray(&p.vu.obj, dst)
case AMF_STRICT_ARRAY: case amfStrictArray:
dst = C_AMF_EncodeArray(&p.p_vu.p_object, dst) dst = amfEncodeArray(&p.vu.obj, dst)
default: default:
log.Println("C_AMF_PropEncode: invalid type!") // ??? log.Println("amfPropEncode: invalid type!")
dst = nil dst = nil
} }
return dst return dst
} }
// int AMFProp_Decode(C_AMFObjectProperty* prop, const char* pBuffer, int nSize, int bDecodeName); func amfProDecode(prop *AMFProperty, data []byte, bDecodeName int32) int32 {
// amf.c +619 prop.name = ""
func C_AMFProp_Decode(prop *C_AMFObjectProperty, data []byte, bDecodeName int32) int32 {
prop.p_name = ""
nOriginalSize := len(data) nOriginalSize := len(data)
if len(data) == 0 { if len(data) == 0 {
// TODO use new logger here // TODO use new logger here
// RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__); // RTMLog(RTMLOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
return -1 return -1
} }
if bDecodeName != 0 && len(data) < 4 { if bDecodeName != 0 && len(data) < 4 {
// at least name (length + at least 1 byte) and 1 byte of data // at least name (length + at least 1 byte) and 1 byte of data
// TODO use new logger here // TODO use new logger here
// RTMP_Log(RTMP_LOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!",__FUNCTION__); // RTMLog(RTMLOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!",__FUNCTION__);
return -1 return -1
} }
if bDecodeName != 0 { if bDecodeName != 0 {
nNameSize := C_AMF_DecodeInt16(data[:2]) nNameSize := amfDecodeInt16(data[:2])
if int(nNameSize) > len(data)-2 { if int(nNameSize) > len(data)-2 {
// TODO use new logger here // TODO use new logger here
//RTMP_Log(RTMP_LOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2",__FUNCTION__, nNameSize, nSize); //RTMLog(RTMLOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2",__FUNCTION__, nNameSize, nSize);
return -1 return -1
} }
prop.p_name = C_AMF_DecodeString(data) prop.name = amfDecodeString(data)
data = data[2+nNameSize:] data = data[2+nNameSize:]
} }
@ -339,122 +333,118 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, data []byte, bDecodeName int32)
return -1 return -1
} }
prop.p_type = C_AMFDataType(data[0]) prop.atype = AMFDataType(data[0])
data = data[1:] data = data[1:]
var nRes int32 var nRes int32
switch prop.p_type { switch prop.atype {
case AMF_NUMBER: case amfNumber:
if len(data) < 8 { if len(data) < 8 {
return -1 return -1
} }
prop.p_vu.p_number = C_AMF_DecodeNumber(data[:8]) prop.vu.number = amfDecodeNumber(data[:8])
data = data[8:] data = data[8:]
case AMF_BOOLEAN: case amfBoolean:
panic("AMF_BOOLEAN not supported") panic("amfBoolean not supported")
case AMF_STRING: case amfString:
nStringSize := C_AMF_DecodeInt16(data[:2]) nStringSize := amfDecodeInt16(data[:2])
if len(data) < int(nStringSize+2) { if len(data) < int(nStringSize+2) {
return -1 return -1
} }
prop.p_vu.p_aval = C_AMF_DecodeString(data) prop.vu.aval = amfDecodeString(data)
data = data[2+nStringSize:] data = data[2+nStringSize:]
case AMF_OBJECT: case amfObject:
nRes := C_AMF_Decode(&prop.p_vu.p_object, data, 1) nRes := amfDecode(&prop.vu.obj, data, 1)
if nRes == -1 { if nRes == -1 {
return -1 return -1
} }
data = data[nRes:] data = data[nRes:]
case AMF_MOVIECLIP: case amfMovieClip:
// TODO use new logger here // TODO use new logger here
log.Println("AMFProp_Decode: MAF_MOVIECLIP reserved!") // ??? log.Println("AMFProDecode: MAF_MOVIECLIP reserved!")
//RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!"); //RTMLog(RTMLOGERROR, "amfMovieClip reserved!");
return -1 return -1
case AMF_NULL, AMF_UNDEFINED, AMF_UNSUPPORTED: case amfNull, amfUndefined, amfUnsupported:
prop.p_type = AMF_NULL prop.atype = amfNull
case AMF_REFERENCE: case amfReference:
// TODO use new logger here // TODO use new logger here
log.Println("AMFProp_Decode: AMF_REFERENCE not supported!") // ??? log.Println("AMFProDecode: amfReference not supported!")
//RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!"); //RTMLog(RTMLOGERROR, "amfReference not supported!");
return -1 return -1
case AMF_ECMA_ARRAY: case amfEcmaArray:
// next comes the rest, mixed array has a final 0x000009 mark and names, so its an object // next comes the rest, mixed array has a final 0x000009 mark and names, so its an object
data = data[4:] data = data[4:]
nRes = C_AMF_Decode(&prop.p_vu.p_object, data, 1) nRes = amfDecode(&prop.vu.obj, data, 1)
if nRes == -1 { if nRes == -1 {
return -1 return -1
} }
data = data[nRes:] data = data[nRes:]
case AMF_OBJECT_END: case amfObjectEnd:
return -1 return -1
case AMF_STRICT_ARRAY: case amfStrictArray:
panic("AMF_STRICT_ARRAY not supported") panic("amfStrictArray not supported")
case AMF_DATE: case amfDate:
panic("AMF_DATE not supported") panic("amfDate not supported")
case AMF_LONG_STRING, AMF_XML_DOC: case amfLongSring, amfXmlDoc:
panic("AMF_LONG_STRING, AMF_XML_DOC not supported") panic("amfLongSring, amfXmlDoc not supported")
case AMF_RECORDSET: case amfRecordset:
// TODO use new logger here // TODO use new logger here
log.Println("AMFProp_Decode: AMF_RECORDSET reserved!") // ??? log.Println("AMFProDecode: amfRecordset reserved!")
//RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!"); //RTMLog(RTMLOGERROR, "amfRecordset reserved!");
return -1 return -1
case AMF_TYPED_OBJECT: case amfTypedObject:
// TODO use new logger here // TODO use new logger here
// RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!") // RTMLog(RTMLOGERROR, "amfTyped_object not supported!")
return -1 return -1
case AMF_AVMPLUS: case amfAvmplus:
panic("AMF_AVMPLUS not supported") panic("amfAvmplus not supported")
default: default:
// TODO use new logger here // TODO use new logger here
//RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__, //RTMLog(RTMLOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__,
//prop.p_type, pBuffer - 1); //prop.atype, pBuffer - 1);
return -1 return -1
} }
return int32(nOriginalSize - len(data)) return int32(nOriginalSize - len(data))
} }
// void AMFProp_Reset(AMFObjectProperty* prop); func amfPropReset(prop *AMFProperty) {
// amf.c +875 if prop.atype == amfObject || prop.atype == amfEcmaArray ||
func C_AMFProp_Reset(prop *C_AMFObjectProperty) { prop.atype == amfStrictArray {
if prop.p_type == AMF_OBJECT || prop.p_type == AMF_ECMA_ARRAY || amfReset(&prop.vu.obj)
prop.p_type == AMF_STRICT_ARRAY {
C_AMF_Reset(&prop.p_vu.p_object)
} else { } else {
prop.p_vu.p_aval = "" prop.vu.aval = ""
} }
prop.p_type = AMF_INVALID prop.atype = amfInvalid
} }
// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd); func amfEncode(a *AMF, dst []byte) []byte {
// amf.c +891
func C_AMF_Encode(obj *C_AMFObject, dst []byte) []byte {
if len(dst) < 5 { if len(dst) < 5 {
return nil return nil
} }
dst[0] = AMF_OBJECT dst[0] = amfObject
dst = dst[1:] dst = dst[1:]
for i := 0; i < len(obj.o_props); i++ { for i := 0; i < len(a.props); i++ {
dst = C_AMF_PropEncode(&obj.o_props[i], dst) dst = amfPropEncode(&a.props[i], dst)
if dst == nil { if dst == nil {
log.Println("C_AMF_Encode: failed to encode property in index") // ??? log.Println("amfEncode: failed to encode property in index")
break break
} }
} }
@ -462,25 +452,23 @@ func C_AMF_Encode(obj *C_AMFObject, dst []byte) []byte {
if len(dst) < 4 { if len(dst) < 4 {
return nil return nil
} }
return C_AMF_EncodeInt24(dst, AMF_OBJECT_END) return amfEncodeInt24(dst, amfObjectEnd)
} }
// char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd); func amfEncodeEcmaArray(a *AMF, dst []byte) []byte {
// amf.c +924
func C_AMF_EncodeEcmaArray(obj *C_AMFObject, dst []byte) []byte {
if len(dst) < 5 { if len(dst) < 5 {
return nil return nil
} }
dst[0] = AMF_ECMA_ARRAY dst[0] = amfEcmaArray
dst = dst[1:] dst = dst[1:]
binary.BigEndian.PutUint32(dst[:4], uint32(len(obj.o_props))) binary.BigEndian.PutUint32(dst[:4], uint32(len(a.props)))
dst = dst[4:] dst = dst[4:]
for i := 0; i < len(obj.o_props); i++ { for i := 0; i < len(a.props); i++ {
dst = C_AMF_PropEncode(&obj.o_props[i], dst) dst = amfPropEncode(&a.props[i], dst)
if dst == nil { if dst == nil {
log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") // ??? log.Println("amfEncodeEcmaArray: failed to encode property!")
break break
} }
} }
@ -488,25 +476,24 @@ func C_AMF_EncodeEcmaArray(obj *C_AMFObject, dst []byte) []byte {
if len(dst) < 4 { if len(dst) < 4 {
return nil return nil
} }
return C_AMF_EncodeInt24(dst, AMF_OBJECT_END) return amfEncodeInt24(dst, amfObjectEnd)
} }
// char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd); // not used?
// amf.c +959 func amfEncodeArray(a *AMF, dst []byte) []byte {
func C_AMF_EncodeArray(obj *C_AMFObject, dst []byte) []byte {
if len(dst) < 5 { if len(dst) < 5 {
return nil return nil
} }
dst[0] = AMF_STRICT_ARRAY dst[0] = amfStrictArray
dst = dst[1:] dst = dst[1:]
binary.BigEndian.PutUint32(dst[:4], uint32(len(obj.o_props))) binary.BigEndian.PutUint32(dst[:4], uint32(len(a.props)))
dst = dst[4:] dst = dst[4:]
for i := 0; i < len(obj.o_props); i++ { for i := 0; i < len(a.props); i++ {
dst = C_AMF_PropEncode(&obj.o_props[i], dst) dst = amfPropEncode(&a.props[i], dst)
if dst == nil { if dst == nil {
log.Println("C_AMF_EncodeArray: failed to encode property!") // ??? log.Println("amfEncodeArray: failed to encode property!")
break break
} }
} }
@ -514,66 +501,48 @@ func C_AMF_EncodeArray(obj *C_AMFObject, dst []byte) []byte {
return dst return dst
} }
// int AMF_Decode(AMFObject *obj, const char* pBuffer, int nSize, int bDecodeName); func amfDecode(a *AMF, data []byte, bDecodeName int32) int32 {
// amf.c +1180
func C_AMF_Decode(obj *C_AMFObject, data []byte, bDecodeName int32) int32 {
nOriginalSize := len(data) nOriginalSize := len(data)
obj.o_props = obj.o_props[:0] a.props = a.props[:0]
for len(data) != 0 { for len(data) != 0 {
if len(data) >= 3 && C_AMF_DecodeInt24(data[:3]) == AMF_OBJECT_END { if len(data) >= 3 && amfDecodeInt24(data[:3]) == amfObjectEnd {
data = data[3:] data = data[3:]
break break
} }
var prop C_AMFObjectProperty var prop AMFProperty
nRes := C_AMFProp_Decode(&prop, data, bDecodeName) nRes := amfProDecode(&prop, data, bDecodeName)
// nRes = int32(C.AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), // nRes = int32(C.AMFProDecode(&prop, (*byte)(unsafe.Pointer(pBuffer)),
// int32(nSize), int32(bDecodeName))) // int32(nSize), int32(bDecodeName)))
if nRes == -1 { if nRes == -1 {
return -1 return -1
} }
data = data[nRes:] data = data[nRes:]
obj.o_props = append(obj.o_props, prop) a.props = append(a.props, prop)
} }
return int32(nOriginalSize - len(data)) return int32(nOriginalSize - len(data))
} }
// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex); func amfGetProp(a *AMF, name string, idx int32) *AMFProperty {
// amf.c + 1249
func C_AMF_GetProp(obj *C_AMFObject, name string, idx int32) *C_AMFObjectProperty {
if idx >= 0 { if idx >= 0 {
if idx < int32(len(obj.o_props)) { if idx < int32(len(a.props)) {
return &obj.o_props[idx] return &a.props[idx]
} }
} else { } else {
for i, p := range obj.o_props { for i, p := range a.props {
if p.p_name == name { if p.name == name {
return &obj.o_props[i] return &a.props[i]
} }
} }
} }
return &AMFProp_Invalid return &amfPropInvalid
} }
// void AMF_Reset(AMFObject* obj); func amfReset(a *AMF) {
// amf.c +1282 for i := range a.props {
func C_AMF_Reset(obj *C_AMFObject) { amfPropReset(&a.props[i])
for i := range obj.o_props {
C_AMFProp_Reset(&obj.o_props[i])
} }
obj.o_props = obj.o_props[:0] *a = AMF{}
} }
/*
// void AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop);
// amf.c +1298
func AMF3CD_AddProp(cd *C.AMF3ClassDef, prop *C_AVal) {
if cd.cd_num&0x0f == 0 {
cd.cd_props = (*C_AVal)(realloc(unsafe.Pointer(cd.cd_props), int(uintptr(cd.cd_num+16)*unsafe.Sizeof(C_AVal{}))))
}
*(*C_AVal)(incPtr(unsafe.Pointer(cd.cd_props), int(cd.cd_num), int(unsafe.Sizeof(C_AVal{})))) = *prop
cd.cd_num++
}
*/

View File

@ -31,51 +31,4 @@ LICENSE
*/ */
package rtmp package rtmp
const (
AMF_NUMBER = iota
AMF_BOOLEAN
AMF_STRING
AMF_OBJECT
AMF_MOVIECLIP /* reserved, not used */
AMF_NULL
AMF_UNDEFINED
AMF_REFERENCE
AMF_ECMA_ARRAY
AMF_OBJECT_END
AMF_STRICT_ARRAY
AMF_DATE
AMF_LONG_STRING
AMF_UNSUPPORTED
AMF_RECORDSET /* reserved, not used */
AMF_XML_DOC
AMF_TYPED_OBJECT
AMF_AVMPLUS /* switch to AMF3 */
AMF_INVALID = 0xff
)
// typedef enum
// amf.h +40
type C_AMFDataType int32
// typedef struct AMF_Object
// amf.h +67
type C_AMFObject struct {
o_props []C_AMFObjectProperty
}
// typedef struct P_vu
// amf.h +73
type P_vu struct {
p_number float64
p_aval string
p_object C_AMFObject
}
// typedef struct AMFObjectProperty
// amf.h +79
type C_AMFObjectProperty struct {
p_name string
p_type C_AMFDataType
p_vu P_vu
p_UTCoffset int16
}

View File

@ -182,9 +182,9 @@ func (pkt *packet) read(s *Session) error {
hSize := len(hbuf) - len(header) + size hSize := len(hbuf) - len(header) + size
if size >= 3 { if size >= 3 {
pkt.timestamp = C_AMF_DecodeInt24(header[:3]) pkt.timestamp = amfDecodeInt24(header[:3])
if size >= 6 { if size >= 6 {
pkt.bodySize = C_AMF_DecodeInt24(header[3:6]) pkt.bodySize = amfDecodeInt24(header[3:6])
pkt.bytesRead = 0 pkt.bytesRead = 0
if size > 6 { if size > 6 {
@ -205,7 +205,7 @@ func (pkt *packet) read(s *Session) error {
return err return err
} }
// TODO: port this // TODO: port this
pkt.timestamp = C_AMF_DecodeInt32(header[size : size+4]) pkt.timestamp = amfDecodeInt32(header[size : size+4])
hSize += 4 hSize += 4
} }
@ -392,12 +392,12 @@ func (pkt *packet) write(s *Session, queue bool) error {
if ts > 0xffffff { if ts > 0xffffff {
res = 0xffffff res = 0xffffff
} }
C_AMF_EncodeInt24(headBytes[headerIdx:], int32(res)) amfEncodeInt24(headBytes[headerIdx:], int32(res))
headerIdx += 3 // 24bits headerIdx += 3 // 24bits
} }
if headerSizes[pkt.headerType] > 4 { if headerSizes[pkt.headerType] > 4 {
C_AMF_EncodeInt24(headBytes[headerIdx:], int32(pkt.bodySize)) amfEncodeInt24(headBytes[headerIdx:], int32(pkt.bodySize))
headerIdx += 3 // 24bits headerIdx += 3 // 24bits
headBytes[headerIdx] = pkt.packetType headBytes[headerIdx] = pkt.packetType
headerIdx++ headerIdx++
@ -409,7 +409,7 @@ func (pkt *packet) write(s *Session, queue bool) error {
} }
if ts >= 0xffffff { if ts >= 0xffffff {
C_AMF_EncodeInt32(headBytes[headerIdx:], int32(ts)) amfEncodeInt32(headBytes[headerIdx:], int32(ts))
headerIdx += 4 // 32bits headerIdx += 4 // 32bits
} }
@ -479,7 +479,7 @@ func (pkt *packet) write(s *Session, queue bool) error {
} }
if ts >= 0xffffff { if ts >= 0xffffff {
extendedTimestamp := headBytes[origIdx+1+cSize:] extendedTimestamp := headBytes[origIdx+1+cSize:]
C_AMF_EncodeInt32(extendedTimestamp[:4], int32(ts)) amfEncodeInt32(extendedTimestamp[:4], int32(ts))
} }
} }
} }
@ -487,12 +487,12 @@ func (pkt *packet) write(s *Session, queue bool) error {
// We invoked a remote method // We invoked a remote method
if pkt.packetType == packetTypeInvoke { if pkt.packetType == packetTypeInvoke {
buf := pkt.body[1:] buf := pkt.body[1:]
meth := C_AMF_DecodeString(buf) meth := amfDecodeString(buf)
s.log(DebugLevel, pkg+"invoking method "+meth) s.log(DebugLevel, pkg+"invoking method "+meth)
// keep it in call queue till result arrives // keep it in call queue till result arrives
if queue { if queue {
buf = buf[3+len(meth):] buf = buf[3+len(meth):]
txn := int32(C_AMF_DecodeNumber(buf[:8])) txn := int32(amfDecodeNumber(buf[:8]))
s.methodCalls = append(s.methodCalls, method{name: meth, num: txn}) s.methodCalls = append(s.methodCalls, method{name: meth, num: txn})
} }
} }

View File

@ -7,7 +7,7 @@ DESCRIPTION
AUTHORS AUTHORS
Saxon Nelson-Milton <saxon@ausocean.org> Saxon Nelson-Milton <saxon@ausocean.org>
Dan Kortschak <dan@ausocean.org> Dan Kortschak <dan@ausocean.org>!
Alan Noble <alan@ausocean.org> Alan Noble <alan@ausocean.org>
LICENSE LICENSE
@ -252,20 +252,20 @@ func handlePacket(s *Session, pkt *packet) error {
switch pkt.packetType { switch pkt.packetType {
case packetTypeChunkSize: case packetTypeChunkSize:
if pkt.bodySize >= 4 { if pkt.bodySize >= 4 {
s.inChunkSize = int32(C_AMF_DecodeInt32(pkt.body[:4])) s.inChunkSize = int32(amfDecodeInt32(pkt.body[:4]))
} }
case packetTypeBytesReadReport: case packetTypeBytesReadReport:
s.serverBW = int32(C_AMF_DecodeInt32(pkt.body[:4])) s.serverBW = int32(amfDecodeInt32(pkt.body[:4]))
case packetTypeControl: case packetTypeControl:
s.log(FatalLevel, pkg+"unsupported packet type packetTypeControl") s.log(FatalLevel, pkg+"unsupported packet type packetTypeControl")
case packetTypeServerBW: case packetTypeServerBW:
s.serverBW = int32(C_AMF_DecodeInt32(pkt.body[:4])) s.serverBW = int32(amfDecodeInt32(pkt.body[:4]))
case packetTypeClientBW: case packetTypeClientBW:
s.clientBW = int32(C_AMF_DecodeInt32(pkt.body[:4])) s.clientBW = int32(amfDecodeInt32(pkt.body[:4]))
if pkt.bodySize > 4 { if pkt.bodySize > 4 {
s.clientBW2 = pkt.body[4] s.clientBW2 = pkt.body[4]
} else { } else {
@ -312,72 +312,72 @@ func sendConnectPacket(s *Session) error {
} }
enc := pkt.body enc := pkt.body
enc = C_AMF_EncodeString(enc, avConnect) enc = amfEncodeString(enc, avConnect)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
s.numInvokes += 1 s.numInvokes += 1
enc = C_AMF_EncodeNumber(enc, float64(s.numInvokes)) enc = amfEncodeNumber(enc, float64(s.numInvokes))
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc[0] = AMF_OBJECT enc[0] = amfObject
enc = enc[1:] enc = enc[1:]
enc = C_AMF_EncodeNamedString(enc, avApp, s.link.app) enc = amfEncodeNamedString(enc, avApp, s.link.app)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
if s.link.protocol&featureWrite != 0 { if s.link.protocol&featureWrite != 0 {
enc = C_AMF_EncodeNamedString(enc, avType, avNonprivate) enc = amfEncodeNamedString(enc, avType, avNonprivate)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
} }
if s.link.flashVer != "" { if s.link.flashVer != "" {
enc = C_AMF_EncodeNamedString(enc, avFlashver, s.link.flashVer) enc = amfEncodeNamedString(enc, avFlashver, s.link.flashVer)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
} }
if s.link.swfUrl != "" { if s.link.swfUrl != "" {
enc = C_AMF_EncodeNamedString(enc, avSwfUrl, s.link.swfUrl) enc = amfEncodeNamedString(enc, avSwfUrl, s.link.swfUrl)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
} }
if s.link.tcUrl != "" { if s.link.tcUrl != "" {
enc = C_AMF_EncodeNamedString(enc, avTcUrl, s.link.tcUrl) enc = amfEncodeNamedString(enc, avTcUrl, s.link.tcUrl)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
} }
if s.link.protocol&featureWrite == 0 { if s.link.protocol&featureWrite == 0 {
enc = C_AMF_EncodeNamedBoolean(enc, avFpad, false) enc = amfEncodeNamedBoolean(enc, avFpad, false)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc = C_AMF_EncodeNamedNumber(enc, avCapabilities, 15) enc = amfEncodeNamedNumber(enc, avCapabilities, 15)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc = C_AMF_EncodeNamedNumber(enc, avAudioCodecs, s.audioCodecs) enc = amfEncodeNamedNumber(enc, avAudioCodecs, s.audioCodecs)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc = C_AMF_EncodeNamedNumber(enc, avVideoCodecs, s.videoCodecs) enc = amfEncodeNamedNumber(enc, avVideoCodecs, s.videoCodecs)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc = C_AMF_EncodeNamedNumber(enc, avVideoFunction, 1) enc = amfEncodeNamedNumber(enc, avVideoFunction, 1)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
if s.link.pageUrl != "" { if s.link.pageUrl != "" {
enc = C_AMF_EncodeNamedString(enc, avPageUrl, s.link.pageUrl) enc = amfEncodeNamedString(enc, avPageUrl, s.link.pageUrl)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
@ -385,29 +385,29 @@ func sendConnectPacket(s *Session) error {
} }
if s.encoding != 0.0 || s.sendEncoding { if s.encoding != 0.0 || s.sendEncoding {
enc = C_AMF_EncodeNamedNumber(enc, avObjectEncoding, s.encoding) enc = amfEncodeNamedNumber(enc, avObjectEncoding, s.encoding)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
} }
copy(enc, []byte{0, 0, AMF_OBJECT_END}) copy(enc, []byte{0, 0, amfObjectEnd})
enc = enc[3:] enc = enc[3:]
// add auth string // add auth string
if s.link.auth != "" { if s.link.auth != "" {
enc = C_AMF_EncodeBoolean(enc, s.link.flags&linkAuth != 0) enc = amfEncodeBoolean(enc, s.link.flags&linkAuth != 0)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc = C_AMF_EncodeString(enc, s.link.auth) enc = amfEncodeString(enc, s.link.auth)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
} }
for i := range s.link.extras.o_props { for i := range s.link.extras.props {
enc = C_AMF_PropEncode(&s.link.extras.o_props[i], enc) enc = amfPropEncode(&s.link.extras.props[i], enc)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
@ -429,16 +429,16 @@ func sendCreateStream(s *Session) error {
} }
enc := pkt.body enc := pkt.body
enc = C_AMF_EncodeString(enc, avCreatestream) enc = amfEncodeString(enc, avCreatestream)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
s.numInvokes++ s.numInvokes++
enc = C_AMF_EncodeNumber(enc, float64(s.numInvokes)) enc = amfEncodeNumber(enc, float64(s.numInvokes))
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc[0] = AMF_NULL enc[0] = amfNull
enc = enc[1:] enc = enc[1:]
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc)) pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
@ -457,18 +457,18 @@ func sendReleaseStream(s *Session) error {
} }
enc := pkt.body enc := pkt.body
enc = C_AMF_EncodeString(enc, avReleasestream) enc = amfEncodeString(enc, avReleasestream)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
s.numInvokes++ s.numInvokes++
enc = C_AMF_EncodeNumber(enc, float64(s.numInvokes)) enc = amfEncodeNumber(enc, float64(s.numInvokes))
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc[0] = AMF_NULL enc[0] = amfNull
enc = enc[1:] enc = enc[1:]
enc = C_AMF_EncodeString(enc, s.link.playpath) enc = amfEncodeString(enc, s.link.playpath)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
@ -488,18 +488,18 @@ func sendFCPublish(s *Session) error {
} }
enc := pkt.body enc := pkt.body
enc = C_AMF_EncodeString(enc, avFCPublish) enc = amfEncodeString(enc, avFCPublish)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
s.numInvokes++ s.numInvokes++
enc = C_AMF_EncodeNumber(enc, float64(s.numInvokes)) enc = amfEncodeNumber(enc, float64(s.numInvokes))
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc[0] = AMF_NULL enc[0] = amfNull
enc = enc[1:] enc = enc[1:]
enc = C_AMF_EncodeString(enc, s.link.playpath) enc = amfEncodeString(enc, s.link.playpath)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
@ -520,18 +520,18 @@ func sendFCUnpublish(s *Session) error {
} }
enc := pkt.body enc := pkt.body
enc = C_AMF_EncodeString(enc, avFCUnpublish) enc = amfEncodeString(enc, avFCUnpublish)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
s.numInvokes++ s.numInvokes++
enc = C_AMF_EncodeNumber(enc, float64(s.numInvokes)) enc = amfEncodeNumber(enc, float64(s.numInvokes))
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc[0] = AMF_NULL enc[0] = amfNull
enc = enc[1:] enc = enc[1:]
enc = C_AMF_EncodeString(enc, s.link.playpath) enc = amfEncodeString(enc, s.link.playpath)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
@ -552,22 +552,22 @@ func sendPublish(s *Session) error {
} }
enc := pkt.body enc := pkt.body
enc = C_AMF_EncodeString(enc, avPublish) enc = amfEncodeString(enc, avPublish)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
s.numInvokes++ s.numInvokes++
enc = C_AMF_EncodeNumber(enc, float64(s.numInvokes)) enc = amfEncodeNumber(enc, float64(s.numInvokes))
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc[0] = AMF_NULL enc[0] = amfNull
enc = enc[1:] enc = enc[1:]
enc = C_AMF_EncodeString(enc, s.link.playpath) enc = amfEncodeString(enc, s.link.playpath)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc = C_AMF_EncodeString(enc, avLive) enc = amfEncodeString(enc, avLive)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
@ -588,18 +588,18 @@ func sendDeleteStream(s *Session, dStreamId float64) error {
} }
enc := pkt.body enc := pkt.body
enc = C_AMF_EncodeString(enc, avDeletestream) enc = amfEncodeString(enc, avDeletestream)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
s.numInvokes++ s.numInvokes++
enc = C_AMF_EncodeNumber(enc, float64(s.numInvokes)) enc = amfEncodeNumber(enc, float64(s.numInvokes))
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc[0] = AMF_NULL enc[0] = amfNull
enc = enc[1:] enc = enc[1:]
enc = C_AMF_EncodeNumber(enc, dStreamId) enc = amfEncodeNumber(enc, dStreamId)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
@ -621,7 +621,7 @@ func sendBytesReceived(s *Session) error {
enc := pkt.body enc := pkt.body
s.nBytesInSent = s.nBytesIn s.nBytesInSent = s.nBytesIn
enc = C_AMF_EncodeInt32(enc, s.nBytesIn) enc = amfEncodeInt32(enc, s.nBytesIn)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
@ -641,16 +641,16 @@ func sendCheckBW(s *Session) error {
} }
enc := pkt.body enc := pkt.body
enc = C_AMF_EncodeString(enc, av_checkbw) enc = amfEncodeString(enc, av_checkbw)
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
s.numInvokes++ s.numInvokes++
enc = C_AMF_EncodeNumber(enc, float64(s.numInvokes)) enc = amfEncodeNumber(enc, float64(s.numInvokes))
if enc == nil { if enc == nil {
return errEncoding return errEncoding
} }
enc[0] = AMF_NULL enc[0] = amfNull
enc = enc[1:] enc = enc[1:]
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc)) pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
@ -670,15 +670,15 @@ func handleInvoke(s *Session, body []byte) error {
if body[0] != 0x02 { if body[0] != 0x02 {
return errInvalidBody return errInvalidBody
} }
var obj C_AMFObject var obj AMF
nRes := C_AMF_Decode(&obj, body, 0) nRes := amfDecode(&obj, body, 0)
if nRes < 0 { if nRes < 0 {
return errDecoding return errDecoding
} }
meth := C_AMFProp_GetString(C_AMF_GetProp(&obj, "", 0)) meth := amfPropGetString(amfGetProp(&obj, "", 0))
s.log(DebugLevel, pkg+"invoking method "+meth) s.log(DebugLevel, pkg+"invoking method "+meth)
txn := C_AMFProp_GetNumber(C_AMF_GetProp(&obj, "", 1)) txn := amfPropGetNumber(amfGetProp(&obj, "", 1))
switch meth { switch meth {
case av_result: case av_result:
@ -718,7 +718,7 @@ func handleInvoke(s *Session, body []byte) error {
} }
case avCreatestream: case avCreatestream:
s.streamID = int32(C_AMFProp_GetNumber(C_AMF_GetProp(&obj, "", 3))) s.streamID = int32(amfPropGetNumber(amfGetProp(&obj, "", 3)))
if s.link.protocol&featureWrite == 0 { if s.link.protocol&featureWrite == 0 {
return errNotWritable return errNotWritable
} }
@ -755,10 +755,10 @@ func handleInvoke(s *Session, body []byte) error {
s.log(FatalLevel, pkg+"unsupported method avClose") s.log(FatalLevel, pkg+"unsupported method avClose")
case avOnStatus: case avOnStatus:
var obj2 C_AMFObject var obj2 AMF
C_AMFProp_GetObject(C_AMF_GetProp(&obj, "", 3), &obj2) amfPropGetObject(amfGetProp(&obj, "", 3), &obj2)
code := C_AMFProp_GetString(C_AMF_GetProp(&obj2, avCode, -1)) code := amfPropGetString(amfGetProp(&obj2, avCode, -1))
level := C_AMFProp_GetString(C_AMF_GetProp(&obj2, avLevel, -1)) level := amfPropGetString(amfGetProp(&obj2, avLevel, -1))
s.log(DebugLevel, pkg+"onStatus", "code", code, "level", level) s.log(DebugLevel, pkg+"onStatus", "code", code, "level", level)
switch code { switch code {
@ -797,7 +797,7 @@ func handleInvoke(s *Session, body []byte) error {
s.log(FatalLevel, pkg+"unknown method "+meth) s.log(FatalLevel, pkg+"unknown method "+meth)
} }
leave: leave:
C_AMF_Reset(&obj) amfReset(&obj)
return nil return nil
} }

View File

@ -79,7 +79,7 @@ type link struct {
auth string auth string
flashVer string flashVer string
token string token string
extras C_AMFObject extras AMF
flags int32 flags int32
swfAge int32 swfAge int32
protocol int32 protocol int32
@ -187,8 +187,8 @@ func (s *Session) Write(data []byte) (int, error) {
pkt := packet{ pkt := packet{
packetType: data[0], packetType: data[0],
bodySize: C_AMF_DecodeInt24(data[1:4]), bodySize: amfDecodeInt24(data[1:4]),
timestamp: C_AMF_DecodeInt24(data[4:7]) | uint32(data[7])<<24, timestamp: amfDecodeInt24(data[4:7]) | uint32(data[7])<<24,
channel: chanSource, channel: chanSource,
info: s.streamID, info: s.streamID,
} }