From 9d1764db7a72f96ad4fe02e6c3e3cdb821932f5d Mon Sep 17 00:00:00 2001 From: Nick McCready Date: Tue, 18 Jun 2013 23:26:41 -0400 Subject: [PATCH 1/3] making transport parser more flexible in the order of :source,:client_port,:server_port --- .gitignore | 3 + lib/rtsp/client.rb | 4 +- lib/rtsp/transport_parser.rb | 3 + .../real_server_wowza_client_use_spec.rb | 249 ++++++++++++++++++ 4 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 spec/integration/real_server_wowza_client_use_spec.rb 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..36af76d 100644 --- a/lib/rtsp/transport_parser.rb +++ b/lib/rtsp/transport_parser.rb @@ -81,7 +81,10 @@ class TransportParser < Parslet::Parser (semi_colon >> destination).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 >> + (semi_colon >> source).maybe >> + (semi_colon >> client_port.as(:client_port)).maybe >> (semi_colon >> interleaved.as(:interleaved)).maybe >> (semi_colon >> ttl).maybe >> (semi_colon >> port.as(:port)).maybe >> 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..2e95118 --- /dev/null +++ b/spec/integration/real_server_wowza_client_use_spec.rb @@ -0,0 +1,249 @@ +=begin +adapted from +https://github.com/turboladen/rtsp +original copyright notice follows: + +Copyright © 2011 sloveless, mkirby + +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 #{transport}" + #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 + # subject.aggregate_control_track.should == + # "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 + # @url = "media2.tripsmarter.com/LiveTV/BTV" + # sdp = SDP::Description.new + # rtspUrl = configatron.rtsp_server_wowza.media_url + # subject.setup(rtspUrl) + # response = subject.announce(rtspUrl, sdp) + # response.should be_a RTSP::Response + # end + # end + # + describe "#setup" do + after do + subject.teardown(@mediaUrl) + end + + it "extracts the session number" do + 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 From e82f3a76dd3a23d366fc29a99783320795daadae Mon Sep 17 00:00:00 2001 From: Nick McCready Date: Wed, 19 Jun 2013 09:35:51 -0400 Subject: [PATCH 2/3] - added better permutations of client_port,server_port, and source to transport_parser - added tests to handle different permutations of the above to client_use_spec - disabled logging in client_use_spec.rb as this should only be on for debugging --- lib/rtsp/transport_parser.rb | 24 ++++- spec/integration/client_use_spec.rb | 39 ++++++- .../real_server_wowza_client_use_spec.rb | 101 +++++++++--------- spec/support/fake_rtsp_server.rb | 6 +- 4 files changed, 113 insertions(+), 57 deletions(-) diff --git a/lib/rtsp/transport_parser.rb b/lib/rtsp/transport_parser.rb index 36af76d..feaeb78 100644 --- a/lib/rtsp/transport_parser.rb +++ b/lib/rtsp/transport_parser.rb @@ -79,13 +79,33 @@ class TransportParser < Parslet::Parser transport_specifier >> (semi_colon >> broadcast_type.as(:broadcast_type)).maybe >> (semi_colon >> destination).maybe >> - (semi_colon >> source).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 >> - (semi_colon >> interleaved.as(:interleaved)).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 >> 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/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 index 2e95118..b29e948 100644 --- a/spec/integration/real_server_wowza_client_use_spec.rb +++ b/spec/integration/real_server_wowza_client_use_spec.rb @@ -3,7 +3,7 @@ https://github.com/turboladen/rtsp original copyright notice follows: -Copyright © 2011 sloveless, mkirby +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 @@ -32,7 +32,9 @@ # block to show raw output for debugging def setup(url) response = subject.setup(@mediaUrl) do |transport| - puts "SETUP RAW RESPONSE #{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]}" @@ -68,51 +70,50 @@ def setup(url) # describe "#describe" do # before do # puts "Before describe" - # #@response = subject.describe + # @response = subject.describe # puts "Response field = #{@response}" # end - - # it "extracts the aggregate control track" do - # subject.aggregate_control_track.should == - # "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 + # + # it "extracts the aggregate control track" do + # puts "Agg #{subject.aggregate_control_track}" + # "rtsp://#{configatron.rtsp_server_wowza.url}/sa.sdp/" + # end # - # describe "#announce" do - # it "returns a Response" do - # @url = "media2.tripsmarter.com/LiveTV/BTV" - # sdp = SDP::Description.new - # rtspUrl = configatron.rtsp_server_wowza.media_url - # subject.setup(rtspUrl) - # response = subject.announce(rtspUrl, sdp) - # response.should be_a RTSP::Response + # 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 @@ -233,17 +234,17 @@ def setup(url) # # 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 + # 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 From dbc4c6d8b047cac59924f519413a7b407b83df38 Mon Sep 17 00:00:00 2001 From: Nick McCready Date: Thu, 20 Jun 2013 12:20:33 -0400 Subject: [PATCH 3/3] verisoning of X.X.X-SNAPSHOT and or X.X.X added to not interfere with release versioned rtsp gems --- lib/rtsp/version.rb | 7 ++++++- spec/unit/rtsp_spec.rb | 13 +++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) 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/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