Refactoring for RTMP source
This commit is contained in:
@@ -1,67 +0,0 @@
|
|||||||
package rtmp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
|
||||||
"github.com/AlexxIT/go2rtc/pkg/flv"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Dial(rawURL string) (*flv.Client, error) {
|
|
||||||
u, err := url.Parse(rawURL)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
host := u.Host
|
|
||||||
if strings.IndexByte(host, ':') < 0 {
|
|
||||||
host += ":1935"
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := net.DialTimeout("tcp", host, core.ConnDialTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rd := &rtmp{
|
|
||||||
url: rawURL,
|
|
||||||
headers: map[uint32]*header{},
|
|
||||||
conn: conn,
|
|
||||||
rd: bufio.NewReaderSize(conn, core.BufferSize),
|
|
||||||
}
|
|
||||||
|
|
||||||
if args := strings.Split(u.Path, "/"); len(args) >= 2 {
|
|
||||||
rd.app = args[1]
|
|
||||||
if len(args) >= 3 {
|
|
||||||
rd.stream = args[2]
|
|
||||||
if u.RawQuery != "" {
|
|
||||||
rd.stream += "?" + u.RawQuery
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rd.handshake(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = rd.sendConfig(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = rd.sendConnect(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = rd.sendPlay(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rd.buf = []byte{
|
|
||||||
'F', 'L', 'V', // signature
|
|
||||||
1, // version
|
|
||||||
0, // flags (has video/audio)
|
|
||||||
0, 0, 0, 9, // header size
|
|
||||||
}
|
|
||||||
|
|
||||||
return flv.Open(rd)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package rtmp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||||
|
"github.com/AlexxIT/go2rtc/pkg/flv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Dial(rawURL string) (core.Producer, error) {
|
||||||
|
u, err := url.Parse(rawURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
host := u.Host
|
||||||
|
if strings.IndexByte(host, ':') < 0 {
|
||||||
|
host += ":1935"
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialTimeout("tcp", host, core.ConnDialTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rd, err := NewReader(u, conn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flv.Open(rd)
|
||||||
|
}
|
||||||
@@ -26,8 +26,7 @@ const (
|
|||||||
|
|
||||||
var ErrResponse = errors.New("rtmp: wrong response")
|
var ErrResponse = errors.New("rtmp: wrong response")
|
||||||
|
|
||||||
// rtmp - implements flv.Transport
|
type Reader struct {
|
||||||
type rtmp struct {
|
|
||||||
url string
|
url string
|
||||||
app string
|
app string
|
||||||
stream string
|
stream string
|
||||||
@@ -41,7 +40,7 @@ type rtmp struct {
|
|||||||
buf []byte
|
buf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) Read(p []byte) (n int, err error) {
|
func (c *Reader) Read(p []byte) (n int, err error) {
|
||||||
// 1. Check temporary tempbuffer
|
// 1. Check temporary tempbuffer
|
||||||
if len(c.buf) == 0 {
|
if len(c.buf) == 0 {
|
||||||
msgType, timeMS, payload, err2 := c.readMessage()
|
msgType, timeMS, payload, err2 := c.readMessage()
|
||||||
@@ -71,7 +70,7 @@ func (c *rtmp) Read(p []byte) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) Close() error {
|
func (c *Reader) Close() error {
|
||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +93,7 @@ type header struct {
|
|||||||
msgType byte
|
msgType byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) readMessage() (byte, uint32, []byte, error) {
|
func (c *Reader) readMessage() (byte, uint32, []byte, error) {
|
||||||
hdrType, sid, err := c.readHeader()
|
hdrType, sid, err := c.readHeader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, nil, err
|
return 0, 0, nil, err
|
||||||
@@ -148,7 +147,7 @@ func (c *rtmp) readMessage() (byte, uint32, []byte, error) {
|
|||||||
timeMS = binary.BigEndian.Uint32(b)
|
timeMS = binary.BigEndian.Uint32(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
//log.Printf("[rtmp] hdrType=%d sid=%d msdTime=%d msgSize=%d msgType=%d", hdrType, sid, hdr.msgTime, hdr.msgSize, hdr.msgType)
|
//log.Printf("[Reader] hdrType=%d sid=%d msdTime=%d msgSize=%d msgType=%d", hdrType, sid, hdr.msgTime, hdr.msgSize, hdr.msgType)
|
||||||
|
|
||||||
// 1. Response zero size
|
// 1. Response zero size
|
||||||
if hdr.msgSize == 0 {
|
if hdr.msgSize == 0 {
|
||||||
@@ -192,7 +191,7 @@ func (c *rtmp) readMessage() (byte, uint32, []byte, error) {
|
|||||||
return hdr.msgType, timeMS, b, nil
|
return hdr.msgType, timeMS, b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) handshake() error {
|
func (c *Reader) handshake() error {
|
||||||
// simple handshake without real random and check response
|
// simple handshake without real random and check response
|
||||||
const randomSize = 4 + 4 + 1528
|
const randomSize = 4 + 4 + 1528
|
||||||
|
|
||||||
@@ -207,7 +206,7 @@ func (c *rtmp) handshake() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if b[0] != 3 {
|
if b[0] != 3 {
|
||||||
return errors.New("rtmp: wrong handshake")
|
return errors.New("Reader: wrong handshake")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := c.conn.Write(b[1:]); err != nil {
|
if _, err := c.conn.Write(b[1:]); err != nil {
|
||||||
@@ -221,7 +220,7 @@ func (c *rtmp) handshake() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) sendConfig() error {
|
func (c *Reader) sendConfig() error {
|
||||||
b := make([]byte, 5)
|
b := make([]byte, 5)
|
||||||
binary.BigEndian.PutUint32(b, 65536)
|
binary.BigEndian.PutUint32(b, 65536)
|
||||||
if err := c.sendRequest(MsgSetPacketSize, 0, b[:4]); err != nil {
|
if err := c.sendRequest(MsgSetPacketSize, 0, b[:4]); err != nil {
|
||||||
@@ -242,7 +241,7 @@ func (c *rtmp) sendConfig() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) sendConnect() error {
|
func (c *Reader) sendConnect() error {
|
||||||
msg := amf.AMF{}
|
msg := amf.AMF{}
|
||||||
msg.WriteString("connect")
|
msg.WriteString("connect")
|
||||||
msg.WriteNumber(1)
|
msg.WriteNumber(1)
|
||||||
@@ -267,13 +266,13 @@ func (c *rtmp) sendConnect() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s != "NetConnection.Connect.Success" {
|
if s != "NetConnection.Connect.Success" {
|
||||||
return errors.New("rtmp: wrong code: " + s)
|
return errors.New("Reader: wrong code: " + s)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) sendPlay() error {
|
func (c *Reader) sendPlay() error {
|
||||||
msg := amf.NewWriter()
|
msg := amf.NewWriter()
|
||||||
msg.WriteString("createStream")
|
msg.WriteString("createStream")
|
||||||
msg.WriteNumber(2)
|
msg.WriteNumber(2)
|
||||||
@@ -314,10 +313,10 @@ func (c *rtmp) sendPlay() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("rtmp: wrong code: " + s)
|
return errors.New("Reader: wrong code: " + s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) sendRequest(msgType byte, streamID uint32, payload []byte) error {
|
func (c *Reader) sendRequest(msgType byte, streamID uint32, payload []byte) error {
|
||||||
n := len(payload)
|
n := len(payload)
|
||||||
b := make([]byte, 12+n)
|
b := make([]byte, 12+n)
|
||||||
_ = b[12]
|
_ = b[12]
|
||||||
@@ -346,7 +345,7 @@ func (c *rtmp) sendRequest(msgType byte, streamID uint32, payload []byte) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) readHeader() (byte, uint32, error) {
|
func (c *Reader) readHeader() (byte, uint32, error) {
|
||||||
b, err := c.readSize(1)
|
b, err := c.readSize(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
@@ -371,7 +370,7 @@ func (c *rtmp) readHeader() (byte, uint32, error) {
|
|||||||
return hdrType, sid, nil
|
return hdrType, sid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) readSize(n uint32) ([]byte, error) {
|
func (c *Reader) readSize(n uint32) ([]byte, error) {
|
||||||
b := make([]byte, n)
|
b := make([]byte, n)
|
||||||
if _, err := io.ReadAtLeast(c.rd, b, int(n)); err != nil {
|
if _, err := io.ReadAtLeast(c.rd, b, int(n)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -379,7 +378,7 @@ func (c *rtmp) readSize(n uint32) ([]byte, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) waitResponse(cmd any, tid any) ([]any, error) {
|
func (c *Reader) waitResponse(cmd any, tid any) ([]any, error) {
|
||||||
for {
|
for {
|
||||||
msgType, _, b, err := c.readMessage()
|
msgType, _, b, err := c.readMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -407,7 +406,7 @@ func (c *rtmp) waitResponse(cmd any, tid any) ([]any, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtmp) waitCode(cmd any, tid any) (string, error) {
|
func (c *Reader) waitCode(cmd any, tid any) (string, error) {
|
||||||
args, err := c.waitResponse(cmd, tid)
|
args, err := c.waitResponse(cmd, tid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
Reference in New Issue
Block a user