package vnc2video import ( "encoding/binary" "net" "github.com/amitbet/vnc2video/logger" "io" "time" ) // Conn represents vnc conection type FbsConn struct { FbsReader protocol string //c net.IServerConn //config *ClientConfig colorMap ColorMap // Encodings supported by the client. This should not be modified // directly. Instead, SetEncodings should be used. encodings []Encoding // Height of the frame buffer in pixels, sent from the server. fbHeight uint16 // Width of the frame buffer in pixels, sent from the server. fbWidth uint16 desktopName string // The pixel format associated with the connection. This shouldn't // be modified. If you wish to set a new pixel format, use the // SetPixelFormat method. pixelFormat PixelFormat } // func (c *FbsConn) Close() error { // return c.fbs.Close() // } // // Read reads data from conn // func (c *FbsConn) Read(buf []byte) (int, error) { // return c.fbs.Read(buf) // } //dummy, no writing to this conn... func (c *FbsConn) Write(buf []byte) (int, error) { return len(buf), nil } func (c *FbsConn) Conn() net.Conn { return nil } func (c *FbsConn) Config() interface{} { return nil } func (c *FbsConn) Protocol() string { return "RFB 003.008" } func (c *FbsConn) PixelFormat() PixelFormat { return c.pixelFormat } func (c *FbsConn) SetPixelFormat(pf PixelFormat) error { c.pixelFormat = pf return nil } func (c *FbsConn) ColorMap() ColorMap { return c.colorMap } func (c *FbsConn) SetColorMap(cm ColorMap) { c.colorMap = cm } func (c *FbsConn) Encodings() []Encoding { return c.encodings } func (c *FbsConn) SetEncodings([]EncodingType) error { return nil } func (c *FbsConn) Width() uint16 { return c.fbWidth } func (c *FbsConn) Height() uint16 { return c.fbHeight } func (c *FbsConn) SetWidth(w uint16) { c.fbWidth = w } func (c *FbsConn) SetHeight(h uint16) { c.fbHeight = h } func (c *FbsConn) DesktopName() []byte { return []byte(c.desktopName) } func (c *FbsConn) SetDesktopName(d []byte) { c.desktopName = string(d) } func (c *FbsConn) Flush() error { return nil } func (c *FbsConn) Wait() {} func (c *FbsConn) SetProtoVersion(string) {} func (c *FbsConn) SetSecurityHandler(SecurityHandler) error { return nil } func (c *FbsConn) SecurityHandler() SecurityHandler { return nil } func (c *FbsConn) GetEncInstance(typ EncodingType) Encoding { for _, enc := range c.encodings { if enc.Type() == typ { return enc } } return nil } type VncStreamFileReader interface { io.Reader CurrentTimestamp() int ReadStartSession() (*ServerInit, error) CurrentPixelFormat() *PixelFormat Encodings() []Encoding } type FBSPlayHelper struct { Conn *FbsConn //Fbs VncStreamFileReader serverMessageMap map[uint8]ServerMessage firstSegDone bool startTime int } func NewFbsConn(filename string, encs []Encoding) (*FbsConn, error) { fbs, err := NewFbsReader(filename) if err != nil { logger.Error("failed to open fbs reader:", err) return nil, err } //NewFbsReader("/Users/amitbet/vncRec/recording.rbs") initMsg, err := fbs.ReadStartSession() if err != nil { logger.Error("failed to open read fbs start session:", err) return nil, err } fbsConn := &FbsConn{FbsReader: *fbs} fbsConn.encodings = encs fbsConn.SetPixelFormat(initMsg.PixelFormat) fbsConn.SetHeight(initMsg.FBHeight) fbsConn.SetWidth(initMsg.FBWidth) fbsConn.SetDesktopName([]byte(initMsg.NameText)) return fbsConn, nil } func NewFBSPlayHelper(r *FbsConn) *FBSPlayHelper { h := &FBSPlayHelper{Conn: r} h.startTime = int(time.Now().UnixNano() / int64(time.Millisecond)) h.serverMessageMap = make(map[uint8]ServerMessage) h.serverMessageMap[0] = &FramebufferUpdate{} h.serverMessageMap[1] = &SetColorMapEntries{} h.serverMessageMap[2] = &Bell{} h.serverMessageMap[3] = &ServerCutText{} return h } // func (handler *FBSPlayHelper) Consume(seg *RfbSegment) error { // switch seg.SegmentType { // case SegmentFullyParsedClientMessage: // clientMsg := seg.Message.(ClientMessage) // logger.Tracef("ClientUpdater.Consume:(vnc-server-bound) got ClientMessage type=%s", clientMsg.Type()) // switch clientMsg.Type() { // case FramebufferUpdateRequestMsgType: // if !handler.firstSegDone { // handler.firstSegDone = true // handler.startTime = int(time.Now().UnixNano() / int64(time.Millisecond)) // } // handler.sendFbsMessage() // } // // server.MsgFramebufferUpdateRequest: // } // return nil // } func (h *FBSPlayHelper) ReadFbsMessage(SyncWithTimestamps bool, SpeedFactor float64) (ServerMessage, error) { var messageType uint8 //messages := make(map[uint8]ServerMessage) fbs := h.Conn //conn := h.Conn err := binary.Read(fbs, binary.BigEndian, &messageType) if err != nil { logger.Error("FBSConn.NewConnHandler: Error in reading FBS: ", err) return nil, err } startTimeMsgHandling := time.Now() //IClientConn{} //binary.Write(h.Conn, binary.BigEndian, messageType) msg := h.serverMessageMap[messageType] if msg == nil { logger.Error("FBSConn.NewConnHandler: Error unknown message type: ", messageType) return nil, err } //read the actual message data //err = binary.Read(fbs, binary.BigEndian, &msg) parsedMsg, err := msg.Read(fbs) if err != nil { logger.Error("FBSConn.NewConnHandler: Error in reading FBS message: ", err) return nil, err } millisSinceStart := int(startTimeMsgHandling.UnixNano()/int64(time.Millisecond)) - h.startTime adjestedTimeStamp := float64(fbs.CurrentTimestamp()) / SpeedFactor millisToSleep := adjestedTimeStamp - float64(millisSinceStart) if millisToSleep > 0 && SyncWithTimestamps { time.Sleep(time.Duration(millisToSleep) * time.Millisecond) } else if millisToSleep < -400 { logger.Errorf("rendering time is noticeably off, change speedup factor: videoTimeLine: %f, currentTime:%d, offset: %f", adjestedTimeStamp, millisSinceStart, millisToSleep) } return parsedMsg, nil }