diff --git a/.gitignore b/.gitignore index 3145523..1fb531c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ doc/ pkg/ *.rtsp .rbx/ +nbproject/ +# vim +*.swp \ No newline at end of file diff --git a/lib/rtsp/client.rb b/lib/rtsp/client.rb index 9d94d91..f25a434 100644 --- a/lib/rtsp/client.rb +++ b/lib/rtsp/client.rb @@ -269,8 +269,10 @@ def setup(track, additional_headers={}) @session = response.session parser = RTSP::TransportParser.new + #pass up raw transport for debug and/or logging + yield response.transport if block_given? @transport = parser.parse(response.transport) - + unless @transport[:transport_protocol].nil? @capturer.transport_protocol = @transport[:transport_protocol] end diff --git a/lib/rtsp/transport_parser.rb b/lib/rtsp/transport_parser.rb index 7df4b0f..feaeb78 100644 --- a/lib/rtsp/transport_parser.rb +++ b/lib/rtsp/transport_parser.rb @@ -79,10 +79,33 @@ class TransportParser < Parslet::Parser transport_specifier >> (semi_colon >> broadcast_type.as(:broadcast_type)).maybe >> (semi_colon >> destination).maybe >> + # server permutation + (semi_colon >> server_port.as(:server_port)).maybe >> + (semi_colon >> client_port.as(:client_port)).maybe >> + (semi_colon >> source).maybe >> + + (semi_colon >> server_port.as(:server_port)).maybe >> (semi_colon >> source).maybe >> (semi_colon >> client_port.as(:client_port)).maybe >> + # client permutation + (semi_colon >> client_port.as(:client_port)).maybe >> + (semi_colon >> server_port.as(:server_port)).maybe >> + (semi_colon >> source).maybe >> + + (semi_colon >> client_port.as(:client_port)).maybe >> + (semi_colon >> source).maybe >> + (semi_colon >> server_port.as(:server_port)).maybe >> + + # source permutation + (semi_colon >> source).maybe >> + (semi_colon >> client_port.as(:client_port)).maybe >> + (semi_colon >> server_port.as(:server_port)).maybe >> + + (semi_colon >> source).maybe >> (semi_colon >> server_port.as(:server_port)).maybe >> - (semi_colon >> interleaved.as(:interleaved)).maybe >> + (semi_colon >> client_port.as(:client_port)).maybe >> + #end permutations for client_port,server_port, and source + (semi_colon >> interleaved.as(:interleaved)).maybe >> (semi_colon >> ttl).maybe >> (semi_colon >> port.as(:port)).maybe >> (semi_colon >> ssrc).maybe >> diff --git a/lib/rtsp/version.rb b/lib/rtsp/version.rb index 801bc4d..a6faf0d 100644 --- a/lib/rtsp/version.rb +++ b/lib/rtsp/version.rb @@ -1,4 +1,9 @@ module RTSP # rtsp version - VERSION = "0.4.3" + VERISON_IS_SNAPSHOT = false + VERISON_IS_RELEASE = false + version = "0.4.4" + snap_str = "#{version}-SNAPSHOT" + daily_str = "#{version}-#{Time.now.strftime("%Y%m%d-%H%M%S")}" + VERSION = (VERISON_IS_RELEASE) ? version : ((VERISON_IS_SNAPSHOT) ? snap_str : daily_str ) end diff --git a/spec/integration/client_use_spec.rb b/spec/integration/client_use_spec.rb index 347877a..436df95 100644 --- a/spec/integration/client_use_spec.rb +++ b/spec/integration/client_use_spec.rb @@ -5,7 +5,12 @@ describe "Client use" do subject do fake_rtsp_server = FakeRTSPServer.new - + + if ! @setup_maybeSource_maybePorts.nil? + fake_rtsp_server.setup_maybeSource_maybePorts = + @setup_maybeSource_maybePorts + end + #puts "SETUP: FakeRTSPServer::setup_maybeSource_maybePorts = #{fake_rtsp_server.setup_maybeSource_maybePorts}!!!!!!!!!!!!" RTSP::Client.new('http://localhost') do |connection| connection.socket = fake_rtsp_server end @@ -66,7 +71,33 @@ subject.teardown("rtsp://localhost/some_track") end - it "extracts the session number" do + it "extracts the session number: default" do + subject.session.should be_empty + subject.setup("rtsp://localhost/some_track") + subject.session[:session_id].should == "1234567890" + end + # order is not specified in the RFC spec , i am a ruby noob, but parselet + # does not seem to work well with things out of order + # is there a better altenative that is more like a JSON parser where order does not matter? + it "extracts the session number with a client_port then source in transport" do + @setup_maybeSource_maybePorts = + "client_port=9000-9001;source=10.221.222.235;server_port=6700-6701" + subject.session.should be_empty + subject.setup("rtsp://localhost/some_track") + subject.session[:session_id].should == "1234567890" + end + + it "extracts the session number with a client_port,server_port,then source in transport" do + @setup_maybeSource_maybePorts = + "client_port=9000-9001;server_port=6700-6701;source=10.221.222.235" + subject.session.should be_empty + subject.setup("rtsp://localhost/some_track") + subject.session[:session_id].should == "1234567890" + end + + it "extracts the session number with a server_port,client_port,then source in transport" do + @setup_maybeSource_maybePorts = + "server_port=6700-6701;client_port=9000-9001;source=10.221.222.235" subject.session.should be_empty subject.setup("rtsp://localhost/some_track") subject.session[:session_id].should == "1234567890" @@ -112,8 +143,8 @@ end it "returns a Response" do - RTSP::Client.log = true - RTP::Logger.log = true + RTSP::Client.log = false + RTP::Logger.log = false response = subject.play("rtsp://localhost/some_track") response.should be_a RTSP::Response end diff --git a/spec/integration/real_server_wowza_client_use_spec.rb b/spec/integration/real_server_wowza_client_use_spec.rb new file mode 100644 index 0000000..b29e948 --- /dev/null +++ b/spec/integration/real_server_wowza_client_use_spec.rb @@ -0,0 +1,250 @@ +=begin +adapted from +https://github.com/turboladen/rtsp +original copyright notice follows: + +Copyright © 2011 sloveless, mkirby, nmccready + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +=end +require 'sdp' +require 'spec_helper' +require 'rtsp/client' + +describe "Real Server (Wowza) Client use" do + + # block to show raw output for debugging + def setup(url) + response = subject.setup(@mediaUrl) do |transport| + puts "SETUP RAW RESPONSE, Trasport: #{transport}" + #by using a block we can now check the error location of the where the + #problem begins + #puts "Pre-ERROR @ RESPONSE #{transport[35]}" + #puts "Pre-ERROR @ RESPONSE #{transport[36]}" + #puts "ERROR @ RESPONSE #{transport[37]}" + end + return response + end + + + subject do + #urls provided by rtsp client adroid app + #alkass TV (updated) + @baseUrl = "78.100.44.238" if @baseUrl.nil? + @mediaUrl = "#{@baseUrl}/live-kass/kass" if @mediaUrl.nil? + puts "RTSP: URL #{@baseUrl}!!!!!" + puts "RTSP: Media URL #{@mediaUrl}!!!!!" + RTSP::Client.new(@baseUrl) + end + + describe "#options" do + it "extracts the server's supported methods" do + subject.options + subject.supported_methods.should == + [:describe, :setup, :teardown, :play, :pause, + :options,:announce,:record,:get_parameter] + end + + it "returns a Response" do + response = subject.options + response.should be_a RTSP::Response + end + end + + # describe "#describe" do + # before do + # puts "Before describe" + # @response = subject.describe + # puts "Response field = #{@response}" + # end + # + # it "extracts the aggregate control track" do + # puts "Agg #{subject.aggregate_control_track}" + # "rtsp://#{configatron.rtsp_server_wowza.url}/sa.sdp/" + # end + # + # it "extracts the media control tracks" do + # subject.media_control_tracks.should == ["rtsp://64.202.98.91:554/sa.sdp/trackID=1"] + # end + # + # it "extracts the SDP object" do + # subject.instance_variable_get(:@session_description).should == + # @response.body + # end + # + # it "extracts the Content-Base header" do + # subject.instance_variable_get(:@content_base).should == + # URI.parse("rtsp://64.202.98.91:554/sa.sdp/") + # end + # + # it "returns a Response" do + # @response.should be_a RTSP::Response + # end + # end + + describe "#announce" do + it "returns a Response" do + sdp = SDP::Description.new + subject.setup(@mediaUrl) + response = subject.announce(@mediaUrl, sdp) + response.should be_a RTSP::Response + end + end + + describe "#setup" do + after do + subject.teardown(@mediaUrl) + end + + it "extracts the session number" do + #RTSP::Client.log = true + subject.session.should be_empty + setup(@mediaUrl) + subject.session[:session_id].to_i.should >= 0 + end + + it "changes the session_state to :ready" do + setup(@mediaUrl) + subject.session_state.should == :ready + end + + it "extracts the transport header info" do + subject.instance_variable_get(:@transport).should be_nil + setup(@mediaUrl) + transport = subject.instance_variable_get(:@transport) + #puts "HASH: transport = #{transport}" + transport[:streaming_protocol].should == "RTP" + transport[:profile].should == "AVP" + transport[:broadcast_type].should == "unicast" + transport[:source].should == "78.100.44.238" + end + + it "returns a Response" do + response = setup(@mediaUrl) + response.should be_a RTSP::Response + end + end + + # describe "#play" do + # before do + # subject.setup(configatron.rtsp_server_wowza.media_url) + # end + # + # after do + # subject.teardown(configatron.rtsp_server_wowza.media_url) + # end + # + # it "changes the session_state to :playing" do + # subject.play(configatron.rtsp_server_wowza.media_url) + # subject.session_state.should == :playing + # end + # + # it "returns a Response" do + # RTSP::Client.log = true + # RTP::Logger.log = true + # response = subject.play(configatron.rtsp_server_wowza.media_url) + # response.should be_a RTSP::Response + # end + # end + # + # describe "#pause" do + # before :each do + # subject.setup("rtsp://localhost/some_track") + # end + # + # after do + # subject.teardown('rtsp://localhost/some_track') + # end + # + # it "changes the session_state from :playing to :ready" do + # subject.play("rtsp://localhost/some_track") + # subject.pause("rtsp://localhost/some_track") + # subject.session_state.should == :ready + # end + # + # it "changes the session_state from :recording to :ready" do + # subject.record("rtsp://localhost/some_track") + # subject.pause("rtsp://localhost/some_track") + # subject.session_state.should == :ready + # end + # + # it "returns a Response" do + # response = subject.pause("rtsp://localhost/some_track") + # response.should be_a RTSP::Response + # end + # end + # + # describe "#teardown" do + # before do + # subject.setup("rtsp://localhost/some_track") + # end + # + # it "changes the session_state to :init" do + # subject.session_state.should_not == :init + # subject.teardown("rtsp://localhost/some_track") + # subject.session_state.should == :init + # end + # + # it "changes the session_id back to 0" do + # subject.session.should_not be_empty + # subject.teardown("rtsp://localhost/some_track") + # subject.session.should be_empty + # end + # + # it "returns a Response" do + # response = subject.teardown("rtsp://localhost/some_track") + # response.should be_a RTSP::Response + # end + # end + # + # describe "#get_parameter" do + # it "returns a Response" do + # response = subject.get_parameter("rtsp://localhost/some_track", "ping!") + # response.should be_a RTSP::Response + # end + # end + # + # describe "#set_parameter" do + # it "returns a Response" do + # response = subject.set_parameter("rtsp://localhost/some_track", "ping!") + # response.should be_a RTSP::Response + # end + # end + # + # describe "#record" do + # before :each do + # subject.setup("rtsp://localhost/some_track") + # end + # + # after do + # subject.teardown('rtsp://localhost/some_track') + # end + # + # it "returns a Response" do + # response = subject.record("rtsp://localhost/some_track") + # response.is_a?(RTSP::Response).should be_true + # end + # + # it "changes the session_state to :recording" do + # subject.session_state.should == :ready + # subject.record("rtsp://localhost/some_track") + # subject.session_state.should == :recording + # end + # end +end \ No newline at end of file diff --git a/spec/support/fake_rtsp_server.rb b/spec/support/fake_rtsp_server.rb index d07de0e..96bcaf3 100644 --- a/spec/support/fake_rtsp_server.rb +++ b/spec/support/fake_rtsp_server.rb @@ -1,7 +1,11 @@ require 'time' class FakeRTSPServer + #allowing the order of things to be mucked with + attr_accessor :setup_maybeSource_maybePorts + def initialize(*args) + @setup_maybeSource_maybePorts = "source=10.221.222.235;client_port=9000-9001;server_port=6700-6701" end def send(*args) @@ -66,7 +70,7 @@ def setup %Q{RTSP/1.0 200 OK\r CSeq: #{@cseq}\r Date: #{Time.now.httpdate}\r -Transport: RTP/AVP;unicast;destination=127.0.0.1;source=10.221.222.235;client_port=9000-9001;server_port=6700-6701\r +Transport: RTP/AVP;unicast;destination=127.0.0.1;#{@setup_maybeSource_maybePorts}\r Session: #{@session}\r \r\n} end diff --git a/spec/unit/rtsp_spec.rb b/spec/unit/rtsp_spec.rb index cb88e84..3717c3f 100644 --- a/spec/unit/rtsp_spec.rb +++ b/spec/unit/rtsp_spec.rb @@ -17,11 +17,16 @@ def self.get_requires end describe RTSP do - it "should have a VERSION constant" do + it "should have a VERSION constant: version is: #{RTSP::VERSION}" do RTSP.const_defined?('VERSION').should be_true end - - it "has version 0.4.3" do - RTSP::VERSION.should == '0.4.3' + it "version should be set correctly" do + if RTSP::VERISON_IS_RELEASE + RTSP::VERSION.should == '0.4.4' + elsif RTSP::VERISON_IS_SNAPSHOT + RTSP::VERSION.should == '0.4.4-SNAPSHOT' + else + RTSP::VERSION.should == "0.4.4-#{Time.now.strftime("%Y%m%d-%H%M%S")}" + end end end