add publishing handle
This commit is contained in:
parent
8bda26aad1
commit
2432a072da
158
server.go
158
server.go
@ -49,26 +49,40 @@ func DialTimeout(uri string, timeout time.Duration) (conn *Conn, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
Debug bool
|
||||||
|
DebugConn bool
|
||||||
Addr string
|
Addr string
|
||||||
HandlePublish func(*Conn)
|
HandlePublish func(*Conn)
|
||||||
HandlePlay func(*Conn)
|
HandlePlay func(*Conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Server) handleConn(conn *Conn) (err error) {
|
func (self *Server) handleConn(conn *Conn) (err error) {
|
||||||
if err = conn.handshake(); err != nil {
|
if err = conn.handshakeServer(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = conn.determineType(); err != nil {
|
if err = conn.determineType(); err != nil {
|
||||||
fmt.Println("rtmp: conn closed:", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if conn.playing {
|
if conn.playing {
|
||||||
if self.HandlePlay != nil {
|
if self.HandlePlay != nil {
|
||||||
self.HandlePlay(conn)
|
self.HandlePlay(conn)
|
||||||
conn.Close()
|
|
||||||
}
|
}
|
||||||
|
} else if conn.publishing {
|
||||||
|
if self.HandlePublish != nil {
|
||||||
|
self.HandlePublish(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn.pollMsg()
|
||||||
|
if conn.msgtypeid == msgtypeidAudioMsg || conn.msgtypeid == msgtypeidVideoMsg {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = conn.Close(); err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -96,7 +110,12 @@ func (self *Server) ListenAndServe() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.Debug {
|
||||||
|
fmt.Println("rtmp: server: accepted")
|
||||||
|
}
|
||||||
|
|
||||||
conn := NewConn(netconn)
|
conn := NewConn(netconn)
|
||||||
|
conn.Debug = self.DebugConn
|
||||||
conn.isserver = true
|
conn.isserver = true
|
||||||
go self.handleConn(conn)
|
go self.handleConn(conn)
|
||||||
}
|
}
|
||||||
@ -120,8 +139,6 @@ type Conn struct {
|
|||||||
writeMaxChunkSize int
|
writeMaxChunkSize int
|
||||||
readMaxChunkSize int
|
readMaxChunkSize int
|
||||||
|
|
||||||
lastcsid uint32
|
|
||||||
lastcs *chunkStream
|
|
||||||
csmap map[uint32]*chunkStream
|
csmap map[uint32]*chunkStream
|
||||||
|
|
||||||
isserver bool
|
isserver bool
|
||||||
@ -152,8 +169,8 @@ func NewConn(netconn net.Conn) *Conn {
|
|||||||
conn.csmap = make(map[uint32]*chunkStream)
|
conn.csmap = make(map[uint32]*chunkStream)
|
||||||
conn.readMaxChunkSize = 128
|
conn.readMaxChunkSize = 128
|
||||||
conn.writeMaxChunkSize = 128
|
conn.writeMaxChunkSize = 128
|
||||||
conn.bufr = bufio.NewReaderSize(netconn, 4096)
|
conn.bufr = bufio.NewReaderSize(netconn, 2048)
|
||||||
conn.bufw = bufio.NewWriterSize(netconn, 4096)
|
conn.bufw = bufio.NewWriterSize(netconn, 2048)
|
||||||
conn.br = pio.NewReader(conn.bufr)
|
conn.br = pio.NewReader(conn.bufr)
|
||||||
conn.bw = pio.NewWriter(conn.bufw)
|
conn.bw = pio.NewWriter(conn.bufw)
|
||||||
conn.intw = pio.NewWriter(nil)
|
conn.intw = pio.NewWriter(nil)
|
||||||
@ -227,7 +244,7 @@ func (self *Conn) pollMsg() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Conn) determineType() (err error) {
|
func (self *Conn) determineType() (err error) {
|
||||||
var connectpath, playpath string
|
var connectpath string
|
||||||
|
|
||||||
// < connect("app")
|
// < connect("app")
|
||||||
if err = self.pollCommand(); err != nil {
|
if err = self.pollCommand(); err != nil {
|
||||||
@ -290,13 +307,46 @@ func (self *Conn) determineType() (err error) {
|
|||||||
flvio.WriteAMF0Val(w, self.avmsgsid) // streamid=1
|
flvio.WriteAMF0Val(w, self.avmsgsid) // streamid=1
|
||||||
self.writeCommandMsgEnd(3, 0)
|
self.writeCommandMsgEnd(3, 0)
|
||||||
|
|
||||||
// < play("path")
|
// < publish("path")
|
||||||
case "play":
|
case "publish":
|
||||||
|
if self.Debug {
|
||||||
|
fmt.Println("rtmp: < publish")
|
||||||
|
}
|
||||||
|
|
||||||
if len(self.commandparams) < 1 {
|
if len(self.commandparams) < 1 {
|
||||||
err = fmt.Errorf("rtmp: play params invalid")
|
err = fmt.Errorf("rtmp: publish params invalid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
playpath, _ = self.commandparams[0].(string)
|
publishpath, _ := self.commandparams[0].(string)
|
||||||
|
|
||||||
|
// > onStatus()
|
||||||
|
w := self.writeCommandMsgStart()
|
||||||
|
flvio.WriteAMF0Val(w, "onStatus")
|
||||||
|
flvio.WriteAMF0Val(w, self.commandtransid)
|
||||||
|
flvio.WriteAMF0Val(w, nil)
|
||||||
|
flvio.WriteAMF0Val(w, flvio.AMFMap{
|
||||||
|
"level": "status",
|
||||||
|
"code": "NetStream.Publish.Start",
|
||||||
|
"description": "Start publishing",
|
||||||
|
})
|
||||||
|
self.writeCommandMsgEnd(5, self.avmsgsid)
|
||||||
|
|
||||||
|
self.Path = fmt.Sprintf("/%s/%s", connectpath, publishpath)
|
||||||
|
self.publishing = true
|
||||||
|
self.reading = true
|
||||||
|
return
|
||||||
|
|
||||||
|
// < play("path")
|
||||||
|
case "play":
|
||||||
|
if self.Debug {
|
||||||
|
fmt.Println("rtmp: < play")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(self.commandparams) < 1 {
|
||||||
|
err = fmt.Errorf("rtmp: command play params invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
playpath, _ := self.commandparams[0].(string)
|
||||||
|
|
||||||
// > streamBegin(streamid)
|
// > streamBegin(streamid)
|
||||||
self.writeStreamBegin(self.avmsgsid)
|
self.writeStreamBegin(self.avmsgsid)
|
||||||
@ -320,10 +370,6 @@ func (self *Conn) determineType() (err error) {
|
|||||||
flvio.WriteAMF0Val(w, true)
|
flvio.WriteAMF0Val(w, true)
|
||||||
self.writeDataMsgEnd(5, self.avmsgsid)
|
self.writeDataMsgEnd(5, self.avmsgsid)
|
||||||
|
|
||||||
if self.Debug {
|
|
||||||
fmt.Println("rtmp: playing")
|
|
||||||
}
|
|
||||||
|
|
||||||
self.Path = fmt.Sprintf("/%s/%s", connectpath, playpath)
|
self.Path = fmt.Sprintf("/%s/%s", connectpath, playpath)
|
||||||
self.playing = true
|
self.playing = true
|
||||||
self.writing = true
|
self.writing = true
|
||||||
@ -592,6 +638,12 @@ func (self *Conn) ReadPacket() (pkt av.Packet, err error) {
|
|||||||
pkt.Data = tag.Data
|
pkt.Data = tag.Data
|
||||||
pkt.Idx = int8(self.audiostreamidx)
|
pkt.Idx = int8(self.audiostreamidx)
|
||||||
break poll
|
break poll
|
||||||
|
|
||||||
|
case msgtypeidUserControl:
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("debug %d %v", self.msgtypeid, self.msgdata)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,7 +653,7 @@ func (self *Conn) ReadPacket() (pkt av.Packet, err error) {
|
|||||||
|
|
||||||
func (self *Conn) ReadHeader() (err error) {
|
func (self *Conn) ReadHeader() (err error) {
|
||||||
if !self.reading && !self.writing {
|
if !self.reading && !self.writing {
|
||||||
if err = self.handshake(); err != nil {
|
if err = self.handshakeClient(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = self.connectPlay(); err != nil {
|
if err = self.connectPlay(); err != nil {
|
||||||
@ -897,6 +949,11 @@ func (self *Conn) writeChunks(csid uint32, timestamp uint32, msgtypeid uint8, ms
|
|||||||
|
|
||||||
if self.Debug {
|
if self.Debug {
|
||||||
fmt.Printf("rtmp: write chunk msgdatalen=%d msgsid=%d\n", msgdatalen, msgsid)
|
fmt.Printf("rtmp: write chunk msgdatalen=%d msgsid=%d\n", msgdatalen, msgsid)
|
||||||
|
b := []byte{}
|
||||||
|
for _, a := range msgdatav {
|
||||||
|
b = append(b, a...)
|
||||||
|
}
|
||||||
|
fmt.Print(hex.Dump(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = self.bufw.Flush(); err != nil {
|
if err = self.bufw.Flush(); err != nil {
|
||||||
@ -932,15 +989,11 @@ func (self *Conn) readChunk() (err error) {
|
|||||||
csid = uint32(i)+64
|
csid = uint32(i)+64
|
||||||
}
|
}
|
||||||
|
|
||||||
var cs *chunkStream
|
cs := self.csmap[csid]
|
||||||
if self.lastcs != nil && self.lastcsid == csid {
|
if cs == nil {
|
||||||
cs = self.lastcs
|
|
||||||
} else {
|
|
||||||
cs = &chunkStream{}
|
cs = &chunkStream{}
|
||||||
self.csmap[csid] = cs
|
self.csmap[csid] = cs
|
||||||
}
|
}
|
||||||
self.lastcs = cs
|
|
||||||
self.lastcsid = csid
|
|
||||||
|
|
||||||
var timestamp uint32
|
var timestamp uint32
|
||||||
|
|
||||||
@ -1085,8 +1138,8 @@ func (self *Conn) readChunk() (err error) {
|
|||||||
cs.msgdataleft -= uint32(size)
|
cs.msgdataleft -= uint32(size)
|
||||||
|
|
||||||
if self.Debug {
|
if self.Debug {
|
||||||
fmt.Printf("rtmp: chunk csid=%d msgsid=%d msgtypeid=%d msghdrtype=%d len=%d left=%d\n",
|
fmt.Printf("rtmp: chunk msgsid=%d msgtypeid=%d msghdrtype=%d len=%d left=%d\n",
|
||||||
csid, cs.msgsid, cs.msgtypeid, cs.msghdrtype, cs.msgdatalen, cs.msgdataleft)
|
cs.msgsid, cs.msgtypeid, cs.msghdrtype, cs.msgdatalen, cs.msgdataleft)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cs.msgdataleft == 0 {
|
if cs.msgdataleft == 0 {
|
||||||
@ -1245,14 +1298,6 @@ func hsCreateC1(p []byte) {
|
|||||||
copy(p[gap:], digest)
|
copy(p[gap:], digest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Conn) handshake() (err error) {
|
|
||||||
if self.isserver {
|
|
||||||
return self.handshakeServer()
|
|
||||||
} else {
|
|
||||||
return self.handshakeClient()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Conn) handshakeClient() (err error) {
|
func (self *Conn) handshakeClient() (err error) {
|
||||||
var random [(1+1536*2)*2]byte
|
var random [(1+1536*2)*2]byte
|
||||||
|
|
||||||
@ -1289,6 +1334,9 @@ func (self *Conn) handshakeClient() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if S1[4] >= 3 {
|
if S1[4] >= 3 {
|
||||||
|
// TODO
|
||||||
|
err = fmt.Errorf("rtmp: newstyle handshake unspported")
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
C2 = S1
|
C2 = S1
|
||||||
}
|
}
|
||||||
@ -1305,6 +1353,48 @@ func (self *Conn) handshakeClient() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Conn) handshakeServer() (err error) {
|
func (self *Conn) handshakeServer() (err error) {
|
||||||
|
var random [(1+1536*2)*2]byte
|
||||||
|
|
||||||
|
C0C1C2 := random[:1536*2+1]
|
||||||
|
C0 := C0C1C2[:1]
|
||||||
|
C1 := C0C1C2[1:1536+1]
|
||||||
|
C0C1 := C0C1C2[:1536+1]
|
||||||
|
C2 := C0C1C2[1536+1:]
|
||||||
|
|
||||||
|
S0S1S2 := random[1536*2+1:]
|
||||||
|
S0 := S0S1S2[:1]
|
||||||
|
S1 := S0S1S2[1:1536+1]
|
||||||
|
//S0S1 := S0S1S2[:1536+1]
|
||||||
|
S2 := S0S1S2[1536+1:]
|
||||||
|
|
||||||
|
// < C0C1
|
||||||
|
if _, err = io.ReadFull(self.br, C0C1); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if C0[0] != 3 {
|
||||||
|
err = fmt.Errorf("rtmp: handshake version=%d invalid", C0[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
S0[0] = 3
|
||||||
|
copy(S1[0:4], C1[0:4])
|
||||||
|
rand.Read(S1[8:])
|
||||||
|
copy(S2[0:4], C1[0:4])
|
||||||
|
copy(S2[8:], C1[8:])
|
||||||
|
|
||||||
|
// > S0S1S2
|
||||||
|
if _, err = self.bw.Write(S0S1S2); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = self.bufw.Flush(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// < C2
|
||||||
|
if _, err = io.ReadFull(self.br, C2); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user