Permalink
Browse files

Transfer header parser fixes & improvements. Closes gh-11.

  • Loading branch information...
1 parent 7b3416d commit 727f14b0033ba188f2dd273dc90f40c4b23ff8ae @turboladen committed Mar 9, 2012
Showing with 177 additions and 46 deletions.
  1. +16 −0 ChangeLog.rdoc
  2. +49 −17 lib/rtsp/transport_parser.rb
  3. +1 −1 lib/rtsp/version.rb
  4. +109 −26 spec/rtsp/transport_parser_spec.rb
  5. +2 −2 spec/rtsp_spec.rb
View
@@ -1,3 +1,19 @@
+=== 0.3.1 / 2012-03-08
+
+* gh-11: Transport header parser bolstering:
+ * values that should be caps, will parse OK as lowercase now.
+ * :broadcast_type now parses 'multicast'.
+ * :destination now returns the value of the destination instead of
+ "destination=x.x.x.x"
+ * :source now returns the value of the source instead of "source=x.x.x.x"
+ * Added parsing for fields:
+ * ttl
+ * port
+ * ssrc
+ * channel
+ * address
+ * mode
+
=== 0.3.0 / 2012-03-02
* Extracted RTP-esque functionality to an +rtp+ gem, on which this gem is now
@@ -7,20 +7,21 @@ module RTSP
# other requests.
class TransportParser < Parslet::Parser
rule(:transport_specifier) do
- match('[A-Z]').repeat(3).as(:streaming_protocol) >> forward_slash >>
- match('[A-Z]').repeat(3).as(:profile) >>
- (forward_slash >> match('[A-Z]').repeat(3).as(:transport_protocol)).maybe
+ match('[A-Za-z]').repeat(3).as(:streaming_protocol) >> forward_slash >>
+ match('[A-Za-z]').repeat(3).as(:profile) >>
+ (forward_slash >> match('[A-Za-z]').repeat(3).as(:transport_protocol)).maybe
end
rule(:broadcast_type) do
- str('unicast')
+ str('unicast') | str('multicast')
end
rule(:destination) do
- str('destination=') >> ip_address
+ str('destination=') >> ip_address.as(:destination)
end
+
rule(:source) do
- str('source=') >> ip_address
+ str('source=') >> ip_address.as(:source)
end
rule(:client_port) do
@@ -33,14 +34,40 @@ class TransportParser < Parslet::Parser
rule(:interleaved) do
str('interleaved=') >> number.as(:rtp_channel) >> dash >>
- number.as(:rtcp_channel)
+ number.as(:rtcp_channel)
+ end
+
+ rule(:ttl) do
+ str('ttl=') >> match('[\d]').repeat(1,3).as(:ttl)
+ end
+
+ rule(:port) do
+ str('port=') >> match('[\d]').repeat(1,5).as(:rtp) >>
+ dash.maybe >> match('[\d]').repeat(1,5).as(:rtcp).maybe
+ end
+
+ rule(:ssrc) do
+ str('ssrc=') >> match('[0-9A-Fa-f]').repeat(8).as(:ssrc)
+ end
+
+ rule(:channel) do
+ str('channel=') >> match('[\w]').repeat(1,3).as(:channel)
+ end
+
+ rule(:address) do
+ str('address=') >> match('[\S]').repeat.as(:address)
+ end
+
+ rule(:mode) do
+ str('mode=') >> str('"').maybe >> match('[A-Za-z]').repeat.as(:mode) >>
+ str('"').maybe
end
rule(:ip_address) do
match('[\d]').repeat(1,3) >> str('.') >>
- match('[\d]').repeat(1,3) >> str('.') >>
- match('[\d]').repeat(1,3) >> str('.') >>
- match('[\d]').repeat(1,3)
+ match('[\d]').repeat(1,3) >> str('.') >>
+ match('[\d]').repeat(1,3) >> str('.') >>
+ match('[\d]').repeat(1,3)
end
rule(:number) { match('[\d]').repeat }
@@ -50,13 +77,18 @@ class TransportParser < Parslet::Parser
rule(:header_field) do
transport_specifier >>
- (semi_colon >> broadcast_type.as(:broadcast_type)).maybe >>
- (semi_colon >> destination.as(:destination)).maybe >>
- (semi_colon >> source.as(:source)).maybe >>
- (semi_colon >> client_port.as(:client_port)).maybe >>
- (semi_colon >> server_port.as(:server_port)).maybe >>
- (semi_colon >> interleaved.as(:interleaved)).maybe
-
+ (semi_colon >> broadcast_type.as(:broadcast_type)).maybe >>
+ (semi_colon >> destination).maybe >>
+ (semi_colon >> source).maybe >>
+ (semi_colon >> client_port.as(:client_port)).maybe >>
+ (semi_colon >> server_port.as(:server_port)).maybe >>
+ (semi_colon >> interleaved.as(:interleaved)).maybe >>
+ (semi_colon >> ttl).maybe >>
+ (semi_colon >> port.as(:port)).maybe >>
+ (semi_colon >> ssrc).maybe >>
+ (semi_colon >> channel).maybe >>
+ (semi_colon >> address).maybe >>
+ (semi_colon >> mode).maybe
end
root :header_field
View
@@ -1,4 +1,4 @@
module RTSP
# rtsp version
- VERSION = "0.3.0"
+ VERSION = "0.3.1"
end
@@ -2,53 +2,136 @@
require 'rtsp/transport_parser'
describe RTSP::TransportParser do
- before do
- @parser = RTSP::TransportParser.new
+ let(:result) { subject.parse transport }
+
+ describe :transport_specifier do
+ context "RTP/AVP" do
+ let(:transport) { "RTP/AVP" }
+ specify { result[:streaming_protocol].should == 'RTP' }
+ specify { result[:profile].should == 'AVP' }
+ end
+
+ context "RTP/AVP/TCP" do
+ let(:transport) { "RTP/AVP/TCP" }
+ specify { result[:streaming_protocol].should == 'RTP' }
+ specify { result[:profile].should == 'AVP' }
+ specify { result[:transport_protocol].should == 'TCP' }
+ end
+
+ context "rtp/avp/tcp" do
+ let(:transport) { "rtp/avp/tcp" }
+ specify { result[:streaming_protocol].should == 'rtp' }
+ specify { result[:profile].should == 'avp' }
+ specify { result[:transport_protocol].should == 'tcp' }
+ end
+ end
+
+ describe :broadcast_type do
+ context "RTP/AVP;unicast" do
+ let(:transport) { "RTP/AVP;unicast" }
+ specify { result[:broadcast_type].should == 'unicast' }
+ end
+
+ context "RTP/AVP;multicast" do
+ let(:transport) { "RTP/AVP;multicast" }
+ specify { result[:broadcast_type].should == 'multicast' }
+ end
+ end
+
+ describe :destination do
+ context "RTP/AVP;multicast;destination=224.2.0.1" do
+ let(:transport) { "RTP/AVP;multicast;destination=224.2.0.1" }
+ specify { result[:destination].should == '224.2.0.1' }
+ end
end
- describe "a basic Transport header" do
- before do
- transport = "RTP/AVP;unicast;client_port=9000-9001"
- @result = @parser.parse transport
+ describe :source do
+ context "RTP/AVP;multicast;destination=22.2.0.1;source=10.0.0.10" do
+ let(:transport) { "RTP/AVP;multicast;destination=22.2.0.1;source=10.0.0.10" }
+ specify { result[:source].should == '10.0.0.10' }
end
+ end
+
+ describe :client_port do
+ context "RTP/AVP;unicast;client_port=9000-9001" do
+ let(:transport) { "RTP/AVP;unicast;client_port=9000-9001" }
+ specify { result[:client_port][:rtp].should == '9000' }
+ specify { result[:client_port][:rtcp].should == '9001' }
+ end
+ end
+
+ describe :server_port do
+ context "RTP/AVP/UCP;unicast;client_port=3058-3059;server_port=5002-5003" do
+ let(:transport) { "RTP/AVP/UCP;unicast;client_port=3058-3059;server_port=5002-5003" }
+ specify { result[:server_port][:rtp].should == "5002" }
+ specify { result[:server_port][:rtcp].should == "5003" }
+ end
+ end
- it "extracts the protocol" do
- @result[:streaming_protocol].should == 'RTP'
+ describe :interleaved do
+ context "RTP/AVP/TCP;unicast;interleaved=0-1" do
+ let(:transport) { "RTP/AVP/TCP;unicast;interleaved=0-1" }
+ specify { result[:interleaved][:rtp_channel].should == '0' }
+ specify { result[:interleaved][:rtcp_channel].should == '1' }
end
+ end
- it "extracts the profile" do
- @result[:profile].should == 'AVP'
+ describe :ttl do
+ context 'RTP/AVP;unicast;ttl=127' do
+ let(:transport) { 'RTP/AVP;unicast;ttl=127' }
+ specify { result[:ttl].should == "127" }
end
+ end
- it "extracts the broadcast type" do
- @result[:broadcast_type].should == 'unicast'
+ describe :port do
+ context 'RTP/AVP;unicast;port=1234' do
+ let(:transport) { 'RTP/AVP;unicast;port=1234' }
+ specify { result[:port][:rtp].should == "1234" }
+ specify { result[:port][:rtcp].should be_nil }
end
- it "extracts the client RTP port" do
- @result[:client_port][:rtp].should == '9000'
+ context 'RTP/AVP;unicast;port=1234-1235' do
+ let(:transport) { 'RTP/AVP;unicast;port=1234-1235' }
+ specify { result[:port][:rtp].should == "1234" }
+ specify { result[:port][:rtcp].should == "1235" }
end
+ end
- it "extracts the client RTCP port" do
- @result[:client_port][:rtcp].should == '9001'
+ describe :ssrc do
+ context 'RTP/AVP;unicast;ssrc=ABCD1234' do
+ let(:transport) { 'RTP/AVP;unicast;ssrc=ABCD1234' }
+ specify { result[:ssrc].should == "ABCD1234" }
end
end
- describe "a TCP binary interleaved Transport header" do
- before do
- transport = "RTP/AVP/TCP;unicast;interleaved=0-1"
- @result = @parser.parse transport
+ describe :channel do
+ context 'RTP/AVP;unicast;channel=RTP' do
+ let(:transport) { 'RTP/AVP;unicast;channel=RTP' }
+ specify { result[:channel].should == "RTP" }
end
+ end
- it "extracts the lower transport type" do
- @result[:transport_protocol].should == 'TCP'
+ describe :address do
+ context 'RTP/AVP;unicast;address=192.168.14.18' do
+ let(:transport) { 'RTP/AVP;unicast;address=192.168.14.18' }
+ specify { result[:address].should == "192.168.14.18" }
end
- it "extracts the interleaved RTP channel" do
- @result[:interleaved][:rtp_channel].should == '0'
+ context 'RTP/AVP;unicast;address=mycomputer.com' do
+ let(:transport) { 'RTP/AVP;unicast;address=mycomputer.com' }
+ specify { result[:address].should == "mycomputer.com" }
+ end
+ end
+
+ describe :mode do
+ context 'RTP/AVP;unicast;mode="PLAY"' do
+ let(:transport) { 'RTP/AVP;unicast;mode="PLAY"' }
+ specify { result[:mode].should == "PLAY" }
end
- it "extracts the interleaved RTCP channel" do
- @result[:interleaved][:rtcp_channel].should == '1'
+ context 'with ttl=127;mode=RECORD' do
+ let(:transport) { 'RTP/AVP;unicast;mode=RECORD' }
+ specify { result[:mode].should == "RECORD" }
end
end
end
View
@@ -21,7 +21,7 @@ def self.get_requires
RTSP.const_defined?('VERSION').should be_true
end
- it "has version 0.2.2" do
- RTSP::VERSION.should == '0.2.2'
+ it "has version 0.3.1" do
+ RTSP::VERSION.should == '0.3.1'
end
end

0 comments on commit 727f14b

Please sign in to comment.