From e5696f389d8822ec9e84a56e2d5ca88fe3bb5099 Mon Sep 17 00:00:00 2001 From: saxon Date: Fri, 20 Jul 2018 01:05:21 +0930 Subject: [PATCH] Wrote rtmpSetupUrl, but need to test --- rtmp/rtmp.go | 169 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 143 insertions(+), 26 deletions(-) diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 2135e258..47d62f43 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -146,6 +146,18 @@ var setDataFrame = AVC("@setDataFrame") var packetSize = [...]int{12, 8, 4, 1} +var RTMPProtocolStringsLower = [...]string{ + "rtmp", + "rtmpt", + "rtmpe", + "rtmpte", + "rtmps", + "rtmpts", + "", + "", + "rtmfp", +} + // Session provides an interface for sending flv tags over rtmp. type Session interface { Open() error @@ -318,13 +330,40 @@ func (s *session) Open() error { 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 { + return 0, Err(1) + } + //if C.RTMP_Write(s.rtmp,(*C.char)(unsafe.Pointer(&data[0])),C.int(len(data))) == 0 { + if rtmpWrite(s.rtmp, data) == 0 { + return 0, Err(2) + } + return len(data), nil +} + func startSession(rtmp *C.RTMP, u string, timeout uint32) (*C.RTMP, error) { - url := C.CString(u) connect_timeout := C.int(timeout) rtmp = rtmpAlloc() rtmpInit(rtmp) rtmp.Link.timeout = connect_timeout - if C.RTMP_SetupURL(rtmp, url) == 0 { + if rtmpSetupUrl(rtmp, u) == 0 { C.RTMP_Close(rtmp) C.RTMP_Free(rtmp) return nil, errors.New("rtmp startSession: Failed to setup URL!") @@ -366,17 +405,75 @@ func rtmpInit(r *C.RTMP) { r.Link.swfAge = 30 } -// Close terminates the rtmp connection -func (s *session) Close() error { - if s.rtmp == nil { - return Err(3) +func rtmpSetupUrl(r *C.RTMP, u string) int32 { + length := len(u) + url := goStrToCStr(u) + + var opt, arg AVal + var p1, p2 *byte + ptr := strchr(url, byte(' ')) + var ret, len int32 + var port uint32 + port = 0 + + len = strlen(url) + ret = int32(C.RTMP_ParseURL((*C.char)(unsafe.Pointer(url)), &r.Link.protocol, &r.Link.hostname, + (*C.uint)(&port), &r.Link.playpath0, &r.Link.app)) + + if ret == 0 { + return ret } - ret := endSession(s.rtmp) - s.rtmp = nil - if ret != 0 { - return Err(ret) + + r.Link.port = C.ushort(port) + r.Link.playpath = r.Link.playpath0 + + if r.Link.tcUrl.av_len == 0 { + r.Link.tcUrl.av_val = url + if r.Link.app.av_len != 0 { + if int(uintptr(unsafe.Pointer(r.Link.app.av_val))) < + int(uintptr(incBytePtr(url, len))) { + + r.Link.tcUrl.av_len = r.Link.app.av_len + + int(uintptr(decBytePtr(r.Link.app.av_val, int(uintptr(unsafe.Pointer(url)))))) + } else { + len = r.Link.hostname.av_len + r.Link.app.av_len + + int(unsafe.Sizeof("rtmpte://:65535/")) + + r.Link.tcUrl.av_val = (*C.char)(allocate(uintptr(len))) + hostname := string(ptrToSlice(unsafe.Pointer(r.Link.hostname.av_val), + int(r.Link.hostname.av_len))) + + app := string(ptrToSlice(unsafe.Pointer(r.Link.app.av_val), + int(r.Link.app.av_len))) + + fString := fmt.Sprintf("%v://%v:%v/%v", + RTMPProtocolStringsLower[r.Link.protocol], hostname, r.Link.port, app) + + r.Link.tcUrl.av_val = (*C.char)(goStrToCStr(fString)) + r.Link.tcUrl.av_len = len(RTMPProtocolStringsLower[r.Link.protocol]) + + len(string("://")) + len(hostname) + len(string(":")) + + len(strconv.Itoa(int(r.Link.port))) + len(string("/")) + len(app) + + r.Link.lFlags |= RTMP_LF_FTCU + } + } else { + r.Link.tcUrl.av_len = strlen(url) + } } - return nil + + C.SocksSetup(r, &r.Link.sockshost) + + if r.Link.port == 0 { + switch { + case r.Link.Protocol & RRTMP_FEATURE_SSL: + r.Link.port = 433 + case r.Link.protocol & RTMP_FEATURE_HTTP: + r.Link.port = 80 + default: + r.Link.port = 1935 + } + } + return 1 } func endSession(rtmp *C.RTMP) uint32 { @@ -389,21 +486,6 @@ func endSession(rtmp *C.RTMP) uint32 { return 0 } -// 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 { - return 0, Err(1) - } - //if C.RTMP_Write(s.rtmp,(*C.char)(unsafe.Pointer(&data[0])),C.int(len(data))) == 0 { - if rtmpWrite(s.rtmp, data) == 0 { - return 0, Err(2) - } - return len(data), nil -} - // rtmpWrite writes data to the current rtmp connection encapsulated by r func rtmpWrite(r *C.RTMP, data []byte) int { buf := sliceToPtr(data) @@ -968,6 +1050,41 @@ func avQueue(vals **C.RTMP_METHOD, num *int, av *C.AVal, txn int) { int(unsafe.Sizeof(rtmpMethodPtr))))).name.av_val = (*C.char)(tmp) } +func goStrToCStr(str string) *byte { + l := len(str) + slice := make([]byte, l+1) + ptr := unsafe.Pointer(&[]byte(str)[0]) + for i := 0; i < l; i++ { + slice[i] = *indxBytePtr(ptr, i) + } + slice[l] = '\000' + return slice +} + +func strlen(str *byte) int32 { + for i := 0; true; i++ { + ptr = indxBytePtr(unsafe.Pointer(str), i) + if *ptr == '\000' { + return i + } + } + return 0 +} + +func strchr(str *byte, val byte) *byte { + var ptr *byte + for i := 0; true; i++ { + ptr = indxBytePtr(unsafe.Pointer(str), i) + if *ptr == val { + return ptr + } + if *ptr == '\000' { + break + } + } + return nil +} + func allocate(nOfBytes uintptr) unsafe.Pointer { mem := make([]byte, int(nOfBytes)) return unsafe.Pointer(&mem[0])