switch streams

This commit is contained in:
cfanfrank 2013-03-20 23:44:56 +08:00
parent fc3c9d7af3
commit 7aeca4e959
4 changed files with 157 additions and 85 deletions

View File

@ -97,25 +97,25 @@ func createResp(b []byte, key []byte) {
func parseChal(b []byte, peerKey []byte, key []byte) (dig []byte, err int) { func parseChal(b []byte, peerKey []byte, key []byte) (dig []byte, err int) {
if b[0] != 0x3 { if b[0] != 0x3 {
l.Printf("handshake: invalid rtmp version\n") l.Printf("handshake: invalid rtmp version")
err = 1 err = 1
return return
} }
epoch := b[1:5] epoch := b[1:5]
ver := b[5:9] ver := b[5:9]
l.Printf("handshake: epoch %v ver %v\n", epoch, ver) l.Printf("handshake: epoch %v ver %v", epoch, ver)
var offs int var offs int
if offs = findDigest(b[1:], peerKey, 772); offs == -1 { if offs = findDigest(b[1:], peerKey, 772); offs == -1 {
if offs = findDigest(b[1:], peerKey, 8); offs == -1 { if offs = findDigest(b[1:], peerKey, 8); offs == -1 {
l.Printf("handshake: digest not found\n") l.Printf("handshake: digest not found")
err = 1 err = 1
return return
} }
} }
l.Printf("handshake: offs = %v\n", offs) l.Printf("handshake: offs = %v", offs)
dig = makeDigest(key, b[1+offs:1+offs+32], -1) dig = makeDigest(key, b[1+offs:1+offs+32], -1)
return return
@ -124,22 +124,22 @@ func parseChal(b []byte, peerKey []byte, key []byte) (dig []byte, err int) {
func handShake(rw io.ReadWriter) { func handShake(rw io.ReadWriter) {
b := ReadBuf(rw, 1537) b := ReadBuf(rw, 1537)
l.Printf("handshake: got client chal\n") l.Printf("handshake: got client chal")
dig, err := parseChal(b, clientKey2, serverKey) dig, err := parseChal(b, clientKey2, serverKey)
if err != 0 { if err != 0 {
return return
} }
createChal(b, serverVersion, serverKey2) createChal(b, serverVersion, serverKey2)
l.Printf("handshake: send server chal\n") l.Printf("handshake: send server chal")
rw.Write(b) rw.Write(b)
b = make([]byte, 1536) b = make([]byte, 1536)
createResp(b, dig) createResp(b, dig)
l.Printf("handshake: send server resp\n") l.Printf("handshake: send server resp")
rw.Write(b) rw.Write(b)
b = ReadBuf(rw, 1536) b = ReadBuf(rw, 1536)
l.Printf("handshake: got client resp\n") l.Printf("handshake: got client resp")
} }

1
msg.go
View File

@ -111,6 +111,7 @@ type MsgStream struct {
Msg map[int]*Msg Msg map[int]*Msg
vts, ats int vts, ats int
meta AMFObj
id string id string
role int role int
stat int stat int

107
server.go
View File

@ -12,6 +12,7 @@ import (
"log" "log"
"time" "time"
"strings" "strings"
_ "runtime/debug"
) )
var ( var (
@ -36,7 +37,12 @@ func (e eventS) String() string {
case E_PLAY: case E_PLAY:
return "play" return "play"
case E_DATA: case E_DATA:
return fmt.Sprintf("data %d bytes ts %d", e.m.data.Len(), e.m.curts) switch e.m.typeid {
case MSG_VIDEO:
return fmt.Sprintf("ts %d video %d bytes key %t", e.m.curts, e.m.data.Len(), e.m.key)
case MSG_AUDIO:
return fmt.Sprintf("ts %d audio %d bytes", e.m.curts, e.m.data.Len())
}
case E_CLOSE: case E_CLOSE:
return "close" return "close"
} }
@ -63,7 +69,6 @@ const (
E_CLOSE E_CLOSE
) )
func handleConnect(mr *MsgStream, trans float64, app string) { func handleConnect(mr *MsgStream, trans float64, app string) {
l.Printf("stream %v: connect: %s", mr, app) l.Printf("stream %v: connect: %s", mr, app)
@ -96,6 +101,7 @@ func handleConnect(mr *MsgStream, trans float64, app string) {
func handleMeta(mr *MsgStream, obj AMFObj) { func handleMeta(mr *MsgStream, obj AMFObj) {
mr.meta = obj
mr.W = int(obj.obj["width"].f64) mr.W = int(obj.obj["width"].f64)
mr.H = int(obj.obj["height"].f64) mr.H = int(obj.obj["height"].f64)
@ -195,6 +201,8 @@ func handlePlay(mr *MsgStream, strid int) {
l.Printf("stream %v: test video %dx%d", mr, mr.W, mr.H) l.Printf("stream %v: test video %dx%d", mr, mr.W, mr.H)
} }
begin := func () {
var b bytes.Buffer var b bytes.Buffer
WriteInt(&b, 0, 2) WriteInt(&b, 0, 2)
WriteInt(&b, strid, 4) WriteInt(&b, strid, 4)
@ -213,7 +221,7 @@ func handlePlay(mr *MsgStream, strid int) {
}, },
}) })
l.Printf("stream %v: video size %dx%d", mr, mr.W, mr.H) l.Printf("stream %v: begin: video %dx%d", mr, mr.W, mr.H)
mr.WriteAMFMeta(5, strid, []AMFObj { mr.WriteAMFMeta(5, strid, []AMFObj {
AMFObj { atype : AMF_STRING, str : "|RtmpSampleAccess", }, AMFObj { atype : AMF_STRING, str : "|RtmpSampleAccess", },
@ -221,8 +229,13 @@ func handlePlay(mr *MsgStream, strid int) {
AMFObj { atype : AMF_BOOLEAN, i: 1, }, AMFObj { atype : AMF_BOOLEAN, i: 1, },
}) })
mr.meta.obj["Server"] = AMFObj { atype : AMF_STRING, str : "Golang Rtmp Server", }
mr.meta.atype = AMF_OBJECT
l.Printf("stream %v: %v", mr, mr.meta)
mr.WriteAMFMeta(5, strid, []AMFObj { mr.WriteAMFMeta(5, strid, []AMFObj {
AMFObj { atype : AMF_STRING, str : "onMetaData", }, AMFObj { atype : AMF_STRING, str : "onMetaData", },
mr.meta,
/*
AMFObj { atype : AMF_OBJECT, AMFObj { atype : AMF_OBJECT,
obj : map[string] AMFObj { obj : map[string] AMFObj {
"Server" : AMFObj { atype : AMF_STRING, str : "Golang Rtmp Server", }, "Server" : AMFObj { atype : AMF_STRING, str : "Golang Rtmp Server", },
@ -238,28 +251,68 @@ func handlePlay(mr *MsgStream, strid int) {
"audiocodecid" : AMFObj { atype : AMF_NUMBER, f64 : 10, }, "audiocodecid" : AMFObj { atype : AMF_NUMBER, f64 : 10, },
}, },
}, },
*/
}) })
}
end := func () {
l.Printf("stream %v: end", mr)
var b bytes.Buffer
WriteInt(&b, 1, 2)
WriteInt(&b, strid, 4)
mr.WriteMsg(0, 2, MSG_USER, 0, 0, b.Bytes()) // stream eof 1
mr.WriteAMFCmd(5, strid, []AMFObj {
AMFObj { atype : AMF_STRING, str : "onStatus", },
AMFObj { atype : AMF_NUMBER, f64 : 0, },
AMFObj { atype : AMF_NULL, },
AMFObj { atype : AMF_OBJECT,
obj : map[string] AMFObj {
"level" : AMFObj { atype : AMF_STRING, str : "status", },
"code" : AMFObj { atype : AMF_STRING, str : "NetStream.Play.Stop", },
"description" : AMFObj { atype : AMF_STRING, str : "Stop live.", },
},
},
})
}
if tsrc == nil { if tsrc == nil {
l.Printf("stream %v: extra size %d %d", mr, len(mr.extraA), len(mr.extraV))
mr.WriteAAC(strid, 0, mr.extraA[2:]) for {
mr.WritePPS(strid, 0, mr.extraV[5:]) nr := 0
l.Printf("stream %v: player wait data", mr)
for { for {
m := <-mr.que m := <-mr.que
l.Printf("data %v: got %v", mr, m) if m == nil {
break
}
//if nr == 0 && !m.key {
// continue
//}
if nr == 0 {
begin()
l.Printf("stream %v: extra size %d %d", mr, len(mr.extraA), len(mr.extraV))
mr.WriteAAC(strid, 0, mr.extraA[2:])
mr.WritePPS(strid, 0, mr.extraV[5:])
}
l.Printf("data %v: got %v curts %v", mr, m, m.curts)
switch m.typeid { switch m.typeid {
case MSG_AUDIO: case MSG_AUDIO:
mr.WriteAudio(strid, m.curts, m.data.Bytes()[2:]) mr.WriteAudio(strid, m.curts, m.data.Bytes()[2:])
case MSG_VIDEO: case MSG_VIDEO:
mr.WriteVideo(strid, m.curts, m.key, m.data.Bytes()[5:]) mr.WriteVideo(strid, m.curts, m.key, m.data.Bytes()[5:])
} }
nr++
} }
end()
}
} else { } else {
begin()
lf, _ := os.Create("/tmp/rtmp.log") lf, _ := os.Create("/tmp/rtmp.log")
ll := log.New(lf, "", 0) ll := log.New(lf, "", 0)
@ -304,6 +357,9 @@ func serve(mr *MsgStream) {
event <- eventS{id:E_CLOSE, mr:mr} event <- eventS{id:E_CLOSE, mr:mr}
<-eventDone <-eventDone
l.Printf("stream %v: closed %v", mr, err) l.Printf("stream %v: closed %v", mr, err)
//if err != "EOF" {
// l.Printf("stream %v: %v", mr, string(debug.Stack()))
//}
} }
}() }()
@ -377,21 +433,27 @@ func listenEvent() {
pubmap[e.mr.app] = e.mr pubmap[e.mr.app] = e.mr
} }
case e.id == E_PLAY: case e.id == E_PLAY:
src, ok := pubmap[e.mr.app]
if !ok || src.stat != WAIT_DATA {
l.Printf("event %v: cannot find publisher with app %s", e.mr, e.mr.app)
e.mr.Close()
} else {
e.mr.W = src.W
e.mr.H = src.H
e.mr.role = PLAYER e.mr.role = PLAYER
e.mr.extraA = src.extraA
e.mr.extraV = src.extraV
e.mr.que = make(chan *Msg, 16) e.mr.que = make(chan *Msg, 16)
for _, mr := range idmap {
if mr.role == PUBLISHER && mr.app == e.mr.app && mr.stat == WAIT_DATA {
e.mr.W = mr.W
e.mr.H = mr.H
e.mr.extraA = mr.extraA
e.mr.extraV = mr.extraV
e.mr.meta = mr.meta
}
} }
case e.id == E_CLOSE: case e.id == E_CLOSE:
if e.mr.role == PUBLISHER { if e.mr.role == PUBLISHER {
delete(pubmap, e.mr.app) delete(pubmap, e.mr.app)
for _, mr := range idmap {
if mr.role == PLAYER && mr.app == e.mr.app {
ch := reflect.ValueOf(mr.que)
var m *Msg = nil
ch.TrySend(reflect.ValueOf(m))
}
}
} }
delete(idmap, e.mr.id) delete(idmap, e.mr.id)
case e.id == E_DATA && e.mr.stat == WAIT_EXTRA: case e.id == E_DATA && e.mr.stat == WAIT_EXTRA:
@ -406,6 +468,15 @@ func listenEvent() {
if len(e.mr.extraA) > 0 && len(e.mr.extraV) > 0 { if len(e.mr.extraA) > 0 && len(e.mr.extraV) > 0 {
l.Printf("event %v: got all extra", e.mr) l.Printf("event %v: got all extra", e.mr)
e.mr.stat = WAIT_DATA e.mr.stat = WAIT_DATA
for _, mr := range idmap {
if mr.role == PLAYER && mr.app == e.mr.app {
mr.W = e.mr.W
mr.H = e.mr.H
mr.extraA = e.mr.extraA
mr.extraV = e.mr.extraV
mr.meta = e.mr.meta
}
}
} }
case e.id == E_DATA && e.mr.stat == WAIT_DATA: case e.id == E_DATA && e.mr.stat == WAIT_DATA:
for _, mr := range idmap { for _, mr := range idmap {

26
util.go
View File

@ -9,29 +9,25 @@ import (
"strings" "strings"
) )
type dummyWriter struct {
}
func (m *dummyWriter) Write(p []byte) (n int, err error) {
return 0, nil
}
type logger int type logger int
func (l logger) Printf(format string, v ...interface{}) { func (l logger) Printf(format string, v ...interface{}) {
str := fmt.Sprintf(format, v...) str := fmt.Sprintf(format, v...)
switch { switch {
case strings.HasPrefix(str, "server") && l >= 0, case strings.HasPrefix(str, "server") && l >= 1,
strings.HasPrefix(str, "stream") && l >= 0, strings.HasPrefix(str, "stream") && l >= 1,
strings.HasPrefix(str, "event") && l >= 0, strings.HasPrefix(str, "event") && l >= 1,
strings.HasPrefix(str, "data") && l >= 0, strings.HasPrefix(str, "data") && l >= 1,
strings.HasPrefix(str, "msg") && l >= 1: strings.HasPrefix(str, "msg") && l >= 2:
l2.Println(str) l2.Println(str)
default:
if l >= 1 {
l2.Println(str)
}
} }
} }
var ( var (
dummyW = &dummyWriter{}
l = logger(0) l = logger(0)
l2 *log.Logger l2 *log.Logger
) )
@ -41,6 +37,10 @@ func init() {
l2.SetFlags(log.Lmicroseconds) l2.SetFlags(log.Lmicroseconds)
} }
func LogLevel(i int) {
l = logger(i)
}
type stream struct { type stream struct {
r io.ReadWriteCloser r io.ReadWriteCloser
} }