From 6019bb455987dcca47a9bc5a9c81a721b6b3e830 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 06:44:15 +0930 Subject: [PATCH 01/33] rtmp: moved amf enum from rtmp.go to amf.go --- rtmp/rtmp.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index d04f1601..d84f42c4 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -89,28 +89,6 @@ const ( // amf.h +40 type C_AMFDataType int32 -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 -) - const ( RTMP_PACKET_TYPE_CHUNK_SIZE = 0x01 RTMP_PACKET_TYPE_BYTES_READ_REPORT = 0x03 From 595fa5a469fd26e74f8e6daf5c443642645214e9 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 06:47:13 +0930 Subject: [PATCH 02/33] rtmp: tracking new file amf.go --- rtmp/amf.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 rtmp/amf.go diff --git a/rtmp/amf.go b/rtmp/amf.go new file mode 100644 index 00000000..5170b278 --- /dev/null +++ b/rtmp/amf.go @@ -0,0 +1,23 @@ +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 +) From 7a9fef826c9568f3917ae34270d2f2360c977bf7 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 06:49:47 +0930 Subject: [PATCH 03/33] rtmp: moved amf structs from rtmp.go to amf.go --- rtmp/amf.go | 29 +++++++++++++++++++++++++++++ rtmp/rtmp.go | 26 -------------------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index 5170b278..a78fd291 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -21,3 +21,32 @@ const ( AMF_AVMPLUS /* switch to AMF3 */ AMF_INVALID = 0xff ) + +var ( + AMFObj_Invalid C_AMFObject + AMFProp_Invalid = C_AMFObjectProperty{p_type: AMF_INVALID} +) + +// typedef struct AMF_Object +// amf.h +67 +type C_AMFObject struct { + o_num int32 + o_props *C_AMFObjectProperty +} + +// typedef struct AMFObjectProperty +// amf.h +79 +type C_AMFObjectProperty struct { + p_name C_AVal + p_type C_AMFDataType + p_vu P_vu + p_UTCoffset int16 +} + +// typedef struct P_vu +// amf.h +73 +type P_vu struct { + p_number float64 + p_aval C_AVal + p_object C_AMFObject +} diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index d84f42c4..72a61385 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -208,8 +208,6 @@ var ( ) var ( - AMFObj_Invalid C_AMFObject - AMFProp_Invalid = C_AMFObjectProperty{p_type: AMF_INVALID} packetSize = [...]int{12, 8, 4, 1} RTMPProtocolStringsLower = [...]string{ "rtmp", @@ -374,30 +372,6 @@ type C_RTMP_LNK struct { port uint16 } -// typedef struct AMF_Object -// amf.h +67 -type C_AMFObject struct { - o_num int32 - o_props *C_AMFObjectProperty -} - -// typedef struct AMFObjectProperty -// amf.h +79 -type C_AMFObjectProperty struct { - p_name C_AVal - p_type C_AMFDataType - p_vu P_vu - p_UTCoffset int16 -} - -// typedef struct P_vu -// amf.h +73 -type P_vu struct { - p_number float64 - p_aval C_AVal - p_object C_AMFObject -} - // NewSession returns a new session. func NewSession(url string, connectTimeout uint) *Session { return &Session{ From 8f3d4b75bf5d8e8f9d09b5da3a1a3f66ea2d9e18 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 06:58:22 +0930 Subject: [PATCH 04/33] rtmp: moved all AMF funcs from rtmp.go to amf.go --- rtmp/amf.go | 874 +++++++++++++++++++++++++++++++++++++++++++++++++ rtmp/rtmp.go | 894 +-------------------------------------------------- 2 files changed, 882 insertions(+), 886 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index a78fd291..7e358082 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -50,3 +50,877 @@ type P_vu struct { p_aval C_AVal p_object C_AMFObject } + +// char* AMFPropEncode(AMFOBjectProperty* prop, char* pBufer, char* pBufEnd); +// amf.c +366 +func C_AMF_PropEncode(p *C_AMFObjectProperty, pBuffer *byte, pBufEnd *byte) *byte { + if p.p_type == AMF_INVALID { + return nil + } + + if p.p_type != AMF_NULL && int(uintptr(unsafe.Pointer(pBuffer)))+ + int(p.p_name.av_len)+2+1 >= int( + uintptr(unsafe.Pointer(pBufEnd))) { + return nil + } + + if p.p_type != AMF_NULL && p.p_name.av_len != 0 { + *indxBytePtr(unsafe.Pointer(pBuffer), 0) = byte(p.p_name.av_len >> 8) + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + *indxBytePtr(unsafe.Pointer(pBuffer), 0) = byte(p.p_name.av_len & 0xff) + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + memmove(unsafe.Pointer(pBuffer), unsafe.Pointer(p.p_name.av_val), + uintptr(p.p_name.av_len)) + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(p.p_name.av_len))) + } + + switch p.p_type { + case AMF_NUMBER: + pBuffer = C_AMF_EncodeNumber(pBuffer, pBufEnd, float64(p.p_vu.p_number)) + case AMF_BOOLEAN: + val := 0 + if p.p_vu.p_number != 0 { + val = 1 + } + pBuffer = C_AMF_EncodeBoolean(pBuffer, pBufEnd, val) + case AMF_STRING: + pBuffer = C_AMF_EncodeString(pBuffer, pBufEnd, &p.p_vu.p_aval) + case AMF_NULL: + if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 1)) >= uintptr(unsafe.Pointer( + pBufEnd)) { + return nil + } + *(*byte)(unsafe.Pointer(pBuffer)) = AMF_NULL + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + case AMF_OBJECT: + pBuffer = C_AMF_Encode(&p.p_vu.p_object, pBuffer, pBufEnd) + //pBuffer = (*byte)(unsafe.Pointer(C.AMF_Encode(&p.p_vu.p_object, (*byte)( + //unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd))))) + case AMF_ECMA_ARRAY: + pBuffer = C_AMF_EncodeEcmaArray(&p.p_vu.p_object, pBuffer, pBufEnd) + //pBuffer = (*byte)(unsafe.Pointer(C.AMF_EncodeEcmaArray(&p.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd))))) + case AMF_STRICT_ARRAY: + //pBuffer = (*byte)(unsafe.Pointer(C.AMF_EncodeArray(&p.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd))))) + pBuffer = C_AMF_EncodeArray(&p.p_vu.p_object, pBuffer, pBufEnd) + default: + log.Println("C_AMF_PropEncode: invalid type!") + pBuffer = nil + } + return pBuffer +} + +// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd); +// amf.c +891 +func C_AMF_Encode(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { + if uintptr(unsafe.Pointer(pBuffer))+uintptr(4) >= uintptr(unsafe.Pointer(pBufEnd)) { + return nil + } + + *pBuffer = AMF_OBJECT + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + + for i := 0; i < int(obj.o_num); i++ { + res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( + obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) + if res == nil { + log.Println("C_AMF_Encode: failed to encode property in index") + break + } else { + pBuffer = res + } + } + + if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 3)) >= uintptr(unsafe.Pointer(pBufEnd)) { + return nil + } + + pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, int32(AMF_OBJECT_END)) + + return pBuffer +} + +// char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd); +// amf.c +924 +func C_AMF_EncodeEcmaArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { + if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) { + return nil + } + + *pBuffer = AMF_ECMA_ARRAY + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + + pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num)) + + for i := 0; i < int(obj.o_num); i++ { + res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( + obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) + if res == nil { + log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") + break + } else { + pBuffer = res + } + } + + if int(uintptr(unsafe.Pointer(pBuffer)))+3 >= int(uintptr(unsafe.Pointer(pBufEnd))) { + return nil + } + + pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END) + + return pBuffer +} + +// char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd); +// amf.c +959 +func C_AMF_EncodeArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { + if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) { + return nil + } + + *pBuffer = AMF_STRICT_ARRAY + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + + pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num)) + + for i := 0; i < int(obj.o_num); i++ { + res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( + obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) + if res == nil { + log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") + break + } else { + pBuffer = res + } + } + + return pBuffer +} + +// int AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize, int nArrayLen, int bDecodeName); +func C_AMF_DecodeArray(obj *C_AMFObject, pBuffer *byte, nSize, nArrayLen, bDecodeName int32) int32 { + nOriginalSize := nSize + var bError int32 = 0 + + obj.o_num = 0 + obj.o_props = nil + for nArrayLen > 0 { + var prop C_AMFObjectProperty + var nRes int32 + nArrayLen-- + + if nSize <= 0 { + bError = 1 + break + } + nRes = C_AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName) + if nRes == -1 { + bError = 1 + break + } else { + nSize -= nRes + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes))) + C_AMF_AddProp(obj, &prop) + } + } + if bError != 0 { + return -1 + } + + return nOriginalSize - nSize +} + +// void AMF_Reset(AMFObject* obj); +// amf.c +1282 +func C_AMF_Reset(obj *C_AMFObject) { + var n int32 + for n = 0; n < int32(obj.o_num); n++ { + C_AMFProp_Reset(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), + int(n), int(unsafe.Sizeof(*obj.o_props)))))) + } + //C.free(unsafe.Pointer(obj.o_props)) + obj.o_props = nil + obj.o_num = 0 +} + +// void AMFProp_Reset(AMFObjectProperty* prop); +// amf.c +875 +func C_AMFProp_Reset(prop *C_AMFObjectProperty) { + if prop.p_type == AMF_OBJECT || prop.p_type == AMF_ECMA_ARRAY || + prop.p_type == AMF_STRICT_ARRAY { + C_AMF_Reset(&prop.p_vu.p_object) + } else { + prop.p_vu.p_aval.av_len = 0 + prop.p_vu.p_aval.av_val = nil + } + prop.p_type = AMF_INVALID +} + +// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str); +// amf.c +func C_AMFProp_GetString(prop *C_AMFObjectProperty, str *C_AVal) { + if prop.p_type == AMF_STRING { + *str = prop.p_vu.p_aval + } else { + *str = AV_empty + } +} + +// void AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj); +// amf.c +351 +func C_AMFProp_GetObject(prop *C_AMFObjectProperty, obj *C_AMFObject) { + if prop.p_type == AMF_OBJECT { + *obj = prop.p_vu.p_object + } else { + *obj = AMFObj_Invalid + } +} + +// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex); +// amf.c + 1249 +func C_AMF_GetProp(obj *C_AMFObject, name *C_AVal, nIndex int32) *C_AMFObjectProperty { + if nIndex >= 0 { + if nIndex < int32(obj.o_num) { + return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), + int(nIndex), int(unsafe.Sizeof(*obj.o_props))))) + //return &obj.o_props[nIndex] + } + } else { + var n int32 + for n = 0; n < int32(obj.o_num); n++ { + if C_AVMATCH(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), + int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name, name) != 0 { + return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), + int(n), int(unsafe.Sizeof(*obj.o_props))))) + } + } + } + return (*C_AMFObjectProperty)(&AMFProp_Invalid) +} + +// double AMFProp_GetNumber(AMFObjectProperty* prop); +// amf.c +330 +func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 { + return float64(prop.p_vu.p_number) +} + +// int AMF_Decode(AMFObject *obj, const char* pBuffer, int nSize, int bDecodeName); +// amf.c +1180 +func C_AMF_Decode(obj *C_AMFObject, pBuffer *byte, nSize int32, bDecodeName int32) int32 { + var nOriginalSize int32 = nSize + var bError int32 = 0 + + obj.o_num = 0 + obj.o_props = nil + + for nSize > 0 { + var prop C_AMFObjectProperty + var nRes int32 + + if nSize >= 3 && C_AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END { + nSize -= 3 + bError = 0 + break + } + + if bError != 0 { + // TODO use new logger here + log.Println("AMF_Decode: decoding error, ignoring bytes until next known pattern!") + nSize-- + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + continue + } + // TODO port AMFProp_Decode + nRes = int32(C_AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), + int32(nSize), int32(bDecodeName))) + // nRes = int32(C.AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), + // int32(nSize), int32(bDecodeName))) + if nRes == -1 { + bError = 1 + break + } else { + nSize -= nRes + if nSize < 0 { + bError = 1 + break + } + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes))) + C_AMF_AddProp(obj, &prop) + } + } + + if bError != 0 { + return -1 + } + + return nOriginalSize - nSize +} + +// int AMFProp_Decode(C_AMFObjectProperty* prop, const char* pBuffer, int nSize, int bDecodeName); +// amf.c +619 +func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeName int32) int32 { + + var nOriginalSize int32 = nSize + var nRes int32 + + prop.p_name.av_len = 0 + prop.p_name.av_val = nil + + if nSize == 0 || pBuffer == nil { + // TODO use new logger here + // RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__); + return -1 + } + + if bDecodeName != 0 && nSize < 4 { + // at least name (length + at least 1 byte) and 1 byte of data + // TODO use new logger here + // RTMP_Log(RTMP_LOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!",__FUNCTION__); + return -1 + } + + if bDecodeName != 0 { + nNameSize := C_AMF_DecodeInt16(pBuffer) + if int32(nNameSize) > nSize-2 { + // TODO use new logger here + //RTMP_Log(RTMP_LOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2",__FUNCTION__, nNameSize, nSize); + return -1 + } + + C_AMF_DecodeString(pBuffer, &prop.p_name) + nSize -= int32(2 + nNameSize) + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(2+nNameSize))) + } + + if nSize == 0 { + return -1 + } + + nSize-- + + prop.p_type = (C_AMFDataType)(int32(*pBuffer)) + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + + switch prop.p_type { + case AMF_NUMBER: + log.Println("1") + if nSize < 8 { + return -1 + } + prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer)) + nSize -= 8 + + /* + case AMF_BOOLEAN: + log.Println("2") + if nSize < 1 { + return -1 + } + prop.p_vu.p_number = float64(C_AMF_DecodeBoolean((*byte)(unsafe.Pointer(pBuffer)))) + nSize-- + */ + case AMF_STRING: + { + log.Println("3") + var nStringSize = C_AMF_DecodeInt16(pBuffer) + + if int64(nSize) < int64(nStringSize)+2 { + return -1 + } + C_AMF_DecodeString(pBuffer, &prop.p_vu.p_aval) + nSize -= int32(2 + nStringSize) + } + + case AMF_OBJECT: + { + log.Println("4") + var nRes int32 = int32(C_AMF_Decode(&prop.p_vu.p_object, pBuffer, nSize, 1)) + if nRes == -1 { + return -1 + } + nSize -= nRes + + } + + case AMF_MOVIECLIP: + { + log.Println("5") + // TODO use new logger here + log.Println("AMFProp_Decode: MAF_MOVIECLIP reserved!") + //RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!"); + return -1 + + } + case AMF_NULL: + log.Println("6") + case AMF_UNDEFINED: + log.Println("7") + case AMF_UNSUPPORTED: + log.Println("8") + prop.p_type = AMF_NULL + + case AMF_REFERENCE: + { + log.Println("9") + // TODO use new logger here + log.Println("AMFProp_Decode: AMF_REFERENCE not supported!") + //RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!"); + return -1 + } + + case AMF_ECMA_ARRAY: + { + log.Println("10") + nSize -= 4 + + // next comes the rest, mixed array has a final 0x000009 mark and names, so its an object + nRes = C_AMF_Decode(&prop.p_vu.p_object, (*byte)(incBytePtr( + unsafe.Pointer(pBuffer), 4)), nSize, 1) + if nRes == -1 { + return -1 + } + nSize -= nRes + } + + case AMF_OBJECT_END: + { + log.Println("11") + return -1 + } + /* + case AMF_STRICT_ARRAY: + { + log.Println("12") + nArrayLen := int32(C_AMF_DecodeInt32(pBuffer)) + nSize -= 4 + + nRes = C_AMF_DecodeArray(&prop.p_vu.p_object, (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 4)), nSize, int32(nArrayLen), FALSE) + if nRes == -1 { + return -1 + } + nSize -= nRes + } + */ + /* + case AMF_DATE: + { + log.Println("13") + // TODO use new logger here + //RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE"); + + if nSize < 10 { + return -1 + } + + prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer)) + prop.p_UTCoffset = C.int16_t(C_AMF_DecodeInt16((*byte)(incBytePtr(unsafe.Pointer(pBuffer), 8)))) + + nSize -= 10 + + } + */ + case AMF_LONG_STRING: + log.Println("14") + /* + case AMF_XML_DOC: + { + log.Println("15") + var nStringSize uint32 = C_AMF_DecodeInt32(pBuffer) + if int64(nSize) < int64(nStringSize)+4 { + return -1 + } + C_AMF_DecodeLongString(pBuffer, &prop.p_vu.p_aval) + nSize -= int32(4 + nStringSize) + if prop.p_type == AMF_LONG_STRING { + prop.p_type = AMF_STRING + } + } + */ + case AMF_RECORDSET: + { + log.Println("16") + // TODO use new logger here + log.Println("AMFProp_Decode: AMF_RECORDSET reserved!") + //RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!"); + return -1 + + } + case AMF_TYPED_OBJECT: + { + log.Println("17") + // TODO use new logger here + // RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!") + return -1 + } + + /* + case AMF_AVMPLUS: + { + log.Println("18") + nRes := int32(C.AMF3_Decode(&prop.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), int32(nSize), 1)) + if nRes == -1 { + return -1 + } + nSize -= nRes + prop.p_type = AMF_OBJECT + } + */ + default: + log.Println("19") + // TODO use new logger here + //RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__, + //prop.p_type, pBuffer - 1); + return -1 + } + + return nOriginalSize - nSize +} + +// void AMF_AddProp(AMFObject* obj, const AMFObjectProperty* prop); +// amf.c + 1234 +func C_AMF_AddProp(obj *C_AMFObject, prop *C_AMFObjectProperty) { + if (obj.o_num & 0x0f) == 0 { + //obj.o_props = (*C_AMFObjectProperty)(realloc(unsafe.Pointer(obj.o_props), + //uint32(int(obj.o_num+16)*int(unsafe.Sizeof(*obj.o_props))))) + obj.o_props = (*C_AMFObjectProperty)(C.realloc(unsafe.Pointer(obj.o_props), + C.size_t(int(obj.o_num+16)*int(unsafe.Sizeof(*obj.o_props))))) + } + memmove(unsafe.Pointer(&(*(*C_AMFObjectProperty)(incPtr( + unsafe.Pointer(obj.o_props), int(obj.o_num), int(unsafe.Sizeof(*obj.o_props)))))), + unsafe.Pointer(prop), unsafe.Sizeof(*obj.o_props)) + obj.o_num++ +} + +// unsigned int AMF_DeocdeInt32(const char* data); +// amf.c +59 +func C_AMF_DecodeInt32(data *byte) uint32 { + c := (*uint8)(data) + val := uint32( + int32(*c)<<24 | + int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 1)))<<16 | + int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 2)))<<8 | + int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 3)))) + return uint32(val) +} + +// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal); +// amf.c +286 +func C_AMF_EncodeNamedNumber(output *byte, outend *byte, strName *C_AVal, dVal float64) *byte { + if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) + memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) + output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) + return C_AMF_EncodeNumber(output, outend, dVal) +} + +// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal); +// amf.c +299 +func C_AMF_EncodeNamedBoolean(output *byte, outend *byte, strName *C_AVal, bVal int) *byte { + if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) + memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) + output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) + return C_AMF_EncodeBoolean(output, outend, bVal) +} + +// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name); +// amf.c +318 +func C_AMFProp_SetName(prop *C_AMFObjectProperty, name *C_AVal) { + prop.p_name = *name +} + +const ( + AMF3_INTEGER_MAX = 268435455 + AMF3_INTEGER_MIN = -268435456 +) + +// int AMF3ReadInteger(const char *data, int32_t *valp); +// amf.c +426 +// TODO test +func C_AMF3ReadInteger(data *byte, valp *int32) int32 { + var i int + var val int32 + + for i <= 2 { + /* handle first 3 bytes */ + if *indxBytePtr(unsafe.Pointer(data), i)&0x80 != 0 { + /* byte used */ + val <<= 7 /* shift up */ + val |= int32(*indxBytePtr(unsafe.Pointer(data), i) & 0x7f) /* add bits */ + i++ + } else { + break + } + } + + if i > 2 { + /* use 4th byte, all 8bits */ + val <<= 8 + val |= int32(*indxBytePtr(unsafe.Pointer(data), 3)) + + /* range check */ + if val > AMF3_INTEGER_MAX { + val -= (1 << 29) + } + } else { + /* use 7bits of last unparsed byte (0xxxxxxx) */ + val <<= 7 + val |= int32(*indxBytePtr(unsafe.Pointer(data), i)) + } + + *valp = val + + if i > 2 { + return 4 + } + return int32(i + 1) +} + +// int AMF3ReadString(const char *data, AVal *str); +// amf.c +466 +func C_AMF3ReadString(data *byte, str *C_AVal) int32 { + var ref int32 + // assert elided - we will get a panic if it's nil. + + len := C_AMF3ReadInteger(data, &ref) + data = indxBytePtr(unsafe.Pointer(data), int(len)) + + if ref&0x1 == 0 { + /* reference: 0xxx */ + // TODO(kortschak) Logging. + // refIndex := (ref >> 1) + // RTMP_Log(RTMP_LOGDEBUG, + // "%s, string reference, index: %d, not supported, ignoring!", + // __FUNCTION__, refIndex); + str.av_val = nil + str.av_len = 0 + return len + } else { + nSize := (ref >> 1) + str.av_val = (*byte)(unsafe.Pointer(data)) + str.av_len = int32(nSize) + return len + nSize + } + return len +} + +// char* AMF_EncodeBoolean(char* output, char* outend, int bVal); +// amf.c +260 +func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal int) *byte { + if int(uintptr(unsafe.Pointer(output)))+2 > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + *(*byte)(unsafe.Pointer(output)) = AMF_BOOLEAN + output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) + val := byte(0x01) + if bVal == 0 { + val = byte(0x00) + } + *(*byte)(unsafe.Pointer(output)) = val + output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) + return output +} + +// char* AMF_EncodeNumber(char* output, char* outend, double dVal); +// amf.c +199 +func C_AMF_EncodeNumber(output *byte, outend *byte, dVal float64) *byte { + if int(uintptr(unsafe.Pointer(output)))+1+8 > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + // TODO: port this + *(*byte)(unsafe.Pointer(output)) = AMF_NUMBER + output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) + // NOTE: here we are assuming little endian for both byte order and float + // word order + var ci, co *uint8 + ci = (*uint8)(unsafe.Pointer(&dVal)) + co = (*uint8)(unsafe.Pointer(output)) + for i := 0; i < 8; i++ { + *indxBytePtr(unsafe.Pointer(co), i) = *indxBytePtr(unsafe.Pointer(ci), 7-i) + } + return (*byte)(incBytePtr(unsafe.Pointer(output), 8)) +} + +// void AMF_DecodeLongString(const char *data, AVal *bv); +// amf.c +75 +func C_AMF_DecodeLongString(data *byte, bv *C_AVal) { + bv.av_len = int32(C_AMF_DecodeInt32(data)) + if bv.av_len > 0 { + bv.av_val = (*byte)(incBytePtr(unsafe.Pointer(data), 4)) + } else { + bv.av_val = nil + } +} + +// double AMF_DecodeNumber(const char* data); +// amf.c +82 +func C_AMF_DecodeNumber(data *byte) float64 { + var dVal float64 + var ci, co *uint8 + ci = (*uint8)(unsafe.Pointer(data)) + co = (*uint8)(unsafe.Pointer(&dVal)) + for i := 0; i < 8; i++ { + *indxBytePtr(unsafe.Pointer(co), i) = *indxBytePtr(unsafe.Pointer(ci), 7-i) + } + return dVal +} + +// int AMF_DecodeBoolean(const char *data); +// amf.c +132 +func C_AMF_DecodeBoolean(data *byte) int32 { + if *data != 0 { + return 1 + } + return 0 +} + +// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue); +// amf.c +273 +func C_AMF_EncodeNamedString(output *byte, outend *byte, strName *C_AVal, strValue *C_AVal) *byte { + if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) + memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) + output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) + return C_AMF_EncodeString(output, outend, strValue) +} + +// void AMF_DecodeString(const char* data, C_AVal* bv); +// amf.c +68 +func C_AMF_DecodeString(data *byte, bv *C_AVal) { + dataPtr := unsafe.Pointer(data) + //bv.av_len = int32(C.AMF_DecodeInt16((*byte)(dataPtr))) + bv.av_len = int32(C_AMF_DecodeInt16((*byte)(dataPtr))) + if bv.av_len > 0 { + bv.av_val = (*byte)(incBytePtr(dataPtr, 2)) + } else { + bv.av_val = nil + } +} + +// unsigned short AMF_DecodeInt16(const char* data); +// amf.c +41 +func C_AMF_DecodeInt16(data *byte) uint16 { + c := unsafe.Pointer(data) + return uint16(*(*uint8)(c)<<8 | *(*byte)(incBytePtr(c, 1))) +} + +// char* AMF_EncodeInt24(char* output, char* outend, int nVal); +// amf.c +149 +func C_AMF_EncodeInt24(output *byte, outend *byte, nVal int32) *byte { + outputPtr := unsafe.Pointer(output) + outendPtr := unsafe.Pointer(outend) + if uintptr(outputPtr)+3 > uintptr(outendPtr) { + // length < 3 + return nil + } + // Assign output[2] + third := (*byte)(incBytePtr(outputPtr, 2)) + *third = (byte)(nVal & 0xff) + // Assign output[1] + second := (*byte)(incBytePtr(outputPtr, 1)) + *second = (byte)(nVal >> 8) + // Assign output[0] + *output = (byte)(nVal >> 16) + return (*byte)(incBytePtr(outputPtr, 3)) +} + +// unsigned int AMF_DecodeInt24(const char* data); +// amf.c +50 +func C_AMF_DecodeInt24(data *byte) uint32 { + // TODO Understand logic and simplify + c := (*uint8)(unsafe.Pointer(data)) + dst := uint32(int32(*c) << 16) + dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + + (uintptr)(int32(1))*unsafe.Sizeof(*c))))) << 8) + dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + + (uintptr)(int32(2))*unsafe.Sizeof(*c)))))) + return dst +} + +// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv); +// amf.c +174 +func C_AMF_EncodeString(output *byte, outend *byte, bv *C_AVal) *byte { + outputPtr := unsafe.Pointer(output) + outendPtr := unsafe.Pointer(outend) + if (bv.av_len < 65536 && uintptr(incBytePtr(outputPtr, 1+2+int(bv.av_len))) > + uintptr(outendPtr)) || uintptr(incBytePtr(outputPtr, 1+4+int(bv.av_len))) > + uintptr(outendPtr) { + return nil + } + if bv.av_len < 65536 { + *(*byte)(outputPtr) = AMF_STRING + outputPtr = incBytePtr(outputPtr, 1) + // TODO: port AMF_EncodeInt16 + outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), (*byte)( + outendPtr), int16(bv.av_len))) + //outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), + //(*byte)(outendPtr), (int16)(bv.av_len))) + } else { + *(*byte)(outputPtr) = AMF_LONG_STRING + outputPtr = incBytePtr(outputPtr, 1) + outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), (*byte)( + outendPtr), int32(bv.av_len))) + //outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), + //(*byte)(outendPtr), (int32)(bv.av_len))) + } + memmove(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), uintptr(bv.av_len)) + //C.memcpy(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), (C.size_t)(bv.av_len)) + outputPtr = incBytePtr(outputPtr, int(bv.av_len)) + return (*byte)(outputPtr) +} + +// char* AMF_EncodeInt16(char* output, char* outend, short nVal); +// amf.c +138 +func C_AMF_EncodeInt16(output *byte, outend *byte, nVal int16) *byte { + outputPtr := unsafe.Pointer(output) + outendPtr := unsafe.Pointer(outend) + if uintptr(outputPtr)+2 > uintptr(outendPtr) { + // length < 2 + return nil + } + // Assign output[1] + second := (*byte)(incBytePtr(outputPtr, 1)) + *second = (byte)(nVal & 0xff) + // Assign output[0] + *output = (byte)(nVal >> 8) + return (*byte)(incBytePtr(outputPtr, 2)) +} + +// char* AMF_EncodeInt32(char* output, char* outend, int nVal); +// amf.c +161 +func C_AMF_EncodeInt32(output *byte, outend *byte, nVal int32) *byte { + outputPtr := unsafe.Pointer(output) + outendPtr := unsafe.Pointer(outend) + if uintptr(outputPtr)+4 > uintptr(outendPtr) { + // length < 4 + return nil + } + // Assign output[3] + forth := (*byte)(incBytePtr(outputPtr, 3)) + *forth = (byte)(nVal & 0xff) + // Assign output[2] + third := (*byte)(incBytePtr(outputPtr, 2)) + *third = (byte)(nVal >> 8) + // Assign output[1] + second := (*byte)(incBytePtr(outputPtr, 1)) + *second = (byte)(nVal >> 16) + // Assign output[0] + *output = (byte)(nVal >> 24) + return (*byte)(incBytePtr(outputPtr, 4)) +} + +// 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++ +} diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 72a61385..3d1defd1 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -152,6 +152,7 @@ const ( const ( minDataSize = 11 debugMode = false + length = 512 ) // av_setDataFrame is a static const global in rtmp.c @@ -207,6 +208,13 @@ var ( av_live = AVC("live") ) +var RTMPT_cmds = []string{ + "open", + "send", + "idle", + "close", +} + var ( packetSize = [...]int{12, 8, 4, 1} RTMPProtocolStringsLower = [...]string{ @@ -1518,185 +1526,6 @@ func C_SendConnectPacket(r *C_RTMP, cp *C_RTMPPacket) int { return C_RTMP_SendPacket(r, &packet, 1) } -// char* AMFPropEncode(AMFOBjectProperty* prop, char* pBufer, char* pBufEnd); -// amf.c +366 -func C_AMF_PropEncode(p *C_AMFObjectProperty, pBuffer *byte, pBufEnd *byte) *byte { - if p.p_type == AMF_INVALID { - return nil - } - - if p.p_type != AMF_NULL && int(uintptr(unsafe.Pointer(pBuffer)))+ - int(p.p_name.av_len)+2+1 >= int( - uintptr(unsafe.Pointer(pBufEnd))) { - return nil - } - - if p.p_type != AMF_NULL && p.p_name.av_len != 0 { - *indxBytePtr(unsafe.Pointer(pBuffer), 0) = byte(p.p_name.av_len >> 8) - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - *indxBytePtr(unsafe.Pointer(pBuffer), 0) = byte(p.p_name.av_len & 0xff) - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - memmove(unsafe.Pointer(pBuffer), unsafe.Pointer(p.p_name.av_val), - uintptr(p.p_name.av_len)) - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(p.p_name.av_len))) - } - - switch p.p_type { - case AMF_NUMBER: - pBuffer = C_AMF_EncodeNumber(pBuffer, pBufEnd, float64(p.p_vu.p_number)) - case AMF_BOOLEAN: - val := 0 - if p.p_vu.p_number != 0 { - val = 1 - } - pBuffer = C_AMF_EncodeBoolean(pBuffer, pBufEnd, val) - case AMF_STRING: - pBuffer = C_AMF_EncodeString(pBuffer, pBufEnd, &p.p_vu.p_aval) - case AMF_NULL: - if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 1)) >= uintptr(unsafe.Pointer( - pBufEnd)) { - return nil - } - *(*byte)(unsafe.Pointer(pBuffer)) = AMF_NULL - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - case AMF_OBJECT: - pBuffer = C_AMF_Encode(&p.p_vu.p_object, pBuffer, pBufEnd) - //pBuffer = (*byte)(unsafe.Pointer(C.AMF_Encode(&p.p_vu.p_object, (*byte)( - //unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd))))) - case AMF_ECMA_ARRAY: - pBuffer = C_AMF_EncodeEcmaArray(&p.p_vu.p_object, pBuffer, pBufEnd) - //pBuffer = (*byte)(unsafe.Pointer(C.AMF_EncodeEcmaArray(&p.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd))))) - case AMF_STRICT_ARRAY: - //pBuffer = (*byte)(unsafe.Pointer(C.AMF_EncodeArray(&p.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd))))) - pBuffer = C_AMF_EncodeArray(&p.p_vu.p_object, pBuffer, pBufEnd) - default: - log.Println("C_AMF_PropEncode: invalid type!") - pBuffer = nil - } - return pBuffer -} - -// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd); -// amf.c +891 -func C_AMF_Encode(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { - if uintptr(unsafe.Pointer(pBuffer))+uintptr(4) >= uintptr(unsafe.Pointer(pBufEnd)) { - return nil - } - - *pBuffer = AMF_OBJECT - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - - for i := 0; i < int(obj.o_num); i++ { - res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( - obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) - if res == nil { - log.Println("C_AMF_Encode: failed to encode property in index") - break - } else { - pBuffer = res - } - } - - if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 3)) >= uintptr(unsafe.Pointer(pBufEnd)) { - return nil - } - - pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, int32(AMF_OBJECT_END)) - - return pBuffer -} - -// char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd); -// amf.c +924 -func C_AMF_EncodeEcmaArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { - if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) { - return nil - } - - *pBuffer = AMF_ECMA_ARRAY - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - - pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num)) - - for i := 0; i < int(obj.o_num); i++ { - res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( - obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) - if res == nil { - log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") - break - } else { - pBuffer = res - } - } - - if int(uintptr(unsafe.Pointer(pBuffer)))+3 >= int(uintptr(unsafe.Pointer(pBufEnd))) { - return nil - } - - pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END) - - return pBuffer -} - -// char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd); -// amf.c +959 -func C_AMF_EncodeArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { - if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) { - return nil - } - - *pBuffer = AMF_STRICT_ARRAY - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - - pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num)) - - for i := 0; i < int(obj.o_num); i++ { - res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( - obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) - if res == nil { - log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") - break - } else { - pBuffer = res - } - } - - return pBuffer -} - -// int AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize, int nArrayLen, int bDecodeName); -func C_AMF_DecodeArray(obj *C_AMFObject, pBuffer *byte, nSize, nArrayLen, bDecodeName int32) int32 { - nOriginalSize := nSize - var bError int32 = 0 - - obj.o_num = 0 - obj.o_props = nil - for nArrayLen > 0 { - var prop C_AMFObjectProperty - var nRes int32 - nArrayLen-- - - if nSize <= 0 { - bError = 1 - break - } - nRes = C_AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName) - if nRes == -1 { - bError = 1 - break - } else { - nSize -= nRes - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes))) - C_AMF_AddProp(obj, &prop) - } - } - if bError != 0 { - return -1 - } - - return nOriginalSize - nSize -} - // int RTMP_ConnectStream(RTMP* r, int seekTime); // rtmp.c +1099 func C_RTMP_ConnectStream(r *C_RTMP, seekTime int32) int { @@ -2187,32 +2016,6 @@ leave: return ret } -// void AMF_Reset(AMFObject* obj); -// amf.c +1282 -func C_AMF_Reset(obj *C_AMFObject) { - var n int32 - for n = 0; n < int32(obj.o_num); n++ { - C_AMFProp_Reset(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), - int(n), int(unsafe.Sizeof(*obj.o_props)))))) - } - //C.free(unsafe.Pointer(obj.o_props)) - obj.o_props = nil - obj.o_num = 0 -} - -// void AMFProp_Reset(AMFObjectProperty* prop); -// amf.c +875 -func C_AMFProp_Reset(prop *C_AMFObjectProperty) { - if prop.p_type == AMF_OBJECT || prop.p_type == AMF_ECMA_ARRAY || - prop.p_type == AMF_STRICT_ARRAY { - C_AMF_Reset(&prop.p_vu.p_object) - } else { - prop.p_vu.p_aval.av_len = 0 - prop.p_vu.p_aval.av_val = nil - } - prop.p_type = AMF_INVALID -} - // int SendReleaseStream(RTMP* r); // rtmp.c +1816 func C_SendReleaseStream(r *C_RTMP) int32 { @@ -2395,54 +2198,6 @@ func C_AVMATCH(a1, a2 *C_AVal) int32 { } } -// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str); -// amf.c -func C_AMFProp_GetString(prop *C_AMFObjectProperty, str *C_AVal) { - if prop.p_type == AMF_STRING { - *str = prop.p_vu.p_aval - } else { - *str = AV_empty - } -} - -// void AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj); -// amf.c +351 -func C_AMFProp_GetObject(prop *C_AMFObjectProperty, obj *C_AMFObject) { - if prop.p_type == AMF_OBJECT { - *obj = prop.p_vu.p_object - } else { - *obj = AMFObj_Invalid - } -} - -// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex); -// amf.c + 1249 -func C_AMF_GetProp(obj *C_AMFObject, name *C_AVal, nIndex int32) *C_AMFObjectProperty { - if nIndex >= 0 { - if nIndex < int32(obj.o_num) { - return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), - int(nIndex), int(unsafe.Sizeof(*obj.o_props))))) - //return &obj.o_props[nIndex] - } - } else { - var n int32 - for n = 0; n < int32(obj.o_num); n++ { - if C_AVMATCH(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), - int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name, name) != 0 { - return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), - int(n), int(unsafe.Sizeof(*obj.o_props))))) - } - } - } - return (*C_AMFObjectProperty)(&AMFProp_Invalid) -} - -// double AMFProp_GetNumber(AMFObjectProperty* prop); -// amf.c +330 -func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 { - return float64(prop.p_vu.p_number) -} - // void AV_erase(C_RTMP_METHOD* vals, int* num, int i, int freeit); // rtmp.c +2393 func C_AV_erase(vals *C_RTMP_METHOD, num *int32, i, freeit int32) { @@ -2693,293 +2448,6 @@ func C_RTMP_ReadPacket(r *C_RTMP, packet *C_RTMPPacket) int32 { return 1 } -// int AMF_Decode(AMFObject *obj, const char* pBuffer, int nSize, int bDecodeName); -// amf.c +1180 -func C_AMF_Decode(obj *C_AMFObject, pBuffer *byte, nSize int32, bDecodeName int32) int32 { - var nOriginalSize int32 = nSize - var bError int32 = 0 - - obj.o_num = 0 - obj.o_props = nil - - for nSize > 0 { - var prop C_AMFObjectProperty - var nRes int32 - - if nSize >= 3 && C_AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END { - nSize -= 3 - bError = 0 - break - } - - if bError != 0 { - // TODO use new logger here - log.Println("AMF_Decode: decoding error, ignoring bytes until next known pattern!") - nSize-- - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - continue - } - // TODO port AMFProp_Decode - nRes = int32(C_AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), - int32(nSize), int32(bDecodeName))) - // nRes = int32(C.AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), - // int32(nSize), int32(bDecodeName))) - if nRes == -1 { - bError = 1 - break - } else { - nSize -= nRes - if nSize < 0 { - bError = 1 - break - } - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes))) - C_AMF_AddProp(obj, &prop) - } - } - - if bError != 0 { - return -1 - } - - return nOriginalSize - nSize -} - -// int AMFProp_Decode(C_AMFObjectProperty* prop, const char* pBuffer, int nSize, int bDecodeName); -// amf.c +619 -func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeName int32) int32 { - - var nOriginalSize int32 = nSize - var nRes int32 - - prop.p_name.av_len = 0 - prop.p_name.av_val = nil - - if nSize == 0 || pBuffer == nil { - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__); - return -1 - } - - if bDecodeName != 0 && nSize < 4 { - // at least name (length + at least 1 byte) and 1 byte of data - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!",__FUNCTION__); - return -1 - } - - if bDecodeName != 0 { - nNameSize := C_AMF_DecodeInt16(pBuffer) - if int32(nNameSize) > nSize-2 { - // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2",__FUNCTION__, nNameSize, nSize); - return -1 - } - - C_AMF_DecodeString(pBuffer, &prop.p_name) - nSize -= int32(2 + nNameSize) - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(2+nNameSize))) - } - - if nSize == 0 { - return -1 - } - - nSize-- - - prop.p_type = (C_AMFDataType)(int32(*pBuffer)) - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - - switch prop.p_type { - case AMF_NUMBER: - log.Println("1") - if nSize < 8 { - return -1 - } - prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer)) - nSize -= 8 - - /* - case AMF_BOOLEAN: - log.Println("2") - if nSize < 1 { - return -1 - } - prop.p_vu.p_number = float64(C_AMF_DecodeBoolean((*byte)(unsafe.Pointer(pBuffer)))) - nSize-- - */ - case AMF_STRING: - { - log.Println("3") - var nStringSize = C_AMF_DecodeInt16(pBuffer) - - if int64(nSize) < int64(nStringSize)+2 { - return -1 - } - C_AMF_DecodeString(pBuffer, &prop.p_vu.p_aval) - nSize -= int32(2 + nStringSize) - } - - case AMF_OBJECT: - { - log.Println("4") - var nRes int32 = int32(C_AMF_Decode(&prop.p_vu.p_object, pBuffer, nSize, 1)) - if nRes == -1 { - return -1 - } - nSize -= nRes - - } - - case AMF_MOVIECLIP: - { - log.Println("5") - // TODO use new logger here - log.Println("AMFProp_Decode: MAF_MOVIECLIP reserved!") - //RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!"); - return -1 - - } - case AMF_NULL: - log.Println("6") - case AMF_UNDEFINED: - log.Println("7") - case AMF_UNSUPPORTED: - log.Println("8") - prop.p_type = AMF_NULL - - case AMF_REFERENCE: - { - log.Println("9") - // TODO use new logger here - log.Println("AMFProp_Decode: AMF_REFERENCE not supported!") - //RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!"); - return -1 - } - - case AMF_ECMA_ARRAY: - { - log.Println("10") - nSize -= 4 - - // next comes the rest, mixed array has a final 0x000009 mark and names, so its an object - nRes = C_AMF_Decode(&prop.p_vu.p_object, (*byte)(incBytePtr( - unsafe.Pointer(pBuffer), 4)), nSize, 1) - if nRes == -1 { - return -1 - } - nSize -= nRes - } - - case AMF_OBJECT_END: - { - log.Println("11") - return -1 - } - /* - case AMF_STRICT_ARRAY: - { - log.Println("12") - nArrayLen := int32(C_AMF_DecodeInt32(pBuffer)) - nSize -= 4 - - nRes = C_AMF_DecodeArray(&prop.p_vu.p_object, (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 4)), nSize, int32(nArrayLen), FALSE) - if nRes == -1 { - return -1 - } - nSize -= nRes - } - */ - /* - case AMF_DATE: - { - log.Println("13") - // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE"); - - if nSize < 10 { - return -1 - } - - prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer)) - prop.p_UTCoffset = C.int16_t(C_AMF_DecodeInt16((*byte)(incBytePtr(unsafe.Pointer(pBuffer), 8)))) - - nSize -= 10 - - } - */ - case AMF_LONG_STRING: - log.Println("14") - /* - case AMF_XML_DOC: - { - log.Println("15") - var nStringSize uint32 = C_AMF_DecodeInt32(pBuffer) - if int64(nSize) < int64(nStringSize)+4 { - return -1 - } - C_AMF_DecodeLongString(pBuffer, &prop.p_vu.p_aval) - nSize -= int32(4 + nStringSize) - if prop.p_type == AMF_LONG_STRING { - prop.p_type = AMF_STRING - } - } - */ - case AMF_RECORDSET: - { - log.Println("16") - // TODO use new logger here - log.Println("AMFProp_Decode: AMF_RECORDSET reserved!") - //RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!"); - return -1 - - } - case AMF_TYPED_OBJECT: - { - log.Println("17") - // TODO use new logger here - // RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!") - return -1 - } - - /* - case AMF_AVMPLUS: - { - log.Println("18") - nRes := int32(C.AMF3_Decode(&prop.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), int32(nSize), 1)) - if nRes == -1 { - return -1 - } - nSize -= nRes - prop.p_type = AMF_OBJECT - } - */ - default: - log.Println("19") - // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__, - //prop.p_type, pBuffer - 1); - return -1 - } - - return nOriginalSize - nSize -} - -// void AMF_AddProp(AMFObject* obj, const AMFObjectProperty* prop); -// amf.c + 1234 -func C_AMF_AddProp(obj *C_AMFObject, prop *C_AMFObjectProperty) { - if (obj.o_num & 0x0f) == 0 { - //obj.o_props = (*C_AMFObjectProperty)(realloc(unsafe.Pointer(obj.o_props), - //uint32(int(obj.o_num+16)*int(unsafe.Sizeof(*obj.o_props))))) - obj.o_props = (*C_AMFObjectProperty)(C.realloc(unsafe.Pointer(obj.o_props), - C.size_t(int(obj.o_num+16)*int(unsafe.Sizeof(*obj.o_props))))) - } - memmove(unsafe.Pointer(&(*(*C_AMFObjectProperty)(incPtr( - unsafe.Pointer(obj.o_props), int(obj.o_num), int(unsafe.Sizeof(*obj.o_props)))))), - unsafe.Pointer(prop), unsafe.Sizeof(*obj.o_props)) - obj.o_num++ -} - // static int DecodeInt32LE(const char* data); // rtmp.c +3527 func C_DecodeInt32LE(data *byte) int32 { @@ -2990,18 +2458,6 @@ func C_DecodeInt32LE(data *byte) int32 { *c) } -// unsigned int AMF_DeocdeInt32(const char* data); -// amf.c +59 -func C_AMF_DecodeInt32(data *byte) uint32 { - c := (*uint8)(data) - val := uint32( - int32(*c)<<24 | - int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 1)))<<16 | - int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 2)))<<8 | - int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 3)))) - return uint32(val) -} - // int EncodeInt32LE(char* output, int nVal); // rtmp.c +3537 func C_EncodeInt32LE(output *byte, nVal int32) int32 { @@ -3446,15 +2902,6 @@ func C_WriteN(r *C_RTMP, buffer unsafe.Pointer, n int) int { return 0 } -const length = 512 - -var RTMPT_cmds = []string{ - "open", - "send", - "idle", - "close", -} - // int RTMPSockBuf_Send(RTMPSockBuf* sb, const char* buf, int len); // rtmp.c +4297 // TODO replace send with golang net connection send @@ -3485,331 +2932,6 @@ func C_AV_queue(vals **C_RTMP_METHOD, num *int32, av *C_AVal, txn int32) { (*num)++ } -// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal); -// amf.c +286 -func C_AMF_EncodeNamedNumber(output *byte, outend *byte, strName *C_AVal, dVal float64) *byte { - if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) - memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) - output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) - return C_AMF_EncodeNumber(output, outend, dVal) -} - -// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal); -// amf.c +299 -func C_AMF_EncodeNamedBoolean(output *byte, outend *byte, strName *C_AVal, bVal int) *byte { - if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) - memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) - output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) - return C_AMF_EncodeBoolean(output, outend, bVal) -} - -// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name); -// amf.c +318 -func C_AMFProp_SetName(prop *C_AMFObjectProperty, name *C_AVal) { - prop.p_name = *name -} - -const ( - AMF3_INTEGER_MAX = 268435455 - AMF3_INTEGER_MIN = -268435456 -) - -// int AMF3ReadInteger(const char *data, int32_t *valp); -// amf.c +426 -// TODO test -func C_AMF3ReadInteger(data *byte, valp *int32) int32 { - var i int - var val int32 - - for i <= 2 { - /* handle first 3 bytes */ - if *indxBytePtr(unsafe.Pointer(data), i)&0x80 != 0 { - /* byte used */ - val <<= 7 /* shift up */ - val |= int32(*indxBytePtr(unsafe.Pointer(data), i) & 0x7f) /* add bits */ - i++ - } else { - break - } - } - - if i > 2 { - /* use 4th byte, all 8bits */ - val <<= 8 - val |= int32(*indxBytePtr(unsafe.Pointer(data), 3)) - - /* range check */ - if val > AMF3_INTEGER_MAX { - val -= (1 << 29) - } - } else { - /* use 7bits of last unparsed byte (0xxxxxxx) */ - val <<= 7 - val |= int32(*indxBytePtr(unsafe.Pointer(data), i)) - } - - *valp = val - - if i > 2 { - return 4 - } - return int32(i + 1) -} - -// int AMF3ReadString(const char *data, AVal *str); -// amf.c +466 -func C_AMF3ReadString(data *byte, str *C_AVal) int32 { - var ref int32 - // assert elided - we will get a panic if it's nil. - - len := C_AMF3ReadInteger(data, &ref) - data = indxBytePtr(unsafe.Pointer(data), int(len)) - - if ref&0x1 == 0 { - /* reference: 0xxx */ - // TODO(kortschak) Logging. - // refIndex := (ref >> 1) - // RTMP_Log(RTMP_LOGDEBUG, - // "%s, string reference, index: %d, not supported, ignoring!", - // __FUNCTION__, refIndex); - str.av_val = nil - str.av_len = 0 - return len - } else { - nSize := (ref >> 1) - str.av_val = (*byte)(unsafe.Pointer(data)) - str.av_len = int32(nSize) - return len + nSize - } - return len -} - -// char* AMF_EncodeBoolean(char* output, char* outend, int bVal); -// amf.c +260 -func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal int) *byte { - if int(uintptr(unsafe.Pointer(output)))+2 > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - *(*byte)(unsafe.Pointer(output)) = AMF_BOOLEAN - output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) - val := byte(0x01) - if bVal == 0 { - val = byte(0x00) - } - *(*byte)(unsafe.Pointer(output)) = val - output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) - return output -} - -// char* AMF_EncodeNumber(char* output, char* outend, double dVal); -// amf.c +199 -func C_AMF_EncodeNumber(output *byte, outend *byte, dVal float64) *byte { - if int(uintptr(unsafe.Pointer(output)))+1+8 > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - // TODO: port this - *(*byte)(unsafe.Pointer(output)) = AMF_NUMBER - output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) - // NOTE: here we are assuming little endian for both byte order and float - // word order - var ci, co *uint8 - ci = (*uint8)(unsafe.Pointer(&dVal)) - co = (*uint8)(unsafe.Pointer(output)) - for i := 0; i < 8; i++ { - *indxBytePtr(unsafe.Pointer(co), i) = *indxBytePtr(unsafe.Pointer(ci), 7-i) - } - return (*byte)(incBytePtr(unsafe.Pointer(output), 8)) -} - -// void AMF_DecodeLongString(const char *data, AVal *bv); -// amf.c +75 -func C_AMF_DecodeLongString(data *byte, bv *C_AVal) { - bv.av_len = int32(C_AMF_DecodeInt32(data)) - if bv.av_len > 0 { - bv.av_val = (*byte)(incBytePtr(unsafe.Pointer(data), 4)) - } else { - bv.av_val = nil - } -} - -// double AMF_DecodeNumber(const char* data); -// amf.c +82 -func C_AMF_DecodeNumber(data *byte) float64 { - var dVal float64 - var ci, co *uint8 - ci = (*uint8)(unsafe.Pointer(data)) - co = (*uint8)(unsafe.Pointer(&dVal)) - for i := 0; i < 8; i++ { - *indxBytePtr(unsafe.Pointer(co), i) = *indxBytePtr(unsafe.Pointer(ci), 7-i) - } - return dVal -} - -// int AMF_DecodeBoolean(const char *data); -// amf.c +132 -func C_AMF_DecodeBoolean(data *byte) int32 { - if *data != 0 { - return 1 - } - return 0 -} - -// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue); -// amf.c +273 -func C_AMF_EncodeNamedString(output *byte, outend *byte, strName *C_AVal, strValue *C_AVal) *byte { - if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) - memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) - output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) - return C_AMF_EncodeString(output, outend, strValue) -} - -// void AMF_DecodeString(const char* data, C_AVal* bv); -// amf.c +68 -func C_AMF_DecodeString(data *byte, bv *C_AVal) { - dataPtr := unsafe.Pointer(data) - //bv.av_len = int32(C.AMF_DecodeInt16((*byte)(dataPtr))) - bv.av_len = int32(C_AMF_DecodeInt16((*byte)(dataPtr))) - if bv.av_len > 0 { - bv.av_val = (*byte)(incBytePtr(dataPtr, 2)) - } else { - bv.av_val = nil - } -} - -// unsigned short AMF_DecodeInt16(const char* data); -// amf.c +41 -func C_AMF_DecodeInt16(data *byte) uint16 { - c := unsafe.Pointer(data) - return uint16(*(*uint8)(c)<<8 | *(*byte)(incBytePtr(c, 1))) -} - -// char* AMF_EncodeInt24(char* output, char* outend, int nVal); -// amf.c +149 -func C_AMF_EncodeInt24(output *byte, outend *byte, nVal int32) *byte { - outputPtr := unsafe.Pointer(output) - outendPtr := unsafe.Pointer(outend) - if uintptr(outputPtr)+3 > uintptr(outendPtr) { - // length < 3 - return nil - } - // Assign output[2] - third := (*byte)(incBytePtr(outputPtr, 2)) - *third = (byte)(nVal & 0xff) - // Assign output[1] - second := (*byte)(incBytePtr(outputPtr, 1)) - *second = (byte)(nVal >> 8) - // Assign output[0] - *output = (byte)(nVal >> 16) - return (*byte)(incBytePtr(outputPtr, 3)) -} - -// unsigned int AMF_DecodeInt24(const char* data); -// amf.c +50 -func C_AMF_DecodeInt24(data *byte) uint32 { - // TODO Understand logic and simplify - c := (*uint8)(unsafe.Pointer(data)) - dst := uint32(int32(*c) << 16) - dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + - (uintptr)(int32(1))*unsafe.Sizeof(*c))))) << 8) - dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + - (uintptr)(int32(2))*unsafe.Sizeof(*c)))))) - return dst -} - -// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv); -// amf.c +174 -func C_AMF_EncodeString(output *byte, outend *byte, bv *C_AVal) *byte { - outputPtr := unsafe.Pointer(output) - outendPtr := unsafe.Pointer(outend) - if (bv.av_len < 65536 && uintptr(incBytePtr(outputPtr, 1+2+int(bv.av_len))) > - uintptr(outendPtr)) || uintptr(incBytePtr(outputPtr, 1+4+int(bv.av_len))) > - uintptr(outendPtr) { - return nil - } - if bv.av_len < 65536 { - *(*byte)(outputPtr) = AMF_STRING - outputPtr = incBytePtr(outputPtr, 1) - // TODO: port AMF_EncodeInt16 - outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), (*byte)( - outendPtr), int16(bv.av_len))) - //outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), - //(*byte)(outendPtr), (int16)(bv.av_len))) - } else { - *(*byte)(outputPtr) = AMF_LONG_STRING - outputPtr = incBytePtr(outputPtr, 1) - outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), (*byte)( - outendPtr), int32(bv.av_len))) - //outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), - //(*byte)(outendPtr), (int32)(bv.av_len))) - } - memmove(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), uintptr(bv.av_len)) - //C.memcpy(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), (C.size_t)(bv.av_len)) - outputPtr = incBytePtr(outputPtr, int(bv.av_len)) - return (*byte)(outputPtr) -} - -// char* AMF_EncodeInt16(char* output, char* outend, short nVal); -// amf.c +138 -func C_AMF_EncodeInt16(output *byte, outend *byte, nVal int16) *byte { - outputPtr := unsafe.Pointer(output) - outendPtr := unsafe.Pointer(outend) - if uintptr(outputPtr)+2 > uintptr(outendPtr) { - // length < 2 - return nil - } - // Assign output[1] - second := (*byte)(incBytePtr(outputPtr, 1)) - *second = (byte)(nVal & 0xff) - // Assign output[0] - *output = (byte)(nVal >> 8) - return (*byte)(incBytePtr(outputPtr, 2)) -} - -// char* AMF_EncodeInt32(char* output, char* outend, int nVal); -// amf.c +161 -func C_AMF_EncodeInt32(output *byte, outend *byte, nVal int32) *byte { - outputPtr := unsafe.Pointer(output) - outendPtr := unsafe.Pointer(outend) - if uintptr(outputPtr)+4 > uintptr(outendPtr) { - // length < 4 - return nil - } - // Assign output[3] - forth := (*byte)(incBytePtr(outputPtr, 3)) - *forth = (byte)(nVal & 0xff) - // Assign output[2] - third := (*byte)(incBytePtr(outputPtr, 2)) - *third = (byte)(nVal >> 8) - // Assign output[1] - second := (*byte)(incBytePtr(outputPtr, 1)) - *second = (byte)(nVal >> 16) - // Assign output[0] - *output = (byte)(nVal >> 24) - return (*byte)(incBytePtr(outputPtr, 4)) -} - -// void AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop); -// amf.c +1298 -// TODO test -/* -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++ -} -*/ - /* func realloc(ptr unsafe.Pointer, newSize uint32) unsafe.Pointer { return unsafe.Pointer(crt.Xrealloc(crt.TLS(uintptr(unsafe.Pointer(nil))), From 68b9f2a5e00797882cdf08cee9a1a19ffa386568 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 07:04:01 +0930 Subject: [PATCH 05/33] rtmp: created parseurl file and moved C_RTMP_ParseURL and C_RTMP_ParsePlaypath from to rtmp.go to parseurl.go --- rtmp/parseurl.go | 296 +++++++++++++++++++++++++++++++++++++++++++++++ rtmp/rtmp.go | 295 ---------------------------------------------- 2 files changed, 296 insertions(+), 295 deletions(-) create mode 100644 rtmp/parseurl.go diff --git a/rtmp/parseurl.go b/rtmp/parseurl.go new file mode 100644 index 00000000..d1106ec4 --- /dev/null +++ b/rtmp/parseurl.go @@ -0,0 +1,296 @@ +package rtmp + +// int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, +// AVal *playpath, AVal *app); +// parseurl.c +33 +func C_RTMP_ParseURL(url *byte, protocol *int32, host *C_AVal, port *uint32, + playpath *C_AVal, app *C_AVal) int { + + var p, end, col, ques, slash *byte + // TODO: use our logger here + // RTMP_Log(RTMP_LOGDEBUG, "Parsing..."); + + *protocol = RTMP_PROTOCOL_RTMP + *port = 0 + playpath.av_len = 0 + playpath.av_val = nil + app.av_len = 0 + app.av_val = nil + + p = strstr(url, goStrToCStr("://")) + + if p == nil { + // TODO: use our logger here + log.Println("RTMP URL: No :// in url!") + return 0 + } + /* + NOTE: the following code nees to be ported if we're using anything other than + rtmp! + { + int len = (int)(p-url); + + if(len == 4 && strncasecmp(url, "rtmp", 4)==0) + *protocol = RTMP_PROTOCOL_RTMP; + else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0) + *protocol = RTMP_PROTOCOL_RTMPT; + else if(len == 5 && strncasecmp(url, "rtmps", 5)==0) + *protocol = RTMP_PROTOCOL_RTMPS; + else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0) + *protocol = RTMP_PROTOCOL_RTMPE; + else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0) + *protocol = RTMP_PROTOCOL_RTMFP; + else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0) + *protocol = RTMP_PROTOCOL_RTMPTE; + else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0) + *protocol = RTMP_PROTOCOL_RTMPTS; + else { + RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n"); + goto parsehost; + } + } + */ + // TODO: implement new logger here + // RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol); + + // Get the hostname + p = (*byte)(incBytePtr(unsafe.Pointer(p), 3)) + + // check for sudden death + if *p == 0 { + // TODO: use new logger here + // RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!"); + return 0 + } + + end = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(strlen(p)))) + col = strchr(p, ':') + ques = strchr(p, '?') + slash = strchr(p, '/') + + { + var hostlen int32 + if slash != nil { + hostlen = int32(uintptr(unsafe.Pointer(slash)) - uintptr(unsafe.Pointer(p))) + } else { + hostlen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) + } + if col != nil && int32(uintptr(unsafe.Pointer(col))-uintptr(unsafe.Pointer(p))) < hostlen { + hostlen = int32(uintptr(unsafe.Pointer(col)) - uintptr(unsafe.Pointer(p))) + } + + if hostlen < 256 { + host.av_val = (*byte)(unsafe.Pointer(p)) + host.av_len = int32(hostlen) + // TODO: use new logger with this + //RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host.av_val); + } else { + // TODO: use new logger with this + // RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!"); + } + + p = (*byte)(incBytePtr(unsafe.Pointer(p), int(hostlen))) + } + + // get port number if available + if *p == ':' { + var p2 uint32 + p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) + tmp, _ := strconv.Atoi(cStrToGoStr(p)) + p2 = uint32(tmp) + if p2 > 65535 { + // TODO: use new logger with this + // RTMP_Log(RTMP_LOGWARNING, "Invalid port number!"); + } else { + *port = p2 + } + } + + if slash == nil { + // TODO: use new logger + // RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!"); + return 1 + } + + p = (*byte)(incBytePtr(unsafe.Pointer(slash), 1)) + + { + /* parse application + * + * rtmp://host[:port]/app[/appinstance][/...] + * application = app[/appinstance] + */ + + var slash2 *byte + var slash3 *byte = nil + var slash4 *byte = nil + var applen, appnamelen int32 + + slash2 = strchr(p, '/') + + if slash2 != nil { + slash3 = strchr((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(slash2))+ + uintptr(1))), '/') + } + if slash3 != nil { + slash4 = strchr((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(slash3))+ + uintptr(1))), '/') + } + + // ondemand, pass all parameters as app + applen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) + appnamelen = applen + + switch { + case ques != nil && strstr(p, goStrToCStr("slist=")) != nil: + appnamelen = int32(uintptr(unsafe.Pointer(ques)) - uintptr(unsafe.Pointer(p))) + case strings.Compare(cStrToGoStr(p)[:9], "ondemand/") == 0: + /* app = ondemand/foobar, only pass app=ondemand */ + applen = 8 + appnamelen = 8 + default: + switch { + case slash4 != nil: + appnamelen = int32(uintptr(unsafe.Pointer(slash4)) - uintptr( + unsafe.Pointer(p))) + case slash3 != nil: + appnamelen = int32(uintptr(unsafe.Pointer(slash3)) - uintptr( + unsafe.Pointer(p))) + case slash2 != nil: + appnamelen = int32(uintptr(unsafe.Pointer(slash2)) - uintptr( + unsafe.Pointer(p))) + } + + applen = appnamelen + } + + app.av_val = (*byte)(unsafe.Pointer(p)) + app.av_len = int32(applen) + // TODO: use new logging here + // RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p); + + p = (*byte)(incBytePtr(unsafe.Pointer(p), int(appnamelen))) + } + + if *p == '/' { + p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) + } + // NOTE: don't think we currently need this section - see 787 for this func + + if int(uintptr(unsafe.Pointer(end))-uintptr(unsafe.Pointer(p))) != 0 { + var av C_AVal + av.av_val = (*byte)(unsafe.Pointer(p)) + av.av_len = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) + // TODO: port THis + //C.RTMP_ParsePlaypath(&av, playpath) + C_RTMP_ParsePlaypath(&av, playpath) + } + + return 1 +} + +// void RTMP_ParsePlaypath(AVal *in, AVal *out); +// parseurl.c +201 +func C_RTMP_ParsePlaypath(in, out *C_AVal) { + var addMP4 int32 = 0 + var addMP3 int32 = 0 + var subExt int32 = 0 + playpath := in.av_val + var temp, q *byte + var ext *byte = nil + ppstart := (*byte)(unsafe.Pointer(playpath)) + var streamname, destptr, p *byte + + pplen := int32(in.av_len) + + out.av_val = nil + out.av_len = 0 + + temp = strstr((*byte)(unsafe.Pointer(ppstart)), goStrToCStr("slist=")) + if *ppstart == '?' && temp != nil { + ppstart = (*byte)(incBytePtr(unsafe.Pointer(temp), 6)) + pplen = int32(strlen(ppstart)) + + temp = strchr(ppstart, '&') + + if temp != nil { + pplen = int32(uintptr(unsafe.Pointer(temp)) - uintptr(unsafe.Pointer(ppstart))) + } + } + + q = strchr(ppstart, '?') + + if pplen >= 4 { + if q != nil { + ext = (*byte)(decBytePtr(unsafe.Pointer(q), 4)) + } else { + ext = (*byte)(indxBytePtr(unsafe.Pointer(ppstart), int(uintptr(pplen)- + uintptr(4)))) + } + switch { + case strings.Compare(cStrToGoStr(ext)[:4], ".f4v") == 0 || + strings.Compare(cStrToGoStr(ext)[:4], ".mp4") == 0: + addMP4 = 1 + subExt = 1 + case ppstart == (*byte)(unsafe.Pointer(playpath)) && strings.Compare( + cStrToGoStr(ext)[:4], ".flv") == 0: + subExt = 1 + case strings.Compare(cStrToGoStr(ext)[:4], ".mp3") == 0: + addMP3 = 1 + subExt = 1 + } + } + + streamname = (*byte)(malloc(uintptr(pplen + 4 + 1))) + + if streamname == nil { + return + } + + destptr = streamname + switch { + case addMP4 != 0: + if strings.Compare(cStrToGoStr(ppstart)[:4], "mp4") != 0 { + memmove(unsafe.Pointer(destptr), unsafe.Pointer(goStrToCStr("mp4:")), + uintptr(len("mp4:"))) + destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 4)) + } else { + subExt = 0 + } + case addMP3 != 0: + if strings.Compare(cStrToGoStr(ppstart)[:4], "mp3") != 0 { + memmove(unsafe.Pointer(destptr), unsafe.Pointer(goStrToCStr("mp3:")), + uintptr(len("mp4:"))) + destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 4)) + } else { + subExt = 0 + } + } + + p = (*byte)(ppstart) + for pplen > 0 { + if subExt != 0 && p == ext { + p = (*byte)(incBytePtr(unsafe.Pointer(p), 4)) + pplen -= 4 + continue + } + if *p == '%' { + var c uint32 + fmt.Sscanf(cStrToGoStr((*byte)(incBytePtr(unsafe.Pointer(p), 1))), "%02x", &c) + *indxBytePtr(unsafe.Pointer(destptr), 0) = byte(c) + destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 1)) + pplen -= 3 + p = (*byte)(incBytePtr(unsafe.Pointer(p), 3)) + } else { + *indxBytePtr(unsafe.Pointer(destptr), 0) = *p + destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 1)) + p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) + pplen-- + } + } + *destptr = '\x00' + + out.av_val = (*byte)(unsafe.Pointer(streamname)) + out.av_len = int32(uintptr(unsafe.Pointer(destptr)) - uintptr(unsafe.Pointer( + streamname))) +} diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 3d1defd1..e329d941 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -576,301 +576,6 @@ func C_RTMP_SetupURL(r *C_RTMP, u string) int32 { return 1 } -// int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, -// AVal *playpath, AVal *app); -// parseurl.c +33 -func C_RTMP_ParseURL(url *byte, protocol *int32, host *C_AVal, port *uint32, - playpath *C_AVal, app *C_AVal) int { - - var p, end, col, ques, slash *byte - // TODO: use our logger here - // RTMP_Log(RTMP_LOGDEBUG, "Parsing..."); - - *protocol = RTMP_PROTOCOL_RTMP - *port = 0 - playpath.av_len = 0 - playpath.av_val = nil - app.av_len = 0 - app.av_val = nil - - p = strstr(url, goStrToCStr("://")) - - if p == nil { - // TODO: use our logger here - log.Println("RTMP URL: No :// in url!") - return 0 - } - /* - NOTE: the following code nees to be ported if we're using anything other than - rtmp! - { - int len = (int)(p-url); - - if(len == 4 && strncasecmp(url, "rtmp", 4)==0) - *protocol = RTMP_PROTOCOL_RTMP; - else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0) - *protocol = RTMP_PROTOCOL_RTMPT; - else if(len == 5 && strncasecmp(url, "rtmps", 5)==0) - *protocol = RTMP_PROTOCOL_RTMPS; - else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0) - *protocol = RTMP_PROTOCOL_RTMPE; - else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0) - *protocol = RTMP_PROTOCOL_RTMFP; - else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0) - *protocol = RTMP_PROTOCOL_RTMPTE; - else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0) - *protocol = RTMP_PROTOCOL_RTMPTS; - else { - RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n"); - goto parsehost; - } - } - */ - // TODO: implement new logger here - // RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol); - - // Get the hostname - p = (*byte)(incBytePtr(unsafe.Pointer(p), 3)) - - // check for sudden death - if *p == 0 { - // TODO: use new logger here - // RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!"); - return 0 - } - - end = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(strlen(p)))) - col = strchr(p, ':') - ques = strchr(p, '?') - slash = strchr(p, '/') - - { - var hostlen int32 - if slash != nil { - hostlen = int32(uintptr(unsafe.Pointer(slash)) - uintptr(unsafe.Pointer(p))) - } else { - hostlen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) - } - if col != nil && int32(uintptr(unsafe.Pointer(col))-uintptr(unsafe.Pointer(p))) < hostlen { - hostlen = int32(uintptr(unsafe.Pointer(col)) - uintptr(unsafe.Pointer(p))) - } - - if hostlen < 256 { - host.av_val = (*byte)(unsafe.Pointer(p)) - host.av_len = int32(hostlen) - // TODO: use new logger with this - //RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host.av_val); - } else { - // TODO: use new logger with this - // RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!"); - } - - p = (*byte)(incBytePtr(unsafe.Pointer(p), int(hostlen))) - } - - // get port number if available - if *p == ':' { - var p2 uint32 - p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) - tmp, _ := strconv.Atoi(cStrToGoStr(p)) - p2 = uint32(tmp) - if p2 > 65535 { - // TODO: use new logger with this - // RTMP_Log(RTMP_LOGWARNING, "Invalid port number!"); - } else { - *port = p2 - } - } - - if slash == nil { - // TODO: use new logger - // RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!"); - return 1 - } - - p = (*byte)(incBytePtr(unsafe.Pointer(slash), 1)) - - { - /* parse application - * - * rtmp://host[:port]/app[/appinstance][/...] - * application = app[/appinstance] - */ - - var slash2 *byte - var slash3 *byte = nil - var slash4 *byte = nil - var applen, appnamelen int32 - - slash2 = strchr(p, '/') - - if slash2 != nil { - slash3 = strchr((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(slash2))+ - uintptr(1))), '/') - } - if slash3 != nil { - slash4 = strchr((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(slash3))+ - uintptr(1))), '/') - } - - // ondemand, pass all parameters as app - applen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) - appnamelen = applen - - switch { - case ques != nil && strstr(p, goStrToCStr("slist=")) != nil: - appnamelen = int32(uintptr(unsafe.Pointer(ques)) - uintptr(unsafe.Pointer(p))) - case strings.Compare(cStrToGoStr(p)[:9], "ondemand/") == 0: - /* app = ondemand/foobar, only pass app=ondemand */ - applen = 8 - appnamelen = 8 - default: - switch { - case slash4 != nil: - appnamelen = int32(uintptr(unsafe.Pointer(slash4)) - uintptr( - unsafe.Pointer(p))) - case slash3 != nil: - appnamelen = int32(uintptr(unsafe.Pointer(slash3)) - uintptr( - unsafe.Pointer(p))) - case slash2 != nil: - appnamelen = int32(uintptr(unsafe.Pointer(slash2)) - uintptr( - unsafe.Pointer(p))) - } - - applen = appnamelen - } - - app.av_val = (*byte)(unsafe.Pointer(p)) - app.av_len = int32(applen) - // TODO: use new logging here - // RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p); - - p = (*byte)(incBytePtr(unsafe.Pointer(p), int(appnamelen))) - } - - if *p == '/' { - p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) - } - // NOTE: don't think we currently need this section - see 787 for this func - - if int(uintptr(unsafe.Pointer(end))-uintptr(unsafe.Pointer(p))) != 0 { - var av C_AVal - av.av_val = (*byte)(unsafe.Pointer(p)) - av.av_len = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) - // TODO: port THis - //C.RTMP_ParsePlaypath(&av, playpath) - C_RTMP_ParsePlaypath(&av, playpath) - } - - return 1 -} - -// void RTMP_ParsePlaypath(AVal *in, AVal *out); -// parseurl.c +201 -func C_RTMP_ParsePlaypath(in, out *C_AVal) { - var addMP4 int32 = 0 - var addMP3 int32 = 0 - var subExt int32 = 0 - playpath := in.av_val - var temp, q *byte - var ext *byte = nil - ppstart := (*byte)(unsafe.Pointer(playpath)) - var streamname, destptr, p *byte - - pplen := int32(in.av_len) - - out.av_val = nil - out.av_len = 0 - - temp = strstr((*byte)(unsafe.Pointer(ppstart)), goStrToCStr("slist=")) - if *ppstart == '?' && temp != nil { - ppstart = (*byte)(incBytePtr(unsafe.Pointer(temp), 6)) - pplen = int32(strlen(ppstart)) - - temp = strchr(ppstart, '&') - - if temp != nil { - pplen = int32(uintptr(unsafe.Pointer(temp)) - uintptr(unsafe.Pointer(ppstart))) - } - } - - q = strchr(ppstart, '?') - - if pplen >= 4 { - if q != nil { - ext = (*byte)(decBytePtr(unsafe.Pointer(q), 4)) - } else { - ext = (*byte)(indxBytePtr(unsafe.Pointer(ppstart), int(uintptr(pplen)- - uintptr(4)))) - } - switch { - case strings.Compare(cStrToGoStr(ext)[:4], ".f4v") == 0 || - strings.Compare(cStrToGoStr(ext)[:4], ".mp4") == 0: - addMP4 = 1 - subExt = 1 - case ppstart == (*byte)(unsafe.Pointer(playpath)) && strings.Compare( - cStrToGoStr(ext)[:4], ".flv") == 0: - subExt = 1 - case strings.Compare(cStrToGoStr(ext)[:4], ".mp3") == 0: - addMP3 = 1 - subExt = 1 - } - } - - streamname = (*byte)(malloc(uintptr(pplen + 4 + 1))) - - if streamname == nil { - return - } - - destptr = streamname - switch { - case addMP4 != 0: - if strings.Compare(cStrToGoStr(ppstart)[:4], "mp4") != 0 { - memmove(unsafe.Pointer(destptr), unsafe.Pointer(goStrToCStr("mp4:")), - uintptr(len("mp4:"))) - destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 4)) - } else { - subExt = 0 - } - case addMP3 != 0: - if strings.Compare(cStrToGoStr(ppstart)[:4], "mp3") != 0 { - memmove(unsafe.Pointer(destptr), unsafe.Pointer(goStrToCStr("mp3:")), - uintptr(len("mp4:"))) - destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 4)) - } else { - subExt = 0 - } - } - - p = (*byte)(ppstart) - for pplen > 0 { - if subExt != 0 && p == ext { - p = (*byte)(incBytePtr(unsafe.Pointer(p), 4)) - pplen -= 4 - continue - } - if *p == '%' { - var c uint32 - fmt.Sscanf(cStrToGoStr((*byte)(incBytePtr(unsafe.Pointer(p), 1))), "%02x", &c) - *indxBytePtr(unsafe.Pointer(destptr), 0) = byte(c) - destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 1)) - pplen -= 3 - p = (*byte)(incBytePtr(unsafe.Pointer(p), 3)) - } else { - *indxBytePtr(unsafe.Pointer(destptr), 0) = *p - destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 1)) - p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) - pplen-- - } - } - *destptr = '\x00' - - out.av_val = (*byte)(unsafe.Pointer(streamname)) - out.av_len = int32(uintptr(unsafe.Pointer(destptr)) - uintptr(unsafe.Pointer( - streamname))) -} - // void SocksSetup(RTMP *r, C_AVal* sockshost); // rtmp.c +410 func C_SocksSetup(r *C_RTMP, sockshost *C_AVal) { From 898c843f18abc4b693d3b83341887fde9e8f302e Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 09:33:05 +0930 Subject: [PATCH 06/33] rtmp: added appropriate imports to each file to correct build errors --- rtmp/amf.go | 28 ++++++++++++++++++++++++++++ rtmp/parseurl.go | 29 +++++++++++++++++++++++++++++ rtmp/rtmp.go | 11 +---------- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index 7e358082..eacb6572 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -1,5 +1,31 @@ package rtmp +/* +#cgo CFLAGS: -I/usr/local/include/librtmp +#cgo LDFLAGS: -lrtmp -Wl,-rpath=/usr/local/lib + +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE +} RTMPTCmd; + +typedef struct sockaddr_in sockaddr_in; +typedef struct sockaddr sockaddr; +*/ +import "C" + +import ( + "log" + "unsafe" +) + const ( AMF_NUMBER = iota AMF_BOOLEAN @@ -915,6 +941,7 @@ func C_AMF_EncodeInt32(output *byte, outend *byte, nVal int32) *byte { return (*byte)(incBytePtr(outputPtr, 4)) } +/* // void AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop); // amf.c +1298 func AMF3CD_AddProp(cd *C.AMF3ClassDef, prop *C_AVal) { @@ -924,3 +951,4 @@ func AMF3CD_AddProp(cd *C.AMF3ClassDef, prop *C_AVal) { *(*C_AVal)(incPtr(unsafe.Pointer(cd.cd_props), int(cd.cd_num), int(unsafe.Sizeof(C_AVal{})))) = *prop cd.cd_num++ } +*/ diff --git a/rtmp/parseurl.go b/rtmp/parseurl.go index d1106ec4..d277efda 100644 --- a/rtmp/parseurl.go +++ b/rtmp/parseurl.go @@ -1,5 +1,34 @@ package rtmp +/* +#cgo CFLAGS: -I/usr/local/include/librtmp +#cgo LDFLAGS: -lrtmp -Wl,-rpath=/usr/local/lib + +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE +} RTMPTCmd; + +typedef struct sockaddr_in sockaddr_in; +typedef struct sockaddr sockaddr; +*/ +import "C" + +import ( + "fmt" + "log" + "strconv" + "strings" + "unsafe" +) + // int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, // AVal *playpath, AVal *app); // parseurl.c +33 diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index e329d941..8ab86b86 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -36,7 +36,7 @@ package rtmp /* #cgo CFLAGS: -I/usr/local/include/librtmp -#cgo LDFLAGS: -lrtmp -lz -Wl,-rpath=/usr/local/lib +#cgo LDFLAGS: -lrtmp -Wl,-rpath=/usr/local/lib #include #include @@ -52,14 +52,6 @@ typedef enum { typedef struct sockaddr_in sockaddr_in; typedef struct sockaddr sockaddr; -int add_addr_info(struct sockaddr_in *service, AVal *host, int port); -RTMP* start_session(RTMP* rtmp, char* url, uint connect_timeout); -int write_frame(RTMP* rtmp, char* data, uint data_length); -int end_session(RTMP* rtmp); -void AV_queue(RTMP_METHOD **vals, int *num, AVal *av, int txn); -int C_WriteN(RTMP *r, const char *buffer, int n); -int EncodeInt32LE(char *output, int nVal); -int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len); */ import "C" @@ -71,7 +63,6 @@ import ( "math/rand" "reflect" "strconv" - "strings" "time" "unsafe" From 0adddd18333bb0bf92d7bd936f12b093ea296ee0 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 09:38:17 +0930 Subject: [PATCH 07/33] rtmp: started reordering funcs in rtmp.go - realised that I need a rtmp_headers.go file to store stuff that's from rtmp.h --- rtmp/amf.go | 4 ++++ rtmp/rtmp.go | 60 ++++++++++++++++++++++++---------------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index eacb6572..a3f08bda 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -53,6 +53,10 @@ var ( AMFProp_Invalid = C_AMFObjectProperty{p_type: AMF_INVALID} ) +// typedef enum +// amf.h +40 +type C_AMFDataType int32 + // typedef struct AMF_Object // amf.h +67 type C_AMFObject struct { diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 8ab86b86..64bcfa6e 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -76,9 +76,12 @@ const ( RTMPT_CLOSE ) -// typedef enum -// amf.h +40 -type C_AMFDataType int32 +// typedef struct C_AVal +// amf.h +57 +type C_AVal struct { + av_val *byte + av_len int32 +} const ( RTMP_PACKET_TYPE_CHUNK_SIZE = 0x01 @@ -228,6 +231,28 @@ type Session struct { timeout uint } +// typedef struct RTMPPacket +// rtmp.h +113 +type C_RTMPPacket struct { + m_headerType uint8 + m_packetType uint8 + m_hasAbsTimestamp uint8 + m_nChannel int32 + m_nTimeStamp uint32 + m_nInfoField2 int32 + m_nBodySize uint32 + m_nBytesRead uint32 + m_chunk *C_RTMPChunk + m_body *byte +} + +// typedef struct RTMPMethod +// rtmp.h +231 +type C_RTMP_METHOD struct { + name C_AVal + num int32 +} + // typedef struct RTMP // rtmp.h +237 type C_RTMP struct { @@ -271,35 +296,6 @@ type C_RTMP struct { Link C_RTMP_LNK } -// typedef struct RTMPPacket -// rtmp.h +113 -type C_RTMPPacket struct { - m_headerType uint8 - m_packetType uint8 - m_hasAbsTimestamp uint8 - m_nChannel int32 - m_nTimeStamp uint32 - m_nInfoField2 int32 - m_nBodySize uint32 - m_nBytesRead uint32 - m_chunk *C_RTMPChunk - m_body *byte -} - -// typedef struct RTMPMethod -// rtmp.h +231 -type C_RTMP_METHOD struct { - name C_AVal - num int32 -} - -// typedef struct C_AVal -// amf.h +57 -type C_AVal struct { - av_val *byte - av_len int32 -} - // typedef struct RTMP_READ // rtmp.h +200 type C_RTMP_READ struct { From dec662d19eacdbc79d34fa7e4b5e834d3405b2f2 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 09:41:02 +0930 Subject: [PATCH 08/33] rtmp: created rtmp_headers.go and amf_headers.go files to store stuff that was in rtmp.h and amf.h files respectively --- rtmp/amf_headers.go | 0 rtmp/rtmp_headers.go | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 rtmp/amf_headers.go create mode 100644 rtmp/rtmp_headers.go diff --git a/rtmp/amf_headers.go b/rtmp/amf_headers.go new file mode 100644 index 00000000..e69de29b diff --git a/rtmp/rtmp_headers.go b/rtmp/rtmp_headers.go new file mode 100644 index 00000000..e69de29b From 4fa0637fa1d019b9a3a7488a8f4ec6185986d407 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 09:47:11 +0930 Subject: [PATCH 09/33] rtmp: moved amf structs into amf_headers.go and rtmp structs into rtmp_headers.go --- rtmp/amf.go | 50 ----------- rtmp/amf_headers.go | 58 ++++++++++++ rtmp/rtmp.go | 210 ------------------------------------------- rtmp/rtmp_headers.go | 204 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 262 insertions(+), 260 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index a3f08bda..6f85f081 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -26,61 +26,11 @@ import ( "unsafe" ) -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 -) - var ( AMFObj_Invalid C_AMFObject AMFProp_Invalid = C_AMFObjectProperty{p_type: AMF_INVALID} ) -// typedef enum -// amf.h +40 -type C_AMFDataType int32 - -// typedef struct AMF_Object -// amf.h +67 -type C_AMFObject struct { - o_num int32 - o_props *C_AMFObjectProperty -} - -// typedef struct AMFObjectProperty -// amf.h +79 -type C_AMFObjectProperty struct { - p_name C_AVal - p_type C_AMFDataType - p_vu P_vu - p_UTCoffset int16 -} - -// typedef struct P_vu -// amf.h +73 -type P_vu struct { - p_number float64 - p_aval C_AVal - p_object C_AMFObject -} - // char* AMFPropEncode(AMFOBjectProperty* prop, char* pBufer, char* pBufEnd); // amf.c +366 func C_AMF_PropEncode(p *C_AMFObjectProperty, pBuffer *byte, pBufEnd *byte) *byte { diff --git a/rtmp/amf_headers.go b/rtmp/amf_headers.go index e69de29b..c79eff87 100644 --- a/rtmp/amf_headers.go +++ b/rtmp/amf_headers.go @@ -0,0 +1,58 @@ +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 struct C_AVal +// amf.h +57 +type C_AVal struct { + av_val *byte + av_len int32 +} + +// typedef enum +// amf.h +40 +type C_AMFDataType int32 + +// typedef struct AMF_Object +// amf.h +67 +type C_AMFObject struct { + o_num int32 + o_props *C_AMFObjectProperty +} + +// typedef struct AMFObjectProperty +// amf.h +79 +type C_AMFObjectProperty struct { + p_name C_AVal + p_type C_AMFDataType + p_vu P_vu + p_UTCoffset int16 +} + +// typedef struct P_vu +// amf.h +73 +type P_vu struct { + p_number float64 + p_aval C_AVal + p_object C_AMFObject +} diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 64bcfa6e..c96e2199 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -69,80 +69,6 @@ import ( "github.com/chamaken/cgolmnl/inet" ) -const ( - RTMPT_OPEN = iota - RTMPT_SEND - RTMPT_IDLE - RTMPT_CLOSE -) - -// typedef struct C_AVal -// amf.h +57 -type C_AVal struct { - av_val *byte - av_len int32 -} - -const ( - RTMP_PACKET_TYPE_CHUNK_SIZE = 0x01 - RTMP_PACKET_TYPE_BYTES_READ_REPORT = 0x03 - RTMP_PACKET_TYPE_CONTROL = 0x04 - RTMP_PACKET_TYPE_SERVER_BW = 0x05 - RTMP_PACKET_TYPE_CLIENT_BW = 0x06 - RTMP_PACKET_TYPE_AUDIO = 0x08 - RTMP_PACKET_TYPE_VIDEO = 0x09 - RTMP_PACKET_TYPE_FLEX_MESSAGE = 0x11 - RTMP_PACKET_TYPE_INFO = 0x12 - RTMP_PACKET_TYPE_INVOKE = 0x14 - RTMP_PACKET_TYPE_FLASH_VIDEO = 0x16 -) - -const ( - RTMP_PACKET_SIZE_LARGE = 0 - RTMP_PACKET_SIZE_MEDIUM = 1 - RTMP_PACKET_SIZE_SMALL = 2 - RTMP_PACKET_SIZE_MINIMUM = 3 -) - -const ( - RTMP_READ_HEADER = 0x01 - RTMP_READ_SEEKING = 0x2 -) - -const ( - RTMP_LF_AUTH = 0x0001 /* using auth param */ - RTMP_LF_LIVE = 0x0002 /* stream is live */ - RTMP_LF_PLST = 0x0008 /* send playlist before play */ - RTMP_LF_FTCU = 0x0020 /* free tcUrl on close */ - RTMP_LF_FAPU = 0x0040 /* free app on close */ -) - -const ( - RTMP_FEATURE_HTTP = 0x01 - RTMP_FEATURE_ENC = 0x02 - RTMP_FEATURE_SSL = 0x04 - RTMP_FEATURE_MFP = 0x08 /* not yet supported */ - RTMP_FEATURE_WRITE = 0x10 /* publish, not play */ -) - -const ( - RTMP_PROTOCOL_RTMP = 0 - RTMP_PROTOCOL_RTMPE = RTMP_FEATURE_ENC - RTMP_PROTOCOL_RTMPT = RTMP_FEATURE_HTTP - RTMP_PROTOCOL_RTMPS = RTMP_FEATURE_SSL - RTMP_PROTOCOL_RTMPTE = (RTMP_FEATURE_HTTP | RTMP_FEATURE_ENC) - RTMP_PROTOCOL_RTMPTS = (RTMP_FEATURE_HTTP | RTMP_FEATURE_SSL) - RTMP_PROTOCOL_RTMFP = RTMP_FEATURE_MFP -) - -const ( - RTMP_DEFAULT_CHUNKSIZE = 128 - RTMP_BUFFER_CACHE_SIZE = (16 * 1024) - RTMP_SIG_SIZE = 1536 - RTMP_LARGE_HEADER_SIZE = 12 - RTMP_MAX_HEADER_SIZE = 18 -) - const ( minDataSize = 11 debugMode = false @@ -231,142 +157,6 @@ type Session struct { timeout uint } -// typedef struct RTMPPacket -// rtmp.h +113 -type C_RTMPPacket struct { - m_headerType uint8 - m_packetType uint8 - m_hasAbsTimestamp uint8 - m_nChannel int32 - m_nTimeStamp uint32 - m_nInfoField2 int32 - m_nBodySize uint32 - m_nBytesRead uint32 - m_chunk *C_RTMPChunk - m_body *byte -} - -// typedef struct RTMPMethod -// rtmp.h +231 -type C_RTMP_METHOD struct { - name C_AVal - num int32 -} - -// typedef struct RTMP -// rtmp.h +237 -type C_RTMP struct { - m_inChunkSize int32 - m_outChunkSize int32 - m_nBWCheckCounter int32 - m_nBytesIn int32 - m_nBytesInSent int32 - m_nBufferMS int32 - m_stream_id int32 - m_mediaChannel int32 - m_mediaStamp uint32 - m_pauseStamp uint32 - m_pausing int32 - m_nServerBW int32 - m_nClientBW int32 - m_nClientBW2 uint8 - m_bPlaying uint8 - m_bSendEncoding uint8 - m_bSendCounter uint8 - m_numInvokes int32 - m_numCalls int32 - m_methodCalls *C_RTMP_METHOD - m_channelsAllocatedIn int32 - m_channelsAllocatedOut int32 - m_vecChannelsIn **C_RTMPPacket - m_vecChannelsOut **C_RTMPPacket - m_channelTimestamp *int32 - m_fAudioCodecs float64 - m_fVideoCodecs float64 - m_fEncoding float64 - m_fDuration float64 - m_msgCounter int32 - m_polling int32 - m_resplen int32 - m_unackd int32 - m_clientID C_AVal - m_read C_RTMP_READ - m_write C_RTMPPacket - m_sb C_RTMPSockBuf - Link C_RTMP_LNK -} - -// typedef struct RTMP_READ -// rtmp.h +200 -type C_RTMP_READ struct { - buf *byte - bufpos *byte - buflen uint - timestamp uint32 - dataType uint8 - flags uint8 - status int8 - initialFrameType uint8 - nResumeTS uint32 - metaHeader *byte - initialFrame *byte - nMetaHeaderSize uint32 - nInitialFrameSize uint32 - nIgnoredFrameCounter uint32 - nIgnoredFlvFrameCounter uint32 -} - -// typedef struct RTMP_READ -// rtmp.h +200 -type C_RTMPSockBuf struct { - sb_socket int32 - sb_size int32 - sb_start *byte - sb_buf [RTMP_BUFFER_CACHE_SIZE]byte // port const - sb_timedout int32 - sb_ssl uintptr -} - -// typedef struct RTMPChunk -// rtmp.h +105 -type C_RTMPChunk struct { - c_headerSize int32 - c_chunkSize int32 - c_chunk *byte - c_header [RTMP_MAX_HEADER_SIZE]byte -} - -// typedef struct RTMP_LNK -// rtmp.h +144 -type C_RTMP_LNK struct { - hostname C_AVal - sockshost C_AVal - playpath0 C_AVal - playpath C_AVal - tcUrl C_AVal - swfUrl C_AVal - pageUrl C_AVal - app C_AVal - auth C_AVal - flashVer C_AVal - subscribepath C_AVal - usherToken C_AVal - token C_AVal - pubUser C_AVal - pubPasswd C_AVal - extras C_AMFObject - edepth int32 - seekTime int32 - stopTime int32 - lFlags int32 - swfAge int32 - protocol int32 - timeout int32 - pFlags int32 - socksport uint16 - port uint16 -} - // NewSession returns a new session. func NewSession(url string, connectTimeout uint) *Session { return &Session{ diff --git a/rtmp/rtmp_headers.go b/rtmp/rtmp_headers.go index e69de29b..35051099 100644 --- a/rtmp/rtmp_headers.go +++ b/rtmp/rtmp_headers.go @@ -0,0 +1,204 @@ +package rtmp + +const ( + RTMPT_OPEN = iota + RTMPT_SEND + RTMPT_IDLE + RTMPT_CLOSE +) + +const ( + RTMP_PACKET_TYPE_CHUNK_SIZE = 0x01 + RTMP_PACKET_TYPE_BYTES_READ_REPORT = 0x03 + RTMP_PACKET_TYPE_CONTROL = 0x04 + RTMP_PACKET_TYPE_SERVER_BW = 0x05 + RTMP_PACKET_TYPE_CLIENT_BW = 0x06 + RTMP_PACKET_TYPE_AUDIO = 0x08 + RTMP_PACKET_TYPE_VIDEO = 0x09 + RTMP_PACKET_TYPE_FLEX_MESSAGE = 0x11 + RTMP_PACKET_TYPE_INFO = 0x12 + RTMP_PACKET_TYPE_INVOKE = 0x14 + RTMP_PACKET_TYPE_FLASH_VIDEO = 0x16 +) + +const ( + RTMP_PACKET_SIZE_LARGE = 0 + RTMP_PACKET_SIZE_MEDIUM = 1 + RTMP_PACKET_SIZE_SMALL = 2 + RTMP_PACKET_SIZE_MINIMUM = 3 +) + +const ( + RTMP_READ_HEADER = 0x01 + RTMP_READ_SEEKING = 0x2 +) + +const ( + RTMP_LF_AUTH = 0x0001 /* using auth param */ + RTMP_LF_LIVE = 0x0002 /* stream is live */ + RTMP_LF_PLST = 0x0008 /* send playlist before play */ + RTMP_LF_FTCU = 0x0020 /* free tcUrl on close */ + RTMP_LF_FAPU = 0x0040 /* free app on close */ +) + +const ( + RTMP_FEATURE_HTTP = 0x01 + RTMP_FEATURE_ENC = 0x02 + RTMP_FEATURE_SSL = 0x04 + RTMP_FEATURE_MFP = 0x08 /* not yet supported */ + RTMP_FEATURE_WRITE = 0x10 /* publish, not play */ +) + +const ( + RTMP_PROTOCOL_RTMP = 0 + RTMP_PROTOCOL_RTMPE = RTMP_FEATURE_ENC + RTMP_PROTOCOL_RTMPT = RTMP_FEATURE_HTTP + RTMP_PROTOCOL_RTMPS = RTMP_FEATURE_SSL + RTMP_PROTOCOL_RTMPTE = (RTMP_FEATURE_HTTP | RTMP_FEATURE_ENC) + RTMP_PROTOCOL_RTMPTS = (RTMP_FEATURE_HTTP | RTMP_FEATURE_SSL) + RTMP_PROTOCOL_RTMFP = RTMP_FEATURE_MFP +) + +const ( + RTMP_DEFAULT_CHUNKSIZE = 128 + RTMP_BUFFER_CACHE_SIZE = (16 * 1024) + RTMP_SIG_SIZE = 1536 + RTMP_LARGE_HEADER_SIZE = 12 + RTMP_MAX_HEADER_SIZE = 18 +) + +// typedef struct RTMPPacket +// rtmp.h +113 +type C_RTMPPacket struct { + m_headerType uint8 + m_packetType uint8 + m_hasAbsTimestamp uint8 + m_nChannel int32 + m_nTimeStamp uint32 + m_nInfoField2 int32 + m_nBodySize uint32 + m_nBytesRead uint32 + m_chunk *C_RTMPChunk + m_body *byte +} + +// typedef struct RTMPMethod +// rtmp.h +231 +type C_RTMP_METHOD struct { + name C_AVal + num int32 +} + +// typedef struct RTMP +// rtmp.h +237 +type C_RTMP struct { + m_inChunkSize int32 + m_outChunkSize int32 + m_nBWCheckCounter int32 + m_nBytesIn int32 + m_nBytesInSent int32 + m_nBufferMS int32 + m_stream_id int32 + m_mediaChannel int32 + m_mediaStamp uint32 + m_pauseStamp uint32 + m_pausing int32 + m_nServerBW int32 + m_nClientBW int32 + m_nClientBW2 uint8 + m_bPlaying uint8 + m_bSendEncoding uint8 + m_bSendCounter uint8 + m_numInvokes int32 + m_numCalls int32 + m_methodCalls *C_RTMP_METHOD + m_channelsAllocatedIn int32 + m_channelsAllocatedOut int32 + m_vecChannelsIn **C_RTMPPacket + m_vecChannelsOut **C_RTMPPacket + m_channelTimestamp *int32 + m_fAudioCodecs float64 + m_fVideoCodecs float64 + m_fEncoding float64 + m_fDuration float64 + m_msgCounter int32 + m_polling int32 + m_resplen int32 + m_unackd int32 + m_clientID C_AVal + m_read C_RTMP_READ + m_write C_RTMPPacket + m_sb C_RTMPSockBuf + Link C_RTMP_LNK +} + +// typedef struct RTMP_READ +// rtmp.h +200 +type C_RTMP_READ struct { + buf *byte + bufpos *byte + buflen uint + timestamp uint32 + dataType uint8 + flags uint8 + status int8 + initialFrameType uint8 + nResumeTS uint32 + metaHeader *byte + initialFrame *byte + nMetaHeaderSize uint32 + nInitialFrameSize uint32 + nIgnoredFrameCounter uint32 + nIgnoredFlvFrameCounter uint32 +} + +// typedef struct RTMP_READ +// rtmp.h +200 +type C_RTMPSockBuf struct { + sb_socket int32 + sb_size int32 + sb_start *byte + sb_buf [RTMP_BUFFER_CACHE_SIZE]byte // port const + sb_timedout int32 + sb_ssl uintptr +} + +// typedef struct RTMPChunk +// rtmp.h +105 +type C_RTMPChunk struct { + c_headerSize int32 + c_chunkSize int32 + c_chunk *byte + c_header [RTMP_MAX_HEADER_SIZE]byte +} + +// typedef struct RTMP_LNK +// rtmp.h +144 +type C_RTMP_LNK struct { + hostname C_AVal + sockshost C_AVal + playpath0 C_AVal + playpath C_AVal + tcUrl C_AVal + swfUrl C_AVal + pageUrl C_AVal + app C_AVal + auth C_AVal + flashVer C_AVal + subscribepath C_AVal + usherToken C_AVal + token C_AVal + pubUser C_AVal + pubPasswd C_AVal + extras C_AMFObject + edepth int32 + seekTime int32 + stopTime int32 + lFlags int32 + swfAge int32 + protocol int32 + timeout int32 + pFlags int32 + socksport uint16 + port uint16 +} From 9cb70ac06b1c933718fdba37cac09f06084740b7 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 09:52:51 +0930 Subject: [PATCH 10/33] rtmp: created session.go file and moved librtmp wrapper functions into this file, i.e. NewSession, Open, Close and Write --- rtmp/rtmp.go | 60 --------------------------------------------- rtmp/session.go | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 60 deletions(-) create mode 100644 rtmp/session.go diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index c96e2199..f2a6c93d 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -150,66 +150,6 @@ var ( } ) -// session provides parameters required for an rtmp communication session. -type Session struct { - rtmp *C_RTMP - url string - timeout uint -} - -// NewSession returns a new session. -func NewSession(url string, connectTimeout uint) *Session { - return &Session{ - url: url, - timeout: connectTimeout, - } -} - -// Open establishes an rtmp connection with the url passed into the -// constructor -func (s *Session) Open() error { - if s.rtmp != nil { - return errors.New("rtmp: attempt to start already running session") - } - var err error - s.rtmp, err = startSession(s.rtmp, s.url, uint32(s.timeout)) - if s.rtmp == nil { - return err - } - return nil -} - -// Close terminates the rtmp connection -func (s *Session) Close() error { - if s.rtmp == nil { - return Err(3) - } - ret := endSession(s.rtmp) - s.rtmp = nil - if ret != 0 { - return Err(ret) - } - return nil -} - -// Write writes a frame (flv tag) to the rtmp connection -func (s *Session) Write(data []byte) (int, error) { - if s.rtmp == nil { - return 0, Err(3) - } - - if C_RTMP_IsConnected(s.rtmp) == 0 { - //if C.RTMP_IsConnected(s.rtmp) == 0 { - return 0, Err(1) - } - - if C_RTMP_Write(s.rtmp, data) == 0 { - //if C.RTMP_Write(s.rtmp, (*byte)(unsafe.Pointer(&data[0])), int32(len(data))) == 0 { - return 0, Err(2) - } - return len(data), nil -} - // int RTMP_IsConnected(RTMP *r); // rtmp.c +363 func C_RTMP_IsConnected(r *C_RTMP) int32 { diff --git a/rtmp/session.go b/rtmp/session.go new file mode 100644 index 00000000..18f88e76 --- /dev/null +++ b/rtmp/session.go @@ -0,0 +1,65 @@ +package rtmp + +import ( + "errors" +) + +// session provides parameters required for an rtmp communication session. +type Session struct { + rtmp *C_RTMP + url string + timeout uint +} + +// NewSession returns a new session. +func NewSession(url string, connectTimeout uint) *Session { + return &Session{ + url: url, + timeout: connectTimeout, + } +} + +// Open establishes an rtmp connection with the url passed into the +// constructor +func (s *Session) Open() error { + if s.rtmp != nil { + return errors.New("rtmp: attempt to start already running session") + } + var err error + s.rtmp, err = startSession(s.rtmp, s.url, uint32(s.timeout)) + if s.rtmp == nil { + return err + } + return nil +} + +// Close terminates the rtmp connection +func (s *Session) Close() error { + if s.rtmp == nil { + return Err(3) + } + ret := endSession(s.rtmp) + s.rtmp = nil + if ret != 0 { + return Err(ret) + } + return nil +} + +// Write writes a frame (flv tag) to the rtmp connection +func (s *Session) Write(data []byte) (int, error) { + if s.rtmp == nil { + return 0, Err(3) + } + + if C_RTMP_IsConnected(s.rtmp) == 0 { + //if C.RTMP_IsConnected(s.rtmp) == 0 { + return 0, Err(1) + } + + if C_RTMP_Write(s.rtmp, data) == 0 { + //if C.RTMP_Write(s.rtmp, (*byte)(unsafe.Pointer(&data[0])), int32(len(data))) == 0 { + return 0, Err(2) + } + return len(data), nil +} From dfa146f276782554247f850fb818086c28d3b49a Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 10:25:36 +0930 Subject: [PATCH 11/33] rtmp: file header comments to reflect file name and appropriate authors --- rtmp/amf.go | 33 +++++++++++++++++++++++++++++++++ rtmp/amf_headers.go | 31 +++++++++++++++++++++++++++++++ rtmp/parseurl.go | 31 +++++++++++++++++++++++++++++++ rtmp/rtmp.go | 3 +-- rtmp/rtmp_headers.go | 31 +++++++++++++++++++++++++++++++ rtmp/session.go | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 159 insertions(+), 2 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index 6f85f081..c71e2dc7 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -1,3 +1,36 @@ +/* +NAME + amf.go + +DESCRIPTION + See Readme.md + +AUTHORS + Saxon Nelson-Milton + Dan Kortschak + Jake Lane + +LICENSE + amf.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) + + 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 + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. + + Derived from librtmp under the GNU Lesser General Public License 2.1 + Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org + Copyright (C) 2008-2009 Andrej Stepanchuk + Copyright (C) 2009-2010 Howard Chu +*/ package rtmp /* diff --git a/rtmp/amf_headers.go b/rtmp/amf_headers.go index c79eff87..54d842ce 100644 --- a/rtmp/amf_headers.go +++ b/rtmp/amf_headers.go @@ -1,3 +1,34 @@ +/* +NAME + amf_headers.go + +DESCRIPTION + See Readme.md + +AUTHORS + Saxon Nelson-Milton + +LICENSE + amf_headers.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) + + 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 + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. + + Derived from librtmp under the GNU Lesser General Public License 2.1 + Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org + Copyright (C) 2008-2009 Andrej Stepanchuk + Copyright (C) 2009-2010 Howard Chu +*/ package rtmp const ( diff --git a/rtmp/parseurl.go b/rtmp/parseurl.go index d277efda..b2c0c2b0 100644 --- a/rtmp/parseurl.go +++ b/rtmp/parseurl.go @@ -1,3 +1,34 @@ +/* +NAME + parseurl.go + +DESCRIPTION + See Readme.md + +AUTHOR + Saxon Nelson-Milton + +LICENSE + parseurl.go is Copyright (C) 2017-2018 the Australian Ocean Lab (AusOcean) + + 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 + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. + + Derived from librtmp under the GNU Lesser General Public License 2.1 + Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org + Copyright (C) 2008-2009 Andrej Stepanchuk + Copyright (C) 2009-2010 Howard Chu +*/ package rtmp /* diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index f2a6c93d..ee99b572 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -5,10 +5,9 @@ NAME DESCRIPTION See Readme.md -AUTHOR +AUTHORS Saxon Nelson-Milton Dan Kortschak - Jake Lane LICENSE rtmp.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) diff --git a/rtmp/rtmp_headers.go b/rtmp/rtmp_headers.go index 35051099..3b25580a 100644 --- a/rtmp/rtmp_headers.go +++ b/rtmp/rtmp_headers.go @@ -1,3 +1,34 @@ +/* +NAME + rtmp_headers.go + +DESCRIPTION + See Readme.md + +AUTHORS + Saxon Nelson-Milton + +LICENSE + rtmp_headers.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) + + 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 + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. + + Derived from librtmp under the GNU Lesser General Public License 2.1 + Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org + Copyright (C) 2008-2009 Andrej Stepanchuk + Copyright (C) 2009-2010 Howard Chu +*/ package rtmp const ( diff --git a/rtmp/session.go b/rtmp/session.go index 18f88e76..d06037e4 100644 --- a/rtmp/session.go +++ b/rtmp/session.go @@ -1,3 +1,35 @@ +/* +NAME + session.go + +DESCRIPTION + See Readme.md + +AUTHORS + Saxon Nelson-Milton + Dan Kortschak + +LICENSE + session.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) + + 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 + Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. + + Derived from librtmp under the GNU Lesser General Public License 2.1 + Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org + Copyright (C) 2008-2009 Andrej Stepanchuk + Copyright (C) 2009-2010 Howard Chu +*/ package rtmp import ( From e22516d9cb0bfc50f68a86db727029c723936bfa Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 10:30:24 +0930 Subject: [PATCH 12/33] rtmp: fixed order of struct declarations in amf_headers.go to match that of amf.h under C librtmp? --- rtmp/amf_headers.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rtmp/amf_headers.go b/rtmp/amf_headers.go index 54d842ce..7ad0fc6b 100644 --- a/rtmp/amf_headers.go +++ b/rtmp/amf_headers.go @@ -53,6 +53,10 @@ const ( AMF_INVALID = 0xff ) +// typedef enum +// amf.h +40 +type C_AMFDataType int32 + // typedef struct C_AVal // amf.h +57 type C_AVal struct { @@ -60,10 +64,6 @@ type C_AVal struct { av_len int32 } -// typedef enum -// amf.h +40 -type C_AMFDataType int32 - // typedef struct AMF_Object // amf.h +67 type C_AMFObject struct { @@ -71,6 +71,14 @@ type C_AMFObject struct { o_props *C_AMFObjectProperty } +// typedef struct P_vu +// amf.h +73 +type P_vu struct { + p_number float64 + p_aval C_AVal + p_object C_AMFObject +} + // typedef struct AMFObjectProperty // amf.h +79 type C_AMFObjectProperty struct { @@ -79,11 +87,3 @@ type C_AMFObjectProperty struct { p_vu P_vu p_UTCoffset int16 } - -// typedef struct P_vu -// amf.h +73 -type P_vu struct { - p_number float64 - p_aval C_AVal - p_object C_AMFObject -} From 1441d1d968192806e25a16468653bdf8c1aee48d Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 10:34:10 +0930 Subject: [PATCH 13/33] rtmp: reordered struct order in rtmp_headers.go such that it matches up with order in rtmp.h under C librtmp --- rtmp/rtmp_headers.go | 142 +++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/rtmp/rtmp_headers.go b/rtmp/rtmp_headers.go index 3b25580a..cbd3230d 100644 --- a/rtmp/rtmp_headers.go +++ b/rtmp/rtmp_headers.go @@ -98,6 +98,15 @@ const ( RTMP_MAX_HEADER_SIZE = 18 ) +// typedef struct RTMPChunk +// rtmp.h +105 +type C_RTMPChunk struct { + c_headerSize int32 + c_chunkSize int32 + c_chunk *byte + c_header [RTMP_MAX_HEADER_SIZE]byte +} + // typedef struct RTMPPacket // rtmp.h +113 type C_RTMPPacket struct { @@ -113,6 +122,68 @@ type C_RTMPPacket struct { m_body *byte } +// typedef struct RTMPSockBuf +// rtmp.h +127 +type C_RTMPSockBuf struct { + sb_socket int32 + sb_size int32 + sb_start *byte + sb_buf [RTMP_BUFFER_CACHE_SIZE]byte // port const + sb_timedout int32 + sb_ssl uintptr +} + +// typedef struct RTMP_LNK +// rtmp.h +144 +type C_RTMP_LNK struct { + hostname C_AVal + sockshost C_AVal + playpath0 C_AVal + playpath C_AVal + tcUrl C_AVal + swfUrl C_AVal + pageUrl C_AVal + app C_AVal + auth C_AVal + flashVer C_AVal + subscribepath C_AVal + usherToken C_AVal + token C_AVal + pubUser C_AVal + pubPasswd C_AVal + extras C_AMFObject + edepth int32 + seekTime int32 + stopTime int32 + lFlags int32 + swfAge int32 + protocol int32 + timeout int32 + pFlags int32 + socksport uint16 + port uint16 +} + +// typedef struct RTMP_READ +// rtmp.h +200 +type C_RTMP_READ struct { + buf *byte + bufpos *byte + buflen uint + timestamp uint32 + dataType uint8 + flags uint8 + status int8 + initialFrameType uint8 + nResumeTS uint32 + metaHeader *byte + initialFrame *byte + nMetaHeaderSize uint32 + nInitialFrameSize uint32 + nIgnoredFrameCounter uint32 + nIgnoredFlvFrameCounter uint32 +} + // typedef struct RTMPMethod // rtmp.h +231 type C_RTMP_METHOD struct { @@ -162,74 +233,3 @@ type C_RTMP struct { m_sb C_RTMPSockBuf Link C_RTMP_LNK } - -// typedef struct RTMP_READ -// rtmp.h +200 -type C_RTMP_READ struct { - buf *byte - bufpos *byte - buflen uint - timestamp uint32 - dataType uint8 - flags uint8 - status int8 - initialFrameType uint8 - nResumeTS uint32 - metaHeader *byte - initialFrame *byte - nMetaHeaderSize uint32 - nInitialFrameSize uint32 - nIgnoredFrameCounter uint32 - nIgnoredFlvFrameCounter uint32 -} - -// typedef struct RTMP_READ -// rtmp.h +200 -type C_RTMPSockBuf struct { - sb_socket int32 - sb_size int32 - sb_start *byte - sb_buf [RTMP_BUFFER_CACHE_SIZE]byte // port const - sb_timedout int32 - sb_ssl uintptr -} - -// typedef struct RTMPChunk -// rtmp.h +105 -type C_RTMPChunk struct { - c_headerSize int32 - c_chunkSize int32 - c_chunk *byte - c_header [RTMP_MAX_HEADER_SIZE]byte -} - -// typedef struct RTMP_LNK -// rtmp.h +144 -type C_RTMP_LNK struct { - hostname C_AVal - sockshost C_AVal - playpath0 C_AVal - playpath C_AVal - tcUrl C_AVal - swfUrl C_AVal - pageUrl C_AVal - app C_AVal - auth C_AVal - flashVer C_AVal - subscribepath C_AVal - usherToken C_AVal - token C_AVal - pubUser C_AVal - pubPasswd C_AVal - extras C_AMFObject - edepth int32 - seekTime int32 - stopTime int32 - lFlags int32 - swfAge int32 - protocol int32 - timeout int32 - pFlags int32 - socksport uint16 - port uint16 -} From 43701a252f21ec48cba6694f4059232d0dac3fb4 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 10:43:34 +0930 Subject: [PATCH 14/33] rtmp: start reordering funcs in rtmp.go, still need to do a few more --- rtmp/rtmp.go | 504 +++++++++++++++++++++++++-------------------------- 1 file changed, 252 insertions(+), 252 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index ee99b572..95ca0b8f 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -149,13 +149,9 @@ var ( } ) -// int RTMP_IsConnected(RTMP *r); -// rtmp.c +363 -func C_RTMP_IsConnected(r *C_RTMP) int32 { - if r.m_sb.sb_socket != -1 { - return 1 - } - return 0 +// TODO: find location in c file +func SET_RCVTIMEO(tv *int32, s int32) { + *tv = s * 1000 } func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { @@ -194,6 +190,12 @@ func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { return rtmp, nil } +// uint32_t RTMP_GetTime(); +// rtmp.c +156 +func C_RTMP_GetTime() int32 { + return int32(time.Now().UnixNano() / 1000000) +} + // RTMP* RTMP_IsConnected(); // rtmp.c +317 func C_RTMP_Alloc() *C_RTMP { @@ -218,6 +220,59 @@ func C_RTMP_Init(r *C_RTMP) { r.Link.swfAge = 30 } +// void RTMP_EnableWrite(RTMP *r); +// rtmp.c +351 +func C_RTMP_EnableWrite(r *C_RTMP) { + r.Link.protocol |= RTMP_FEATURE_WRITE +} + +// int RTMP_IsConnected(RTMP *r); +// rtmp.c +363 +func C_RTMP_IsConnected(r *C_RTMP) int32 { + if r.m_sb.sb_socket != -1 { + return 1 + } + return 0 +} + +// void RTMP_SetBufferMS(RTMP *r, int size); +// rtmp.c +381 +func C_RTMP_SetBufferMS(r *C_RTMP, size int32) { + r.m_nBufferMS = int32(size) +} + +// void SocksSetup(RTMP *r, C_AVal* sockshost); +// rtmp.c +410 +func C_SocksSetup(r *C_RTMP, sockshost *C_AVal) { + if sockshost.av_len != 0 { + socksport := strchr((*byte)(unsafe.Pointer(sockshost.av_val)), ':') + hostname := strdup((*byte)(unsafe.Pointer(sockshost.av_val))) + + if unsafe.Pointer(socksport) != nil { + *indxBytePtr(unsafe.Pointer(hostname), + int(uintptr(decBytePtr(unsafe.Pointer(socksport), + int(uintptr(unsafe.Pointer(sockshost.av_val))))))) = '\000' + r.Link.sockshost.av_val = (*byte)(unsafe.Pointer(hostname)) + r.Link.sockshost.av_len = int32(strlen(hostname)) + + value, err := strconv.Atoi(string(ptrToSlice(unsafe.Pointer(uintptr( + unsafe.Pointer(socksport))+uintptr(1)), int(strlen((*byte)(unsafe.Pointer( + uintptr(unsafe.Pointer(socksport))+uintptr(1)))))+1))) + if err != nil { + log.Println("C_SocksSetup: bad string conversion!") + } + if uintptr(unsafe.Pointer(socksport)) == 0 { + value = 1080 + } + r.Link.socksport = uint16(value) + } + } else { + r.Link.sockshost.av_val = nil + r.Link.sockshost.av_len = 0 + r.Link.socksport = 0 + } +} + // int RTMP_SetupURL(RTMP *r, char* url); // rtmp.c +757 // NOTE: code dealing with rtmp over http has been disregarded @@ -292,38 +347,6 @@ func C_RTMP_SetupURL(r *C_RTMP, u string) int32 { return 1 } -// void SocksSetup(RTMP *r, C_AVal* sockshost); -// rtmp.c +410 -func C_SocksSetup(r *C_RTMP, sockshost *C_AVal) { - if sockshost.av_len != 0 { - socksport := strchr((*byte)(unsafe.Pointer(sockshost.av_val)), ':') - hostname := strdup((*byte)(unsafe.Pointer(sockshost.av_val))) - - if unsafe.Pointer(socksport) != nil { - *indxBytePtr(unsafe.Pointer(hostname), - int(uintptr(decBytePtr(unsafe.Pointer(socksport), - int(uintptr(unsafe.Pointer(sockshost.av_val))))))) = '\000' - r.Link.sockshost.av_val = (*byte)(unsafe.Pointer(hostname)) - r.Link.sockshost.av_len = int32(strlen(hostname)) - - value, err := strconv.Atoi(string(ptrToSlice(unsafe.Pointer(uintptr( - unsafe.Pointer(socksport))+uintptr(1)), int(strlen((*byte)(unsafe.Pointer( - uintptr(unsafe.Pointer(socksport))+uintptr(1)))))+1))) - if err != nil { - log.Println("C_SocksSetup: bad string conversion!") - } - if uintptr(unsafe.Pointer(socksport)) == 0 { - value = 1080 - } - r.Link.socksport = uint16(value) - } - } else { - r.Link.sockshost.av_val = nil - r.Link.sockshost.av_len = 0 - r.Link.socksport = 0 - } -} - /* func rtmpClose(r *C_RTMP) { closeInternal(r, 0) @@ -408,55 +431,6 @@ func closeInternal(r *C_RTMP, reconnect int32) { } */ -// void RTMP_EnableWrite(RTMP *r); -// rtmp.c +351 -func C_RTMP_EnableWrite(r *C_RTMP) { - r.Link.protocol |= RTMP_FEATURE_WRITE -} - -// void RTMP_SetBufferMS(RTMP *r, int size); -// rtmp.c +381 -func C_RTMP_SetBufferMS(r *C_RTMP, size int32) { - r.m_nBufferMS = int32(size) -} - -// int RTMP_Connect(RTMP *r, RTMPPacket* cp); -// rtmp.c +1032 -func C_RTMP_Connect(r *C_RTMP, cp *C_RTMPPacket) int { - // TODO: port this - var service C.sockaddr_in - - if r.Link.hostname.av_len == 0 { - return 0 - } - memset((*byte)(unsafe.Pointer(&service)), 0, int(unsafe.Sizeof(service))) - - // TODO: port this - service.sin_family = C.AF_INET - - if r.Link.socksport != 0 { - // TODO: port this - if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.sockshost)), C.int(r.Link.socksport)) == 0 { - return 0 - } - } else { - // connect directly - if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.hostname)), - C.int(r.Link.port)) == 0 { - return 0 - } - } - //if C.RTMP_Connect0(r, (*C.sockaddr)(unsafe.Pointer(&service))) == 0 { - if C_RTMP_Connect0(r, (*C.sockaddr)(unsafe.Pointer(&service))) == 0 { - return 0 - } - - r.m_bSendCounter = 1 - - return int(C_RTMP_Connect1(r, cp)) - //return int(C.RTMP_Connect1(r, cp)) -} - // int RTMP_Connect0(RTMP *r, struct sockaddr* service); // rtmp.c +906 func C_RTMP_Connect0(r *C_RTMP, service *C.sockaddr) int { @@ -505,6 +479,65 @@ func C_RTMP_Connect0(r *C_RTMP, service *C.sockaddr) int { return 1 } +// int RTMP_Connect1(RTMP* r, RTMPPacket* cp); +// rtmp.c +978 +func C_RTMP_Connect1(r *C_RTMP, cp *C_RTMPPacket) int { + if debugMode { + log.Println("... connected, handshaking...") + } + //if C.HandShake(r, 1) == 0 { + if C_HandShake(r, 1) == 0 { + log.Println("C_RTMP_Connect1: handshake failed!") + return 0 + } + if debugMode { + log.Println("... handshaked...") + } + //if C.SendConnectPacket(r, cp) == 0 { + if C_SendConnectPacket(r, cp) == 0 { + log.Println("RTMP connect failed!") + return 0 + } + return 1 +} + +// int RTMP_Connect(RTMP *r, RTMPPacket* cp); +// rtmp.c +1032 +func C_RTMP_Connect(r *C_RTMP, cp *C_RTMPPacket) int { + // TODO: port this + var service C.sockaddr_in + + if r.Link.hostname.av_len == 0 { + return 0 + } + memset((*byte)(unsafe.Pointer(&service)), 0, int(unsafe.Sizeof(service))) + + // TODO: port this + service.sin_family = C.AF_INET + + if r.Link.socksport != 0 { + // TODO: port this + if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.sockshost)), C.int(r.Link.socksport)) == 0 { + return 0 + } + } else { + // connect directly + if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.hostname)), + C.int(r.Link.port)) == 0 { + return 0 + } + } + //if C.RTMP_Connect0(r, (*C.sockaddr)(unsafe.Pointer(&service))) == 0 { + if C_RTMP_Connect0(r, (*C.sockaddr)(unsafe.Pointer(&service))) == 0 { + return 0 + } + + r.m_bSendCounter = 1 + + return int(C_RTMP_Connect1(r, cp)) + //return int(C.RTMP_Connect1(r, cp)) +} + // int SocksNegotiate(RTMP* r); // rtmp.c +1062 func C_SocksNegotiate(r *C_RTMP) int { @@ -542,115 +575,6 @@ func C_SocksNegotiate(r *C_RTMP) int { } } -// TODO: find location in c file -func SET_RCVTIMEO(tv *int32, s int32) { - *tv = s * 1000 -} - -// int RTMP_Connect1(RTMP* r, RTMPPacket* cp); -// rtmp.c +978 -func C_RTMP_Connect1(r *C_RTMP, cp *C_RTMPPacket) int { - if debugMode { - log.Println("... connected, handshaking...") - } - //if C.HandShake(r, 1) == 0 { - if C_HandShake(r, 1) == 0 { - log.Println("C_RTMP_Connect1: handshake failed!") - return 0 - } - if debugMode { - log.Println("... handshaked...") - } - //if C.SendConnectPacket(r, cp) == 0 { - if C_SendConnectPacket(r, cp) == 0 { - log.Println("RTMP connect failed!") - return 0 - } - return 1 -} - -// int HandShake(RTMP* r, int FP9HandShake); -// rtmp.c +3744 -func C_HandShake(r *C_RTMP, FP9HandShake int32) int { - var bMatch int - //uptime := uint32(0) - //suptime := uint32(0) - //typ := byte(0) - var uptime, suptime uint32 - var typ byte - //clientbuf := make([]byte, RTMP_SIG_SIZE+1) - var clientbuf [RTMP_SIG_SIZE + 1]byte - clientsig := (*byte)(incBytePtr(unsafe.Pointer(&clientbuf[0]), 1)) - //serversig := make([]byte, RTMP_SIG_SIZE) - var serversig [RTMP_SIG_SIZE]byte - - clientbuf[0] = 0x03 // not encrypted - - // TODO: port rtmp_getTime - //uptime = inet.Htonl(uint32(C.RTMP_GetTime())) - uptime = inet.Htonl(uint32(C_RTMP_GetTime())) - memmove(unsafe.Pointer(clientsig), unsafe.Pointer(&uptime), 4) - - memset(indxBytePtr(unsafe.Pointer(clientsig), 4), 0, 4) - - for i := 8; i < RTMP_SIG_SIZE; i++ { - *indxBytePtr(unsafe.Pointer(clientsig), i) = byte(rand.Intn(256)) - } - - if C_WriteN(r, unsafe.Pointer(&clientbuf[0]), RTMP_SIG_SIZE+1) == 0 { - return 0 - } - - //if C.ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { - if C_ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { - return 0 - } - - if debugMode { - log.Println("C_HandShake: Type answer: %v", typ) - } - if typ != clientbuf[0] { - log.Println("C_HandShake: type mismatch: client sent %v, server sent: %v", - clientbuf[0], typ) - } - if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - return 0 - } - - // decode server response - memmove(unsafe.Pointer(&suptime), unsafe.Pointer(&serversig[0]), 4) - suptime = inet.Ntohl(suptime) - - // 2nd part of handshake - if C_WriteN(r, unsafe.Pointer(&serversig[0]), RTMP_SIG_SIZE) == 0 { - return 0 - } - - if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - return 0 - } - - // TODO: find golang memcmp - bMatch = 0 - if memcmp(unsafe.Pointer(&serversig[0]), unsafe.Pointer(clientsig), - RTMP_SIG_SIZE) == 0 { - bMatch = 1 - } - - if bMatch == 0 { - log.Println("Client signature does not match!") - } - return 1 -} - -// uint32_t RTMP_GetTime(); -// rtmp.c +156 -func C_RTMP_GetTime() int32 { - return int32(time.Now().UnixNano() / 1000000) -} - // int ReadN(RTMP* r, char* buffer, int n); // rtmp.c +1390 func C_ReadN(r *C_RTMP, buffer *byte, n int) int { @@ -712,61 +636,6 @@ func C_ReadN(r *C_RTMP, buffer *byte, n int) int { return nOriginalSize - n } -// int RTMPSockBuf_Fill(RTMPSockBuf* sb); -// rtmp.c +4253 -func C_RTMPSockBuf_Fill(sb *C_RTMPSockBuf) int { - var nBytes int - - if sb.sb_size == 0 { - sb.sb_start = &sb.sb_buf[0] - } - - for { - nBytes = int(unsafe.Sizeof(sb.sb_buf)) - 1 - int(sb.sb_size) - - int(uintptr(unsafe.Pointer(sb.sb_start))-uintptr(unsafe.Pointer( - &sb.sb_buf[0]))) - - // TODO: figure out what to do with recv - nBytes = int(C.recv(C.int(sb.sb_socket), unsafe.Pointer(uintptr(unsafe.Pointer( - sb.sb_start))+uintptr(int(sb.sb_size))), C.size_t(nBytes), 0)) - - if nBytes != -1 { - sb.sb_size += int32(nBytes) - } else { - log.Println("C_RTMPSockBuf_Fill: recv error!") - } - break - } - return nBytes -} - -// int SendBytesReceived(RTMP* r); -// rtmp.c +2080 -func C_SendBytesReceived(r *C_RTMP) int { - var packet C_RTMPPacket - var pbuf [256]byte - pend := (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), 256)) - - packet.m_nChannel = 0x02 /* control channel (invoke) */ - packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM - packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT - packet.m_nTimeStamp = 0 - packet.m_nInfoField2 = 0 - packet.m_hasAbsTimestamp = 0 - packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), - RTMP_MAX_HEADER_SIZE)) - - packet.m_nBodySize = 4 - - C_AMF_EncodeInt32((*byte)(unsafe.Pointer(packet.m_body)), pend, int32(r.m_nBytesIn)) - // C.AMF_EncodeInt32(packet.m_body, (*byte)(unsafe.Pointer(pend)), r.m_nBytesIn) - - r.m_nBytesInSent = r.m_nBytesIn - - //return int(C.RTMP_SendPacket(r, &packet, 0)) - return C_RTMP_SendPacket(r, &packet, 0) -} - // int SendConnectPacket(RTMP* r, RTMPPacket* cp); // rtmp.c +1579 func C_SendConnectPacket(r *C_RTMP, cp *C_RTMPPacket) int { @@ -947,6 +816,137 @@ func C_SendConnectPacket(r *C_RTMP, cp *C_RTMPPacket) int { return C_RTMP_SendPacket(r, &packet, 1) } +// int SendBytesReceived(RTMP* r); +// rtmp.c +2080 +func C_SendBytesReceived(r *C_RTMP) int { + var packet C_RTMPPacket + var pbuf [256]byte + pend := (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), 256)) + + packet.m_nChannel = 0x02 /* control channel (invoke) */ + packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM + packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = 0 + packet.m_hasAbsTimestamp = 0 + packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), + RTMP_MAX_HEADER_SIZE)) + + packet.m_nBodySize = 4 + + C_AMF_EncodeInt32((*byte)(unsafe.Pointer(packet.m_body)), pend, int32(r.m_nBytesIn)) + // C.AMF_EncodeInt32(packet.m_body, (*byte)(unsafe.Pointer(pend)), r.m_nBytesIn) + + r.m_nBytesInSent = r.m_nBytesIn + + //return int(C.RTMP_SendPacket(r, &packet, 0)) + return C_RTMP_SendPacket(r, &packet, 0) +} + +// int HandShake(RTMP* r, int FP9HandShake); +// rtmp.c +3744 +func C_HandShake(r *C_RTMP, FP9HandShake int32) int { + var bMatch int + //uptime := uint32(0) + //suptime := uint32(0) + //typ := byte(0) + var uptime, suptime uint32 + var typ byte + //clientbuf := make([]byte, RTMP_SIG_SIZE+1) + var clientbuf [RTMP_SIG_SIZE + 1]byte + clientsig := (*byte)(incBytePtr(unsafe.Pointer(&clientbuf[0]), 1)) + //serversig := make([]byte, RTMP_SIG_SIZE) + var serversig [RTMP_SIG_SIZE]byte + + clientbuf[0] = 0x03 // not encrypted + + // TODO: port rtmp_getTime + //uptime = inet.Htonl(uint32(C.RTMP_GetTime())) + uptime = inet.Htonl(uint32(C_RTMP_GetTime())) + memmove(unsafe.Pointer(clientsig), unsafe.Pointer(&uptime), 4) + + memset(indxBytePtr(unsafe.Pointer(clientsig), 4), 0, 4) + + for i := 8; i < RTMP_SIG_SIZE; i++ { + *indxBytePtr(unsafe.Pointer(clientsig), i) = byte(rand.Intn(256)) + } + + if C_WriteN(r, unsafe.Pointer(&clientbuf[0]), RTMP_SIG_SIZE+1) == 0 { + return 0 + } + + //if C.ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { + if C_ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { + return 0 + } + + if debugMode { + log.Println("C_HandShake: Type answer: %v", typ) + } + if typ != clientbuf[0] { + log.Println("C_HandShake: type mismatch: client sent %v, server sent: %v", + clientbuf[0], typ) + } + if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + return 0 + } + + // decode server response + memmove(unsafe.Pointer(&suptime), unsafe.Pointer(&serversig[0]), 4) + suptime = inet.Ntohl(suptime) + + // 2nd part of handshake + if C_WriteN(r, unsafe.Pointer(&serversig[0]), RTMP_SIG_SIZE) == 0 { + return 0 + } + + if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + return 0 + } + + // TODO: find golang memcmp + bMatch = 0 + if memcmp(unsafe.Pointer(&serversig[0]), unsafe.Pointer(clientsig), + RTMP_SIG_SIZE) == 0 { + bMatch = 1 + } + + if bMatch == 0 { + log.Println("Client signature does not match!") + } + return 1 +} + +// int RTMPSockBuf_Fill(RTMPSockBuf* sb); +// rtmp.c +4253 +func C_RTMPSockBuf_Fill(sb *C_RTMPSockBuf) int { + var nBytes int + + if sb.sb_size == 0 { + sb.sb_start = &sb.sb_buf[0] + } + + for { + nBytes = int(unsafe.Sizeof(sb.sb_buf)) - 1 - int(sb.sb_size) - + int(uintptr(unsafe.Pointer(sb.sb_start))-uintptr(unsafe.Pointer( + &sb.sb_buf[0]))) + + // TODO: figure out what to do with recv + nBytes = int(C.recv(C.int(sb.sb_socket), unsafe.Pointer(uintptr(unsafe.Pointer( + sb.sb_start))+uintptr(int(sb.sb_size))), C.size_t(nBytes), 0)) + + if nBytes != -1 { + sb.sb_size += int32(nBytes) + } else { + log.Println("C_RTMPSockBuf_Fill: recv error!") + } + break + } + return nBytes +} + // int RTMP_ConnectStream(RTMP* r, int seekTime); // rtmp.c +1099 func C_RTMP_ConnectStream(r *C_RTMP, seekTime int32) int { From d23ab3b1a0d07dc4739689def88f54d00df666fb Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 18:50:04 +0930 Subject: [PATCH 15/33] rtmp: Finished reordering funcs in rtmp.go to better reflect order in rtmp.c in C librtmp --- rtmp/rtmp.go | 1375 +++++++++++++++++++++++++------------------------- 1 file changed, 676 insertions(+), 699 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 95ca0b8f..aaac0d87 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -190,12 +190,72 @@ func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { return rtmp, nil } +func endSession(rtmp *C_RTMP) uint32 { + if rtmp == nil { + return 3 + } + + //C.RTMP_Close(rtmp) + //C.RTMP_Free(rtmp) + return 0 +} + +// #define AVMATCH(a1,a2) +// amf.h +63 +func C_AVMATCH(a1, a2 *C_AVal) int32 { + if a1.av_len == a2.av_len && memcmp(unsafe.Pointer(a1.av_val), + unsafe.Pointer(a2.av_val), int(a1.av_len)) == 0 { + return 1 + } else { + return 0 + } +} + +// #define RTMPPacket_IsReady(a) +// rtmp.h +142 +func C_RTMPPacket_IsReady(p *C_RTMPPacket) int { + if p.m_nBytesRead == p.m_nBodySize { + return 1 + } + return 0 +} + // uint32_t RTMP_GetTime(); // rtmp.c +156 func C_RTMP_GetTime() int32 { return int32(time.Now().UnixNano() / 1000000) } +// int RTMPPacket_Alloc(RTMPPacket* p, uint32_t nSize); +// rtmp.c +189 +func C_RTMPPacket_Alloc(p *C_RTMPPacket, nSize uint32) int { + var ptr *byte + // TODO: port C.SIZE_MAX + // also work out how to deal with the overfloat + /* + if int64(nSize) > (C.SIZE_MAX - RTMP_MAX_HEADER_SIZE) { + return 0 + } + */ + ptr = (*byte)(calloc(1, uintptr(nSize+RTMP_MAX_HEADER_SIZE))) + + if ptr == nil { + return 0 + } + p.m_body = (*byte)(incBytePtr(unsafe.Pointer(ptr), RTMP_MAX_HEADER_SIZE)) + p.m_nBytesRead = 0 + return 1 +} + +// void RTMPPacket_Free(RTMPPacket* p); +// rtmp.c +203 +func C_RTMPPacket_Free(p *C_RTMPPacket) { + if p.m_body != nil { + //C.free(decBytePtr(unsafe.Pointer(p.m_body), RTMP_MAX_HEADER_SIZE)) + p.m_body = nil + } +} + // RTMP* RTMP_IsConnected(); // rtmp.c +317 func C_RTMP_Alloc() *C_RTMP { @@ -575,6 +635,181 @@ func C_SocksNegotiate(r *C_RTMP) int { } } +// int RTMP_ConnectStream(RTMP* r, int seekTime); +// rtmp.c +1099 +func C_RTMP_ConnectStream(r *C_RTMP, seekTime int32) int { + var packet C_RTMPPacket + memset((*byte)(unsafe.Pointer(&packet)), 0, int(unsafe.Sizeof(packet))) + + if seekTime > 0 { + r.Link.seekTime = int32(seekTime) + } + + r.m_mediaChannel = 0 + + // TODO: read packet + for r.m_bPlaying == 0 && C_RTMP_IsConnected(r) != 0 && + //C.RTMP_ReadPacket(r, &packet) != 0 { + C_RTMP_ReadPacket(r, &packet) != 0 { + + // TODO: port is ready + if C_RTMPPacket_IsReady(&packet) != 0 { + if packet.m_nBodySize == 0 { + continue + } + + if packet.m_packetType == RTMP_PACKET_TYPE_AUDIO || + packet.m_packetType == RTMP_PACKET_TYPE_VIDEO || + packet.m_packetType == RTMP_PACKET_TYPE_INFO { + log.Println("C_RTMP_ConnectStream: got packet before play()! Ignoring.") + C_RTMPPacket_Free(&packet) + continue + } + + //C.RTMP_ClientPacket(r, &packet) + C_RTMP_ClientPacket(r, &packet) + C_RTMPPacket_Free(&packet) + } + } + return int(r.m_bPlaying) +} + +// int RTMP_ClientPacket() +// rtmp.c +1226 +// NOTE cases have been commented out that are not currently used by AusOcean +func C_RTMP_ClientPacket(r *C_RTMP, packet *C_RTMPPacket) int32 { + var bHasMediaPacket int32 = 0 + switch packet.m_packetType { + + case RTMP_PACKET_TYPE_CHUNK_SIZE: + log.Println("RTMP_PACKET_TYPE_CHUNK_SIZE") + // TODO: port this + //C.HandleChangeChunkSize(r, packet) + C_HandleChangeChunkSize(r, packet) + /* + case RTMP_PACKET_TYPE_BYTES_READ_REPORT: + log.Println("RTMP_PACKET_TYPE_BYTES_READ_REPORT") + // TODO: usue new logger here + //RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__); + + case RTMP_PACKET_TYPE_CONTROL: + log.Println("RTMP_PACKET_TYPE_CONTROL") + // TODO: port this + C.HandleCtrl(r, packet) + */ + case RTMP_PACKET_TYPE_SERVER_BW: + log.Println("RTMP_PACKET_TYPE_SERVER_BW") + // TODO: port this + //C.HandleServerBW(r, packet) + C_HandlServerBW(r, packet) + + case RTMP_PACKET_TYPE_CLIENT_BW: + log.Println("RTMP_PACKET_TYPE_CLIENT_BW") + // TODO: port this + //C.HandleClientBW(r, packet) + C_HandleClientBW(r, packet) + /* + case RTMP_PACKET_TYPE_AUDIO: + log.Println("RTMP_PACKET_TYPE_AUDIO") + // TODO port this + //C.HandleAudio(r, packet) NOTE this does nothing + bHasMediaPacket = 1 + if r.m_mediaChannel == 0 { + r.m_mediaChannel = packet.m_nChannel + } + + if r.m_pausing == 0 { + r.m_mediaStamp = packet.m_nTimeStamp + } + + case RTMP_PACKET_TYPE_VIDEO: + log.Println("RTMP_PACKET_TYPE_VIDEO:") + // TODO port this + // C.HandleVideo(r, packet) NOTE this does nothing + bHasMediaPacket = 1 + if r.m_mediaChannel == 0 { + r.m_mediaChannel = packet.m_nChannel + } + if r.m_pausing == 0 { + r.m_mediaStamp = packet.m_nTimeStamp + } + + case RTMP_PACKET_TYPE_FLEX_MESSAGE: + log.Println("RTMP_PACKET_TYPE_FLEX_MESSAGE:") + { + // TODO use new logger here + // RTMP_Log(RTMP_LOGDEBUG,"%s, flex message, size %u bytes, not fully supported", __FUNCTION__, packet.m_nBodySize); + + if C.HandleInvoke(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), 1)), + C.uint(packet.m_nBodySize-1)) == 1 { + bHasMediaPacket = 2 + } + } + case RTMP_PACKET_TYPE_INFO: + log.Println(" RTMP_PACKET_TYPE_INFO:") + // TODO use new logger here + //RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,packet.m_nBodySize); + if C.HandleMetadata(r, packet.m_body, C.uint(packet.m_nBodySize)) != 0 { + bHasMediaPacket = 1 + } + */ + + case RTMP_PACKET_TYPE_INVOKE: + log.Println("RTMP_PACKET_TYPE_INVOKE:") + // TODO use new logger here + //RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,packet.m_nBodySize); + + //if C.HandleInvoke(r, packet.m_body, C.uint(packet.m_nBodySize)) == 1 { + if C_HandleInvoke(r, (*byte)(unsafe.Pointer(packet.m_body)), uint32(packet.m_nBodySize)) == 1 { + log.Println("HasMediaPacket") + bHasMediaPacket = 2 + } + /* + case RTMP_PACKET_TYPE_FLASH_VIDEO: + log.Println("RTMP_PACKET_TYPE_FLASH_VIDEO:") + { + var pos uint32 = 0 + var nTimeStamp uint32 = uint32(packet.m_nTimeStamp) + + for pos+11 < uint32(packet.m_nBodySize) { + var dataSize uint32 = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( + packet.m_body), int(pos+1)))) + + if pos+11+dataSize+4 > uint32(packet.m_nBodySize) { + // TODO use new logger here + // RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!"); + break + } + + switch { + case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 0x12: + C.HandleMetadata(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), + int(pos+11))), C.uint(dataSize)) + case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 8 || + *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 9: + nTimeStamp = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( + packet.m_body), int(pos+4)))) + nTimeStamp |= uint32(*indxBytePtr(unsafe.Pointer(packet.m_body), + int(pos+7)) << 24) + } + pos += (11 + dataSize + 4) + } + if r.m_pausing == 0 { + r.m_mediaStamp = uint32(nTimeStamp) + } + + bHasMediaPacket = 1 + + } + default: + log.Println("DEFAULT") + // TODO use new logger here + // RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,packet.m_packetType); + */ + } + return bHasMediaPacket +} + // int ReadN(RTMP* r, char* buffer, int n); // rtmp.c +1390 func C_ReadN(r *C_RTMP, buffer *byte, n int) int { @@ -636,6 +871,40 @@ func C_ReadN(r *C_RTMP, buffer *byte, n int) int { return nOriginalSize - n } +// int WriteN(RTMP* r, const char* buffer, int n); +// rtmp.c +1502 +func C_WriteN(r *C_RTMP, buffer unsafe.Pointer, n int) int { + ptr := buffer + for n > 0 { + var nBytes int + + nBytes = int(C_RTMPSockBuf_Send(&r.m_sb, (*byte)(ptr), int32(n))) + + if nBytes < 0 { + if debugMode { + log.Println("C_WriteN, RTMP send error") + } + + // TODO: port this + //C.RTMP_Close(r) + n = 1 + break + } + + if nBytes == 0 { + break + } + + n -= nBytes + ptr = incBytePtr(ptr, nBytes) + } + + if n == 0 { + return 1 + } + return 0 +} + // int SendConnectPacket(RTMP* r, RTMPPacket* cp); // rtmp.c +1579 func C_SendConnectPacket(r *C_RTMP, cp *C_RTMPPacket) int { @@ -816,6 +1085,146 @@ func C_SendConnectPacket(r *C_RTMP, cp *C_RTMPPacket) int { return C_RTMP_SendPacket(r, &packet, 1) } +// int RTMP_SendCreateStream(RTMP* r); +// rtmp.c +1725 +func C_RTMP_SendCreateStream(r *C_RTMP) int32 { + var packet C_RTMPPacket + var pbuf [256]byte + var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + + unsafe.Sizeof(pbuf))) + var enc *byte + + packet.m_nChannel = 0x03 /* control channel (invoke) */ + packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM + packet.m_packetType = RTMP_PACKET_TYPE_INVOKE + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = 0 + packet.m_hasAbsTimestamp = 0 + packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), + int(RTMP_MAX_HEADER_SIZE))) + + enc = (*byte)(unsafe.Pointer(packet.m_body)) + enc = C_AMF_EncodeString(enc, pend, &av_createStream) + r.m_numInvokes++ + enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) + *enc = AMF_NULL + enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) + + packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( + unsafe.Pointer(packet.m_body))) + + return int32(C_RTMP_SendPacket(r, &packet, 1)) +} + +// int SendReleaseStream(RTMP* r); +// rtmp.c +1816 +func C_SendReleaseStream(r *C_RTMP) int32 { + var packet C_RTMPPacket + var pbuf [1024]byte + var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + + unsafe.Sizeof(pbuf))) + var enc *byte + + packet.m_nChannel = 0x03 /* control channel (invoke) */ + packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM + packet.m_packetType = RTMP_PACKET_TYPE_INVOKE + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = 0 + packet.m_hasAbsTimestamp = 0 + packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), + int(RTMP_MAX_HEADER_SIZE))) + + enc = (*byte)(unsafe.Pointer(packet.m_body)) + enc = C_AMF_EncodeString(enc, pend, &av_releaseStream) + r.m_numInvokes++ + enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) + *enc = AMF_NULL + enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) + enc = C_AMF_EncodeString(enc, pend, &r.Link.playpath) + if enc == nil { + return 0 + } + packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( + unsafe.Pointer(packet.m_body))) + + return int32(C_RTMP_SendPacket(r, &packet, 0)) +} + +// int SendFCPublish(RTMP* r); +// rtmp.c +1846 +func C_SendFCPublish(r *C_RTMP) int32 { + var packet C_RTMPPacket + var pbuf [1024]byte + var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + + unsafe.Sizeof(pbuf))) + var enc *byte + + packet.m_nChannel = 0x03 /* control channel (invoke) */ + packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM + packet.m_packetType = RTMP_PACKET_TYPE_INVOKE + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = 0 + packet.m_hasAbsTimestamp = 0 + packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), + int(RTMP_MAX_HEADER_SIZE))) + + enc = (*byte)(unsafe.Pointer(packet.m_body)) + enc = C_AMF_EncodeString(enc, pend, &av_FCPublish) + r.m_numInvokes++ + enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) + *enc = AMF_NULL + enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) + enc = C_AMF_EncodeString(enc, pend, &r.Link.playpath) + if enc == nil { + return 0 + } + packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( + unsafe.Pointer(packet.m_body))) + + return int32(C_RTMP_SendPacket(r, &packet, 0)) +} + +// int SendPublish(RTMP* r); +// rtmp.c +1908 +func C_SendPublish(r *C_RTMP) int32 { + var packet C_RTMPPacket + var pbuf [1024]byte + var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + + unsafe.Sizeof(pbuf))) + var enc *byte + + packet.m_nChannel = 0x04 /* source channel (invoke) */ + packet.m_headerType = RTMP_PACKET_SIZE_LARGE + packet.m_packetType = RTMP_PACKET_TYPE_INVOKE + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = int32(r.m_stream_id) + packet.m_hasAbsTimestamp = 0 + packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), + int(RTMP_MAX_HEADER_SIZE))) + + enc = (*byte)(unsafe.Pointer(packet.m_body)) + enc = C_AMF_EncodeString(enc, pend, &av_publish) + r.m_numInvokes++ + enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) + *enc = AMF_NULL + enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) + enc = C_AMF_EncodeString(enc, pend, &r.Link.playpath) + + if enc == nil { + return 0 + } + + enc = C_AMF_EncodeString(enc, pend, &av_live) + if enc == nil { + return 0 + } + + packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( + unsafe.Pointer(packet.m_body))) + + return int32(C_RTMP_SendPacket(r, &packet, 1)) +} + // int SendBytesReceived(RTMP* r); // rtmp.c +2080 func C_SendBytesReceived(r *C_RTMP) int { @@ -843,320 +1252,56 @@ func C_SendBytesReceived(r *C_RTMP) int { return C_RTMP_SendPacket(r, &packet, 0) } -// int HandShake(RTMP* r, int FP9HandShake); -// rtmp.c +3744 -func C_HandShake(r *C_RTMP, FP9HandShake int32) int { - var bMatch int - //uptime := uint32(0) - //suptime := uint32(0) - //typ := byte(0) - var uptime, suptime uint32 - var typ byte - //clientbuf := make([]byte, RTMP_SIG_SIZE+1) - var clientbuf [RTMP_SIG_SIZE + 1]byte - clientsig := (*byte)(incBytePtr(unsafe.Pointer(&clientbuf[0]), 1)) - //serversig := make([]byte, RTMP_SIG_SIZE) - var serversig [RTMP_SIG_SIZE]byte - - clientbuf[0] = 0x03 // not encrypted - - // TODO: port rtmp_getTime - //uptime = inet.Htonl(uint32(C.RTMP_GetTime())) - uptime = inet.Htonl(uint32(C_RTMP_GetTime())) - memmove(unsafe.Pointer(clientsig), unsafe.Pointer(&uptime), 4) - - memset(indxBytePtr(unsafe.Pointer(clientsig), 4), 0, 4) - - for i := 8; i < RTMP_SIG_SIZE; i++ { - *indxBytePtr(unsafe.Pointer(clientsig), i) = byte(rand.Intn(256)) - } - - if C_WriteN(r, unsafe.Pointer(&clientbuf[0]), RTMP_SIG_SIZE+1) == 0 { - return 0 - } - - //if C.ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { - if C_ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { - return 0 - } - - if debugMode { - log.Println("C_HandShake: Type answer: %v", typ) - } - if typ != clientbuf[0] { - log.Println("C_HandShake: type mismatch: client sent %v, server sent: %v", - clientbuf[0], typ) - } - if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - return 0 - } - - // decode server response - memmove(unsafe.Pointer(&suptime), unsafe.Pointer(&serversig[0]), 4) - suptime = inet.Ntohl(suptime) - - // 2nd part of handshake - if C_WriteN(r, unsafe.Pointer(&serversig[0]), RTMP_SIG_SIZE) == 0 { - return 0 - } - - if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - return 0 - } - - // TODO: find golang memcmp - bMatch = 0 - if memcmp(unsafe.Pointer(&serversig[0]), unsafe.Pointer(clientsig), - RTMP_SIG_SIZE) == 0 { - bMatch = 1 - } - - if bMatch == 0 { - log.Println("Client signature does not match!") - } - return 1 -} - -// int RTMPSockBuf_Fill(RTMPSockBuf* sb); -// rtmp.c +4253 -func C_RTMPSockBuf_Fill(sb *C_RTMPSockBuf) int { - var nBytes int - - if sb.sb_size == 0 { - sb.sb_start = &sb.sb_buf[0] - } - - for { - nBytes = int(unsafe.Sizeof(sb.sb_buf)) - 1 - int(sb.sb_size) - - int(uintptr(unsafe.Pointer(sb.sb_start))-uintptr(unsafe.Pointer( - &sb.sb_buf[0]))) - - // TODO: figure out what to do with recv - nBytes = int(C.recv(C.int(sb.sb_socket), unsafe.Pointer(uintptr(unsafe.Pointer( - sb.sb_start))+uintptr(int(sb.sb_size))), C.size_t(nBytes), 0)) - - if nBytes != -1 { - sb.sb_size += int32(nBytes) - } else { - log.Println("C_RTMPSockBuf_Fill: recv error!") - } - break - } - return nBytes -} - -// int RTMP_ConnectStream(RTMP* r, int seekTime); -// rtmp.c +1099 -func C_RTMP_ConnectStream(r *C_RTMP, seekTime int32) int { +// int SendCheckBW(RTMP* r); +// rtmp.c +2105 +func C_SendCheckBW(r *C_RTMP) int32 { var packet C_RTMPPacket - memset((*byte)(unsafe.Pointer(&packet)), 0, int(unsafe.Sizeof(packet))) + var pbuf [256]byte + var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + + unsafe.Sizeof(pbuf))) + var enc *byte - if seekTime > 0 { - r.Link.seekTime = int32(seekTime) - } + packet.m_nChannel = 0x03 /* control channel (invoke) */ + packet.m_headerType = RTMP_PACKET_SIZE_LARGE + packet.m_packetType = RTMP_PACKET_TYPE_INVOKE + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = 0 + packet.m_hasAbsTimestamp = 0 + packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), + int(RTMP_MAX_HEADER_SIZE))) - r.m_mediaChannel = 0 + enc = (*byte)(unsafe.Pointer(packet.m_body)) + enc = C_AMF_EncodeString(enc, pend, &av__checkbw) + r.m_numInvokes++ + enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) + *enc = AMF_NULL + enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) - // TODO: read packet - for r.m_bPlaying == 0 && C_RTMP_IsConnected(r) != 0 && - //C.RTMP_ReadPacket(r, &packet) != 0 { - C_RTMP_ReadPacket(r, &packet) != 0 { + packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( + unsafe.Pointer(packet.m_body))) - // TODO: port is ready - if C_RTMPPacket_IsReady(&packet) != 0 { - if packet.m_nBodySize == 0 { - continue - } - - if packet.m_packetType == RTMP_PACKET_TYPE_AUDIO || - packet.m_packetType == RTMP_PACKET_TYPE_VIDEO || - packet.m_packetType == RTMP_PACKET_TYPE_INFO { - log.Println("C_RTMP_ConnectStream: got packet before play()! Ignoring.") - C_RTMPPacket_Free(&packet) - continue - } - - //C.RTMP_ClientPacket(r, &packet) - C_RTMP_ClientPacket(r, &packet) - C_RTMPPacket_Free(&packet) - } - } - return int(r.m_bPlaying) + return int32(C_RTMP_SendPacket(r, &packet, 0)) } -// int RTMP_ClientPacket() -// rtmp.c +1226 -// NOTE cases have been commented out that are not currently used by AusOcean -func C_RTMP_ClientPacket(r *C_RTMP, packet *C_RTMPPacket) int32 { - var bHasMediaPacket int32 = 0 - switch packet.m_packetType { - - case RTMP_PACKET_TYPE_CHUNK_SIZE: - log.Println("RTMP_PACKET_TYPE_CHUNK_SIZE") - // TODO: port this - //C.HandleChangeChunkSize(r, packet) - C_HandleChangeChunkSize(r, packet) - /* - case RTMP_PACKET_TYPE_BYTES_READ_REPORT: - log.Println("RTMP_PACKET_TYPE_BYTES_READ_REPORT") - // TODO: usue new logger here - //RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__); - - case RTMP_PACKET_TYPE_CONTROL: - log.Println("RTMP_PACKET_TYPE_CONTROL") - // TODO: port this - C.HandleCtrl(r, packet) - */ - case RTMP_PACKET_TYPE_SERVER_BW: - log.Println("RTMP_PACKET_TYPE_SERVER_BW") - // TODO: port this - //C.HandleServerBW(r, packet) - C_HandlServerBW(r, packet) - - case RTMP_PACKET_TYPE_CLIENT_BW: - log.Println("RTMP_PACKET_TYPE_CLIENT_BW") - // TODO: port this - //C.HandleClientBW(r, packet) - C_HandleClientBW(r, packet) - /* - case RTMP_PACKET_TYPE_AUDIO: - log.Println("RTMP_PACKET_TYPE_AUDIO") - // TODO port this - //C.HandleAudio(r, packet) NOTE this does nothing - bHasMediaPacket = 1 - if r.m_mediaChannel == 0 { - r.m_mediaChannel = packet.m_nChannel - } - - if r.m_pausing == 0 { - r.m_mediaStamp = packet.m_nTimeStamp - } - - case RTMP_PACKET_TYPE_VIDEO: - log.Println("RTMP_PACKET_TYPE_VIDEO:") - // TODO port this - // C.HandleVideo(r, packet) NOTE this does nothing - bHasMediaPacket = 1 - if r.m_mediaChannel == 0 { - r.m_mediaChannel = packet.m_nChannel - } - if r.m_pausing == 0 { - r.m_mediaStamp = packet.m_nTimeStamp - } - - case RTMP_PACKET_TYPE_FLEX_MESSAGE: - log.Println("RTMP_PACKET_TYPE_FLEX_MESSAGE:") - { - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG,"%s, flex message, size %u bytes, not fully supported", __FUNCTION__, packet.m_nBodySize); - - if C.HandleInvoke(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), 1)), - C.uint(packet.m_nBodySize-1)) == 1 { - bHasMediaPacket = 2 - } - } - case RTMP_PACKET_TYPE_INFO: - log.Println(" RTMP_PACKET_TYPE_INFO:") - // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,packet.m_nBodySize); - if C.HandleMetadata(r, packet.m_body, C.uint(packet.m_nBodySize)) != 0 { - bHasMediaPacket = 1 - } - */ - - case RTMP_PACKET_TYPE_INVOKE: - log.Println("RTMP_PACKET_TYPE_INVOKE:") - // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,packet.m_nBodySize); - - //if C.HandleInvoke(r, packet.m_body, C.uint(packet.m_nBodySize)) == 1 { - if C_HandleInvoke(r, (*byte)(unsafe.Pointer(packet.m_body)), uint32(packet.m_nBodySize)) == 1 { - log.Println("HasMediaPacket") - bHasMediaPacket = 2 - } - /* - case RTMP_PACKET_TYPE_FLASH_VIDEO: - log.Println("RTMP_PACKET_TYPE_FLASH_VIDEO:") - { - var pos uint32 = 0 - var nTimeStamp uint32 = uint32(packet.m_nTimeStamp) - - for pos+11 < uint32(packet.m_nBodySize) { - var dataSize uint32 = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( - packet.m_body), int(pos+1)))) - - if pos+11+dataSize+4 > uint32(packet.m_nBodySize) { - // TODO use new logger here - // RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!"); - break - } - - switch { - case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 0x12: - C.HandleMetadata(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), - int(pos+11))), C.uint(dataSize)) - case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 8 || - *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 9: - nTimeStamp = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( - packet.m_body), int(pos+4)))) - nTimeStamp |= uint32(*indxBytePtr(unsafe.Pointer(packet.m_body), - int(pos+7)) << 24) - } - pos += (11 + dataSize + 4) - } - if r.m_pausing == 0 { - r.m_mediaStamp = uint32(nTimeStamp) - } - - bHasMediaPacket = 1 - - } - default: - log.Println("DEFAULT") - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,packet.m_packetType); - */ +// void AV_erase(C_RTMP_METHOD* vals, int* num, int i, int freeit); +// rtmp.c +2393 +func C_AV_erase(vals *C_RTMP_METHOD, num *int32, i, freeit int32) { + if freeit != 0 { + //C.free(unsafe.Pointer((*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), + //int(unsafe.Sizeof(*vals))))).name.av_val)) } - return bHasMediaPacket -} - -// void HandleChangeChunkSize(RTMP* r, const RTMPPacket* packet); -// rtmp.c +3345 -func C_HandleChangeChunkSize(r *C_RTMP, packet *C_RTMPPacket) { - if packet.m_nBodySize >= 4 { - //r.m_inChunkSize = int32(C.AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) - r.m_inChunkSize = int32(C_AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__, r.m_inChunkSize); + (*num)-- + for ; i < *num; i++ { + *(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), + int(unsafe.Sizeof(*vals)))) = *(*C_RTMP_METHOD)(incPtr( + unsafe.Pointer(vals), int(i+1), int(unsafe.Sizeof(*vals)))) } -} - -// void HandleServerBW(RTMP* r, const RTMPPacket* packet); -// rtmp.c +3508 -func C_HandlServerBW(r *C_RTMP, packet *C_RTMPPacket) { - r.m_nServerBW = int32(C_AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) - //r.m_nServerBW = int32(C.AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r.m_nServerBW); -} - -// void HandleClientBW(RTMP* r, const RTMPPacket* packet); -// rtmp.c +3515 -func C_HandleClientBW(r *C_RTMP, packet *C_RTMPPacket) { - r.m_nClientBW = int32(C_AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) - //r.m_nClientBW = int32(C.AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) - - if packet.m_nBodySize > 4 { - r.m_nClientBW2 = (uint8)(*indxBytePtr(unsafe.Pointer(packet.m_body), 4)) - } else { - //r.m_nClientBW2 = -1 - r.m_nClientBW2 = 0 - } - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r.m_nClientBW, - //r.m_nClientBW2); + (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), + int(unsafe.Sizeof(*vals))))).name.av_val = nil + (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), + int(unsafe.Sizeof(*vals))))).name.av_len = 0 + (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), + int(unsafe.Sizeof(*vals))))).num = 0 } // int HandleInvoke(RTMP* r, const char* body, unsigned int nBodySize); @@ -1437,216 +1582,64 @@ leave: return ret } -// int SendReleaseStream(RTMP* r); -// rtmp.c +1816 -func C_SendReleaseStream(r *C_RTMP) int32 { - var packet C_RTMPPacket - var pbuf [1024]byte - var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + - unsafe.Sizeof(pbuf))) - var enc *byte - - packet.m_nChannel = 0x03 /* control channel (invoke) */ - packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM - packet.m_packetType = RTMP_PACKET_TYPE_INVOKE - packet.m_nTimeStamp = 0 - packet.m_nInfoField2 = 0 - packet.m_hasAbsTimestamp = 0 - packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), - int(RTMP_MAX_HEADER_SIZE))) - - enc = (*byte)(unsafe.Pointer(packet.m_body)) - enc = C_AMF_EncodeString(enc, pend, &av_releaseStream) - r.m_numInvokes++ - enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) - *enc = AMF_NULL - enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) - enc = C_AMF_EncodeString(enc, pend, &r.Link.playpath) - if enc == nil { - return 0 +// void HandleChangeChunkSize(RTMP* r, const RTMPPacket* packet); +// rtmp.c +3345 +func C_HandleChangeChunkSize(r *C_RTMP, packet *C_RTMPPacket) { + if packet.m_nBodySize >= 4 { + //r.m_inChunkSize = int32(C.AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) + r.m_inChunkSize = int32(C_AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) + // TODO use new logger here + // RTMP_Log(RTMP_LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__, r.m_inChunkSize); } - packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( - unsafe.Pointer(packet.m_body))) - - return int32(C_RTMP_SendPacket(r, &packet, 0)) } -// int SendFCPublish(RTMP* r); -// rtmp.c +1846 -func C_SendFCPublish(r *C_RTMP) int32 { - var packet C_RTMPPacket - var pbuf [1024]byte - var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + - unsafe.Sizeof(pbuf))) - var enc *byte - - packet.m_nChannel = 0x03 /* control channel (invoke) */ - packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM - packet.m_packetType = RTMP_PACKET_TYPE_INVOKE - packet.m_nTimeStamp = 0 - packet.m_nInfoField2 = 0 - packet.m_hasAbsTimestamp = 0 - packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), - int(RTMP_MAX_HEADER_SIZE))) - - enc = (*byte)(unsafe.Pointer(packet.m_body)) - enc = C_AMF_EncodeString(enc, pend, &av_FCPublish) - r.m_numInvokes++ - enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) - *enc = AMF_NULL - enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) - enc = C_AMF_EncodeString(enc, pend, &r.Link.playpath) - if enc == nil { - return 0 - } - packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( - unsafe.Pointer(packet.m_body))) - - return int32(C_RTMP_SendPacket(r, &packet, 0)) +// void HandleServerBW(RTMP* r, const RTMPPacket* packet); +// rtmp.c +3508 +func C_HandlServerBW(r *C_RTMP, packet *C_RTMPPacket) { + r.m_nServerBW = int32(C_AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) + //r.m_nServerBW = int32(C.AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) + // TODO use new logger here + // RTMP_Log(RTMP_LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r.m_nServerBW); } -// int RTMP_SendCreateStream(RTMP* r); -// rtmp.c +1725 -func C_RTMP_SendCreateStream(r *C_RTMP) int32 { - var packet C_RTMPPacket - var pbuf [256]byte - var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + - unsafe.Sizeof(pbuf))) - var enc *byte +// void HandleClientBW(RTMP* r, const RTMPPacket* packet); +// rtmp.c +3515 +func C_HandleClientBW(r *C_RTMP, packet *C_RTMPPacket) { + r.m_nClientBW = int32(C_AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) + //r.m_nClientBW = int32(C.AMF_DecodeInt32((*byte)(unsafe.Pointer(packet.m_body)))) - packet.m_nChannel = 0x03 /* control channel (invoke) */ - packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM - packet.m_packetType = RTMP_PACKET_TYPE_INVOKE - packet.m_nTimeStamp = 0 - packet.m_nInfoField2 = 0 - packet.m_hasAbsTimestamp = 0 - packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), - int(RTMP_MAX_HEADER_SIZE))) - - enc = (*byte)(unsafe.Pointer(packet.m_body)) - enc = C_AMF_EncodeString(enc, pend, &av_createStream) - r.m_numInvokes++ - enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) - *enc = AMF_NULL - enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) - - packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( - unsafe.Pointer(packet.m_body))) - - return int32(C_RTMP_SendPacket(r, &packet, 1)) -} - -// int SendPublish(RTMP* r); -// rtmp.c +1908 -func C_SendPublish(r *C_RTMP) int32 { - var packet C_RTMPPacket - var pbuf [1024]byte - var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + - unsafe.Sizeof(pbuf))) - var enc *byte - - packet.m_nChannel = 0x04 /* source channel (invoke) */ - packet.m_headerType = RTMP_PACKET_SIZE_LARGE - packet.m_packetType = RTMP_PACKET_TYPE_INVOKE - packet.m_nTimeStamp = 0 - packet.m_nInfoField2 = int32(r.m_stream_id) - packet.m_hasAbsTimestamp = 0 - packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), - int(RTMP_MAX_HEADER_SIZE))) - - enc = (*byte)(unsafe.Pointer(packet.m_body)) - enc = C_AMF_EncodeString(enc, pend, &av_publish) - r.m_numInvokes++ - enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) - *enc = AMF_NULL - enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) - enc = C_AMF_EncodeString(enc, pend, &r.Link.playpath) - - if enc == nil { - return 0 - } - - enc = C_AMF_EncodeString(enc, pend, &av_live) - if enc == nil { - return 0 - } - - packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( - unsafe.Pointer(packet.m_body))) - - return int32(C_RTMP_SendPacket(r, &packet, 1)) -} - -// int SendCheckBW(RTMP* r); -// rtmp.c +2105 -func C_SendCheckBW(r *C_RTMP) int32 { - var packet C_RTMPPacket - var pbuf [256]byte - var pend *byte = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&pbuf[0])) + - unsafe.Sizeof(pbuf))) - var enc *byte - - packet.m_nChannel = 0x03 /* control channel (invoke) */ - packet.m_headerType = RTMP_PACKET_SIZE_LARGE - packet.m_packetType = RTMP_PACKET_TYPE_INVOKE - packet.m_nTimeStamp = 0 - packet.m_nInfoField2 = 0 - packet.m_hasAbsTimestamp = 0 - packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), - int(RTMP_MAX_HEADER_SIZE))) - - enc = (*byte)(unsafe.Pointer(packet.m_body)) - enc = C_AMF_EncodeString(enc, pend, &av__checkbw) - r.m_numInvokes++ - enc = C_AMF_EncodeNumber(enc, pend, float64(r.m_numInvokes)) - *enc = AMF_NULL - enc = (*byte)(incBytePtr(unsafe.Pointer(enc), 1)) - - packet.m_nBodySize = uint32(uintptr(unsafe.Pointer(enc)) - uintptr( - unsafe.Pointer(packet.m_body))) - - return int32(C_RTMP_SendPacket(r, &packet, 0)) -} - -// #define AVMATCH(a1,a2) -// amf.h +63 -func C_AVMATCH(a1, a2 *C_AVal) int32 { - if a1.av_len == a2.av_len && memcmp(unsafe.Pointer(a1.av_val), - unsafe.Pointer(a2.av_val), int(a1.av_len)) == 0 { - return 1 + if packet.m_nBodySize > 4 { + r.m_nClientBW2 = (uint8)(*indxBytePtr(unsafe.Pointer(packet.m_body), 4)) } else { - return 0 + //r.m_nClientBW2 = -1 + r.m_nClientBW2 = 0 } + // TODO use new logger here + // RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r.m_nClientBW, + //r.m_nClientBW2); } -// void AV_erase(C_RTMP_METHOD* vals, int* num, int i, int freeit); -// rtmp.c +2393 -func C_AV_erase(vals *C_RTMP_METHOD, num *int32, i, freeit int32) { - if freeit != 0 { - //C.free(unsafe.Pointer((*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), - //int(unsafe.Sizeof(*vals))))).name.av_val)) - } - (*num)-- - for ; i < *num; i++ { - *(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), - int(unsafe.Sizeof(*vals)))) = *(*C_RTMP_METHOD)(incPtr( - unsafe.Pointer(vals), int(i+1), int(unsafe.Sizeof(*vals)))) - } - (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), - int(unsafe.Sizeof(*vals))))).name.av_val = nil - (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), - int(unsafe.Sizeof(*vals))))).name.av_len = 0 - (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(vals), int(i), - int(unsafe.Sizeof(*vals))))).num = 0 +// static int DecodeInt32LE(const char* data); +// rtmp.c +3527 +func C_DecodeInt32LE(data *byte) int32 { + var c *uint8 = (*uint8)(data) + return int32((*indxBytePtr(unsafe.Pointer(c), 3) << 24) | + (*indxBytePtr(unsafe.Pointer(c), 2) << 16) | + (*indxBytePtr(unsafe.Pointer(c), 1) << 8) | + *c) } -// void RTMPPacket_Free(RTMPPacket* p); -// rtmp.c +203 -func C_RTMPPacket_Free(p *C_RTMPPacket) { - if p.m_body != nil { - //C.free(decBytePtr(unsafe.Pointer(p.m_body), RTMP_MAX_HEADER_SIZE)) - p.m_body = nil - } +// int EncodeInt32LE(char* output, int nVal); +// rtmp.c +3537 +func C_EncodeInt32LE(output *byte, nVal int32) int32 { + *output = byte(nVal) + nVal >>= 8 + *indxBytePtr(unsafe.Pointer(output), 1) = byte(nVal) + nVal >>= 8 + *indxBytePtr(unsafe.Pointer(output), 2) = byte(nVal) + nVal >>= 8 + *indxBytePtr(unsafe.Pointer(output), 3) = byte(nVal) + return 4 } // int RTMP_ReadPacket(RTMP* r, RTMPPacket* packet); @@ -1869,161 +1862,79 @@ func C_RTMP_ReadPacket(r *C_RTMP, packet *C_RTMPPacket) int32 { return 1 } -// static int DecodeInt32LE(const char* data); -// rtmp.c +3527 -func C_DecodeInt32LE(data *byte) int32 { - var c *uint8 = (*uint8)(data) - return int32((*indxBytePtr(unsafe.Pointer(c), 3) << 24) | - (*indxBytePtr(unsafe.Pointer(c), 2) << 16) | - (*indxBytePtr(unsafe.Pointer(c), 1) << 8) | - *c) -} +// int HandShake(RTMP* r, int FP9HandShake); +// rtmp.c +3744 +func C_HandShake(r *C_RTMP, FP9HandShake int32) int { + var bMatch int + //uptime := uint32(0) + //suptime := uint32(0) + //typ := byte(0) + var uptime, suptime uint32 + var typ byte + //clientbuf := make([]byte, RTMP_SIG_SIZE+1) + var clientbuf [RTMP_SIG_SIZE + 1]byte + clientsig := (*byte)(incBytePtr(unsafe.Pointer(&clientbuf[0]), 1)) + //serversig := make([]byte, RTMP_SIG_SIZE) + var serversig [RTMP_SIG_SIZE]byte -// int EncodeInt32LE(char* output, int nVal); -// rtmp.c +3537 -func C_EncodeInt32LE(output *byte, nVal int32) int32 { - *output = byte(nVal) - nVal >>= 8 - *indxBytePtr(unsafe.Pointer(output), 1) = byte(nVal) - nVal >>= 8 - *indxBytePtr(unsafe.Pointer(output), 2) = byte(nVal) - nVal >>= 8 - *indxBytePtr(unsafe.Pointer(output), 3) = byte(nVal) - return 4 -} + clientbuf[0] = 0x03 // not encrypted -// #define RTMPPacket_IsReady(a) -// rtmp.h +142 -func C_RTMPPacket_IsReady(p *C_RTMPPacket) int { - if p.m_nBytesRead == p.m_nBodySize { - return 1 - } - return 0 -} + // TODO: port rtmp_getTime + //uptime = inet.Htonl(uint32(C.RTMP_GetTime())) + uptime = inet.Htonl(uint32(C_RTMP_GetTime())) + memmove(unsafe.Pointer(clientsig), unsafe.Pointer(&uptime), 4) -func endSession(rtmp *C_RTMP) uint32 { - if rtmp == nil { - return 3 + memset(indxBytePtr(unsafe.Pointer(clientsig), 4), 0, 4) + + for i := 8; i < RTMP_SIG_SIZE; i++ { + *indxBytePtr(unsafe.Pointer(clientsig), i) = byte(rand.Intn(256)) } - //C.RTMP_Close(rtmp) - //C.RTMP_Free(rtmp) - return 0 -} - -// int RTMP_Write(RTMP* r, const char* buf, int size); -// rtmp.c +5095 -func C_RTMP_Write(r *C_RTMP, data []byte) int { - buf := sliceToPtr(data) - // TODO: port RTMPPacket - var pkt = &r.m_write - var pend, enc unsafe.Pointer - size := len(data) - s2 := size - var ret, num int - - pkt.m_nChannel = 0x04 - pkt.m_nInfoField2 = int32(r.m_stream_id) - for s2 != 0 { - if pkt.m_nBytesRead == 0 { - if size < minDataSize { - log.Printf("size: %d\n", size) - log.Printf("too small \n") - return 0 - } - - if *indxBytePtr(buf, 0) == 'F' && *indxBytePtr(buf, 1) == 'L' && *indxBytePtr(buf, 2) == 'V' { - buf = unsafe.Pointer(uintptr(buf) + uintptr(13)) - s2 -= 13 - } - - pkt.m_packetType = uint8(*indxBytePtr(buf, 0)) - buf = incBytePtr(buf, 1) - pkt.m_nBodySize = uint32(C_AMF_DecodeInt24((*byte)(buf))) - buf = incBytePtr(buf, 3) - pkt.m_nTimeStamp = uint32(C_AMF_DecodeInt24((*byte)(buf))) - buf = incBytePtr(buf, 3) - pkt.m_nTimeStamp |= uint32(*indxBytePtr(buf, 0)) << 24 - buf = incBytePtr(buf, 4) - s2 -= 11 - - if ((pkt.m_packetType == RTMP_PACKET_TYPE_AUDIO || - pkt.m_packetType == RTMP_PACKET_TYPE_VIDEO) && - pkt.m_nTimeStamp == 0) || pkt.m_packetType == RTMP_PACKET_TYPE_INFO { - - pkt.m_headerType = RTMP_PACKET_SIZE_LARGE - - if pkt.m_packetType == RTMP_PACKET_TYPE_INFO { - pkt.m_nBodySize += 16 - } - } else { - pkt.m_headerType = RTMP_PACKET_SIZE_MEDIUM - } - // TODO: Port this - if int(C_RTMPPacket_Alloc(pkt, uint32(pkt.m_nBodySize))) == 0 { - log.Println("Failed to allocate packet") - return 0 - } - - enc = unsafe.Pointer(pkt.m_body) - pend = incBytePtr(enc, int(pkt.m_nBodySize)) - - if pkt.m_packetType == RTMP_PACKET_TYPE_INFO { - enc = unsafe.Pointer(C_AMF_EncodeString((*byte)(enc), (*byte)(pend), &setDataFrame)) - pkt.m_nBytesRead = uint32(math.Abs(float64(uintptr(enc) - - uintptr(unsafe.Pointer(pkt.m_body))))) - } - - } else { - enc = incBytePtr(unsafe.Pointer(pkt.m_body), int(pkt.m_nBytesRead)) - } - num = int(pkt.m_nBodySize - pkt.m_nBytesRead) - if num > s2 { - num = s2 - } - - memmove(enc, buf, uintptr(num)) - pkt.m_nBytesRead += uint32(num) - s2 -= num - buf = incBytePtr(buf, num) - if pkt.m_nBytesRead == pkt.m_nBodySize { - // TODO: Port this - ret = C_RTMP_SendPacket(r, pkt, 0) - // TODO: Port this - //C.RTMPPacket_Free(pkt) - C_RTMPPacket_Free(pkt) - pkt.m_nBytesRead = 0 - if ret == 0 { - return -1 - } - buf = incBytePtr(buf, 4) - s2 -= 4 - if s2 < 0 { - break - } - } - } - return size + s2 -} - -// int RTMPPacket_Alloc(RTMPPacket* p, uint32_t nSize); -// rtmp.c +189 -func C_RTMPPacket_Alloc(p *C_RTMPPacket, nSize uint32) int { - var ptr *byte - // TODO: port C.SIZE_MAX - // also work out how to deal with the overfloat - /* - if int64(nSize) > (C.SIZE_MAX - RTMP_MAX_HEADER_SIZE) { - return 0 - } - */ - ptr = (*byte)(calloc(1, uintptr(nSize+RTMP_MAX_HEADER_SIZE))) - - if ptr == nil { + if C_WriteN(r, unsafe.Pointer(&clientbuf[0]), RTMP_SIG_SIZE+1) == 0 { return 0 } - p.m_body = (*byte)(incBytePtr(unsafe.Pointer(ptr), RTMP_MAX_HEADER_SIZE)) - p.m_nBytesRead = 0 + + //if C.ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { + if C_ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { + return 0 + } + + if debugMode { + log.Println("C_HandShake: Type answer: %v", typ) + } + if typ != clientbuf[0] { + log.Println("C_HandShake: type mismatch: client sent %v, server sent: %v", + clientbuf[0], typ) + } + if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + return 0 + } + + // decode server response + memmove(unsafe.Pointer(&suptime), unsafe.Pointer(&serversig[0]), 4) + suptime = inet.Ntohl(suptime) + + // 2nd part of handshake + if C_WriteN(r, unsafe.Pointer(&serversig[0]), RTMP_SIG_SIZE) == 0 { + return 0 + } + + if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + return 0 + } + + // TODO: find golang memcmp + bMatch = 0 + if memcmp(unsafe.Pointer(&serversig[0]), unsafe.Pointer(clientsig), + RTMP_SIG_SIZE) == 0 { + bMatch = 1 + } + + if bMatch == 0 { + log.Println("Client signature does not match!") + } return 1 } @@ -2289,38 +2200,32 @@ func C_RTMP_SendPacket(r *C_RTMP, packet *C_RTMPPacket, queue int) int { return 1 } -// int WriteN(RTMP* r, const char* buffer, int n); -// rtmp.c +1502 -func C_WriteN(r *C_RTMP, buffer unsafe.Pointer, n int) int { - ptr := buffer - for n > 0 { - var nBytes int +// int RTMPSockBuf_Fill(RTMPSockBuf* sb); +// rtmp.c +4253 +func C_RTMPSockBuf_Fill(sb *C_RTMPSockBuf) int { + var nBytes int - nBytes = int(C_RTMPSockBuf_Send(&r.m_sb, (*byte)(ptr), int32(n))) - - if nBytes < 0 { - if debugMode { - log.Println("C_WriteN, RTMP send error") - } - - // TODO: port this - //C.RTMP_Close(r) - n = 1 - break - } - - if nBytes == 0 { - break - } - - n -= nBytes - ptr = incBytePtr(ptr, nBytes) + if sb.sb_size == 0 { + sb.sb_start = &sb.sb_buf[0] } - if n == 0 { - return 1 + for { + nBytes = int(unsafe.Sizeof(sb.sb_buf)) - 1 - int(sb.sb_size) - + int(uintptr(unsafe.Pointer(sb.sb_start))-uintptr(unsafe.Pointer( + &sb.sb_buf[0]))) + + // TODO: figure out what to do with recv + nBytes = int(C.recv(C.int(sb.sb_socket), unsafe.Pointer(uintptr(unsafe.Pointer( + sb.sb_start))+uintptr(int(sb.sb_size))), C.size_t(nBytes), 0)) + + if nBytes != -1 { + sb.sb_size += int32(nBytes) + } else { + log.Println("C_RTMPSockBuf_Fill: recv error!") + } + break } - return 0 + return nBytes } // int RTMPSockBuf_Send(RTMPSockBuf* sb, const char* buf, int len); @@ -2330,27 +2235,99 @@ func C_RTMPSockBuf_Send(sb *C_RTMPSockBuf, buf *byte, l int32) int32 { return int32(C.send(C.int(sb.sb_socket), unsafe.Pointer(buf), C.size_t(l), 0)) } -// void AV_queue(RTMP_METHOD** vals, int* num, C_AVal* av, int txn); -// rtmp.c +2414 -func C_AV_queue(vals **C_RTMP_METHOD, num *int32, av *C_AVal, txn int32) { - if (*num & 0x0f) == 0 { - //*vals = (*C_RTMP_METHOD)(realloc(unsafe.Pointer(*vals), uint32((*num+16)* - //int32(unsafe.Sizeof(*(*vals)))))) - *vals = (*C_RTMP_METHOD)(C.realloc(unsafe.Pointer(*vals), C.size_t((*num+16)* - int32(unsafe.Sizeof(*(*vals)))))) - } - tmp := malloc(uintptr(av.av_len + 1)) - //tmp := allocate(uintptr(av.av_len + 1)) - memmove(tmp, unsafe.Pointer(av.av_val), uintptr(av.av_len)) - *indxBytePtr(tmp, int(av.av_len)) = '\000' +// int RTMP_Write(RTMP* r, const char* buf, int size); +// rtmp.c +5095 +func C_RTMP_Write(r *C_RTMP, data []byte) int { + buf := sliceToPtr(data) + // TODO: port RTMPPacket + var pkt = &r.m_write + var pend, enc unsafe.Pointer + size := len(data) + s2 := size + var ret, num int - (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(*vals), int(*num), - int(unsafe.Sizeof(*(*vals)))))).num = int32(txn) - (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(*vals), int(*num), - int(unsafe.Sizeof(*(*vals)))))).name.av_len = av.av_len - (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(*vals), int(*num), - int(unsafe.Sizeof(*(*vals)))))).name.av_val = (*byte)(tmp) - (*num)++ + pkt.m_nChannel = 0x04 + pkt.m_nInfoField2 = int32(r.m_stream_id) + for s2 != 0 { + if pkt.m_nBytesRead == 0 { + if size < minDataSize { + log.Printf("size: %d\n", size) + log.Printf("too small \n") + return 0 + } + + if *indxBytePtr(buf, 0) == 'F' && *indxBytePtr(buf, 1) == 'L' && *indxBytePtr(buf, 2) == 'V' { + buf = unsafe.Pointer(uintptr(buf) + uintptr(13)) + s2 -= 13 + } + + pkt.m_packetType = uint8(*indxBytePtr(buf, 0)) + buf = incBytePtr(buf, 1) + pkt.m_nBodySize = uint32(C_AMF_DecodeInt24((*byte)(buf))) + buf = incBytePtr(buf, 3) + pkt.m_nTimeStamp = uint32(C_AMF_DecodeInt24((*byte)(buf))) + buf = incBytePtr(buf, 3) + pkt.m_nTimeStamp |= uint32(*indxBytePtr(buf, 0)) << 24 + buf = incBytePtr(buf, 4) + s2 -= 11 + + if ((pkt.m_packetType == RTMP_PACKET_TYPE_AUDIO || + pkt.m_packetType == RTMP_PACKET_TYPE_VIDEO) && + pkt.m_nTimeStamp == 0) || pkt.m_packetType == RTMP_PACKET_TYPE_INFO { + + pkt.m_headerType = RTMP_PACKET_SIZE_LARGE + + if pkt.m_packetType == RTMP_PACKET_TYPE_INFO { + pkt.m_nBodySize += 16 + } + } else { + pkt.m_headerType = RTMP_PACKET_SIZE_MEDIUM + } + // TODO: Port this + if int(C_RTMPPacket_Alloc(pkt, uint32(pkt.m_nBodySize))) == 0 { + log.Println("Failed to allocate packet") + return 0 + } + + enc = unsafe.Pointer(pkt.m_body) + pend = incBytePtr(enc, int(pkt.m_nBodySize)) + + if pkt.m_packetType == RTMP_PACKET_TYPE_INFO { + enc = unsafe.Pointer(C_AMF_EncodeString((*byte)(enc), (*byte)(pend), &setDataFrame)) + pkt.m_nBytesRead = uint32(math.Abs(float64(uintptr(enc) - + uintptr(unsafe.Pointer(pkt.m_body))))) + } + + } else { + enc = incBytePtr(unsafe.Pointer(pkt.m_body), int(pkt.m_nBytesRead)) + } + num = int(pkt.m_nBodySize - pkt.m_nBytesRead) + if num > s2 { + num = s2 + } + + memmove(enc, buf, uintptr(num)) + pkt.m_nBytesRead += uint32(num) + s2 -= num + buf = incBytePtr(buf, num) + if pkt.m_nBytesRead == pkt.m_nBodySize { + // TODO: Port this + ret = C_RTMP_SendPacket(r, pkt, 0) + // TODO: Port this + //C.RTMPPacket_Free(pkt) + C_RTMPPacket_Free(pkt) + pkt.m_nBytesRead = 0 + if ret == 0 { + return -1 + } + buf = incBytePtr(buf, 4) + s2 -= 4 + if s2 < 0 { + break + } + } + } + return size + s2 } /* From ecb3f3f4c2c0ed3ef526b64ece1c6fc2233c68e1 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 24 Aug 2018 22:30:40 +0930 Subject: [PATCH 16/33] rtmp: finished reordering amf.go such that it resembles the C amf.c file more closely - also readded C_AV_Queue, which I must have deleted somehow --- rtmp/amf.go | 1093 +++++++++++++++++++++++++------------------------- rtmp/rtmp.go | 23 ++ 2 files changed, 570 insertions(+), 546 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index c71e2dc7..581b06ef 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -64,6 +64,286 @@ var ( AMFProp_Invalid = C_AMFObjectProperty{p_type: AMF_INVALID} ) +const ( + AMF3_INTEGER_MAX = 268435455 + AMF3_INTEGER_MIN = -268435456 +) + +// unsigned short AMF_DecodeInt16(const char* data); +// amf.c +41 +func C_AMF_DecodeInt16(data *byte) uint16 { + c := unsafe.Pointer(data) + return uint16(*(*uint8)(c)<<8 | *(*byte)(incBytePtr(c, 1))) +} + +// unsigned int AMF_DecodeInt24(const char* data); +// amf.c +50 +func C_AMF_DecodeInt24(data *byte) uint32 { + // TODO Understand logic and simplify + c := (*uint8)(unsafe.Pointer(data)) + dst := uint32(int32(*c) << 16) + dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + + (uintptr)(int32(1))*unsafe.Sizeof(*c))))) << 8) + dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + + (uintptr)(int32(2))*unsafe.Sizeof(*c)))))) + return dst +} + +// unsigned int AMF_DeocdeInt32(const char* data); +// amf.c +59 +func C_AMF_DecodeInt32(data *byte) uint32 { + c := (*uint8)(data) + val := uint32( + int32(*c)<<24 | + int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 1)))<<16 | + int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 2)))<<8 | + int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 3)))) + return uint32(val) +} + +// void AMF_DecodeString(const char* data, C_AVal* bv); +// amf.c +68 +func C_AMF_DecodeString(data *byte, bv *C_AVal) { + dataPtr := unsafe.Pointer(data) + //bv.av_len = int32(C.AMF_DecodeInt16((*byte)(dataPtr))) + bv.av_len = int32(C_AMF_DecodeInt16((*byte)(dataPtr))) + if bv.av_len > 0 { + bv.av_val = (*byte)(incBytePtr(dataPtr, 2)) + } else { + bv.av_val = nil + } +} + +// void AMF_DecodeLongString(const char *data, AVal *bv); +// amf.c +75 +func C_AMF_DecodeLongString(data *byte, bv *C_AVal) { + bv.av_len = int32(C_AMF_DecodeInt32(data)) + if bv.av_len > 0 { + bv.av_val = (*byte)(incBytePtr(unsafe.Pointer(data), 4)) + } else { + bv.av_val = nil + } +} + +// double AMF_DecodeNumber(const char* data); +// amf.c +82 +func C_AMF_DecodeNumber(data *byte) float64 { + var dVal float64 + var ci, co *uint8 + ci = (*uint8)(unsafe.Pointer(data)) + co = (*uint8)(unsafe.Pointer(&dVal)) + for i := 0; i < 8; i++ { + *indxBytePtr(unsafe.Pointer(co), i) = *indxBytePtr(unsafe.Pointer(ci), 7-i) + } + return dVal +} + +// int AMF_DecodeBoolean(const char *data); +// amf.c +132 +func C_AMF_DecodeBoolean(data *byte) int32 { + if *data != 0 { + return 1 + } + return 0 +} + +// char* AMF_EncodeInt16(char* output, char* outend, short nVal); +// amf.c +138 +func C_AMF_EncodeInt16(output *byte, outend *byte, nVal int16) *byte { + outputPtr := unsafe.Pointer(output) + outendPtr := unsafe.Pointer(outend) + if uintptr(outputPtr)+2 > uintptr(outendPtr) { + // length < 2 + return nil + } + // Assign output[1] + second := (*byte)(incBytePtr(outputPtr, 1)) + *second = (byte)(nVal & 0xff) + // Assign output[0] + *output = (byte)(nVal >> 8) + return (*byte)(incBytePtr(outputPtr, 2)) +} + +// char* AMF_EncodeInt24(char* output, char* outend, int nVal); +// amf.c +149 +func C_AMF_EncodeInt24(output *byte, outend *byte, nVal int32) *byte { + outputPtr := unsafe.Pointer(output) + outendPtr := unsafe.Pointer(outend) + if uintptr(outputPtr)+3 > uintptr(outendPtr) { + // length < 3 + return nil + } + // Assign output[2] + third := (*byte)(incBytePtr(outputPtr, 2)) + *third = (byte)(nVal & 0xff) + // Assign output[1] + second := (*byte)(incBytePtr(outputPtr, 1)) + *second = (byte)(nVal >> 8) + // Assign output[0] + *output = (byte)(nVal >> 16) + return (*byte)(incBytePtr(outputPtr, 3)) +} + +// char* AMF_EncodeInt32(char* output, char* outend, int nVal); +// amf.c +161 +func C_AMF_EncodeInt32(output *byte, outend *byte, nVal int32) *byte { + outputPtr := unsafe.Pointer(output) + outendPtr := unsafe.Pointer(outend) + if uintptr(outputPtr)+4 > uintptr(outendPtr) { + // length < 4 + return nil + } + // Assign output[3] + forth := (*byte)(incBytePtr(outputPtr, 3)) + *forth = (byte)(nVal & 0xff) + // Assign output[2] + third := (*byte)(incBytePtr(outputPtr, 2)) + *third = (byte)(nVal >> 8) + // Assign output[1] + second := (*byte)(incBytePtr(outputPtr, 1)) + *second = (byte)(nVal >> 16) + // Assign output[0] + *output = (byte)(nVal >> 24) + return (*byte)(incBytePtr(outputPtr, 4)) +} + +// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv); +// amf.c +174 +func C_AMF_EncodeString(output *byte, outend *byte, bv *C_AVal) *byte { + outputPtr := unsafe.Pointer(output) + outendPtr := unsafe.Pointer(outend) + if (bv.av_len < 65536 && uintptr(incBytePtr(outputPtr, 1+2+int(bv.av_len))) > + uintptr(outendPtr)) || uintptr(incBytePtr(outputPtr, 1+4+int(bv.av_len))) > + uintptr(outendPtr) { + return nil + } + if bv.av_len < 65536 { + *(*byte)(outputPtr) = AMF_STRING + outputPtr = incBytePtr(outputPtr, 1) + // TODO: port AMF_EncodeInt16 + outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), (*byte)( + outendPtr), int16(bv.av_len))) + //outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), + //(*byte)(outendPtr), (int16)(bv.av_len))) + } else { + *(*byte)(outputPtr) = AMF_LONG_STRING + outputPtr = incBytePtr(outputPtr, 1) + outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), (*byte)( + outendPtr), int32(bv.av_len))) + //outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), + //(*byte)(outendPtr), (int32)(bv.av_len))) + } + memmove(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), uintptr(bv.av_len)) + //C.memcpy(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), (C.size_t)(bv.av_len)) + outputPtr = incBytePtr(outputPtr, int(bv.av_len)) + return (*byte)(outputPtr) +} + +// char* AMF_EncodeNumber(char* output, char* outend, double dVal); +// amf.c +199 +func C_AMF_EncodeNumber(output *byte, outend *byte, dVal float64) *byte { + if int(uintptr(unsafe.Pointer(output)))+1+8 > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + // TODO: port this + *(*byte)(unsafe.Pointer(output)) = AMF_NUMBER + output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) + // NOTE: here we are assuming little endian for both byte order and float + // word order + var ci, co *uint8 + ci = (*uint8)(unsafe.Pointer(&dVal)) + co = (*uint8)(unsafe.Pointer(output)) + for i := 0; i < 8; i++ { + *indxBytePtr(unsafe.Pointer(co), i) = *indxBytePtr(unsafe.Pointer(ci), 7-i) + } + return (*byte)(incBytePtr(unsafe.Pointer(output), 8)) +} + +// char* AMF_EncodeBoolean(char* output, char* outend, int bVal); +// amf.c +260 +func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal int) *byte { + if int(uintptr(unsafe.Pointer(output)))+2 > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + *(*byte)(unsafe.Pointer(output)) = AMF_BOOLEAN + output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) + val := byte(0x01) + if bVal == 0 { + val = byte(0x00) + } + *(*byte)(unsafe.Pointer(output)) = val + output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) + return output +} + +// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue); +// amf.c +273 +func C_AMF_EncodeNamedString(output *byte, outend *byte, strName *C_AVal, strValue *C_AVal) *byte { + if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) + memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) + output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) + return C_AMF_EncodeString(output, outend, strValue) +} + +// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal); +// amf.c +286 +func C_AMF_EncodeNamedNumber(output *byte, outend *byte, strName *C_AVal, dVal float64) *byte { + if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) + memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) + output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) + return C_AMF_EncodeNumber(output, outend, dVal) +} + +// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal); +// amf.c +299 +func C_AMF_EncodeNamedBoolean(output *byte, outend *byte, strName *C_AVal, bVal int) *byte { + if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { + return nil + } + output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) + memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) + output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) + return C_AMF_EncodeBoolean(output, outend, bVal) +} + +// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name); +// amf.c +318 +func C_AMFProp_SetName(prop *C_AMFObjectProperty, name *C_AVal) { + prop.p_name = *name +} + +// double AMFProp_GetNumber(AMFObjectProperty* prop); +// amf.c +330 +func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 { + return float64(prop.p_vu.p_number) +} + +// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str); +// amf.c +341 +func C_AMFProp_GetString(prop *C_AMFObjectProperty, str *C_AVal) { + if prop.p_type == AMF_STRING { + *str = prop.p_vu.p_aval + } else { + *str = AV_empty + } +} + +// void AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj); +// amf.c +351 +func C_AMFProp_GetObject(prop *C_AMFObjectProperty, obj *C_AMFObject) { + if prop.p_type == AMF_OBJECT { + *obj = prop.p_vu.p_object + } else { + *obj = AMFObj_Invalid + } +} + // char* AMFPropEncode(AMFOBjectProperty* prop, char* pBufer, char* pBufEnd); // amf.c +366 func C_AMF_PropEncode(p *C_AMFObjectProperty, pBuffer *byte, pBufEnd *byte) *byte { @@ -122,251 +402,74 @@ func C_AMF_PropEncode(p *C_AMFObjectProperty, pBuffer *byte, pBufEnd *byte) *byt return pBuffer } -// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd); -// amf.c +891 -func C_AMF_Encode(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { - if uintptr(unsafe.Pointer(pBuffer))+uintptr(4) >= uintptr(unsafe.Pointer(pBufEnd)) { - return nil - } +// int AMF3ReadInteger(const char *data, int32_t *valp); +// amf.c +426 +// TODO test +func C_AMF3ReadInteger(data *byte, valp *int32) int32 { + var i int + var val int32 - *pBuffer = AMF_OBJECT - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - - for i := 0; i < int(obj.o_num); i++ { - res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( - obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) - if res == nil { - log.Println("C_AMF_Encode: failed to encode property in index") - break + for i <= 2 { + /* handle first 3 bytes */ + if *indxBytePtr(unsafe.Pointer(data), i)&0x80 != 0 { + /* byte used */ + val <<= 7 /* shift up */ + val |= int32(*indxBytePtr(unsafe.Pointer(data), i) & 0x7f) /* add bits */ + i++ } else { - pBuffer = res - } - } - - if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 3)) >= uintptr(unsafe.Pointer(pBufEnd)) { - return nil - } - - pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, int32(AMF_OBJECT_END)) - - return pBuffer -} - -// char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd); -// amf.c +924 -func C_AMF_EncodeEcmaArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { - if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) { - return nil - } - - *pBuffer = AMF_ECMA_ARRAY - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - - pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num)) - - for i := 0; i < int(obj.o_num); i++ { - res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( - obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) - if res == nil { - log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") - break - } else { - pBuffer = res - } - } - - if int(uintptr(unsafe.Pointer(pBuffer)))+3 >= int(uintptr(unsafe.Pointer(pBufEnd))) { - return nil - } - - pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END) - - return pBuffer -} - -// char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd); -// amf.c +959 -func C_AMF_EncodeArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { - if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) { - return nil - } - - *pBuffer = AMF_STRICT_ARRAY - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - - pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num)) - - for i := 0; i < int(obj.o_num); i++ { - res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( - obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) - if res == nil { - log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") - break - } else { - pBuffer = res - } - } - - return pBuffer -} - -// int AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize, int nArrayLen, int bDecodeName); -func C_AMF_DecodeArray(obj *C_AMFObject, pBuffer *byte, nSize, nArrayLen, bDecodeName int32) int32 { - nOriginalSize := nSize - var bError int32 = 0 - - obj.o_num = 0 - obj.o_props = nil - for nArrayLen > 0 { - var prop C_AMFObjectProperty - var nRes int32 - nArrayLen-- - - if nSize <= 0 { - bError = 1 break } - nRes = C_AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName) - if nRes == -1 { - bError = 1 - break - } else { - nSize -= nRes - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes))) - C_AMF_AddProp(obj, &prop) - } - } - if bError != 0 { - return -1 } - return nOriginalSize - nSize -} + if i > 2 { + /* use 4th byte, all 8bits */ + val <<= 8 + val |= int32(*indxBytePtr(unsafe.Pointer(data), 3)) -// void AMF_Reset(AMFObject* obj); -// amf.c +1282 -func C_AMF_Reset(obj *C_AMFObject) { - var n int32 - for n = 0; n < int32(obj.o_num); n++ { - C_AMFProp_Reset(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), - int(n), int(unsafe.Sizeof(*obj.o_props)))))) - } - //C.free(unsafe.Pointer(obj.o_props)) - obj.o_props = nil - obj.o_num = 0 -} - -// void AMFProp_Reset(AMFObjectProperty* prop); -// amf.c +875 -func C_AMFProp_Reset(prop *C_AMFObjectProperty) { - if prop.p_type == AMF_OBJECT || prop.p_type == AMF_ECMA_ARRAY || - prop.p_type == AMF_STRICT_ARRAY { - C_AMF_Reset(&prop.p_vu.p_object) - } else { - prop.p_vu.p_aval.av_len = 0 - prop.p_vu.p_aval.av_val = nil - } - prop.p_type = AMF_INVALID -} - -// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str); -// amf.c -func C_AMFProp_GetString(prop *C_AMFObjectProperty, str *C_AVal) { - if prop.p_type == AMF_STRING { - *str = prop.p_vu.p_aval - } else { - *str = AV_empty - } -} - -// void AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj); -// amf.c +351 -func C_AMFProp_GetObject(prop *C_AMFObjectProperty, obj *C_AMFObject) { - if prop.p_type == AMF_OBJECT { - *obj = prop.p_vu.p_object - } else { - *obj = AMFObj_Invalid - } -} - -// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex); -// amf.c + 1249 -func C_AMF_GetProp(obj *C_AMFObject, name *C_AVal, nIndex int32) *C_AMFObjectProperty { - if nIndex >= 0 { - if nIndex < int32(obj.o_num) { - return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), - int(nIndex), int(unsafe.Sizeof(*obj.o_props))))) - //return &obj.o_props[nIndex] + /* range check */ + if val > AMF3_INTEGER_MAX { + val -= (1 << 29) } } else { - var n int32 - for n = 0; n < int32(obj.o_num); n++ { - if C_AVMATCH(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), - int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name, name) != 0 { - return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), - int(n), int(unsafe.Sizeof(*obj.o_props))))) - } - } + /* use 7bits of last unparsed byte (0xxxxxxx) */ + val <<= 7 + val |= int32(*indxBytePtr(unsafe.Pointer(data), i)) } - return (*C_AMFObjectProperty)(&AMFProp_Invalid) + + *valp = val + + if i > 2 { + return 4 + } + return int32(i + 1) } -// double AMFProp_GetNumber(AMFObjectProperty* prop); -// amf.c +330 -func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 { - return float64(prop.p_vu.p_number) -} +// int AMF3ReadString(const char *data, AVal *str); +// amf.c +466 +func C_AMF3ReadString(data *byte, str *C_AVal) int32 { + var ref int32 + // assert elided - we will get a panic if it's nil. -// int AMF_Decode(AMFObject *obj, const char* pBuffer, int nSize, int bDecodeName); -// amf.c +1180 -func C_AMF_Decode(obj *C_AMFObject, pBuffer *byte, nSize int32, bDecodeName int32) int32 { - var nOriginalSize int32 = nSize - var bError int32 = 0 + len := C_AMF3ReadInteger(data, &ref) + data = indxBytePtr(unsafe.Pointer(data), int(len)) - obj.o_num = 0 - obj.o_props = nil - - for nSize > 0 { - var prop C_AMFObjectProperty - var nRes int32 - - if nSize >= 3 && C_AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END { - nSize -= 3 - bError = 0 - break - } - - if bError != 0 { - // TODO use new logger here - log.Println("AMF_Decode: decoding error, ignoring bytes until next known pattern!") - nSize-- - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) - continue - } - // TODO port AMFProp_Decode - nRes = int32(C_AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), - int32(nSize), int32(bDecodeName))) - // nRes = int32(C.AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), - // int32(nSize), int32(bDecodeName))) - if nRes == -1 { - bError = 1 - break - } else { - nSize -= nRes - if nSize < 0 { - bError = 1 - break - } - pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes))) - C_AMF_AddProp(obj, &prop) - } + if ref&0x1 == 0 { + /* reference: 0xxx */ + // TODO(kortschak) Logging. + // refIndex := (ref >> 1) + // RTMP_Log(RTMP_LOGDEBUG, + // "%s, string reference, index: %d, not supported, ignoring!", + // __FUNCTION__, refIndex); + str.av_val = nil + str.av_len = 0 + return len + } else { + nSize := (ref >> 1) + str.av_val = (*byte)(unsafe.Pointer(data)) + str.av_len = int32(nSize) + return len + nSize } - - if bError != 0 { - return -1 - } - - return nOriginalSize - nSize + return len } // int AMFProp_Decode(C_AMFObjectProperty* prop, const char* pBuffer, int nSize, int bDecodeName); @@ -589,6 +692,193 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa return nOriginalSize - nSize } +// void AMFProp_Reset(AMFObjectProperty* prop); +// amf.c +875 +func C_AMFProp_Reset(prop *C_AMFObjectProperty) { + if prop.p_type == AMF_OBJECT || prop.p_type == AMF_ECMA_ARRAY || + prop.p_type == AMF_STRICT_ARRAY { + C_AMF_Reset(&prop.p_vu.p_object) + } else { + prop.p_vu.p_aval.av_len = 0 + prop.p_vu.p_aval.av_val = nil + } + prop.p_type = AMF_INVALID +} + +// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd); +// amf.c +891 +func C_AMF_Encode(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { + if uintptr(unsafe.Pointer(pBuffer))+uintptr(4) >= uintptr(unsafe.Pointer(pBufEnd)) { + return nil + } + + *pBuffer = AMF_OBJECT + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + + for i := 0; i < int(obj.o_num); i++ { + res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( + obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) + if res == nil { + log.Println("C_AMF_Encode: failed to encode property in index") + break + } else { + pBuffer = res + } + } + + if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 3)) >= uintptr(unsafe.Pointer(pBufEnd)) { + return nil + } + + pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, int32(AMF_OBJECT_END)) + + return pBuffer +} + +// char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd); +// amf.c +924 +func C_AMF_EncodeEcmaArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { + if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) { + return nil + } + + *pBuffer = AMF_ECMA_ARRAY + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + + pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num)) + + for i := 0; i < int(obj.o_num); i++ { + res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( + obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) + if res == nil { + log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") + break + } else { + pBuffer = res + } + } + + if int(uintptr(unsafe.Pointer(pBuffer)))+3 >= int(uintptr(unsafe.Pointer(pBufEnd))) { + return nil + } + + pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END) + + return pBuffer +} + +// char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd); +// amf.c +959 +func C_AMF_EncodeArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte { + if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) { + return nil + } + + *pBuffer = AMF_STRICT_ARRAY + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + + pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num)) + + for i := 0; i < int(obj.o_num); i++ { + res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer( + obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd) + if res == nil { + log.Println("C_AMF_EncodeEcmaArray: failed to encode property!") + break + } else { + pBuffer = res + } + } + + return pBuffer +} + +// int AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize, int nArrayLen, int bDecodeName); +// amf.c +993 +func C_AMF_DecodeArray(obj *C_AMFObject, pBuffer *byte, nSize, nArrayLen, bDecodeName int32) int32 { + nOriginalSize := nSize + var bError int32 = 0 + + obj.o_num = 0 + obj.o_props = nil + for nArrayLen > 0 { + var prop C_AMFObjectProperty + var nRes int32 + nArrayLen-- + + if nSize <= 0 { + bError = 1 + break + } + nRes = C_AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName) + if nRes == -1 { + bError = 1 + break + } else { + nSize -= nRes + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes))) + C_AMF_AddProp(obj, &prop) + } + } + if bError != 0 { + return -1 + } + + return nOriginalSize - nSize +} + +// int AMF_Decode(AMFObject *obj, const char* pBuffer, int nSize, int bDecodeName); +// amf.c +1180 +func C_AMF_Decode(obj *C_AMFObject, pBuffer *byte, nSize int32, bDecodeName int32) int32 { + var nOriginalSize int32 = nSize + var bError int32 = 0 + + obj.o_num = 0 + obj.o_props = nil + + for nSize > 0 { + var prop C_AMFObjectProperty + var nRes int32 + + if nSize >= 3 && C_AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END { + nSize -= 3 + bError = 0 + break + } + + if bError != 0 { + // TODO use new logger here + log.Println("AMF_Decode: decoding error, ignoring bytes until next known pattern!") + nSize-- + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) + continue + } + // TODO port AMFProp_Decode + nRes = int32(C_AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), + int32(nSize), int32(bDecodeName))) + // nRes = int32(C.AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), + // int32(nSize), int32(bDecodeName))) + if nRes == -1 { + bError = 1 + break + } else { + nSize -= nRes + if nSize < 0 { + bError = 1 + break + } + pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes))) + C_AMF_AddProp(obj, &prop) + } + } + + if bError != 0 { + return -1 + } + + return nOriginalSize - nSize +} + // void AMF_AddProp(AMFObject* obj, const AMFObjectProperty* prop); // amf.c + 1234 func C_AMF_AddProp(obj *C_AMFObject, prop *C_AMFObjectProperty) { @@ -604,328 +894,39 @@ func C_AMF_AddProp(obj *C_AMFObject, prop *C_AMFObjectProperty) { obj.o_num++ } -// unsigned int AMF_DeocdeInt32(const char* data); -// amf.c +59 -func C_AMF_DecodeInt32(data *byte) uint32 { - c := (*uint8)(data) - val := uint32( - int32(*c)<<24 | - int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 1)))<<16 | - int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 2)))<<8 | - int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 3)))) - return uint32(val) -} - -// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal); -// amf.c +286 -func C_AMF_EncodeNamedNumber(output *byte, outend *byte, strName *C_AVal, dVal float64) *byte { - if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) - memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) - output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) - return C_AMF_EncodeNumber(output, outend, dVal) -} - -// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal); -// amf.c +299 -func C_AMF_EncodeNamedBoolean(output *byte, outend *byte, strName *C_AVal, bVal int) *byte { - if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) - memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) - output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) - return C_AMF_EncodeBoolean(output, outend, bVal) -} - -// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name); -// amf.c +318 -func C_AMFProp_SetName(prop *C_AMFObjectProperty, name *C_AVal) { - prop.p_name = *name -} - -const ( - AMF3_INTEGER_MAX = 268435455 - AMF3_INTEGER_MIN = -268435456 -) - -// int AMF3ReadInteger(const char *data, int32_t *valp); -// amf.c +426 -// TODO test -func C_AMF3ReadInteger(data *byte, valp *int32) int32 { - var i int - var val int32 - - for i <= 2 { - /* handle first 3 bytes */ - if *indxBytePtr(unsafe.Pointer(data), i)&0x80 != 0 { - /* byte used */ - val <<= 7 /* shift up */ - val |= int32(*indxBytePtr(unsafe.Pointer(data), i) & 0x7f) /* add bits */ - i++ - } else { - break - } - } - - if i > 2 { - /* use 4th byte, all 8bits */ - val <<= 8 - val |= int32(*indxBytePtr(unsafe.Pointer(data), 3)) - - /* range check */ - if val > AMF3_INTEGER_MAX { - val -= (1 << 29) +// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex); +// amf.c + 1249 +func C_AMF_GetProp(obj *C_AMFObject, name *C_AVal, nIndex int32) *C_AMFObjectProperty { + if nIndex >= 0 { + if nIndex < int32(obj.o_num) { + return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), + int(nIndex), int(unsafe.Sizeof(*obj.o_props))))) + //return &obj.o_props[nIndex] } } else { - /* use 7bits of last unparsed byte (0xxxxxxx) */ - val <<= 7 - val |= int32(*indxBytePtr(unsafe.Pointer(data), i)) + var n int32 + for n = 0; n < int32(obj.o_num); n++ { + if C_AVMATCH(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), + int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name, name) != 0 { + return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), + int(n), int(unsafe.Sizeof(*obj.o_props))))) + } + } } - - *valp = val - - if i > 2 { - return 4 - } - return int32(i + 1) + return (*C_AMFObjectProperty)(&AMFProp_Invalid) } -// int AMF3ReadString(const char *data, AVal *str); -// amf.c +466 -func C_AMF3ReadString(data *byte, str *C_AVal) int32 { - var ref int32 - // assert elided - we will get a panic if it's nil. - - len := C_AMF3ReadInteger(data, &ref) - data = indxBytePtr(unsafe.Pointer(data), int(len)) - - if ref&0x1 == 0 { - /* reference: 0xxx */ - // TODO(kortschak) Logging. - // refIndex := (ref >> 1) - // RTMP_Log(RTMP_LOGDEBUG, - // "%s, string reference, index: %d, not supported, ignoring!", - // __FUNCTION__, refIndex); - str.av_val = nil - str.av_len = 0 - return len - } else { - nSize := (ref >> 1) - str.av_val = (*byte)(unsafe.Pointer(data)) - str.av_len = int32(nSize) - return len + nSize +// void AMF_Reset(AMFObject* obj); +// amf.c +1282 +func C_AMF_Reset(obj *C_AMFObject) { + var n int32 + for n = 0; n < int32(obj.o_num); n++ { + C_AMFProp_Reset(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), + int(n), int(unsafe.Sizeof(*obj.o_props)))))) } - return len -} - -// char* AMF_EncodeBoolean(char* output, char* outend, int bVal); -// amf.c +260 -func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal int) *byte { - if int(uintptr(unsafe.Pointer(output)))+2 > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - *(*byte)(unsafe.Pointer(output)) = AMF_BOOLEAN - output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) - val := byte(0x01) - if bVal == 0 { - val = byte(0x00) - } - *(*byte)(unsafe.Pointer(output)) = val - output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) - return output -} - -// char* AMF_EncodeNumber(char* output, char* outend, double dVal); -// amf.c +199 -func C_AMF_EncodeNumber(output *byte, outend *byte, dVal float64) *byte { - if int(uintptr(unsafe.Pointer(output)))+1+8 > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - // TODO: port this - *(*byte)(unsafe.Pointer(output)) = AMF_NUMBER - output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) - // NOTE: here we are assuming little endian for both byte order and float - // word order - var ci, co *uint8 - ci = (*uint8)(unsafe.Pointer(&dVal)) - co = (*uint8)(unsafe.Pointer(output)) - for i := 0; i < 8; i++ { - *indxBytePtr(unsafe.Pointer(co), i) = *indxBytePtr(unsafe.Pointer(ci), 7-i) - } - return (*byte)(incBytePtr(unsafe.Pointer(output), 8)) -} - -// void AMF_DecodeLongString(const char *data, AVal *bv); -// amf.c +75 -func C_AMF_DecodeLongString(data *byte, bv *C_AVal) { - bv.av_len = int32(C_AMF_DecodeInt32(data)) - if bv.av_len > 0 { - bv.av_val = (*byte)(incBytePtr(unsafe.Pointer(data), 4)) - } else { - bv.av_val = nil - } -} - -// double AMF_DecodeNumber(const char* data); -// amf.c +82 -func C_AMF_DecodeNumber(data *byte) float64 { - var dVal float64 - var ci, co *uint8 - ci = (*uint8)(unsafe.Pointer(data)) - co = (*uint8)(unsafe.Pointer(&dVal)) - for i := 0; i < 8; i++ { - *indxBytePtr(unsafe.Pointer(co), i) = *indxBytePtr(unsafe.Pointer(ci), 7-i) - } - return dVal -} - -// int AMF_DecodeBoolean(const char *data); -// amf.c +132 -func C_AMF_DecodeBoolean(data *byte) int32 { - if *data != 0 { - return 1 - } - return 0 -} - -// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue); -// amf.c +273 -func C_AMF_EncodeNamedString(output *byte, outend *byte, strName *C_AVal, strValue *C_AVal) *byte { - if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { - return nil - } - output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) - memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) - output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) - return C_AMF_EncodeString(output, outend, strValue) -} - -// void AMF_DecodeString(const char* data, C_AVal* bv); -// amf.c +68 -func C_AMF_DecodeString(data *byte, bv *C_AVal) { - dataPtr := unsafe.Pointer(data) - //bv.av_len = int32(C.AMF_DecodeInt16((*byte)(dataPtr))) - bv.av_len = int32(C_AMF_DecodeInt16((*byte)(dataPtr))) - if bv.av_len > 0 { - bv.av_val = (*byte)(incBytePtr(dataPtr, 2)) - } else { - bv.av_val = nil - } -} - -// unsigned short AMF_DecodeInt16(const char* data); -// amf.c +41 -func C_AMF_DecodeInt16(data *byte) uint16 { - c := unsafe.Pointer(data) - return uint16(*(*uint8)(c)<<8 | *(*byte)(incBytePtr(c, 1))) -} - -// char* AMF_EncodeInt24(char* output, char* outend, int nVal); -// amf.c +149 -func C_AMF_EncodeInt24(output *byte, outend *byte, nVal int32) *byte { - outputPtr := unsafe.Pointer(output) - outendPtr := unsafe.Pointer(outend) - if uintptr(outputPtr)+3 > uintptr(outendPtr) { - // length < 3 - return nil - } - // Assign output[2] - third := (*byte)(incBytePtr(outputPtr, 2)) - *third = (byte)(nVal & 0xff) - // Assign output[1] - second := (*byte)(incBytePtr(outputPtr, 1)) - *second = (byte)(nVal >> 8) - // Assign output[0] - *output = (byte)(nVal >> 16) - return (*byte)(incBytePtr(outputPtr, 3)) -} - -// unsigned int AMF_DecodeInt24(const char* data); -// amf.c +50 -func C_AMF_DecodeInt24(data *byte) uint32 { - // TODO Understand logic and simplify - c := (*uint8)(unsafe.Pointer(data)) - dst := uint32(int32(*c) << 16) - dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + - (uintptr)(int32(1))*unsafe.Sizeof(*c))))) << 8) - dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + - (uintptr)(int32(2))*unsafe.Sizeof(*c)))))) - return dst -} - -// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv); -// amf.c +174 -func C_AMF_EncodeString(output *byte, outend *byte, bv *C_AVal) *byte { - outputPtr := unsafe.Pointer(output) - outendPtr := unsafe.Pointer(outend) - if (bv.av_len < 65536 && uintptr(incBytePtr(outputPtr, 1+2+int(bv.av_len))) > - uintptr(outendPtr)) || uintptr(incBytePtr(outputPtr, 1+4+int(bv.av_len))) > - uintptr(outendPtr) { - return nil - } - if bv.av_len < 65536 { - *(*byte)(outputPtr) = AMF_STRING - outputPtr = incBytePtr(outputPtr, 1) - // TODO: port AMF_EncodeInt16 - outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), (*byte)( - outendPtr), int16(bv.av_len))) - //outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), - //(*byte)(outendPtr), (int16)(bv.av_len))) - } else { - *(*byte)(outputPtr) = AMF_LONG_STRING - outputPtr = incBytePtr(outputPtr, 1) - outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), (*byte)( - outendPtr), int32(bv.av_len))) - //outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), - //(*byte)(outendPtr), (int32)(bv.av_len))) - } - memmove(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), uintptr(bv.av_len)) - //C.memcpy(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), (C.size_t)(bv.av_len)) - outputPtr = incBytePtr(outputPtr, int(bv.av_len)) - return (*byte)(outputPtr) -} - -// char* AMF_EncodeInt16(char* output, char* outend, short nVal); -// amf.c +138 -func C_AMF_EncodeInt16(output *byte, outend *byte, nVal int16) *byte { - outputPtr := unsafe.Pointer(output) - outendPtr := unsafe.Pointer(outend) - if uintptr(outputPtr)+2 > uintptr(outendPtr) { - // length < 2 - return nil - } - // Assign output[1] - second := (*byte)(incBytePtr(outputPtr, 1)) - *second = (byte)(nVal & 0xff) - // Assign output[0] - *output = (byte)(nVal >> 8) - return (*byte)(incBytePtr(outputPtr, 2)) -} - -// char* AMF_EncodeInt32(char* output, char* outend, int nVal); -// amf.c +161 -func C_AMF_EncodeInt32(output *byte, outend *byte, nVal int32) *byte { - outputPtr := unsafe.Pointer(output) - outendPtr := unsafe.Pointer(outend) - if uintptr(outputPtr)+4 > uintptr(outendPtr) { - // length < 4 - return nil - } - // Assign output[3] - forth := (*byte)(incBytePtr(outputPtr, 3)) - *forth = (byte)(nVal & 0xff) - // Assign output[2] - third := (*byte)(incBytePtr(outputPtr, 2)) - *third = (byte)(nVal >> 8) - // Assign output[1] - second := (*byte)(incBytePtr(outputPtr, 1)) - *second = (byte)(nVal >> 16) - // Assign output[0] - *output = (byte)(nVal >> 24) - return (*byte)(incBytePtr(outputPtr, 4)) + //C.free(unsafe.Pointer(obj.o_props)) + obj.o_props = nil + obj.o_num = 0 } /* diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index aaac0d87..2cd12e22 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -1304,6 +1304,29 @@ func C_AV_erase(vals *C_RTMP_METHOD, num *int32, i, freeit int32) { int(unsafe.Sizeof(*vals))))).num = 0 } +// void AV_queue(RTMP_METHOD** vals, int* num, C_AVal* av, int txn); +// rtmp.c +2414 +func C_AV_queue(vals **C_RTMP_METHOD, num *int32, av *C_AVal, txn int32) { + if (*num & 0x0f) == 0 { + //*vals = (*C_RTMP_METHOD)(realloc(unsafe.Pointer(*vals), uint32((*num+16)* + //int32(unsafe.Sizeof(*(*vals)))))) + *vals = (*C_RTMP_METHOD)(C.realloc(unsafe.Pointer(*vals), C.size_t((*num+16)* + int32(unsafe.Sizeof(*(*vals)))))) + } + tmp := malloc(uintptr(av.av_len + 1)) + //tmp := allocate(uintptr(av.av_len + 1)) + memmove(tmp, unsafe.Pointer(av.av_val), uintptr(av.av_len)) + *indxBytePtr(tmp, int(av.av_len)) = '\000' + + (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(*vals), int(*num), + int(unsafe.Sizeof(*(*vals)))))).num = int32(txn) + (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(*vals), int(*num), + int(unsafe.Sizeof(*(*vals)))))).name.av_len = av.av_len + (*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(*vals), int(*num), + int(unsafe.Sizeof(*(*vals)))))).name.av_val = (*byte)(tmp) + (*num)++ +} + // int HandleInvoke(RTMP* r, const char* body, unsigned int nBodySize); // rtmp.c +2912 func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { From 36dfa31c48aaf66880d203cfdf1274921e67025d Mon Sep 17 00:00:00 2001 From: saxon Date: Sat, 25 Aug 2018 17:37:36 +0930 Subject: [PATCH 17/33] rtmp: fixed broken cases, removed braces from cases, added panic to unsupported types in AMFPRop_Decode --- rtmp/amf.go | 230 +++++++++++++++++++++++----------------------------- 1 file changed, 100 insertions(+), 130 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index 581b06ef..a72efecf 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -79,14 +79,18 @@ func C_AMF_DecodeInt16(data *byte) uint16 { // unsigned int AMF_DecodeInt24(const char* data); // amf.c +50 func C_AMF_DecodeInt24(data *byte) uint32 { - // TODO Understand logic and simplify - c := (*uint8)(unsafe.Pointer(data)) - dst := uint32(int32(*c) << 16) - dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + - (uintptr)(int32(1))*unsafe.Sizeof(*c))))) << 8) - dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + - (uintptr)(int32(2))*unsafe.Sizeof(*c)))))) - return dst + c := (*[3]byte)(unsafe.Pointer(data)) + return (uint32(c[0]) << 16) | (uint32(c[1]) << 8) | uint32(c[2]) + /* + // TODO Understand logic and simplify + c := (*uint8)(unsafe.Pointer(data)) + dst := uint32(int32(*c) << 16) + dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + + (uintptr)(int32(1))*unsafe.Sizeof(*c))))) << 8) + dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + + (uintptr)(int32(2))*unsafe.Sizeof(*c)))))) + return dst + */ } // unsigned int AMF_DeocdeInt32(const char* data); @@ -519,170 +523,136 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa switch prop.p_type { case AMF_NUMBER: - log.Println("1") if nSize < 8 { return -1 } prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer)) nSize -= 8 + case AMF_BOOLEAN: + panic("AMF_BOOLEAN not supported") /* - case AMF_BOOLEAN: - log.Println("2") - if nSize < 1 { - return -1 - } - prop.p_vu.p_number = float64(C_AMF_DecodeBoolean((*byte)(unsafe.Pointer(pBuffer)))) - nSize-- + if nSize < 1 { + return -1 + } + prop.p_vu.p_number = float64(C_AMF_DecodeBoolean((*byte)(unsafe.Pointer(pBuffer)))) + nSize-- */ case AMF_STRING: - { - log.Println("3") - var nStringSize = C_AMF_DecodeInt16(pBuffer) + var nStringSize = C_AMF_DecodeInt16(pBuffer) - if int64(nSize) < int64(nStringSize)+2 { - return -1 - } - C_AMF_DecodeString(pBuffer, &prop.p_vu.p_aval) - nSize -= int32(2 + nStringSize) + if int64(nSize) < int64(nStringSize)+2 { + return -1 } + C_AMF_DecodeString(pBuffer, &prop.p_vu.p_aval) + nSize -= int32(2 + nStringSize) case AMF_OBJECT: - { - log.Println("4") - var nRes int32 = int32(C_AMF_Decode(&prop.p_vu.p_object, pBuffer, nSize, 1)) - if nRes == -1 { - return -1 - } - nSize -= nRes - + var nRes int32 = int32(C_AMF_Decode(&prop.p_vu.p_object, pBuffer, nSize, 1)) + if nRes == -1 { + return -1 } + nSize -= nRes case AMF_MOVIECLIP: - { - log.Println("5") - // TODO use new logger here - log.Println("AMFProp_Decode: MAF_MOVIECLIP reserved!") - //RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!"); - return -1 + // TODO use new logger here + log.Println("AMFProp_Decode: MAF_MOVIECLIP reserved!") + //RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!"); + return -1 - } - case AMF_NULL: - log.Println("6") - case AMF_UNDEFINED: - log.Println("7") - case AMF_UNSUPPORTED: - log.Println("8") + case AMF_NULL, AMF_UNDEFINED, AMF_UNSUPPORTED: prop.p_type = AMF_NULL case AMF_REFERENCE: - { - log.Println("9") - // TODO use new logger here - log.Println("AMFProp_Decode: AMF_REFERENCE not supported!") - //RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!"); - return -1 - } + + // TODO use new logger here + log.Println("AMFProp_Decode: AMF_REFERENCE not supported!") + //RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!"); + return -1 case AMF_ECMA_ARRAY: - { - log.Println("10") + + nSize -= 4 + + // next comes the rest, mixed array has a final 0x000009 mark and names, so its an object + nRes = C_AMF_Decode(&prop.p_vu.p_object, (*byte)(incBytePtr( + unsafe.Pointer(pBuffer), 4)), nSize, 1) + if nRes == -1 { + return -1 + } + nSize -= nRes + + case AMF_OBJECT_END: + + return -1 + + case AMF_STRICT_ARRAY: + panic("AMF_STRICT_ARRAY not supported") + /* + nArrayLen := int32(C_AMF_DecodeInt32(pBuffer)) nSize -= 4 - // next comes the rest, mixed array has a final 0x000009 mark and names, so its an object - nRes = C_AMF_Decode(&prop.p_vu.p_object, (*byte)(incBytePtr( - unsafe.Pointer(pBuffer), 4)), nSize, 1) + nRes = C_AMF_DecodeArray(&prop.p_vu.p_object, (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 4)), nSize, int32(nArrayLen), FALSE) if nRes == -1 { return -1 } nSize -= nRes - } + */ - case AMF_OBJECT_END: - { - log.Println("11") - return -1 - } - /* - case AMF_STRICT_ARRAY: - { - log.Println("12") - nArrayLen := int32(C_AMF_DecodeInt32(pBuffer)) - nSize -= 4 + case AMF_DATE: + panic("AMF_DATE not supported") - nRes = C_AMF_DecodeArray(&prop.p_vu.p_object, (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 4)), nSize, int32(nArrayLen), FALSE) - if nRes == -1 { - return -1 - } - nSize -= nRes + /* + // TODO use new logger here + //RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE"); + + if nSize < 10 { + return -1 } - */ - /* - case AMF_DATE: - { - log.Println("13") - // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE"); - if nSize < 10 { - return -1 - } + prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer)) + prop.p_UTCoffset = C.int16_t(C_AMF_DecodeInt16((*byte)(incBytePtr(unsafe.Pointer(pBuffer), 8)))) - prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer)) - prop.p_UTCoffset = C.int16_t(C_AMF_DecodeInt16((*byte)(incBytePtr(unsafe.Pointer(pBuffer), 8)))) - - nSize -= 10 + nSize -= 10 + */ + case AMF_LONG_STRING, AMF_XML_DOC: + panic("AMF_LONG_STRING, AMF_XML_DOC not supported") + /* + var nStringSize uint32 = C_AMF_DecodeInt32(pBuffer) + if int64(nSize) < int64(nStringSize)+4 { + return -1 } - */ - case AMF_LONG_STRING: - log.Println("14") - /* - case AMF_XML_DOC: - { - log.Println("15") - var nStringSize uint32 = C_AMF_DecodeInt32(pBuffer) - if int64(nSize) < int64(nStringSize)+4 { - return -1 - } - C_AMF_DecodeLongString(pBuffer, &prop.p_vu.p_aval) - nSize -= int32(4 + nStringSize) - if prop.p_type == AMF_LONG_STRING { - prop.p_type = AMF_STRING - } + C_AMF_DecodeLongString(pBuffer, &prop.p_vu.p_aval) + nSize -= int32(4 + nStringSize) + if prop.p_type == AMF_LONG_STRING { + prop.p_type = AMF_STRING } - */ + */ case AMF_RECORDSET: - { - log.Println("16") - // TODO use new logger here - log.Println("AMFProp_Decode: AMF_RECORDSET reserved!") - //RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!"); - return -1 + // TODO use new logger here + log.Println("AMFProp_Decode: AMF_RECORDSET reserved!") + //RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!"); + return -1 - } case AMF_TYPED_OBJECT: - { - log.Println("17") - // TODO use new logger here - // RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!") - return -1 - } - /* - case AMF_AVMPLUS: - { - log.Println("18") - nRes := int32(C.AMF3_Decode(&prop.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), int32(nSize), 1)) - if nRes == -1 { - return -1 - } - nSize -= nRes - prop.p_type = AMF_OBJECT + // TODO use new logger here + // RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!") + return -1 + + case AMF_AVMPLUS: + panic("AMF_AVMPLUS not supported") + /* + log.Println("18") + nRes := int32(C.AMF3_Decode(&prop.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), int32(nSize), 1)) + if nRes == -1 { + return -1 } - */ + nSize -= nRes + prop.p_type = AMF_OBJECT + */ default: - log.Println("19") // TODO use new logger here //RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__, //prop.p_type, pBuffer - 1); From a08c29ce817970e1a8fd4d671819073576d4ed02 Mon Sep 17 00:00:00 2001 From: saxon Date: Sat, 25 Aug 2018 22:27:20 +0930 Subject: [PATCH 18/33] rtmp: moved C_AVMATCH and C_AVC into amf_headers.go - consistent with C structure --- rtmp/amf_headers.go | 28 ++++++++++++++++++++++++++++ rtmp/rtmp.go | 24 ------------------------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/rtmp/amf_headers.go b/rtmp/amf_headers.go index 7ad0fc6b..02e5343b 100644 --- a/rtmp/amf_headers.go +++ b/rtmp/amf_headers.go @@ -31,6 +31,10 @@ LICENSE */ package rtmp +import ( + "unsafe" +) + const ( AMF_NUMBER = iota AMF_BOOLEAN @@ -64,6 +68,30 @@ type C_AVal struct { av_len int32 } +// C_AVal is in amf.h +// amf.h +62 +func AVC(str string) C_AVal { + var aval C_AVal + if len(str) != 0 { + aval.av_val = &([]byte(str)[0]) + } else { + aval.av_val = nil + } + aval.av_len = int32(len(str)) + return aval +} + +// #define AVMATCH(a1,a2) +// amf.h +63 +func C_AVMATCH(a1, a2 *C_AVal) int32 { + if a1.av_len == a2.av_len && memcmp(unsafe.Pointer(a1.av_val), + unsafe.Pointer(a2.av_val), int(a1.av_len)) == 0 { + return 1 + } else { + return 0 + } +} + // typedef struct AMF_Object // amf.h +67 type C_AMFObject struct { diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 2cd12e22..6be90ce2 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -200,17 +200,6 @@ func endSession(rtmp *C_RTMP) uint32 { return 0 } -// #define AVMATCH(a1,a2) -// amf.h +63 -func C_AVMATCH(a1, a2 *C_AVal) int32 { - if a1.av_len == a2.av_len && memcmp(unsafe.Pointer(a1.av_val), - unsafe.Pointer(a2.av_val), int(a1.av_len)) == 0 { - return 1 - } else { - return 0 - } -} - // #define RTMPPacket_IsReady(a) // rtmp.h +142 func C_RTMPPacket_IsReady(p *C_RTMPPacket) int { @@ -2589,19 +2578,6 @@ func ptrToSlice(data unsafe.Pointer, size int) []byte { return ret } -// C_AVal is in amf.h -// See AVC(str) {str, sizeof(str)-1} in amf.h -func AVC(str string) C_AVal { - var aval C_AVal - if len(str) != 0 { - aval.av_val = &([]byte(str)[0]) - } else { - aval.av_val = nil - } - aval.av_len = int32(len(str)) - return aval -} - var rtmpErrs = [...]string{ 1: "rtmp: not connected", 2: "rtmp: write error", From 0ed5d4bc72c99fb2d89935c6aa5e7705e5c9e283 Mon Sep 17 00:00:00 2001 From: saxon Date: Sat, 25 Aug 2018 22:28:59 +0930 Subject: [PATCH 19/33] rtmp: put C_RTMPPacket_IsReady in rtmp_headers.go - consistent with C librtmp structure --- rtmp/rtmp.go | 9 --------- rtmp/rtmp_headers.go | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 6be90ce2..7f0669fb 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -200,15 +200,6 @@ func endSession(rtmp *C_RTMP) uint32 { return 0 } -// #define RTMPPacket_IsReady(a) -// rtmp.h +142 -func C_RTMPPacket_IsReady(p *C_RTMPPacket) int { - if p.m_nBytesRead == p.m_nBodySize { - return 1 - } - return 0 -} - // uint32_t RTMP_GetTime(); // rtmp.c +156 func C_RTMP_GetTime() int32 { diff --git a/rtmp/rtmp_headers.go b/rtmp/rtmp_headers.go index cbd3230d..b20268ec 100644 --- a/rtmp/rtmp_headers.go +++ b/rtmp/rtmp_headers.go @@ -133,6 +133,15 @@ type C_RTMPSockBuf struct { sb_ssl uintptr } +// #define RTMPPacket_IsReady(a) +// rtmp.h +142 +func C_RTMPPacket_IsReady(p *C_RTMPPacket) int { + if p.m_nBytesRead == p.m_nBodySize { + return 1 + } + return 0 +} + // typedef struct RTMP_LNK // rtmp.h +144 type C_RTMP_LNK struct { From 77393a1de7a44f5f4df55e0b7998b0075e4bc3fa Mon Sep 17 00:00:00 2001 From: saxon Date: Sat, 25 Aug 2018 22:32:24 +0930 Subject: [PATCH 20/33] rtmp: simplified C_RTMP_Alloc and zeroed C_RTMP object in C_RTMP_Init --- rtmp/rtmp.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 7f0669fb..523bf36e 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -239,14 +239,14 @@ func C_RTMPPacket_Free(p *C_RTMPPacket) { // RTMP* RTMP_IsConnected(); // rtmp.c +317 func C_RTMP_Alloc() *C_RTMP { - var r C_RTMP - return (*C_RTMP)(malloc(uintptr(unsafe.Sizeof(r)))) + return &C_RTMP{} //return (*C_RTMP)(allocate(unsafe.Sizeof(r))) } // void RTMP_Init(RTMP *r); // rtmp.c +329 func C_RTMP_Init(r *C_RTMP) { + *r = C_RTMP{} r.m_sb.sb_socket = -1 r.m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE r.m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE From 6c84506af22efcb24b2bb09f84e5182804906405 Mon Sep 17 00:00:00 2001 From: saxon Date: Sat, 25 Aug 2018 23:22:22 +0930 Subject: [PATCH 21/33] rtmp: dealt with unsupported cases in C_RTMP_ClientPacket --- rtmp/rtmp.go | 176 ++++++++++++++++++++++++++------------------------- 1 file changed, 90 insertions(+), 86 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 523bf36e..bea19140 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -662,76 +662,80 @@ func C_RTMP_ClientPacket(r *C_RTMP, packet *C_RTMPPacket) int32 { switch packet.m_packetType { case RTMP_PACKET_TYPE_CHUNK_SIZE: - log.Println("RTMP_PACKET_TYPE_CHUNK_SIZE") // TODO: port this //C.HandleChangeChunkSize(r, packet) C_HandleChangeChunkSize(r, packet) - /* - case RTMP_PACKET_TYPE_BYTES_READ_REPORT: - log.Println("RTMP_PACKET_TYPE_BYTES_READ_REPORT") - // TODO: usue new logger here - //RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__); - case RTMP_PACKET_TYPE_CONTROL: - log.Println("RTMP_PACKET_TYPE_CONTROL") - // TODO: port this - C.HandleCtrl(r, packet) + case RTMP_PACKET_TYPE_BYTES_READ_REPORT: + // TODO: usue new logger here + //RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__); + + case RTMP_PACKET_TYPE_CONTROL: + panic("Unsupported packet type RTMP_PACKET_TYPE_CONTROL") + /* + log.Println("RTMP_PACKET_TYPE_CONTROL") + // TODO: port this + C.HandleCtrl(r, packet) */ case RTMP_PACKET_TYPE_SERVER_BW: - log.Println("RTMP_PACKET_TYPE_SERVER_BW") // TODO: port this //C.HandleServerBW(r, packet) C_HandlServerBW(r, packet) case RTMP_PACKET_TYPE_CLIENT_BW: - log.Println("RTMP_PACKET_TYPE_CLIENT_BW") // TODO: port this //C.HandleClientBW(r, packet) C_HandleClientBW(r, packet) + + case RTMP_PACKET_TYPE_AUDIO: + panic("Unsupported packet type RTMP_PACKET_TYPE_AUDIO") /* - case RTMP_PACKET_TYPE_AUDIO: - log.Println("RTMP_PACKET_TYPE_AUDIO") - // TODO port this - //C.HandleAudio(r, packet) NOTE this does nothing - bHasMediaPacket = 1 - if r.m_mediaChannel == 0 { - r.m_mediaChannel = packet.m_nChannel - } + // TODO port this + //C.HandleAudio(r, packet) NOTE this does nothing + bHasMediaPacket = 1 + if r.m_mediaChannel == 0 { + r.m_mediaChannel = packet.m_nChannel + } - if r.m_pausing == 0 { - r.m_mediaStamp = packet.m_nTimeStamp - } + if r.m_pausing == 0 { + r.m_mediaStamp = packet.m_nTimeStamp + } + */ - case RTMP_PACKET_TYPE_VIDEO: - log.Println("RTMP_PACKET_TYPE_VIDEO:") - // TODO port this - // C.HandleVideo(r, packet) NOTE this does nothing - bHasMediaPacket = 1 - if r.m_mediaChannel == 0 { - r.m_mediaChannel = packet.m_nChannel - } - if r.m_pausing == 0 { - r.m_mediaStamp = packet.m_nTimeStamp - } - - case RTMP_PACKET_TYPE_FLEX_MESSAGE: - log.Println("RTMP_PACKET_TYPE_FLEX_MESSAGE:") - { - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG,"%s, flex message, size %u bytes, not fully supported", __FUNCTION__, packet.m_nBodySize); - - if C.HandleInvoke(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), 1)), - C.uint(packet.m_nBodySize-1)) == 1 { - bHasMediaPacket = 2 - } - } - case RTMP_PACKET_TYPE_INFO: - log.Println(" RTMP_PACKET_TYPE_INFO:") + case RTMP_PACKET_TYPE_VIDEO: + panic("Unsupported packet type RTMP_PACKET_TYPE_VIDEO") + /* + // TODO port this + // C.HandleVideo(r, packet) NOTE this does nothing + bHasMediaPacket = 1 + if r.m_mediaChannel == 0 { + r.m_mediaChannel = packet.m_nChannel + } + if r.m_pausing == 0 { + r.m_mediaStamp = packet.m_nTimeStamp + } + */ + case RTMP_PACKET_TYPE_FLEX_MESSAGE: + panic("Unsupported packet type RTMP_PACKET_TYPE_FLEX_MESSAGE") + /* + { // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,packet.m_nBodySize); - if C.HandleMetadata(r, packet.m_body, C.uint(packet.m_nBodySize)) != 0 { - bHasMediaPacket = 1 + // RTMP_Log(RTMP_LOGDEBUG,"%s, flex message, size %u bytes, not fully supported", __FUNCTION__, packet.m_nBodySize); + + if C.HandleInvoke(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), 1)), + C.uint(packet.m_nBodySize-1)) == 1 { + bHasMediaPacket = 2 } + } + */ + case RTMP_PACKET_TYPE_INFO: + panic("Unsupported packet type RTMP_PACKET_TYPE_INFO") + /* + // TODO use new logger here + //RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,packet.m_nBodySize); + if C.HandleMetadata(r, packet.m_body, C.uint(packet.m_nBodySize)) != 0 { + bHasMediaPacket = 1 + } */ case RTMP_PACKET_TYPE_INVOKE: @@ -744,48 +748,48 @@ func C_RTMP_ClientPacket(r *C_RTMP, packet *C_RTMPPacket) int32 { log.Println("HasMediaPacket") bHasMediaPacket = 2 } + + case RTMP_PACKET_TYPE_FLASH_VIDEO: + panic("Unsupported packet type RTMP_PACKET_TYPE_FLASH_VIDEO") /* - case RTMP_PACKET_TYPE_FLASH_VIDEO: - log.Println("RTMP_PACKET_TYPE_FLASH_VIDEO:") - { - var pos uint32 = 0 - var nTimeStamp uint32 = uint32(packet.m_nTimeStamp) + { + var pos uint32 = 0 + var nTimeStamp uint32 = uint32(packet.m_nTimeStamp) - for pos+11 < uint32(packet.m_nBodySize) { - var dataSize uint32 = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( - packet.m_body), int(pos+1)))) + for pos+11 < uint32(packet.m_nBodySize) { + var dataSize uint32 = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( + packet.m_body), int(pos+1)))) - if pos+11+dataSize+4 > uint32(packet.m_nBodySize) { - // TODO use new logger here - // RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!"); - break - } - - switch { - case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 0x12: - C.HandleMetadata(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), - int(pos+11))), C.uint(dataSize)) - case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 8 || - *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 9: - nTimeStamp = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( - packet.m_body), int(pos+4)))) - nTimeStamp |= uint32(*indxBytePtr(unsafe.Pointer(packet.m_body), - int(pos+7)) << 24) - } - pos += (11 + dataSize + 4) - } - if r.m_pausing == 0 { - r.m_mediaStamp = uint32(nTimeStamp) + if pos+11+dataSize+4 > uint32(packet.m_nBodySize) { + // TODO use new logger here + // RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!"); + break } - bHasMediaPacket = 1 - + switch { + case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 0x12: + C.HandleMetadata(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), + int(pos+11))), C.uint(dataSize)) + case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 8 || + *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 9: + nTimeStamp = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( + packet.m_body), int(pos+4)))) + nTimeStamp |= uint32(*indxBytePtr(unsafe.Pointer(packet.m_body), + int(pos+7)) << 24) + } + pos += (11 + dataSize + 4) } - default: - log.Println("DEFAULT") - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,packet.m_packetType); + if r.m_pausing == 0 { + r.m_mediaStamp = uint32(nTimeStamp) + } + + bHasMediaPacket = 1 + + } */ + default: + // TODO use new logger here + // RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,packet.m_packetType); } return bHasMediaPacket } From ba9ce9b37f2b1a30839c1ea0097f3723eb1076a1 Mon Sep 17 00:00:00 2001 From: saxon Date: Sat, 25 Aug 2018 23:29:40 +0930 Subject: [PATCH 22/33] rtmp: created rtmp_sys.go file to emulate rtmp_sys.c in c librtmp library and moved SET_RCVTIMEO there --- rtmp/rtmp.go | 5 ----- rtmp/rtmp_sys.go | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 rtmp/rtmp_sys.go diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index bea19140..728deaed 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -149,11 +149,6 @@ var ( } ) -// TODO: find location in c file -func SET_RCVTIMEO(tv *int32, s int32) { - *tv = s * 1000 -} - func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { connect_timeout := int32(timeout) rtmp = C_RTMP_Alloc() diff --git a/rtmp/rtmp_sys.go b/rtmp/rtmp_sys.go new file mode 100644 index 00000000..13fdc361 --- /dev/null +++ b/rtmp/rtmp_sys.go @@ -0,0 +1,7 @@ +package rtmp + +// #define SET_RCVTIMEO(tv,s) int tv = s*1000 +// rtmp_sys.h +43 +func SET_RCVTIMEO(tv *int32, s int32) { + *tv = s * 1000 +} From 7e6b2ee0b2ab366a5413add05c28c385e839b80a Mon Sep 17 00:00:00 2001 From: saxon Date: Sat, 25 Aug 2018 23:49:54 +0930 Subject: [PATCH 23/33] rtmp: uncommented usage of C_RTMP_Close - created todos in C_CloseInternal --- rtmp/rtmp.go | 154 ++++++++++++++++++++++++++------------------------- 1 file changed, 80 insertions(+), 74 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 728deaed..7391d5c9 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -158,7 +158,7 @@ func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { rtmp.Link.timeout = connect_timeout if C_RTMP_SetupURL(rtmp, u) == 0 { // if C.RTMP_SetupURL(rtmp, C.CString(u)) == 0 { - //C.RTMP_Close(rtmp) + C_RTMP_Close(rtmp) //C.RTMP_Free(rtmp) return nil, errors.New("rtmp startSession: Failed to setup URL!") } @@ -169,7 +169,7 @@ func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { //C.RTMP_SetBufferMS(rtmp, 3600*1000) if C_RTMP_Connect(rtmp, nil) == 0 { //if C.RTMP_Connect(rtmp, nil) == 0 { - //C.RTMP_Close(rtmp) + C_RTMP_Close(rtmp) //C.RTMP_Free(rtmp) return nil, errors.New("rtmp startSession: Failed to connect!") } @@ -177,7 +177,7 @@ func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { // TODO: port this if C_RTMP_ConnectStream(rtmp, 0) == 0 { //if C.RTMP_ConnectStream(rtmp, 0) == 0 { - //C.RTMP_Close(rtmp) + C_RTMP_Close(rtmp) //C.RTMP_Free(rtmp) return nil, errors.New("rtmp startSession: Failed to connect stream!") } @@ -190,7 +190,7 @@ func endSession(rtmp *C_RTMP) uint32 { return 3 } - //C.RTMP_Close(rtmp) + C_RTMP_Close(rtmp) //C.RTMP_Free(rtmp) return 0 } @@ -382,89 +382,95 @@ func C_RTMP_SetupURL(r *C_RTMP, u string) int32 { return 1 } -/* -func rtmpClose(r *C_RTMP) { - closeInternal(r, 0) +func C_RTMP_Close(r *C_RTMP) { + C_CloseInternal(r, 0) } -func closeInternal(r *C_RTMP, reconnect int32) { - var i int32 +func C_CloseInternal(r *C_RTMP, reconnect int32) { + // TODO: port SendFCUnpublish + // TODO: port SendDeleteStream + // TODO: port RTMPSockBuf_Close + // TODO: port AV_Clear + /* + var i int32 - if C_RTMP_IsConnected(r) != 0 { - if r.m_stream_id > 0 { - i = int32(r.m_stream_id) - if r.Link.protocol&RTMP_FEATURE_WRITE != 0 { - C.SendFCUnpublish(r) + if C_RTMP_IsConnected(r) != 0 { + if r.m_stream_id > 0 { + i = int32(r.m_stream_id) + if r.Link.protocol&RTMP_FEATURE_WRITE != 0 { + C.SendFCUnpublish(r) + } + C.SendDeleteStream(r, float64(i)) } - C.SendDeleteStream(r, float64(i)) + C.RTMPSockBuf_Close(&r.m_sb) } - C.RTMPSockBuf_Close(&r.m_sb) - } - r.m_stream_id = -1 - r.m_sb.sb_socket = -1 - r.m_nBWCheckCounter = 0 - r.m_nBytesIn = 0 - r.m_nBytesInSent = 0 + r.m_stream_id = -1 + r.m_sb.sb_socket = -1 + r.m_nBWCheckCounter = 0 + r.m_nBytesIn = 0 + r.m_nBytesInSent = 0 - if r.m_read.flags&RTMP_READ_HEADER != 0 { - //C.free(unsafe.Pointer(r.m_read.buf)) - r.m_read.buf = nil - } - - r.m_read.dataType = 0 - r.m_read.flags = 0 - r.m_read.status = 0 - r.m_read.nResumeTS = 0 - r.m_read.nIgnoredFrameCounter = 0 - r.m_read.nIgnoredFlvFrameCounter = 0 - - r.m_write.m_nBytesRead = 0 - C.RTMPPacket_Free(&r.m_write) - - for i := 0; i < int(r.m_channelsAllocatedIn); i++ { - if *(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), i, - int(unsafe.Sizeof(&r.m_write)))) != nil { - - C.RTMPPacket_Free(*(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), i, - int(unsafe.Sizeof(&r.m_write))))) - - //C.free(unsafe.Pointer(*(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), - i, int(unsafe.Sizeof(&r.m_write)))))) - - *(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), - i, int(unsafe.Sizeof(&r.m_write)))) = nil + if r.m_read.flags&RTMP_READ_HEADER != 0 { + //C.free(unsafe.Pointer(r.m_read.buf)) + r.m_read.buf = nil } - } - //C.free(unsafe.Pointer(r.m_vecChannelsOut)) - r.m_vecChannelsOut = nil - r.m_channelsAllocatedOut = 0 - C.AV_clear(r.m_methodCalls, r.m_numCalls) + r.m_read.dataType = 0 + r.m_read.flags = 0 + r.m_read.status = 0 + r.m_read.nResumeTS = 0 + r.m_read.nIgnoredFrameCounter = 0 + r.m_read.nIgnoredFlvFrameCounter = 0 - r.m_methodCalls = nil - r.m_numCalls = 0 - r.m_numInvokes = 0 + r.m_write.m_nBytesRead = 0 + C.RTMPPacket_Free(&r.m_write) - r.m_bPlaying = C.uchar(0) - r.m_sb.sb_size = 0 + // NOTE: C frees - not using in our case + for i := 0; i < int(r.m_channelsAllocatedIn); i++ { + if *(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), i, + int(unsafe.Sizeof(&r.m_write)))) != nil { - r.m_msgCounter = 0 - r.m_resplen = 0 - r.m_unackd = 0 + //C.RTMPPacket_Free(*(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), i, + //int(unsafe.Sizeof(&r.m_write))))) - if ((r.Link.lFlags & RTMP_LF_FTCU) != 0) && (reconnect == 0) { - //C.free(unsafe.Pointer(r.Link.app.av_val)) - r.Link.app.av_val = nil - r.Link.lFlags ^= RTMP_LF_FAPU - } + //C.free(unsafe.Pointer(*(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), + //i, int(unsafe.Sizeof(&r.m_write)))))) - if reconnect == 0 { - //C.free(unsafe.Pointer(r.Link.playpath0.av_val)) - r.Link.playpath0.av_val = nil - } + *(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), + i, int(unsafe.Sizeof(&r.m_write)))) = nil + } + } + + + //C.free(unsafe.Pointer(r.m_vecChannelsOut)) + r.m_vecChannelsOut = nil + r.m_channelsAllocatedOut = 0 + C.AV_clear(r.m_methodCalls, r.m_numCalls) + + r.m_methodCalls = nil + r.m_numCalls = 0 + r.m_numInvokes = 0 + + r.m_bPlaying = C.uchar(0) + r.m_sb.sb_size = 0 + + r.m_msgCounter = 0 + r.m_resplen = 0 + r.m_unackd = 0 + + if ((r.Link.lFlags & RTMP_LF_FTCU) != 0) && (reconnect == 0) { + //C.free(unsafe.Pointer(r.Link.app.av_val)) + r.Link.app.av_val = nil + r.Link.lFlags ^= RTMP_LF_FAPU + } + + if reconnect == 0 { + //C.free(unsafe.Pointer(r.Link.playpath0.av_val)) + r.Link.playpath0.av_val = nil + } + */ } -*/ // int RTMP_Connect0(RTMP *r, struct sockaddr* service); // rtmp.c +906 @@ -839,7 +845,7 @@ func C_ReadN(r *C_RTMP, buffer *byte, n int) int { if nBytes == 0 { log.Println("RTMP socket closed by peer") - // C.RTMP_Close(r) + C_RTMP_Close(r) break } @@ -865,7 +871,7 @@ func C_WriteN(r *C_RTMP, buffer unsafe.Pointer, n int) int { } // TODO: port this - //C.RTMP_Close(r) + C_RTMP_Close(r) n = 1 break } From 9b67dc1ef0333f3d5f0f212f264d482e22ff9d0d Mon Sep 17 00:00:00 2001 From: saxon Date: Sun, 26 Aug 2018 00:13:08 +0930 Subject: [PATCH 24/33] rtmp: added comments above C_RTMP_Close and C_CloseInternal to indicate location in C library, and reordered to better resemble C library --- rtmp/rtmp.go | 192 +++++++++++++++++++++++++++------------------------ 1 file changed, 102 insertions(+), 90 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 7391d5c9..1ca37a46 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -382,96 +382,6 @@ func C_RTMP_SetupURL(r *C_RTMP, u string) int32 { return 1 } -func C_RTMP_Close(r *C_RTMP) { - C_CloseInternal(r, 0) -} - -func C_CloseInternal(r *C_RTMP, reconnect int32) { - // TODO: port SendFCUnpublish - // TODO: port SendDeleteStream - // TODO: port RTMPSockBuf_Close - // TODO: port AV_Clear - /* - var i int32 - - if C_RTMP_IsConnected(r) != 0 { - if r.m_stream_id > 0 { - i = int32(r.m_stream_id) - if r.Link.protocol&RTMP_FEATURE_WRITE != 0 { - C.SendFCUnpublish(r) - } - C.SendDeleteStream(r, float64(i)) - } - C.RTMPSockBuf_Close(&r.m_sb) - } - - r.m_stream_id = -1 - r.m_sb.sb_socket = -1 - r.m_nBWCheckCounter = 0 - r.m_nBytesIn = 0 - r.m_nBytesInSent = 0 - - if r.m_read.flags&RTMP_READ_HEADER != 0 { - //C.free(unsafe.Pointer(r.m_read.buf)) - r.m_read.buf = nil - } - - r.m_read.dataType = 0 - r.m_read.flags = 0 - r.m_read.status = 0 - r.m_read.nResumeTS = 0 - r.m_read.nIgnoredFrameCounter = 0 - r.m_read.nIgnoredFlvFrameCounter = 0 - - r.m_write.m_nBytesRead = 0 - C.RTMPPacket_Free(&r.m_write) - - // NOTE: C frees - not using in our case - for i := 0; i < int(r.m_channelsAllocatedIn); i++ { - if *(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), i, - int(unsafe.Sizeof(&r.m_write)))) != nil { - - //C.RTMPPacket_Free(*(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), i, - //int(unsafe.Sizeof(&r.m_write))))) - - //C.free(unsafe.Pointer(*(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), - //i, int(unsafe.Sizeof(&r.m_write)))))) - - *(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), - i, int(unsafe.Sizeof(&r.m_write)))) = nil - } - } - - - //C.free(unsafe.Pointer(r.m_vecChannelsOut)) - r.m_vecChannelsOut = nil - r.m_channelsAllocatedOut = 0 - C.AV_clear(r.m_methodCalls, r.m_numCalls) - - r.m_methodCalls = nil - r.m_numCalls = 0 - r.m_numInvokes = 0 - - r.m_bPlaying = C.uchar(0) - r.m_sb.sb_size = 0 - - r.m_msgCounter = 0 - r.m_resplen = 0 - r.m_unackd = 0 - - if ((r.Link.lFlags & RTMP_LF_FTCU) != 0) && (reconnect == 0) { - //C.free(unsafe.Pointer(r.Link.app.av_val)) - r.Link.app.av_val = nil - r.Link.lFlags ^= RTMP_LF_FAPU - } - - if reconnect == 0 { - //C.free(unsafe.Pointer(r.Link.playpath0.av_val)) - r.Link.playpath0.av_val = nil - } - */ -} - // int RTMP_Connect0(RTMP *r, struct sockaddr* service); // rtmp.c +906 func C_RTMP_Connect0(r *C_RTMP, service *C.sockaddr) int { @@ -1169,6 +1079,14 @@ func C_SendFCPublish(r *C_RTMP) int32 { return int32(C_RTMP_SendPacket(r, &packet, 0)) } +// int SendFCUnpublish(RTMP *r); +// rtmp.c +1875 +func C_SendFCUnpublish(r *C_RTMP) int32 { + /* + */ + return 0 +} + // int SendPublish(RTMP* r); // rtmp.c +1908 func C_SendPublish(r *C_RTMP) int32 { @@ -2208,6 +2126,100 @@ func C_RTMP_SendPacket(r *C_RTMP, packet *C_RTMPPacket, queue int) int { return 1 } +// void RTMP_Close(RTMP *r); +// rtmp.c +4168 +func C_RTMP_Close(r *C_RTMP) { + C_CloseInternal(r, 0) +} + +// static void CloseInternal(RTMP *r, int reconnect); +// rtmp.c +4175 +func C_CloseInternal(r *C_RTMP, reconnect int32) { + // TODO: port SendFCUnpublish + // TODO: port SendDeleteStream + // TODO: port RTMPSockBuf_Close + // TODO: port AV_Clear + /* + var i int32 + + if C_RTMP_IsConnected(r) != 0 { + if r.m_stream_id > 0 { + i = int32(r.m_stream_id) + if r.Link.protocol&RTMP_FEATURE_WRITE != 0 { + C.SendFCUnpublish(r) + } + C.SendDeleteStream(r, float64(i)) + } + C.RTMPSockBuf_Close(&r.m_sb) + } + + r.m_stream_id = -1 + r.m_sb.sb_socket = -1 + r.m_nBWCheckCounter = 0 + r.m_nBytesIn = 0 + r.m_nBytesInSent = 0 + + if r.m_read.flags&RTMP_READ_HEADER != 0 { + //C.free(unsafe.Pointer(r.m_read.buf)) + r.m_read.buf = nil + } + + r.m_read.dataType = 0 + r.m_read.flags = 0 + r.m_read.status = 0 + r.m_read.nResumeTS = 0 + r.m_read.nIgnoredFrameCounter = 0 + r.m_read.nIgnoredFlvFrameCounter = 0 + + r.m_write.m_nBytesRead = 0 + C.RTMPPacket_Free(&r.m_write) + + // NOTE: C frees - not using in our case + for i := 0; i < int(r.m_channelsAllocatedIn); i++ { + if *(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), i, + int(unsafe.Sizeof(&r.m_write)))) != nil { + + //C.RTMPPacket_Free(*(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), i, + //int(unsafe.Sizeof(&r.m_write))))) + + //C.free(unsafe.Pointer(*(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), + //i, int(unsafe.Sizeof(&r.m_write)))))) + + *(**C_RTMPPacket)(incPtr(unsafe.Pointer(r.m_vecChannelsIn), + i, int(unsafe.Sizeof(&r.m_write)))) = nil + } + } + + + //C.free(unsafe.Pointer(r.m_vecChannelsOut)) + r.m_vecChannelsOut = nil + r.m_channelsAllocatedOut = 0 + C.AV_clear(r.m_methodCalls, r.m_numCalls) + + r.m_methodCalls = nil + r.m_numCalls = 0 + r.m_numInvokes = 0 + + r.m_bPlaying = C.uchar(0) + r.m_sb.sb_size = 0 + + r.m_msgCounter = 0 + r.m_resplen = 0 + r.m_unackd = 0 + + if ((r.Link.lFlags & RTMP_LF_FTCU) != 0) && (reconnect == 0) { + //C.free(unsafe.Pointer(r.Link.app.av_val)) + r.Link.app.av_val = nil + r.Link.lFlags ^= RTMP_LF_FAPU + } + + if reconnect == 0 { + //C.free(unsafe.Pointer(r.Link.playpath0.av_val)) + r.Link.playpath0.av_val = nil + } + */ +} + // int RTMPSockBuf_Fill(RTMPSockBuf* sb); // rtmp.c +4253 func C_RTMPSockBuf_Fill(sb *C_RTMPSockBuf) int { From 93849271131fed366ee1f2b0c3c154e28e165a83 Mon Sep 17 00:00:00 2001 From: saxon Date: Sun, 26 Aug 2018 00:18:28 +0930 Subject: [PATCH 25/33] rtmp: start porting C_SendFCUnpublish --- rtmp/rtmp.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 1ca37a46..62cfae1d 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -1082,8 +1082,12 @@ func C_SendFCPublish(r *C_RTMP) int32 { // int SendFCUnpublish(RTMP *r); // rtmp.c +1875 func C_SendFCUnpublish(r *C_RTMP) int32 { + // TODO finish porting /* - */ + var packet C_RTMPPacket + var pbuf [1024]byte + var pend []byte = + */ return 0 } From b846dbf2d7f7f1b689b143eec05cb2c9fb822e51 Mon Sep 17 00:00:00 2001 From: saxon Date: Sun, 26 Aug 2018 00:27:38 +0930 Subject: [PATCH 26/33] rtmp: continued to port C_SendFCUnpublish - paused - need to work out best way to get rid of unsafe pointers --- rtmp/rtmp.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 62cfae1d..f4c280ca 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -1086,7 +1086,31 @@ func C_SendFCUnpublish(r *C_RTMP) int32 { /* var packet C_RTMPPacket var pbuf [1024]byte - var pend []byte = + var pend []byte = pbuf[1024:] + var enc []byte + + packet.m_nChannel = 0x03 + packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM + packet.m_packetType = RTMP_PACKET_TYPE_INVOKE + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = 0 + packet.m_hasAbsTimestamp = 0 + packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE + + // NOTE use of unsafe pointer will be remove here when packet.m_nBody becomes []byte + enc = []byte(unsafe.Pointer(packet.m_nBody)) + enc = C_AMF_EncodeString((*byte)(unsafe.Pointer(&enc[0])), + (*byte)(unsafe.Pointer(&pend[0])), &av_FCUnpublish) + r.m_numInvokes++ + enc = C_AMF_EncodeNumber(enc, pend, r->m_numInvokes); + *enc++ = AMF_NULL; + enc = AMF_EncodeString(enc, pend, &r->Link.playpath); + if (!enc) + return FALSE; + + packet.m_nBodySize = enc - packet.m_body; + + return RTMP_SendPacket(r, &packet, FALSE); */ return 0 } From bd630fd893770e5f64567ebf59cd9175ef5a1e68 Mon Sep 17 00:00:00 2001 From: saxon Date: Sun, 26 Aug 2018 14:33:34 +0930 Subject: [PATCH 27/33] rtmp: added all consts/flags from C library --- rtmp/rtmp_headers.go | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/rtmp/rtmp_headers.go b/rtmp/rtmp_headers.go index b20268ec..a45afd69 100644 --- a/rtmp/rtmp_headers.go +++ b/rtmp/rtmp_headers.go @@ -39,17 +39,19 @@ const ( ) const ( - RTMP_PACKET_TYPE_CHUNK_SIZE = 0x01 - RTMP_PACKET_TYPE_BYTES_READ_REPORT = 0x03 - RTMP_PACKET_TYPE_CONTROL = 0x04 - RTMP_PACKET_TYPE_SERVER_BW = 0x05 - RTMP_PACKET_TYPE_CLIENT_BW = 0x06 - RTMP_PACKET_TYPE_AUDIO = 0x08 - RTMP_PACKET_TYPE_VIDEO = 0x09 - RTMP_PACKET_TYPE_FLEX_MESSAGE = 0x11 - RTMP_PACKET_TYPE_INFO = 0x12 - RTMP_PACKET_TYPE_INVOKE = 0x14 - RTMP_PACKET_TYPE_FLASH_VIDEO = 0x16 + RTMP_PACKET_TYPE_CHUNK_SIZE = 0x01 + RTMP_PACKET_TYPE_BYTES_READ_REPORT = 0x03 + RTMP_PACKET_TYPE_CONTROL = 0x04 + RTMP_PACKET_TYPE_SERVER_BW = 0x05 + RTMP_PACKET_TYPE_CLIENT_BW = 0x06 + RTMP_PACKET_TYPE_AUDIO = 0x08 + RTMP_PACKET_TYPE_VIDEO = 0x09 + RTMP_PACKET_TYPE_FLEX_STREAM_SEND = 0x0F + RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT = 0x10 + RTMP_PACKET_TYPE_FLEX_MESSAGE = 0x11 + RTMP_PACKET_TYPE_INFO = 0x12 + RTMP_PACKET_TYPE_INVOKE = 0x14 + RTMP_PACKET_TYPE_FLASH_VIDEO = 0x16 ) const ( @@ -58,16 +60,25 @@ const ( RTMP_PACKET_SIZE_SMALL = 2 RTMP_PACKET_SIZE_MINIMUM = 3 ) - const ( - RTMP_READ_HEADER = 0x01 - RTMP_READ_SEEKING = 0x2 + RTMP_READ_HEADER = 0x01 + RTMP_READ_RESUME = 0x02 + RTMP_READ_NO_IGNORE = 0x04 + RTMP_READ_GOTKF = 0x08 + RTMP_READ_GOTFLVK = 0x10 + RTMP_READ_SEEKING = 0x20 + RTMP_READ_COMPLETE = -3 + RTMP_READ_ERROR = -2 + RTMP_READ_EOF = -1 + RTMP_READ_IGNORE = 0 ) const ( RTMP_LF_AUTH = 0x0001 /* using auth param */ RTMP_LF_LIVE = 0x0002 /* stream is live */ + RTMP_LF_SWFV = 0x0004 /* do SWF verification */ RTMP_LF_PLST = 0x0008 /* send playlist before play */ + RTMP_LF_BUFX = 0x0010 /* toggle stream on BufferEmpty msg */ RTMP_LF_FTCU = 0x0020 /* free tcUrl on close */ RTMP_LF_FAPU = 0x0040 /* free app on close */ ) @@ -78,6 +89,7 @@ const ( RTMP_FEATURE_SSL = 0x04 RTMP_FEATURE_MFP = 0x08 /* not yet supported */ RTMP_FEATURE_WRITE = 0x10 /* publish, not play */ + RTMP_FEATURE_HTTP2 = 0x20 /* server-side rtmpt */ ) const ( @@ -133,7 +145,7 @@ type C_RTMPSockBuf struct { sb_ssl uintptr } -// #define RTMPPacket_IsReady(a) +// RTMPPacket_IsReady(a) // rtmp.h +142 func C_RTMPPacket_IsReady(p *C_RTMPPacket) int { if p.m_nBytesRead == p.m_nBodySize { From 8318f34be4c386b9ab3c550714a1578e6a99e156 Mon Sep 17 00:00:00 2001 From: saxon Date: Tue, 28 Aug 2018 18:40:10 +0930 Subject: [PATCH 28/33] rtmp: removed case braces in C_HandlInvoke and replaced code not run with panics in case we do get those cases --- rtmp/rtmp.go | 288 ++++++++++++++++++++------------------------------- 1 file changed, 114 insertions(+), 174 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index f4c280ca..d82b9669 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -1084,33 +1084,33 @@ func C_SendFCPublish(r *C_RTMP) int32 { func C_SendFCUnpublish(r *C_RTMP) int32 { // TODO finish porting /* - var packet C_RTMPPacket - var pbuf [1024]byte - var pend []byte = pbuf[1024:] - var enc []byte + var packet C_RTMPPacket + var pbuf [1024]byte + var pend []byte = pbuf[1024:] + var enc []byte - packet.m_nChannel = 0x03 - packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM - packet.m_packetType = RTMP_PACKET_TYPE_INVOKE - packet.m_nTimeStamp = 0 - packet.m_nInfoField2 = 0 - packet.m_hasAbsTimestamp = 0 - packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE + packet.m_nChannel = 0x03 + packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM + packet.m_packetType = RTMP_PACKET_TYPE_INVOKE + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = 0 + packet.m_hasAbsTimestamp = 0 + packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE - // NOTE use of unsafe pointer will be remove here when packet.m_nBody becomes []byte - enc = []byte(unsafe.Pointer(packet.m_nBody)) - enc = C_AMF_EncodeString((*byte)(unsafe.Pointer(&enc[0])), - (*byte)(unsafe.Pointer(&pend[0])), &av_FCUnpublish) - r.m_numInvokes++ - enc = C_AMF_EncodeNumber(enc, pend, r->m_numInvokes); - *enc++ = AMF_NULL; - enc = AMF_EncodeString(enc, pend, &r->Link.playpath); - if (!enc) - return FALSE; + // NOTE use of unsafe pointer will be remove here when packet.m_nBody becomes []byte + enc = []byte(unsafe.Pointer(packet.m_nBody)) + enc = C_AMF_EncodeString((*byte)(unsafe.Pointer(&enc[0])), + (*byte)(unsafe.Pointer(&pend[0])), &av_FCUnpublish) + r.m_numInvokes++ + enc = C_AMF_EncodeNumber(enc, pend, r->m_numInvokes); + *enc++ = AMF_NULL; + enc = AMF_EncodeString(enc, pend, &r->Link.playpath); + if (!enc) + return FALSE; - packet.m_nBodySize = enc - packet.m_body; + packet.m_nBodySize = enc - packet.m_body; - return RTMP_SendPacket(r, &packet, FALSE); + return RTMP_SendPacket(r, &packet, FALSE); */ return 0 } @@ -1315,10 +1315,9 @@ func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { //methodInvoked.av_val); switch { case C_AVMATCH(&methodInvoked, &av_connect) != 0: - { - /* NOTE This code doesn't run in our use case - TODO port this eventually - if r.Link.token.av_len != 0 { + if r.Link.token.av_len != 0 { + panic("No support for link token") + /* log.Println("2.1") var p C_AMFObjectProperty if C.RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p) != 0 { @@ -1326,21 +1325,24 @@ func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { C.DecodeTEA(&r.Link.token, &p.p_vu.p_aval) C.SendSecureTokenResponse(r, &p.p_vu.p_aval) } - } */ - if (r.Link.protocol & RTMP_FEATURE_WRITE) != 0 { - C_SendReleaseStream(r) - C_SendFCPublish(r) - } /* NOTE This code doesn't run in our use case - else { + } + if (r.Link.protocol & RTMP_FEATURE_WRITE) != 0 { + C_SendReleaseStream(r) + C_SendFCPublish(r) + } else { + panic("Link protocol has no RTMP_FEATURE_WRITE") + /* log.Println("2.4") C.RTMP_SendServerBW(r) C.RTMP_SendCtrl(r, 3, 0, 300) - } */ - C_RTMP_SendCreateStream(r) - /* NOTE This code doesn't run in our use case - if (r.Link.protocol & RTMP_FEATURE_WRITE) == 0 { + } + + C_RTMP_SendCreateStream(r) + if (r.Link.protocol & RTMP_FEATURE_WRITE) == 0 { + panic("Link protocol has no RTMP_FEATURE_WRITE") + /* log.Println("2.5") // Authenticate on Justin.tv legacy servers before sending FCSubscribe if r.Link.usherToken.av_len != 0 { @@ -1360,17 +1362,17 @@ func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { C.SendFCSubscribe(r, &r.Link.playpath) } } - } */ } - case C_AVMATCH(&methodInvoked, &av_createStream) != 0: - { - r.m_stream_id = int32(C_AMFProp_GetNumber(C_AMF_GetProp(&obj, nil, 3))) - if (r.Link.protocol & RTMP_FEATURE_WRITE) != 0 { - C_SendPublish(r) - } /* NOTE This code doesn't run in our use case - else { + case C_AVMATCH(&methodInvoked, &av_createStream) != 0: + r.m_stream_id = int32(C_AMFProp_GetNumber(C_AMF_GetProp(&obj, nil, 3))) + + if (r.Link.protocol & RTMP_FEATURE_WRITE) != 0 { + C_SendPublish(r) + } else { + panic("Link protocol has no RTMP_FEATURE_WRITE") + /* log.Println("5.2") if (r.Link.lFlags & RTMP_LF_PLST) != 0 { log.Println("5.3") @@ -1378,158 +1380,96 @@ func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { } C.SendPlay(r) C.RTMP_SendCtrl(r, 3, C.uint(r.m_stream_id), C.uint(r.m_nBufferMS)) - } */ } - /*NOTE This code doesn't run in our use case - case C_AVMATCH(&methodInvoked, &av_play) != 0 || - C_AVMATCH(&methodInvoked, &av_publish) != 0: - { - log.Println("6") - r.m_bPlaying = 1 - } - */ + + case C_AVMATCH(&methodInvoked, &av_play) != 0 || + C_AVMATCH(&methodInvoked, &av_publish) != 0: + panic("Unsupported method av_play/av_publish") } //C.free(unsafe.Pointer(methodInvoked.av_val)) } case C_AVMATCH(&method, &av_onBWDone) != 0: - { - if r.m_nBWCheckCounter == 0 { - C_SendCheckBW(r) - } - } - /*NOTE This code doesn't run in our use case - case C_AVMATCH(&method, &av_onFCSubscribe) != 0: - case C_AVMATCH(&method, &av_onFCUnsubscribe) != 0: - { - log.Println("8") - C.RTMP_Close(r) - ret = 1 + if r.m_nBWCheckCounter == 0 { + C_SendCheckBW(r) } + + case C_AVMATCH(&method, &av_onFCUnsubscribe) != 0 || C_AVMATCH(&method, &av_onFCSubscribe) != 0: + panic("Unsupported method av_onFCUnsubscribe/av_onFCSubscribe") + case C_AVMATCH(&method, &av_ping) != 0: - { - log.Println("9") + panic("Unsupported method av_ping") + /* C.SendPong(r, float64(txn)) - } + */ case C_AVMATCH(&method, &av__onbwcheck) != 0: - { + panic("Unsupported method av_onbwcheck") + /* log.Println("10") C.SendCheckBWResult(r, float64(txn)) - } + */ case C_AVMATCH(&method, &av__onbwdone) != 0: - { - log.Println("11") + panic("Unsupported method av_onbwdone") + + case C_AVMATCH(&method, &av_close) != 0: + panic("Unsupported method av_close") + + case C_AVMATCH(&method, &av_onStatus) != 0: + var obj2 C_AMFObject + var code, level C_AVal + C_AMFProp_GetObject(C_AMF_GetProp(&obj, nil, 3), &obj2) + C_AMFProp_GetString(C_AMF_GetProp(&obj2, &av_code, -1), &code) + C_AMFProp_GetString(C_AMF_GetProp(&obj2, &av_level, -1), &level) + + // TODO use new logger + // RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val); + switch { + case C_AVMATCH(&code, &av_NetStream_Failed) != 0 || + C_AVMATCH(&code, &av_NetStream_Play_Failed) != 0 || + C_AVMATCH(&code, &av_NetStream_Play_StreamNotFound) != 0 || + C_AVMATCH(&code, &av_NetConnection_Connect_InvalidApp) != 0: + panic("Unsupported method av_NetStream/av_NetStream_Play_Failed/av_netSTream_Play_StreamNotFound/av_netConnection_Connect_invalidApp") + + case C_AVMATCH(&code, &av_NetStream_Play_Start) != 0 || + C_AVMATCH(&code, &av_NetStream_Play_PublishNotify) != 0: + panic("Unsupported method av_NetStream_Play_Start/av_NetStream_Play_PublishNotify") + + case C_AVMATCH(&code, &av_NetStream_Publish_Start) != 0: + var i int32 + r.m_bPlaying = 1 for i = 0; i < int32(r.m_numCalls); i++ { if C_AVMATCH(&(*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(r.m_methodCalls), int(i), - int(unsafe.Sizeof(*r.m_methodCalls))))).name, &av__checkbw) != 0 { - C.AV_erase(r.m_methodCalls, &r.m_numCalls, int32(i), 1) + int(unsafe.Sizeof(*r.m_methodCalls))))).name, &av_publish) != 0 { + //C.AV_erase(r.m_methodCalls, &r.m_numCalls, int32(i), 1) + C_AV_erase(r.m_methodCalls, (*int32)(&r.m_numCalls), int32(i), 1) break } } - } - case C_AVMATCH(&method, &av_close) != 0: - { - log.Println("12") - // TODO use new logger - //RTMP_Log(RTMP_LOGERROR, "rtmp server requested close"); - C.RTMP_Close(r) - } - */ - case C_AVMATCH(&method, &av_onStatus) != 0: - { - var obj2 C_AMFObject - var code, level C_AVal - C_AMFProp_GetObject(C_AMF_GetProp(&obj, nil, 3), &obj2) - C_AMFProp_GetString(C_AMF_GetProp(&obj2, &av_code, -1), &code) - C_AMFProp_GetString(C_AMF_GetProp(&obj2, &av_level, -1), &level) - // TODO use new logger - // RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val); - switch { - /*NOTE This code doesn't run in our use case - case C_AVMATCH(&code, &av_NetStream_Failed) != 0 || - C_AVMATCH(&code, &av_NetStream_Play_Failed) != 0 || - C_AVMATCH(&code, &av_NetStream_Play_StreamNotFound) != 0 || - C_AVMATCH(&code, &av_NetConnection_Connect_InvalidApp) != 0: - { - log.Println("14") - r.m_stream_id = -1 - C.RTMP_Close(r) - // TODO use new logger - // RTMP_Log(RTMP_LOGERROR, "Closing connection: %s", code.av_val); - } - case C_AVMATCH(&code, &av_NetStream_Play_Start) != 0 || - C_AVMATCH(&code, &av_NetStream_Play_PublishNotify) != 0: - { - log.Println("15") - var i int32 - r.m_bPlaying = 1 - for i = 0; i < int32(r.m_numCalls); i++ { - if C_AVMATCH(&(*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(r.m_methodCalls), int(i), - int(unsafe.Sizeof(*r.m_methodCalls))))).name, &av_play) != 0 { - log.Println("15.1") - C.AV_erase(r.m_methodCalls, &r.m_numCalls, int32(i), 1) - break - } - } + case C_AVMATCH(&code, &av_NetStream_Play_Complete) != 0 || + C_AVMATCH(&code, &av_NetStream_Play_Stop) != 0 || + C_AVMATCH(&code, &av_NetStream_Play_UnpublishNotify) != 0: + panic("Unsupported method av_NetStream_Play_Complete/av_NetStream_Play_Stop/av_NetStream_Play_UnpublishNotify") + + case C_AVMATCH(&code, &av_NetStream_Seek_Notify) != 0: + panic("Unsupported method av_netStream_Seek_Notify") + + case C_AVMATCH(&code, &av_NetStream_Pause_Notify) != 0: + panic("Unsupported method av_NetStream_Pause_Notify") + /* + log.Println("19") + if r.m_pausing == 1 || r.m_pausing == 2 { + C.RTMP_SendPause(r, 0, int32(r.m_pauseStamp)) + r.m_pausing = 3 } */ - case C_AVMATCH(&code, &av_NetStream_Publish_Start) != 0: - { - var i int32 - r.m_bPlaying = 1 - for i = 0; i < int32(r.m_numCalls); i++ { - if C_AVMATCH(&(*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(r.m_methodCalls), int(i), - int(unsafe.Sizeof(*r.m_methodCalls))))).name, &av_publish) != 0 { - //C.AV_erase(r.m_methodCalls, &r.m_numCalls, int32(i), 1) - C_AV_erase(r.m_methodCalls, (*int32)(&r.m_numCalls), int32(i), 1) - break - } - } - } - /*NOTE This code doesn't run in our use case - case C_AVMATCH(&code, &av_NetStream_Play_Complete) != 0 || - C_AVMATCH(&code, &av_NetStream_Play_Stop) != 0 || - C_AVMATCH(&code, &av_NetStream_Play_UnpublishNotify) != 0: - { - log.Println("17") - C.RTMP_Close(r) - ret = 1 - } - case C_AVMATCH(&code, &av_NetStream_Seek_Notify) != 0: - { - log.Println("18") - // NOTE ~ has been replace by ^ - is this correct ? - r.m_read.flags = uint8(int8(r.m_read.flags) & ^RTMP_READ_SEEKING) - } - case C_AVMATCH(&code, &av_NetStream_Pause_Notify) != 0: - { - log.Println("19") - if r.m_pausing == 1 || r.m_pausing == 2 { - C.RTMP_SendPause(r, 0, int32(r.m_pauseStamp)) - r.m_pausing = 3 - } - } - */ - } } - /*NOTE This code doesn't run in our use case - case C_AVMATCH(&method, &av_playlist_ready) != 0: - { - log.Println("19") - var i int32 - for i = 0; i < int32(r.m_numCalls); i++ { - if C_AVMATCH(&(*(*C_RTMP_METHOD)(incPtr(unsafe.Pointer(r.m_methodCalls), int(i), - int(unsafe.Sizeof(*r.m_methodCalls))))).name, &av_set_playlist) != 0 { - C.AV_erase(r.m_methodCalls, &r.m_numCalls, int32(i), 1) - break - } - } - } - default: - log.Println("20") - */ + + case C_AVMATCH(&method, &av_playlist_ready) != 0: + panic("Unsupported method av_playlist_ready") + + default: } leave: C_AMF_Reset(&obj) From 766d30e2f6bbe8e9135fb25ad7e5a3343088c36c Mon Sep 17 00:00:00 2001 From: saxon Date: Tue, 28 Aug 2018 18:50:51 +0930 Subject: [PATCH 29/33] rtmp: setting r.m_nClientBW2 to 255 rather than 0 (which was incorrect in C_HandlClientBW --- rtmp/rtmp.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index d82b9669..1d5aa03e 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -1505,8 +1505,7 @@ func C_HandleClientBW(r *C_RTMP, packet *C_RTMPPacket) { if packet.m_nBodySize > 4 { r.m_nClientBW2 = (uint8)(*indxBytePtr(unsafe.Pointer(packet.m_body), 4)) } else { - //r.m_nClientBW2 = -1 - r.m_nClientBW2 = 0 + r.m_nClientBW2 = 255 } // TODO use new logger here // RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r.m_nClientBW, From 01f3caa8eced353ac29ef9003d9e3e02daf80eb4 Mon Sep 17 00:00:00 2001 From: saxon Date: Tue, 28 Aug 2018 19:18:13 +0930 Subject: [PATCH 30/33] rtmp: created NOT_PORTED.txt to hold names of funcs not ported and also deleted sections of code not run in our case --- rtmp/NOT_PORTED.txt | 16 ++++++ rtmp/rtmp.go | 137 ++------------------------------------------ 2 files changed, 20 insertions(+), 133 deletions(-) create mode 100644 rtmp/NOT_PORTED.txt diff --git a/rtmp/NOT_PORTED.txt b/rtmp/NOT_PORTED.txt new file mode 100644 index 00000000..b1c983e3 --- /dev/null +++ b/rtmp/NOT_PORTED.txt @@ -0,0 +1,16 @@ +HandleAudio +HandleVideo +HandleMetadata +DecodeTEA +SendSecureTokenResponse +RTMP_FindFirstMatchingProperty +RTMP_SendServerBW +RTMP_SendCtrl +SendUsherToken +SendFCSubscribe +SendPlaylist +SendPlay +SendPlaylist +SendPong +SendCheckBWResult +RTMP_SendPause diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 1d5aa03e..a1b1a221 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -600,54 +600,15 @@ func C_RTMP_ClientPacket(r *C_RTMP, packet *C_RTMPPacket) int32 { case RTMP_PACKET_TYPE_AUDIO: panic("Unsupported packet type RTMP_PACKET_TYPE_AUDIO") - /* - // TODO port this - //C.HandleAudio(r, packet) NOTE this does nothing - bHasMediaPacket = 1 - if r.m_mediaChannel == 0 { - r.m_mediaChannel = packet.m_nChannel - } - - if r.m_pausing == 0 { - r.m_mediaStamp = packet.m_nTimeStamp - } - */ case RTMP_PACKET_TYPE_VIDEO: panic("Unsupported packet type RTMP_PACKET_TYPE_VIDEO") - /* - // TODO port this - // C.HandleVideo(r, packet) NOTE this does nothing - bHasMediaPacket = 1 - if r.m_mediaChannel == 0 { - r.m_mediaChannel = packet.m_nChannel - } - if r.m_pausing == 0 { - r.m_mediaStamp = packet.m_nTimeStamp - } - */ + case RTMP_PACKET_TYPE_FLEX_MESSAGE: panic("Unsupported packet type RTMP_PACKET_TYPE_FLEX_MESSAGE") - /* - { - // TODO use new logger here - // RTMP_Log(RTMP_LOGDEBUG,"%s, flex message, size %u bytes, not fully supported", __FUNCTION__, packet.m_nBodySize); - if C.HandleInvoke(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), 1)), - C.uint(packet.m_nBodySize-1)) == 1 { - bHasMediaPacket = 2 - } - } - */ case RTMP_PACKET_TYPE_INFO: panic("Unsupported packet type RTMP_PACKET_TYPE_INFO") - /* - // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,packet.m_nBodySize); - if C.HandleMetadata(r, packet.m_body, C.uint(packet.m_nBodySize)) != 0 { - bHasMediaPacket = 1 - } - */ case RTMP_PACKET_TYPE_INVOKE: log.Println("RTMP_PACKET_TYPE_INVOKE:") @@ -662,42 +623,7 @@ func C_RTMP_ClientPacket(r *C_RTMP, packet *C_RTMPPacket) int32 { case RTMP_PACKET_TYPE_FLASH_VIDEO: panic("Unsupported packet type RTMP_PACKET_TYPE_FLASH_VIDEO") - /* - { - var pos uint32 = 0 - var nTimeStamp uint32 = uint32(packet.m_nTimeStamp) - for pos+11 < uint32(packet.m_nBodySize) { - var dataSize uint32 = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( - packet.m_body), int(pos+1)))) - - if pos+11+dataSize+4 > uint32(packet.m_nBodySize) { - // TODO use new logger here - // RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!"); - break - } - - switch { - case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 0x12: - C.HandleMetadata(r, (*byte)(incBytePtr(unsafe.Pointer(packet.m_body), - int(pos+11))), C.uint(dataSize)) - case *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 8 || - *indxBytePtr(unsafe.Pointer(packet.m_body), int(pos)) == 9: - nTimeStamp = C_AMF_DecodeInt24((*byte)(incBytePtr(unsafe.Pointer( - packet.m_body), int(pos+4)))) - nTimeStamp |= uint32(*indxBytePtr(unsafe.Pointer(packet.m_body), - int(pos+7)) << 24) - } - pos += (11 + dataSize + 4) - } - if r.m_pausing == 0 { - r.m_mediaStamp = uint32(nTimeStamp) - } - - bHasMediaPacket = 1 - - } - */ default: // TODO use new logger here // RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,packet.m_packetType); @@ -1317,52 +1243,18 @@ func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { case C_AVMATCH(&methodInvoked, &av_connect) != 0: if r.Link.token.av_len != 0 { panic("No support for link token") - /* - log.Println("2.1") - var p C_AMFObjectProperty - if C.RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p) != 0 { - log.Println("2.2") - C.DecodeTEA(&r.Link.token, &p.p_vu.p_aval) - C.SendSecureTokenResponse(r, &p.p_vu.p_aval) - } - */ + } if (r.Link.protocol & RTMP_FEATURE_WRITE) != 0 { C_SendReleaseStream(r) C_SendFCPublish(r) } else { panic("Link protocol has no RTMP_FEATURE_WRITE") - /* - log.Println("2.4") - C.RTMP_SendServerBW(r) - C.RTMP_SendCtrl(r, 3, 0, 300) - */ } C_RTMP_SendCreateStream(r) if (r.Link.protocol & RTMP_FEATURE_WRITE) == 0 { panic("Link protocol has no RTMP_FEATURE_WRITE") - /* - log.Println("2.5") - // Authenticate on Justin.tv legacy servers before sending FCSubscribe - if r.Link.usherToken.av_len != 0 { - log.Println("2.6") - C.SendUsherToken(r, &r.Link.usherToken) - } - // Send the FCSubscribe if live stream or if subscribepath is set - switch { - case r.Link.subscribepath.av_len != 0: - { - log.Println("3") - C.SendFCSubscribe(r, &r.Link.subscribepath) - } - case (r.Link.lFlags & RTMP_LF_LIVE) != 0: - { - log.Println("4") - C.SendFCSubscribe(r, &r.Link.playpath) - } - } - */ } case C_AVMATCH(&methodInvoked, &av_createStream) != 0: @@ -1372,15 +1264,6 @@ func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { C_SendPublish(r) } else { panic("Link protocol has no RTMP_FEATURE_WRITE") - /* - log.Println("5.2") - if (r.Link.lFlags & RTMP_LF_PLST) != 0 { - log.Println("5.3") - C.SendPlaylist(r) - } - C.SendPlay(r) - C.RTMP_SendCtrl(r, 3, C.uint(r.m_stream_id), C.uint(r.m_nBufferMS)) - */ } case C_AVMATCH(&methodInvoked, &av_play) != 0 || @@ -1399,15 +1282,10 @@ func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { case C_AVMATCH(&method, &av_ping) != 0: panic("Unsupported method av_ping") - /* - C.SendPong(r, float64(txn)) - */ + case C_AVMATCH(&method, &av__onbwcheck) != 0: panic("Unsupported method av_onbwcheck") - /* - log.Println("10") - C.SendCheckBWResult(r, float64(txn)) - */ + case C_AVMATCH(&method, &av__onbwdone) != 0: panic("Unsupported method av_onbwdone") @@ -1457,13 +1335,6 @@ func C_HandleInvoke(r *C_RTMP, body *byte, nBodySize uint32) int32 { case C_AVMATCH(&code, &av_NetStream_Pause_Notify) != 0: panic("Unsupported method av_NetStream_Pause_Notify") - /* - log.Println("19") - if r.m_pausing == 1 || r.m_pausing == 2 { - C.RTMP_SendPause(r, 0, int32(r.m_pauseStamp)) - r.m_pausing = 3 - } - */ } case C_AVMATCH(&method, &av_playlist_ready) != 0: From e0c3cd3b32ab5f0d305bf6c0e56592f3deaee724 Mon Sep 17 00:00:00 2001 From: saxon Date: Tue, 28 Aug 2018 20:10:13 +0930 Subject: [PATCH 31/33] rtmp: added more funcs to NOT_PORTED and removed commented out sections from AMFProp_Decode in amf.go --- rtmp/amf.go | 54 +++-------------------------------------------------- 1 file changed, 3 insertions(+), 51 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index a72efecf..4229c9a8 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -531,13 +531,7 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa case AMF_BOOLEAN: panic("AMF_BOOLEAN not supported") - /* - if nSize < 1 { - return -1 - } - prop.p_vu.p_number = float64(C_AMF_DecodeBoolean((*byte)(unsafe.Pointer(pBuffer)))) - nSize-- - */ + case AMF_STRING: var nStringSize = C_AMF_DecodeInt16(pBuffer) @@ -588,47 +582,13 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa case AMF_STRICT_ARRAY: panic("AMF_STRICT_ARRAY not supported") - /* - nArrayLen := int32(C_AMF_DecodeInt32(pBuffer)) - nSize -= 4 - - nRes = C_AMF_DecodeArray(&prop.p_vu.p_object, (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 4)), nSize, int32(nArrayLen), FALSE) - if nRes == -1 { - return -1 - } - nSize -= nRes - */ case AMF_DATE: panic("AMF_DATE not supported") - /* - // TODO use new logger here - //RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE"); - - if nSize < 10 { - return -1 - } - - prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer)) - prop.p_UTCoffset = C.int16_t(C_AMF_DecodeInt16((*byte)(incBytePtr(unsafe.Pointer(pBuffer), 8)))) - - nSize -= 10 - - */ case AMF_LONG_STRING, AMF_XML_DOC: panic("AMF_LONG_STRING, AMF_XML_DOC not supported") - /* - var nStringSize uint32 = C_AMF_DecodeInt32(pBuffer) - if int64(nSize) < int64(nStringSize)+4 { - return -1 - } - C_AMF_DecodeLongString(pBuffer, &prop.p_vu.p_aval) - nSize -= int32(4 + nStringSize) - if prop.p_type == AMF_LONG_STRING { - prop.p_type = AMF_STRING - } - */ + case AMF_RECORDSET: // TODO use new logger here log.Println("AMFProp_Decode: AMF_RECORDSET reserved!") @@ -643,15 +603,7 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa case AMF_AVMPLUS: panic("AMF_AVMPLUS not supported") - /* - log.Println("18") - nRes := int32(C.AMF3_Decode(&prop.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), int32(nSize), 1)) - if nRes == -1 { - return -1 - } - nSize -= nRes - prop.p_type = AMF_OBJECT - */ + default: // TODO use new logger here //RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__, From 7da8c11c58bc95272d039031f6ac7a2dc2bd4679 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 30 Aug 2018 20:31:19 +0930 Subject: [PATCH 32/33] rtmp: port add_addr_info and remove unused includes --- rtmp/amf.go | 26 +++++----------------- rtmp/parseurl.go | 31 +++++--------------------- rtmp/rtmp.go | 58 ++++++++++++++++++++++++++++++------------------ 3 files changed, 47 insertions(+), 68 deletions(-) diff --git a/rtmp/amf.go b/rtmp/amf.go index 4229c9a8..5745ff70 100644 --- a/rtmp/amf.go +++ b/rtmp/amf.go @@ -24,33 +24,17 @@ LICENSE for more details. You should have received a copy of the GNU General Public License - along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. - Derived from librtmp under the GNU Lesser General Public License 2.1 - Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org - Copyright (C) 2008-2009 Andrej Stepanchuk - Copyright (C) 2009-2010 Howard Chu + Derived from librtmp under the GNU Lesser General Public License 2.1 + Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org + Copyright (C) 2008-2009 Andrej Stepanchuk + Copyright (C) 2009-2010 Howard Chu */ package rtmp /* -#cgo CFLAGS: -I/usr/local/include/librtmp -#cgo LDFLAGS: -lrtmp -Wl,-rpath=/usr/local/lib - #include -#include -#include -#include -#include -#include -#include - -typedef enum { - RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE -} RTMPTCmd; - -typedef struct sockaddr_in sockaddr_in; -typedef struct sockaddr sockaddr; */ import "C" diff --git a/rtmp/parseurl.go b/rtmp/parseurl.go index b2c0c2b0..06b871db 100644 --- a/rtmp/parseurl.go +++ b/rtmp/parseurl.go @@ -22,36 +22,15 @@ LICENSE for more details. You should have received a copy of the GNU General Public License - along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. - Derived from librtmp under the GNU Lesser General Public License 2.1 - Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org - Copyright (C) 2008-2009 Andrej Stepanchuk - Copyright (C) 2009-2010 Howard Chu + Derived from librtmp under the GNU Lesser General Public License 2.1 + Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org + Copyright (C) 2008-2009 Andrej Stepanchuk + Copyright (C) 2009-2010 Howard Chu */ package rtmp -/* -#cgo CFLAGS: -I/usr/local/include/librtmp -#cgo LDFLAGS: -lrtmp -Wl,-rpath=/usr/local/lib - -#include -#include -#include -#include -#include -#include -#include - -typedef enum { - RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE -} RTMPTCmd; - -typedef struct sockaddr_in sockaddr_in; -typedef struct sockaddr sockaddr; -*/ -import "C" - import ( "fmt" "log" diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index a1b1a221..fcf49df1 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -23,31 +23,21 @@ LICENSE for more details. You should have received a copy of the GNU General Public License - along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. + along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. - Derived from librtmp under the GNU Lesser General Public License 2.1 - Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org - Copyright (C) 2008-2009 Andrej Stepanchuk - Copyright (C) 2009-2010 Howard Chu + Derived from librtmp under the GNU Lesser General Public License 2.1 + Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org + Copyright (C) 2008-2009 Andrej Stepanchuk + Copyright (C) 2009-2010 Howard Chu */ package rtmp /* -#cgo CFLAGS: -I/usr/local/include/librtmp -#cgo LDFLAGS: -lrtmp -Wl,-rpath=/usr/local/lib - #include -#include -#include -#include -#include -#include #include - -typedef enum { - RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE -} RTMPTCmd; +#include +#include typedef struct sockaddr_in sockaddr_in; typedef struct sockaddr sockaddr; @@ -382,6 +372,33 @@ func C_RTMP_SetupURL(r *C_RTMP, u string) int32 { return 1 } +// int add_addr_info(struct sockaddr_in *service, AVal *host, int port) +// rtmp.c +869 +func C_add_addr_info(service *C.sockaddr_in, host *C_AVal, port C.int) int32 { + var hostname *byte + if (*[1 << 20]byte)(unsafe.Pointer(host.av_val))[host.av_len] != 0 { + name := make([]byte, host.av_len+1) + copy(name, (*[1 << 20]byte)(unsafe.Pointer(host.av_val))[:host.av_len]) + name[len(name)-1] = 0 + hostname = (*byte)(unsafe.Pointer(&name[0])) + } else { + hostname = host.av_val + } + + service.sin_addr.s_addr = C.inet_addr((*C.char)(unsafe.Pointer(hostname))) + if service.sin_addr.s_addr == C.INADDR_NONE { + host := C.gethostbyname((*C.char)(unsafe.Pointer(hostname))) + if host == nil || *host.h_addr_list == nil { + //RTMP_Log(RTMP_LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname) + return 0 + } + service.sin_addr = *(*C.struct_in_addr)(unsafe.Pointer(*host.h_addr_list)) + } + + service.sin_port = C.ushort(inet.Htons(uint16(port))) + return 1 +} + // int RTMP_Connect0(RTMP *r, struct sockaddr* service); // rtmp.c +906 func C_RTMP_Connect0(r *C_RTMP, service *C.sockaddr) int { @@ -467,13 +484,12 @@ func C_RTMP_Connect(r *C_RTMP, cp *C_RTMPPacket) int { service.sin_family = C.AF_INET if r.Link.socksport != 0 { - // TODO: port this - if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.sockshost)), C.int(r.Link.socksport)) == 0 { + if C_add_addr_info(&service, (*C_AVal)(unsafe.Pointer(&r.Link.sockshost)), C.int(r.Link.socksport)) == 0 { return 0 } } else { // connect directly - if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.hostname)), + if C_add_addr_info(&service, (*C_AVal)(unsafe.Pointer(&r.Link.hostname)), C.int(r.Link.port)) == 0 { return 0 } @@ -497,7 +513,7 @@ func C_SocksNegotiate(r *C_RTMP) int { memset((*byte)(unsafe.Pointer(&service)), 0, int(unsafe.Sizeof(service))) - C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.hostname)), C.int(r.Link.port)) + C_add_addr_info(&service, (*C_AVal)(unsafe.Pointer(&r.Link.hostname)), C.int(r.Link.port)) addr = int32(inet.Htonl(uint32(service.sin_addr.s_addr))) { From 4aad7bac04754cd99117d7819aa8bfe67fec5122 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 30 Aug 2018 20:34:09 +0930 Subject: [PATCH 33/33] rtmp: remove rtmp.c --- rtmp/rtmp.c | 86 ----------------------------------------------------- 1 file changed, 86 deletions(-) delete mode 100644 rtmp/rtmp.c diff --git a/rtmp/rtmp.c b/rtmp/rtmp.c deleted file mode 100644 index 663052a4..00000000 --- a/rtmp/rtmp.c +++ /dev/null @@ -1,86 +0,0 @@ -/* -NAME - rtmp.c - -DESCRIPTION - See Readme.md - -AUTHOR - Saxon Nelson-Milton - Dan Kortschak - -LICENSE - RTMPWrapper.c is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) - - 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 - Free Software Foundation, either version 3 of the License, or (at your - option) any later version. - - It is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. -*/ -#include -#include -#include -#include -#include -#include -#include - -RTMP* start_session(RTMP* rtmp, char* url, uint connect_timeout) { - rtmp = RTMP_Alloc(); - RTMP_Init(rtmp); - rtmp->Link.timeout = connect_timeout; - if (!RTMP_SetupURL(rtmp, url)) { - RTMP_Close(rtmp); - RTMP_Free(rtmp); - errno = EINVAL; - return NULL; - } - - RTMP_EnableWrite(rtmp); - RTMP_SetBufferMS(rtmp, 3600 * 1000); - if (!RTMP_Connect(rtmp, NULL)) { - RTMP_Close(rtmp); - RTMP_Free(rtmp); - errno = EIO; - return NULL; - } - - if (!RTMP_ConnectStream(rtmp, 0)) { - RTMP_Close(rtmp); - RTMP_Free(rtmp); - errno = EIO; - return NULL; - } - - return rtmp; -} - -unsigned int write_frame(RTMP* rtmp, char* data, uint data_length) { - if (!RTMP_IsConnected(rtmp)) { - return 1; - } - - if (!RTMP_Write(rtmp, (const char*)data, data_length)) { - return 2; - } - - return 0; -} - -unsigned int end_session(RTMP* rtmp) { - if (rtmp == NULL) { - return 3; - } - - RTMP_Close(rtmp); - RTMP_Free(rtmp); - return 0; -}