/* NAME session.go DESCRIPTION See Readme.md AUTHORS Saxon Nelson-Milton Dan Kortschak Alan Noble LICENSE session.go is Copyright (C) 2017-2019 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. Derived from librtmp under the GNU Lesser General Public License 2.1 Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org Copyright (C) 2008-2009 Andrej Stepanchuk Copyright (C) 2009-2010 Howard Chu */ package rtmp import ( "errors" ) // Session holds the state for an RTMP session. type Session struct { url string timeout uint inChunkSize int32 outChunkSize int32 bwCheckCounter int32 nBytesIn int32 nBytesInSent int32 streamID int32 serverBW int32 clientBW int32 clientBW2 uint8 isPlaying bool sendEncoding bool numInvokes int32 methodCalls []method channelsAllocatedIn int32 channelsAllocatedOut int32 vecChannelsIn []*packet vecChannelsOut []*packet channelTimestamp []int32 audioCodecs float64 videoCodecs float64 encoding float64 write packet defered []byte link link } // NewSession returns a new Session. func NewSession(url string, connectTimeout uint) *Session { return &Session{ url: url, timeout: connectTimeout, } } // Open establishes an rtmp connection with the url passed into the constructor. func (s *Session) Open() error { if s.isConnected() { return errors.New("rtmp: attempt to start already running session") } err := s.start() if err != nil { return err } return nil } // start does the heavylifting for Open(). func (s *Session) start() error { s.init() err := C_RTMP_SetupURL(s, s.url) if err != nil { s.close() return err } C_RTMP_EnableWrite(s) err = C_RTMP_Connect(s, nil) if err != nil { s.close() return err } err = C_RTMP_ConnectStream(s, 0) if err != nil { s.close() return err } return nil } // init initializes various RTMP defauls. // ToDo: define consts for the magic numbers. func (s *Session) init() { s.inChunkSize = RTMP_DEFAULT_CHUNKSIZE s.outChunkSize = RTMP_DEFAULT_CHUNKSIZE s.clientBW = 2500000 s.clientBW2 = 2 s.serverBW = 2500000 s.audioCodecs = 3191.0 s.videoCodecs = 252.0 s.link.timeout = s.timeout s.link.swfAge = 30 } // Close terminates the rtmp connection, func (s *Session) Close() error { if !s.isConnected() { return Err(3) } s.close() return nil } // close does the heavylifting for Close(). // Any errors are ignored as it is often called in response to an earlier error. func (s *Session) close() { if s.isConnected() { if s.streamID > 0 { if s.link.protocol&RTMP_FEATURE_WRITE != 0 { C_SendFCUnpublish(s) } C_SendDeleteStream(s, float64(s.streamID)) } s.link.conn.Close() } s = &Session{} } // Write writes a frame (flv tag) to the rtmp connection. func (s *Session) Write(data []byte) (int, error) { if !s.isConnected() { return 0, Err(1) } err := C_RTMP_Write(s, data) if err != nil { // TODO: propagate err return 0, Err(2) } return len(data), nil } // isConnected returns true if the RTMP connection is up. func (s *Session) isConnected() bool { return s.link.conn != nil }