diff --git a/protocol/rtsp/cmd/stream/main.go b/protocol/rtsp/cmd/stream/main.go index 7a9a5d87..e53e4fe5 100644 --- a/protocol/rtsp/cmd/stream/main.go +++ b/protocol/rtsp/cmd/stream/main.go @@ -1,9 +1,63 @@ +/* +NAME + main.go + +DESCRIPTION + main.go provides a program to connect to an RTSP server and request for an + RTP stream. + +AUTHORS + Saxon A. Nelson-Milton + +LICENSE + This is Copyright (C) 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 + in gpl.txt. If not, see http://www.gnu.org/licenses. + + Copyright (c) 2015, T. Jameson Little + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ package main import ( "flag" "fmt" - "io" "log" "bitbucket.org/ausocean/av/protocol/rtsp" @@ -15,28 +69,26 @@ func main() { trackPtr := flag.String("track", "track1", "The track that we would like to receive media from") flag.Parse() - sess := rtsp.NewSession() - res, err := sess.Options(*rtspServerPtr) + sess, err := rtsp.NewSession(*rtspServerPtr) + if err != nil { + panic(fmt.Sprintf("creating RTSP session failed with error: %v", err)) + } + + res, err := sess.Options() if err != nil { log.Fatalln(err) } fmt.Println("Options:") fmt.Println(res) - res, err = sess.Describe(*rtspServerPtr) + res, err = sess.Describe() if err != nil { log.Fatalln(err) } fmt.Println("Describe:") fmt.Println(res) - p, err := rtsp.ParseSdp(&io.LimitedReader{R: res.Body, N: res.ContentLength}) - if err != nil { - log.Fatalln(err) - } - log.Printf("%+v", p) - - res, err = sess.Setup(*rtspServerPtr+"/"+*trackPtr, fmt.Sprintf("RTP/AVP;unicast;client_port=%d-%d", *clientPortPtr, *clientPortPtr+1)) + res, err = sess.Setup(*trackPtr, fmt.Sprintf("RTP/AVP;unicast;client_port=%d-%d", *clientPortPtr, *clientPortPtr+1)) if err != nil { log.Fatalln(err) } diff --git a/protocol/rtsp/rtsp.go b/protocol/rtsp/rtsp.go index 84cf5276..3920a5d3 100644 --- a/protocol/rtsp/rtsp.go +++ b/protocol/rtsp/rtsp.go @@ -78,18 +78,19 @@ const ( setup = "SETUP" ) -// session describes an RTSP session. -type session struct { +// Session describes an RTSP Session. +type Session struct { cSeq int + urlStr string url *url.URL conn net.Conn - session string + Session string } -// NewSession returns a pointer to a new session. The URL u will be parsed and +// NewSession returns a pointer to a new Session. The URL u will be parsed and // a connection to the RTSP server will be made. -func NewSession(u string) (*session, error) { - s := &session{} +func NewSession(u string) (*Session, error) { + s := &Session{urlStr: u} var err error s.url, err = url.Parse(u) if err != nil { @@ -103,40 +104,45 @@ func NewSession(u string) (*session, error) { } // Describe forms and sends an RTSP request of method DESCRIBE to the RTSP server. -func (s *session) Describe() (*Response, error) { - return s.writeRequest(describe, func(req *Request) { req.Header.Add("Accept", "application/sdp") }, nil) +func (s *Session) Describe() (*Response, error) { + return s.writeRequest(s.url, describe, func(req *Request) { req.Header.Add("Accept", "application/sdp") }, nil) } // Options forms and sends an RTSP request of method OPTIONS to the RTSP server. -func (s *session) Options(urlStr string) (*Response, error) { - return s.writeRequest(options, nil, nil) +func (s *Session) Options() (*Response, error) { + return s.writeRequest(s.url, options, nil, nil) } // Setup forms and sends an RTSP request of method SETUP to the RTSP server. -func (s *session) Setup(transport string) (*Response, error) { +func (s *Session) Setup(track, transport string) (*Response, error) { + url, err := url.Parse(s.urlStr + "/" + track) + if err != nil { + return nil, err + } return s.writeRequest( + url, setup, func(req *Request) { req.Header.Add("Transport", transport) }, func(resp *Response) { - s.session = resp.Header.Get("session") + s.Session = resp.Header.Get("Session") }, ) } // Play forms and sends an RTSP request of method PLAY to the RTSP server -func (s *session) Play() (*Response, error) { - return s.writeRequest(play, func(req *Request) { req.Header.Add("session", s.session) }, nil) +func (s *Session) Play() (*Response, error) { + return s.writeRequest(s.url, play, func(req *Request) { req.Header.Add("Session", s.Session) }, nil) } // writeRequest creates an RTSP request of the method given and writes it to the -// the session connection. +// the Session connection. // //headerOp and respOp define any operation that needs // to occur to the request or response for the given method. -func (s *session) writeRequest(method string, headerOp func(*Request), respOp func(*Response)) (*Response, error) { - req, err := NewRequest(method, s.nextCSeq(), s.url, nil) +func (s *Session) writeRequest(url *url.URL, method string, headerOp func(*Request), respOp func(*Response)) (*Response, error) { + req, err := NewRequest(method, s.nextCSeq(), url, nil) if err != nil { return nil, err } @@ -161,7 +167,7 @@ func (s *session) writeRequest(method string, headerOp func(*Request), respOp fu return res, nil } -func (s *session) nextCSeq() string { +func (s *Session) nextCSeq() string { s.cSeq++ return strconv.Itoa(s.cSeq) }