README ¶
RTMP
The RTMP package (and it's subordinate packages) are dual licensed with both Apache2 and MIT licenses.
This code is a working fork of github.com/gwuhaolin/livego and as part of the original MIT license we are distributing this license.
Refactoring
I am currently refactoring a lot of this library to make it more extensible.
I plan on adding unit tests, and adding some better idomatic Go practices.
I have no longterm plans for this, and will maintain the original license and host the source code here.
Original credit goes to the original author.
Documentation ¶
Index ¶
- Constants
- Variables
- func CheckAppName(appname string) bool
- func GetStaticPushUrlList(appname string) ([]string, bool)
- func PrintMetrics(duration time.Duration)
- type Application
- type ChunkStream
- type ChunkStreamReader
- type ChunkStreamRouter
- type Client
- type ClientConn
- func (cc *ClientConn) Close()
- func (cc *ClientConn) Dial(address string) error
- func (cc *ClientConn) Flush() error
- func (cc *ClientConn) GetStreamId() uint32
- func (cc *ClientConn) LogDecodeBatch(r io.Reader, ver amf.Version) (ret []interface{}, err error)
- func (cc *ClientConn) NextChunk() (*ChunkStream, error)
- func (cc *ClientConn) Play() error
- func (cc *ClientConn) Publish() error
- func (cc *ClientConn) Read(c *ChunkStream) (err error)
- func (cc *ClientConn) Route(x *ChunkStream) error
- func (cc *ClientConn) RoutePackets() error
- func (cc *ClientConn) Write(c *ChunkStream) error
- type ClientMethod
- type CompliantMember
- type Conn
- func (conn *Conn) Close()
- func (conn *Conn) Flush() error
- func (conn *Conn) HandshakeClient() (err error)
- func (conn *Conn) HandshakeServer() (err error)
- func (conn *Conn) LocalAddr() net.Addr
- func (conn *Conn) Read(c *ChunkStream) error
- func (conn *Conn) RemoteAddr() net.Addr
- func (conn *Conn) SetDeadline(t time.Time) error
- func (conn *Conn) Write(c *ChunkStream) error
- type ConnEvent
- type ConnResp
- type ConnectInfo
- type JWT
- type Listener
- type MessageID
- type MetaData
- type Metrics
- type Pool
- type ProxyMetrics
- type PublishInfo
- type ReadWriter
- func (rw *ReadWriter) Flush() error
- func (rw *ReadWriter) Read(p []byte) (int, error)
- func (rw *ReadWriter) ReadError() error
- func (rw *ReadWriter) ReadUintBE(n int) (uint32, error)
- func (rw *ReadWriter) ReadUintLE(n int) (uint32, error)
- func (rw *ReadWriter) Write(p []byte) (int, error)
- func (rw *ReadWriter) WriteError() error
- func (rw *ReadWriter) WriteUintBE(v uint32, n int) error
- func (rw *ReadWriter) WriteUintLE(v uint32, n int) error
- type RoomKeysType
- func (r *RoomKeysType) DeleteChannel(channel string) bool
- func (r *RoomKeysType) DeleteKey(key string) bool
- func (r *RoomKeysType) GetChannel(key string) (channel string, err error)
- func (r *RoomKeysType) GetKey(channel string) (newKey string, err error)
- func (r *RoomKeysType) SetKey(channel string) (key string, err error)
- type Server
- type ServerClientType
- type ServerConn
- func (s *ServerConn) Close()
- func (s *ServerConn) Flush() error
- func (s *ServerConn) LogDecodeBatch(r io.Reader, ver amf.Version) ([]interface{}, error)
- func (s *ServerConn) NextChunk() (*ChunkStream, error)
- func (s *ServerConn) Read(packet *ChunkStream) (err error)
- func (s *ServerConn) Route(x *ChunkStream) error
- func (s *ServerConn) RoutePackets() error
- func (s *ServerConn) Write(x *ChunkStream) error
- type Stream
- type URLAddr
- func (a *URLAddr) App() string
- func (a *URLAddr) Host() string
- func (a *URLAddr) Key() string
- func (a *URLAddr) Network() string
- func (a *URLAddr) NewConn() (*Conn, error)
- func (a *URLAddr) NewNetConn() (net.Conn, error)
- func (a *URLAddr) SafeKey() string
- func (a *URLAddr) SafeURL() string
- func (a *URLAddr) Scheme() string
- func (a *URLAddr) StreamURL() string
- func (a *URLAddr) String() string
Constants ¶
const ( // TimeoutDurationSeconds is the timeout used for all // connection timeouts. TimeoutDurationSeconds time.Duration = 1 * time.Second DefaultRTMPChunkSizeBytes uint32 = 128 DefaultRTMPChunkSizeBytesLarge uint32 = DefaultRTMPChunkSizeBytes * 64 DefaultWindowAcknowledgementSizeBytes uint32 = 2500000 DefaultPeerBandwidthSizeBytes uint32 = 2500000 DefaultMaximumPoolSizeBytes int = 1024 * 1024 * 512 DefaultConnBufferSizeBytes int = 1024 * 1024 * 512 DefaultServerFMSVersion string = "FMS/3,0,1,123" ClientMethodPlay ClientMethod = "play" ClientMethodPublish ClientMethod = "publish" PublishCommandLive string = "live" PublishCommandRecord string = "record" PublishCommandAppend string = "append" CommandConnect string = "connect" CommandCreateStream string = "createStream" CommandPlay string = "play" CommandPublish string = "publish" CommandDeleteStream string = "deleteStream" CommandGetStreamLength string = "getStreamLength" CommandReleaseStream string = "releaseStream" CommandFCPublish string = "FCPublish" CommandFCUnpublish string = "FCUnpublish" CommandFCSubscribe string = "FCSubscribe" CommandFCUnsubscribed string = "FCUnsubscribe" CommandType_Result = "_result" CommandType_Error = "_error" CommandTypeOnStatus = "onStatus" CommandNetStreamPublishStart = "NetStream.Publish.Start" CommandNetStreamPublishNotify = "NetStream.Publish.Notify" CommandNetStreamPlayStart = "NetStream.Play.Start" CommandNetStreamPlayReset = "NetStream.Play.Reset" CommandNetStreamDataStart = "NetStream.Data.Start" CommandNetStreamConnectSuccess = "NetConnection.Connect.Success" CommandOnBWDone = "CommandOnBWDone" DataMessageOnMetaData = "onMetaData" StreamBegin uint32 = 0 StreamEOF uint32 = 1 StreamDry uint32 = 2 SetBufferLen uint32 = 3 StreamIsRecorded uint32 = 4 UserMessagePingRequest uint32 = 6 UserMessagePingResponse uint32 = 7 DefaultProtocol string = "tcp" DefaultLocalHost string = "localhost" DefaultLo string = "127.0.0.1" DefaultLocalPort string = "1935" DefaultScheme string = "rtmp" DefaultRTMPApp string = "twinx" DefaultGenerateKeyLength int = 20 DefaultGenerateKeyPrefix string = "twinx_" StreamKeyRandomBytePool string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" TAG_AUDIO uint32 = 8 TAG_VIDEO uint32 = 9 TAG_SCRIPTDATAAMF0 uint32 = 18 TAG_SCRIPTDATAAMF3 uint32 = 0xf MetadatAMF0 uint8 = 0x12 MetadataAMF3 uint8 = 0xf SOUND_MP3 uint8 = 2 SOUND_NELLYMOSER_16KHZ_MONO uint8 = 4 SOUND_NELLYMOSER_8KHZ_MONO uint8 = 5 SOUND_NELLYMOSER uint8 = 6 SOUND_ALAW uint8 = 7 SOUND_MULAW uint8 = 8 SOUND_AAC uint8 = 10 SOUND_SPEEX uint8 = 11 SOUND_5_5Khz uint8 = 0 SOUND_11Khz uint8 = 1 SOUND_22Khz uint8 = 2 SOUND_44Khz uint8 = 3 SOUND_8BIT uint8 = 0 SOUND_16BIT uint8 = 1 SOUND_MONO uint8 = 0 SOUND_STEREO uint8 = 1 AAC_SEQHDR uint8 = 0 AAC_RAW uint8 = 1 AVC_SEQHDR uint8 = 0 AVC_NALU uint8 = 1 AVC_EOS uint8 = 2 FRAME_KEY uint8 = 1 FRAME_INTER uint8 = 2 VIDEO_H264 uint8 = 7 )
const ( ConnInfoKeyApp string = "app" ConnInfoKeyType string = "type" ConnInfoKeyTcURL string = "tcUrl" ConnInfoKeyFlashVer string = "flashVer" ConnInfoKeySWFURL string = "swfUrl" ConnInfoObjectEncoding string = "objectEncoding" )
const ( ConnRespFMSVer string = "fmsVer" ConnRespCapabilities string = "capabilities" )
const ( ConnEventLevel string = "level" ConnEventCode string = "code" ConnEventDescription string = "description" ConnEventObjectEncoding string = "objectEncoding" ConnEventStatus string = "status" )
const ( SetChunkSizeMessage string = "setChunkSize" SetChunkSizeMessageID uint32 = 1 AbortMessage string = "abort" AbortMessageID uint32 = 2 AcknowledgementMessage string = "acknowledgement" AcknowledgementMessageID uint32 = 3 WindowAcknowledgementSizeMessage string = "windowAcknowledgementSize" WindowAcknowledgementSizeMessageID uint32 = 5 SetPeerBandwidthMessage string = "setPeerBandwidth" SetPeerBandwidthMessageID uint32 = 6 UserControlMessage string = "userControl" UserControlMessageID uint32 = 4 CommandMessage string = "command" CommandMessageAMF3ID uint32 = 17 CommandMessageAMF0ID uint32 = 20 DataMessage string = "data" DataMessageAMF3ID uint32 = 15 DataMessageAMF0ID uint32 = 18 AudioMessage string = "audio" AudioMessageID uint32 = 8 VideoMessage string = "video" VideoMessageID uint32 = 9 AggregateMessage string = "aggregate" AggregateMessageID uint32 = 22 // UnknownMessageID should never happen, but we default // all unknown message type IDs to this string UnknownMessageID = "UNKNOWN" )
const ( // MaximumPacketQueueRecords // // Similar to how HTTP-based transmission protocols like // HLS and DASH behave, RTMP too, breaks a multimedia // stream into fragments that are usually: // - 64 bytes for audio // - 128 bytes for video // // The size of the fragments can be negotiated between the client and the server. MaximumPacketQueueRecords int = 1024 // SaveStaticMediaTimeIntervalMilliseconds // // The time delay (in MS) between saving static media SaveStaticMediaTimeIntervalMilliseconds int64 = 5000 ReadTimeout int = 10 WriteTimeout int = 10 )
const (
CommandConnectWellKnownID float64 = 1
)
Variables ¶
var ( HandshakeClientKey = []byte{ 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1', 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE, } HandshakeServerKey = []byte{ 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ', 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1', 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE, } HandshakeClientPartial30 []byte = HandshakeClientKey[:30] HandshakeServerPartial36 []byte = HandshakeServerKey[:36] )
var (
DefaultUnimplementedError = errors.New("**UNIMPLEMENTED**")
)
var RoomKeys = &RoomKeysType{
localCache: cache.New(cache.NoExpiration, 0),
}
var (
WellKnownClosedClientError = errors.New("closed 🛑 client: EOF")
)
Functions ¶
func CheckAppName ¶
func GetStaticPushUrlList ¶
func PrintMetrics ¶
Types ¶
type Application ¶
type ChunkStream ¶
type ChunkStream struct { // Timestamp of the message. This field can transport 4 // bytes. Timestamp uint32 // Length of the message payload. If the message header cannot // be elided, it should be included in the length. This field // occupies 3 bytes in the chunk header. Length uint32 // A range of type IDs are reserved for protocol control // messages. These messages which propagate information are handled // by both RTMP Chunk Stream protocol and the higher-level protocol. // All other type IDs are available for use by the higher-level // protocol, and treated as opaque values by RTMP Chunk Stream. In // fact, nothing in RTMP Chunk Stream requires these values to be // used as a type; all (non-protocol) messages could be of the same // type, or the application could use this field to distinguish // simultaneous tracks rather than types. This field occupies 1 byte // in the chunk header. TypeID uint32 // The message stream ID can be any arbitrary value. // Different message streams multiplexed onto the same chunk stream // are demultiplexed based on their message stream IDs. Beyond that, // as far as RTMP Chunk Stream is concerned, this is an opaque value. // This field occupies 4 bytes in the chunk header in little endian // format. StreamID uint32 // Data is the set of bytes in the Chunk. The chunk payload. Data []byte Format uint32 CSID uint32 // contains filtered or unexported fields }
ChunkStream
5.1.
The format of a message that can be split into chunks to support multiplexing depends on a higher level protocol. The message format SHOULD however contain the following fields which are necessary for creating the chunks.
type ChunkStreamReader ¶
type ChunkStreamReader interface { Read(x *ChunkStream) error NextChunk() (*ChunkStream, error) }
type ChunkStreamRouter ¶
type ChunkStreamRouter interface { // RoutePackets just reads packets and calls Route() RoutePackets() error Route(x *ChunkStream) error }
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
func (*Client) Client ¶
func (c *Client) Client() *ClientConn
type ClientConn ¶
type ClientConn struct {
// contains filtered or unexported fields
}
func NewClientConn ¶
func NewClientConn() *ClientConn
func (*ClientConn) Close ¶
func (cc *ClientConn) Close()
func (*ClientConn) Dial ¶
func (cc *ClientConn) Dial(address string) error
func (*ClientConn) Flush ¶
func (cc *ClientConn) Flush() error
func (*ClientConn) GetStreamId ¶
func (cc *ClientConn) GetStreamId() uint32
func (*ClientConn) LogDecodeBatch ¶
func (*ClientConn) NextChunk ¶
func (cc *ClientConn) NextChunk() (*ChunkStream, error)
func (*ClientConn) Play ¶
func (cc *ClientConn) Play() error
Play will attempt to start a Play stream with a configured server.
func (*ClientConn) Publish ¶
func (cc *ClientConn) Publish() error
Publish will hang and attempt to start a Publish stream with a configured server.
func (*ClientConn) Read ¶
func (cc *ClientConn) Read(c *ChunkStream) (err error)
func (*ClientConn) Route ¶
func (cc *ClientConn) Route(x *ChunkStream) error
func (*ClientConn) RoutePackets ¶
func (cc *ClientConn) RoutePackets() error
func (*ClientConn) Write ¶
func (cc *ClientConn) Write(c *ChunkStream) error
type ClientMethod ¶
type ClientMethod string
type CompliantMember ¶
type CompliantMember interface {
// contains filtered or unexported methods
}
CompliantMember is a member that validates that both servers and clients have associated methods to respond to each other.
This allows a clearer understanding of communication between the entities and ensures that we always offer support for both server and client functionality.
This is this packages interpretation of the RTMP spec, and our guarantees about our server and client code.
We us "RX" and "TX" to identify the direction of packets.
RX = Receive : Packets coming from a remote to this process TX = Transmit : Packets sending to a remote from this process
type Conn ¶
Conn
Conn is the base type for all RTMP connections. Conn is embedded with native Go types
- net.Conn
- net.Addr
- url.URL
Both ClientConn and ServerConn are extensions of base Conn
func (*Conn) HandshakeClient ¶
func (*Conn) HandshakeServer ¶
func (*Conn) Read ¶
func (conn *Conn) Read(c *ChunkStream) error
func (*Conn) RemoteAddr ¶
func (*Conn) Write ¶
func (conn *Conn) Write(c *ChunkStream) error
type ConnEvent ¶
type ConnEvent struct { Level string `amf:"level"` Code string `amf:"code"` Description string `amf:"description"` ObjectEncoding int `amf:"objectEncoding"` }
func ConnEventMapToInstance ¶
type ConnectInfo ¶
type ConnectInfo struct { App string `amf:"app" json:"app"` FlashVer string `amf:"flashVer" json:"flashVer"` SwfUrl string `amf:"swfUrl" json:"swfUrl"` TcUrl string `amf:"tcUrl" json:"tcUrl"` Fpad bool `amf:"fpad" json:"fpad"` AudioCodecs int `amf:"audioCodecs" json:"audioCodecs"` VideoCodecs int `amf:"videoCodecs" json:"videoCodecs"` VideoFunction int `amf:"videoFunction" json:"videoFunction"` PageUrl string `amf:"pageUrl" json:"pageUrl"` ObjectEncoding int `amf:"objectEncoding" json:"objectEncoding"` }
ConnectInfo is the RTMP spec's parameters of the key value pairs passed during a connect command message
The following is the description of the name-value pairs used in Command
Object of the connect command. +-----------+--------+-----------------------------+----------------+ | Property | Type | Description | Example Value | +-----------+--------+-----------------------------+----------------+ | app | String | The Server application name | testapp | | | | the client is connected to. | | +-----------+--------+-----------------------------+----------------+ | flashver | String | Flash Player version. It is | FMSc/1.0 | | | | the same string as returned | | | | | by the ApplicationScript | | | | | getversion () function. | | +-----------+--------+-----------------------------+----------------+ | swfUrl | String | URL of the source SWF file | file://C:/ | | | | making the connection. | FlvPlayer.swf | +-----------+--------+-----------------------------+----------------+ | tcUrl | String | URL of the Server. | rtmp://local | | | | It has the following format.| host:1935/test | | | | protocol://servername:port/ | app/instance1 | | | | appName/appInstance | | +-----------+--------+-----------------------------+----------------+ | fpad | Boolean| True if proxy is being used.| true or false | +-----------+--------+-----------------------------+----------------+ |audioCodecs| Number | Indicates what audio codecs | SUPPORT_SND | | | | the client supports. | _MP3 | +-----------+--------+-----------------------------+----------------+ |videoCodecs| Number | Indicates what video codecs | SUPPORT_VID | | | | are supported. | _SORENSON | +-----------+--------+-----------------------------+----------------+ |videoFunct-| Number | Indicates what special video| SUPPORT_VID | |ion | | functions are supported. | _CLIENT_SEEK | +-----------+--------+-----------------------------+----------------+ | pageUrl | String | URL of the web page from | http:// | | | | where the SWF file was | somehost/ | | | | loaded. | sample.html | +-----------+--------+-----------------------------+----------------+ | object | Number | AMF encoding method. | AMF3 | | Encoding | | | | +-----------+--------+-----------------------------+----------------+
func ConnectInfoMapToInstance ¶
func ConnectInfoMapToInstance(i interface{}) (*ConnectInfo, error)
type MessageID ¶
type MessageID uint32
MessageID is the main "Message stream ID" for each packet sent over the RTMP protocol
3. Definitions Message stream ID: Each message has an ID associated with it to identify the message stream in which it is flowing.
type MetaData ¶
type MetaData struct { V21 bool `amf:"2.1" json:"2.1"` V31 bool `amf:"3.1" json:"3.1"` V40 bool `amf:"4.0" json:"4.0"` V41 bool `amf:"4.1" json:"4.1"` V51 bool `amf:"5.1" json:"5.1"` V71 bool `amf:"7.1" json:"7.1"` AudioChannels int `amf:"audiochannels" json:"audiochannels"` AudioCodecID int `amf:"audiocodecid" json:"audiocodecid"` AudioDataRate int `amf:"audiodatarate" json:"audiodatarate"` AudioSampleRate int `amf:"audiosamplerate" json:"audiosamplerate"` AudioSampleSize int `amf:"audiosamplesize" json:"audiosamplesize"` Duration int `amf:"duration" json:"duration"` Encoder string `amf:"encoder" json:"encoder"` FileSize int `amf:"filesize" json:"filesize"` FrameRate int `amf:"framerate" json:"framerate"` Height int `amf:"height" json:"height"` Stereo bool `amf:"stereo" json:"stereo"` VideoCodecID int `amf:"videocodecid" json:"videocodecid"` VideoDataRate int `amf:"videodatarate" json:"videodatarate"` Width int `amf:"width" json:"width"` }
MetaData is found in clients such as OBS
Example map: 2.1:false 3.1:false 4.0:false 4.1:false 5.1:false 7.1:false audiochannels:2 audiocodecid:10 audiodatarate:160 audiosamplerate:48000 audiosamplesize:16 duration:0 encoder:obs-output module (libobs version 27.0.1-3) fileSize:0 framerate:30 height:720 stereo:true videocodecid:7 videodatarate:2500 width:1280
func MetaDataMapToInstance ¶
func VirtualOBSOutputClientMetadata ¶
func VirtualOBSOutputClientMetadata() *MetaData
VirtualOBSOutputClientMetadata
A virtual metadata object that resembles common OBS configuration.
(map[2.1:false 3.1:false 4.0:false 4.1:false 5.1:false 7.1:false audiochannels:2 audiocodecid:10 audiodatarate:160 audiosamplerate:48000 audiosamplesize:16 duration:0 encoder:obs-output module (libobs version 27.0.1-3) fileSize:0 framerate:30 height:720 stereo:true videocodecid:7 videodatarate:2500 width:1280])
type Metrics ¶
type Metrics struct { ServerAddrRX string ServerTotalPacketsRX int ServerTotalBytesRX int ServerPacketOffset int ServerKeyHash string PacketsPerSecond float64 StartTime time.Time // Proxies is a map indexed on SafeURL() Proxies map[string]*ProxyMetrics sync.Mutex }
Metrics is a data structure that will aggregate metrics about our RTMP connections, and streams.
type ProxyMetrics ¶
type ProxyMetrics struct { ProxyAddrTX string ProxyTotalBytesTX int ProxyTotalPacketsTX int ProxyKeyHash string }
func P ¶
func P(name string) *ProxyMetrics
type PublishInfo ¶
type ReadWriter ¶
type ReadWriter struct { *bufio.ReadWriter // contains filtered or unexported fields }
func NewReadWriter ¶
func NewReadWriter(rw io.ReadWriter, bufSize int) *ReadWriter
func (*ReadWriter) Flush ¶
func (rw *ReadWriter) Flush() error
func (*ReadWriter) ReadError ¶
func (rw *ReadWriter) ReadError() error
func (*ReadWriter) ReadUintBE ¶
func (rw *ReadWriter) ReadUintBE(n int) (uint32, error)
func (*ReadWriter) ReadUintLE ¶
func (rw *ReadWriter) ReadUintLE(n int) (uint32, error)
func (*ReadWriter) WriteError ¶
func (rw *ReadWriter) WriteError() error
func (*ReadWriter) WriteUintBE ¶
func (rw *ReadWriter) WriteUintBE(v uint32, n int) error
func (*ReadWriter) WriteUintLE ¶
func (rw *ReadWriter) WriteUintLE(v uint32, n int) error
type RoomKeysType ¶
type RoomKeysType struct {
// contains filtered or unexported fields
}
func (*RoomKeysType) DeleteChannel ¶
func (r *RoomKeysType) DeleteChannel(channel string) bool
func (*RoomKeysType) DeleteKey ¶
func (r *RoomKeysType) DeleteKey(key string) bool
func (*RoomKeysType) GetChannel ¶
func (r *RoomKeysType) GetChannel(key string) (channel string, err error)
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
func (*Server) ListenAndServe ¶
func (*Server) PlayClient ¶
func (s *Server) PlayClient(f *ServerConn)
func (*Server) Proxy ¶
Proxy will configure forward addresses for the RTMP server.
Proxy can be called before or after Serve() and the backend server will be smart enough to sync clients.
func (*Server) ProxyClient ¶
func (s *Server) ProxyClient(f *ClientConn) error
ProxyClient will add clients to this server.
Client forwarding is handled at the server level. We trust each subsequent stream to update to the configured clients as they are added.
func (*Server) PublishClient ¶
func (s *Server) PublishClient(f *ServerConn)
type ServerClientType ¶
type ServerClientType int
const ( PlayClient ServerClientType = 1 PublishClient ServerClientType = 2 )
type ServerConn ¶
type ServerConn struct {
// contains filtered or unexported fields
}
func NewServerConn ¶
func NewServerConn(conn *Conn) *ServerConn
func (*ServerConn) Close ¶
func (s *ServerConn) Close()
func (*ServerConn) Flush ¶
func (s *ServerConn) Flush() error
func (*ServerConn) LogDecodeBatch ¶
func (*ServerConn) NextChunk ¶
func (s *ServerConn) NextChunk() (*ChunkStream, error)
NextChunk will read the next packet of data from the client, and will attempt to respond to the packet based on it's content and the appropriate response per the RTMP spec.
func (*ServerConn) Read ¶
func (s *ServerConn) Read(packet *ChunkStream) (err error)
func (*ServerConn) Route ¶
func (s *ServerConn) Route(x *ChunkStream) error
func (*ServerConn) RoutePackets ¶
func (s *ServerConn) RoutePackets() error
RoutePackets will hang and route packets for this connection
func (*ServerConn) Write ¶
func (s *ServerConn) Write(x *ChunkStream) error
type Stream ¶
type Stream struct { URLAddr // contains filtered or unexported fields }
func Multiplex ¶
Multiplex onto key
All bytes written to this key (the base key) will be multiplexed onto any configured proxy clients.
func (*Stream) AddMetaData ¶
func (s *Stream) AddMetaData(x *ChunkStream) error
func (*Stream) GetMetaData ¶
func (s *Stream) GetMetaData() *ChunkStream
func (*Stream) RemoveConn ¶
func (*Stream) SetChunkSize ¶
func (*Stream) Write ¶
func (s *Stream) Write(x *ChunkStream) error
[ Write ]
The almighty Write() method.
This method is effectively a single threaded Write() method.
If this blocks. All corresponding *Conn objects will also block.
type URLAddr ¶
URLAddr is a flexible RTMP address member that resembles url.URL.
func NewURLAddr ¶
func (*URLAddr) App ¶
App will return the first parameter of the path. Such as rtmp://host:port/app/key
func (*URLAddr) Host ¶
Host will return a net.Listener compatible host string as verbosely as possible. Given inputs such as:
localhost: localhost:1935 :1935 :
We should see
localhost:1935
func (*URLAddr) Key ¶
Key should return the stream key for this instance of *rtmp.Addr All instances will generate a key if one is not provided.
func (*URLAddr) SafeURL ¶
SafeURL will log the StreamURL() without the key.
rtmp://localhost:1935/app/[obfuscated]