rtsp_server 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/ChangeLog.rdoc +74 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.rdoc +20 -0
  6. data/README.rdoc +152 -0
  7. data/Rakefile +23 -0
  8. data/bin/rtsp_client +133 -0
  9. data/features/client_changes_state.feature +58 -0
  10. data/features/client_requests.feature +27 -0
  11. data/features/control_streams_as_client.feature +26 -0
  12. data/features/step_definitions/client_changes_state_steps.rb +52 -0
  13. data/features/step_definitions/client_requests_steps.rb +68 -0
  14. data/features/step_definitions/control_streams_as_client_steps.rb +34 -0
  15. data/features/support/env.rb +50 -0
  16. data/features/support/hooks.rb +3 -0
  17. data/lib/ext/logger.rb +8 -0
  18. data/lib/rtsp/client.rb +520 -0
  19. data/lib/rtsp/common.rb +148 -0
  20. data/lib/rtsp/error.rb +6 -0
  21. data/lib/rtsp/global.rb +63 -0
  22. data/lib/rtsp/helpers.rb +28 -0
  23. data/lib/rtsp/message.rb +272 -0
  24. data/lib/rtsp/request.rb +39 -0
  25. data/lib/rtsp/response.rb +47 -0
  26. data/lib/rtsp/server.rb +303 -0
  27. data/lib/rtsp/socat_streaming.rb +309 -0
  28. data/lib/rtsp/stream_server.rb +37 -0
  29. data/lib/rtsp/transport_parser.rb +96 -0
  30. data/lib/rtsp/version.rb +4 -0
  31. data/lib/rtsp.rb +6 -0
  32. data/rtsp.gemspec +42 -0
  33. data/spec/rtsp/client_spec.rb +326 -0
  34. data/spec/rtsp/helpers_spec.rb +53 -0
  35. data/spec/rtsp/message_spec.rb +420 -0
  36. data/spec/rtsp/response_spec.rb +306 -0
  37. data/spec/rtsp/transport_parser_spec.rb +137 -0
  38. data/spec/rtsp_spec.rb +27 -0
  39. data/spec/spec_helper.rb +88 -0
  40. data/spec/support/fake_rtsp_server.rb +123 -0
  41. data/tasks/roodi.rake +9 -0
  42. data/tasks/roodi_config.yaml +14 -0
  43. data/tasks/stats.rake +12 -0
  44. metadata +280 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 77b1c4b86a85675da639393964752c3197adf745
4
+ data.tar.gz: 55b4a43b06260e899293283b5f2395517f0d4092
5
+ SHA512:
6
+ metadata.gz: 88e84cdb94758caa71064a75101bc660094db2eee6542bbe9bc5f52b9f3a4577de135fec7973d70551c98f94c0fa83d74afb00238beb062a4a18cbba348c7d4d
7
+ data.tar.gz: e83171aa472d1810dade7ca92a412c323390f9d9f3b1306fd5b7052c9e59dd954e71c7300a6fdfe24d5077617560c7cfa955077dcfbc3d254215ff6fe64c2a19
data/.gemtest ADDED
File without changes
data/ChangeLog.rdoc ADDED
@@ -0,0 +1,74 @@
1
+ === 0.4.0 / 2012-03-08
2
+
3
+ * gh-11: Transport header parser bolstering:
4
+ * values that should be caps, will parse OK as lowercase now.
5
+ * :broadcast_type now parses 'multicast'.
6
+ * :destination now returns the value of the destination instead of
7
+ "destination=x.x.x.x"
8
+ * :source now returns the value of the source instead of "source=x.x.x.x"
9
+ * Added parsing for fields:
10
+ * ttl
11
+ * port
12
+ * ssrc
13
+ * channel
14
+ * address
15
+ * mode
16
+ * gh-10: Session header now detects timeout value. This means that where use
17
+ of the value extracted from this header used to be a simple Integer, now you
18
+ have a session Hash with :session_id and :timeout keys.
19
+
20
+ === 0.3.0 / 2012-03-02
21
+
22
+ * Extracted RTP-esque functionality to an +rtp+ gem, on which this gem is now
23
+ dependent on version 0.0.1 of that.
24
+ * Laxed dependency requirement on parslet.
25
+ * Bumped dependency requirement on sdp to ~> 0.2.6, due to parslet conflicts
26
+
27
+ === 0.2.2 / 2011-11-02
28
+
29
+ * Added a queue for listening and building the RTP file from the received data.
30
+ * Fixed bugs:
31
+ * gh-6: .gemspec was missing +parslet+ dependency. Thanks [tindron[http://github.com/tindron]].
32
+
33
+ === 0.2.1 / 2011-09-20
34
+
35
+ * `gem test rtsp` is failing; added rtsp.gemspec to list of files in the spec.
36
+
37
+ === 0.2.0 / 2011-09-19
38
+
39
+ * Changed RTSP::Capturer init_*_server methods to take params in order to reduce
40
+ dependency on state of the Capturer object.
41
+ * Improvements:
42
+ * If RTSP::Capturer can't open port 9000, it increments by 1 and tries again,
43
+ 50 times, then raises.
44
+ * gh-4: Remove dependency on ore en lieu of standard gem commands.
45
+ * Participate in http://test.rubygems.org!
46
+ * Fixed bugs:
47
+ * gh-5: Fixed 'Bad file descriptor' bug when capturing to file.
48
+
49
+ === 0.1.2 / 2011-04-14
50
+
51
+ * Manually released; the gemspec that Ore created didn't install bin/rtsp_client.
52
+
53
+ === 0.1.1 / 2011-04-14
54
+
55
+ * Fixed bugs:
56
+ * gh-1: No longer use Socket::SO_REUSEADDR or Socket::SO_REUSEPORT.
57
+ * gh-2: rtsp_client now requires the installed rtsp/client.
58
+ * Capturer#run's log message now says what it's logging.
59
+ * bin/rtsp_client:
60
+ * Fixed bad description for --stream.
61
+ * Added --version.
62
+ * Updated README.rdoc:
63
+ * ...to clarify that REDIRECT isn't yet supported.
64
+ * ...with brief usage on bin/rtsp_client.
65
+
66
+ === 0.1.0 / 2011-04-12
67
+
68
+ * Happy birthday!
69
+ * All standard RTSP methods supported.
70
+ * Captures RTP data to a file, but doesn't ensure RTP sequencing before putting to file.
71
+ * One client object can only handle 1 stream; use a client per stream until this functionality
72
+ gets implemented.
73
+ * Only handles unicast, UDP streams.
74
+ * RTSP exceptions are all +RTSP::Error+s; this will change.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE.rdoc ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 sloveless, mkirby
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,152 @@
1
+ = rtsp
2
+
3
+ * https://github.com/turboladen/rtsp
4
+
5
+ == DESCRIPTION:
6
+
7
+ This library intends to follow the RTSP RFC document (2326) to allow for working
8
+ with RTSP servers. At this point, it's up to you to parse the data from a play
9
+ call, but we'll get there. ...eventually.
10
+
11
+ For more information
12
+
13
+ RTSP: http://tools.ietf.org/html/rfc2326
14
+
15
+ SDP: http://tools.ietf.org/html/rfc4566
16
+
17
+ == FEATURES/PROBLEMS:
18
+
19
+ * All standard RTSP methods supported except REDIRECT.
20
+ * Captures RTP data to a file, but doesn't ensure RTP sequencing before putting to file.
21
+ * One client object can only handle 1 stream; use a client per stream until this functionality
22
+ gets implemented.
23
+ * Only handles unicast, UDP streams.
24
+ * RTSP exceptions are all +RTSP::Error+s; this will change.
25
+
26
+ == SYNOPSIS:
27
+
28
+ === Basic Usage
29
+
30
+ RTSP::Client.log? # => true
31
+ RTSP::Client.log = false
32
+ client = RTSP::Client.new "rtsp://64.202.98.91/sa.sdp" do |connection, capturer|
33
+ connection.timeout = 5
34
+ capturer.rtp_port = 8554
35
+ capturer.rtp_file = File.open("captured_stuff.rtp", "wb")
36
+ end
37
+
38
+ client.server_uri # => #<URI::Generic:0x00000100ba4db0 URL:rtsp://64.202.98.91:554/sa.sdp>
39
+ client.session_state # => :init
40
+ client.cseq # => 1
41
+ client.connection.do_capture # => true
42
+ client.connection.interleave # => false
43
+ client.connection.timeout # => 5
44
+ client.capturer.broadcast_type # => :unicast
45
+ client.capturer.rtp_port # => 8554
46
+ client.capturer.rtp_file # => #<File:captured_stuff.rtp>
47
+ client.capturer.transport_protocol # => :UDP
48
+
49
+ response = client.options
50
+ response.class # => RTSP::Response
51
+ response.code # => 200
52
+ response.message # => "OK"
53
+ client.cseq # => 2
54
+
55
+ response = client.describe
56
+ response.body.class # => SDP::Description
57
+ response.content_type # => "application/sdp"
58
+ response.server # => "DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )"
59
+ client.aggregate_control_track # => "rtsp://64.202.98.91:554/sa.sdp/"
60
+ client.media_control_tracks # => ["rtsp://64.202.98.91:554/sa.sdp/trackID=1"]
61
+ client.cseq # => 3
62
+
63
+ response = client.setup(client.media_control_tracks.first)
64
+ response.session[:session_id] # => 7098486223178290313
65
+ client.session[:session_id] # => 7098486223178290313
66
+ client.cseq # => 4
67
+ client.session_state # => :ready
68
+
69
+
70
+ response = client.play(client.aggregate_control_track)
71
+ response.range # => "npt=now="
72
+ resposne.rtp_info # => "url=rtsp://64.202.98.91:554/sa.sdp/trackID=1"
73
+ client.session_state # => :playing
74
+
75
+ # Wait while the video streams
76
+ sleep 5
77
+
78
+ client.pause(client.aggregate_control_track)
79
+ client.session_state # => :ready
80
+
81
+ # Wait while the video is paused
82
+ sleep 2
83
+
84
+ client.teardown(client.aggregate_control_track)
85
+ client.session[:session_id] # => 0
86
+ client.session_state # => :init
87
+
88
+ # Check the streamed file's contents
89
+ puts client.capturer.rtp_file # => (Lots of data)
90
+
91
+ === CLI App
92
+
93
+ RTSP also provides a +rtsp_client+ executable that allows a little talking to
94
+ an RTSP server.
95
+
96
+ Knowing which tracks are available on the server can help you determine which
97
+ tracks to use in your programmatic use of an RTSP::Client object to try to
98
+ play. Show the available aggregate control track and media control tracks:
99
+
100
+ $ rtsp_client --show-tracks rtsp://64.202.98.91/sa.sdp
101
+
102
+ Or if you want the entire SDP description from the server:
103
+
104
+ $ rtsp_client --describe rtsp://64.202.98.91/sa.sdp
105
+
106
+ And then, of course, pull a stream (this assumes you SETUP the first media
107
+ track and call play on the aggregate track):
108
+
109
+ $ rtsp_client --stream rtsp://64.202.98.91/sa.sdp
110
+
111
+ As usual, get help by:
112
+
113
+ $ rtsp_client --help
114
+
115
+
116
+ == REQUIREMENTS:
117
+
118
+ * (Tested) Rubies
119
+ * 1.9.2-p180
120
+ * RubyGems
121
+ * sdp, '~> 0.2.2'
122
+ * RubyGems (development)
123
+ * bundler, '~> 1.0.0'
124
+ * code_statistics, '~> 0.2.13'
125
+ * metric_fu, '>= 2.0.0'
126
+ * ore, '~> 0.7.2'
127
+ * ore-core, '~> 0.1.0'
128
+ * ore-tasks, '~> 0.3.0'
129
+ * rake, '~> 0.8.7'
130
+ * rspec, '~> 2.5.0'
131
+ * simplecov, '>= 0.4.0'
132
+ * yard, '~> 0.6.0'
133
+
134
+ == INSTALL:
135
+
136
+ * (sudo) gem install rtsp
137
+
138
+ == DEVELOPERS:
139
+
140
+ After checking out the source, run:
141
+
142
+ $ bundle install
143
+
144
+ This task will install any missing dependencies.
145
+
146
+ == LICENSE:
147
+
148
+ (The MIT License)
149
+
150
+ Copyright (c) 2011 Steve Loveless, Mike Kirby
151
+
152
+ See LICENSE.rdoc for details.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'yard'
4
+
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.rspec_opts = ['--format', 'documentation', '--color']
7
+ end
8
+
9
+ namespace :spec do
10
+ RSpec::Core::RakeTask.new(:warnings) do |t|
11
+ t.ruby_opts = "-w"
12
+ t.rspec_opts = ['--format', 'documentation', '--color']
13
+ end
14
+ end
15
+ task :default => :spec
16
+ task :test => :spec # for `gem test`
17
+
18
+ YARD::Rake::YardocTask.new do |t|
19
+ t.options = ['--verbose']
20
+ end
21
+
22
+ # Load all extra rake tasks
23
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].each { |ext| load ext }
data/bin/rtsp_client ADDED
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tempfile'
4
+ require 'optparse'
5
+ require 'rtsp/client'
6
+
7
+ optparse = OptionParser.new do |opts|
8
+ opts.banner = "Usage: #{__FILE__} [options] url"
9
+
10
+ #----------------------------------------------------------------------------
11
+ # Turn on logging
12
+ RTSP::Client.configure { |c| c.log = false }
13
+ opts.on('-d', '--debug', "Turn on RTSP::Client logging.") do
14
+ RTSP::Client.configure { |c| c.log = true }
15
+ end
16
+
17
+ #----------------------------------------------------------------------------
18
+ # Get description
19
+ opts.on('--describe [URL]', "Get description from the given URL.") do |url|
20
+ if url.nil?
21
+ puts "Must pass in a URL."
22
+ exit
23
+ end
24
+
25
+ rtsp_client = RTSP::Client.new(url)
26
+ puts rtsp_client.describe.body.inspect
27
+ exit
28
+ end
29
+
30
+ #----------------------------------------------------------------------------
31
+ # Show available tracks
32
+ opts.on('--show-tracks [URL]', "Show available tracks from the given URL.") do |url|
33
+ if url.nil?
34
+ puts "Must pass in a URL."
35
+ exit
36
+ end
37
+
38
+ rtsp_client = RTSP::Client.new(url)
39
+ rtsp_client.describe
40
+ puts "Aggregate control track: #{rtsp_client.aggregate_control_track}"
41
+ puts "Media control tracks: #{rtsp_client.media_control_tracks}"
42
+ exit
43
+ end
44
+
45
+ #----------------------------------------------------------------------------
46
+ # Stream
47
+ opts.on('--stream [URL]', "Pull the first media stream from the given URL.") do |url|
48
+ if url.nil?
49
+ puts "Must pass in a URL."
50
+ exit
51
+ end
52
+
53
+ rtsp_client = RTSP::Client.new(url) do |connection, capturer|
54
+ capturer.rtp_file = File.open("#{Dir.pwd}/rtsp_client_stream.rtp", "wb")
55
+ end
56
+
57
+ begin
58
+ puts "Getting server options..."
59
+ response = rtsp_client.options
60
+ puts "\tServer: #{response.server}"
61
+ puts "\tSupported methods: #{response.public}"
62
+ puts ""
63
+
64
+ puts "Getting description..."
65
+ response = rtsp_client.describe
66
+ puts "\tcache_control: #{response.cache_control}" if response.respond_to? "cache_control"
67
+ puts "\tdate: #{response.date}"
68
+ puts "\texpires: #{response.expires}" if response.respond_to? "expires"
69
+ puts "\tcontent_type: #{response.content_type}"
70
+ puts "\tcontent_base: #{response.content_base}"
71
+ puts "\tAggregate control track: #{rtsp_client.aggregate_control_track}"
72
+ puts "\tMedia control tracks: #{rtsp_client.media_control_tracks}"
73
+ puts ""
74
+
75
+ puts "Setting up #{rtsp_client.media_control_tracks.first}"
76
+ response = rtsp_client.setup rtsp_client.media_control_tracks.first
77
+ puts "\ttransport: #{response.transport}"
78
+ puts ""
79
+
80
+ if response.message == "OK"
81
+ puts "Playing #{rtsp_client.aggregate_control_track}"
82
+ r = rtsp_client.play rtsp_client.aggregate_control_track
83
+ puts "\trange: #{r.range}"
84
+ puts "\trtp_info: #{r.rtp_info}"
85
+ puts ""
86
+
87
+
88
+ 1...5.times do
89
+ print "."
90
+ sleep 1
91
+ end
92
+ puts ""
93
+
94
+ if rtsp_client.capturer.rtp_file.size.zero?
95
+ puts "Captured 0 bytes. Your firewall might be blocking the RTP traffic on port #{rtsp_client.capturer.rtp_port}."
96
+ else
97
+ puts "RTP data captured to file: #{rtsp_client.capturer.rtp_file}"
98
+ end
99
+
100
+ puts "Tearing down..."
101
+ r2 = rtsp_client.teardown(rtsp_client.aggregate_control_track)
102
+ puts "\tconnection: #{r2.connection}" if r2.respond_to? "connection"
103
+ else
104
+ puts "Play call returned: #{response.message}. Exiting."
105
+ exit
106
+ end
107
+ rescue RTSP::Error => ex
108
+ puts ex.backtrace
109
+ puts ex.message
110
+ end
111
+ end
112
+
113
+ #----------------------------------------------------------------------------
114
+ # Help
115
+ opts.on('--version', "The version of the Ruby RTSP gem used for this.") do
116
+ puts RTSP::VERSION
117
+ exit
118
+ end
119
+
120
+ #----------------------------------------------------------------------------
121
+ # Help
122
+ opts.on('-h', '--help', "You're looking at it.") do
123
+ puts opts
124
+ exit
125
+ end
126
+ end
127
+
128
+ if ARGV.size.zero?
129
+ puts optparse.help if ARGV.size.zero?
130
+ exit
131
+ end
132
+ optparse.parse!
133
+
@@ -0,0 +1,58 @@
1
+ Feature: Client changes state
2
+ As an RTSP client user
3
+ I want to monitor the state of my client
4
+ So that I can be sure of what my client is doing at any time
5
+
6
+ Scenario Outline: State doesn't change after certain requests
7
+ Given I haven't made any RTSP requests
8
+ When I issue an "<request_type>" request with "<parameters>"
9
+ Then the state stays the same
10
+ Examples:
11
+ | request_type | parameters |
12
+ | options | |
13
+ | describe | |
14
+
15
+ Scenario Outline: State changes from Init
16
+ Given I haven't made any RTSP requests
17
+ When I issue an "<request_type>" request with "<parameters>"
18
+ Then the state changes to "<state_result>"
19
+ Examples:
20
+ | request_type | parameters | state_result |
21
+ | setup | url | ready |
22
+ | teardown | url | init |
23
+
24
+ Scenario Outline: State changes from Ready
25
+ Given I have set up a stream
26
+ When I issue an "<request_type>" request with "<parameters>"
27
+ Then the state changes to "<state_result>"
28
+ Examples:
29
+ | request_type | parameters | state_result |
30
+ | play | url | playing |
31
+ | record | url | recording |
32
+ | teardown | url | init |
33
+ | setup | url | ready |
34
+
35
+ Scenario Outline: State changes from Playing
36
+ Given I have set up a stream
37
+ And I have started playing a stream
38
+ When I issue an "<request_type>" request with "<parameters>"
39
+ Then the state changes to "<state_result>"
40
+ Examples:
41
+ | request_type | parameters | state_result |
42
+ | pause | url | ready |
43
+ | teardown | url | init |
44
+ | play | url | playing |
45
+ | setup | url | playing |
46
+
47
+ Scenario Outline: State changes from Recording
48
+ Given I have set up a stream
49
+ And I have started recording a stream
50
+ When I issue an "<request_type>" request with "<parameters>"
51
+ Then the state changes to "<state_result>"
52
+ Examples:
53
+ | request_type | parameters | state_result |
54
+ | pause | url | ready |
55
+ | teardown | url | init |
56
+ | record | url | recording |
57
+ | setup | url | recording |
58
+
@@ -0,0 +1,27 @@
1
+ Feature: Client request messages
2
+ As an RTSP client API user
3
+ I want to make RTSP requests
4
+ So that I can build a client using these request messages
5
+
6
+ Scenario: OPTIONS
7
+ Given a known RTSP server
8
+ When I make a "options" request
9
+ Then I should receive an RTSP response to that OPTIONS request
10
+
11
+ Scenario: DESCRIBE
12
+ Given a known RTSP server
13
+ When I make a "describe" request
14
+ Then I should receive an RTSP response to that DESCRIBE request
15
+
16
+ Scenario: ANNOUNCE
17
+ Given a known RTSP server
18
+ When I make a "announce" request
19
+ Then I should receive an RTSP response to that ANNOUNCE request
20
+
21
+ Scenario: SETUP
22
+ Given a known RTSP server
23
+ When I make a "setup" request with headers:
24
+ | header | value |
25
+ | transport | RTP/AVP |
26
+ Then I should receive an RTSP response to that SETUP request
27
+
@@ -0,0 +1,26 @@
1
+ Feature: Control stream from an RTSP server
2
+ As an RTSP consumer
3
+ I want to be able to control RTSP streams from a server
4
+ So that I can view its contents as I desire
5
+
6
+ @wip
7
+ Scenario: Play single stream
8
+ Given an RTSP server at "10.221.222.235" and port 9010 and URL ""
9
+ When I play a stream from that server
10
+ Then I should not receive any errors
11
+ And I should receive data on the same port
12
+
13
+ Scenario: Play then pause single stream
14
+ Given an RTSP server at "10.221.222.235" and port 9010 and URL ""
15
+ When I play a stream from that server for 10 seconds
16
+ And I pause that stream
17
+ Then I should not receive data on the same port
18
+
19
+ Scenario: Play two streams individually and simultaneously
20
+
21
+ Scenario: Play then pause two streams individually and simultaneously
22
+
23
+ Scenario: Play two streams using the aggregate control URL
24
+
25
+ Scenario: Play then pause two streams using the aggregate control URL
26
+
@@ -0,0 +1,52 @@
1
+ Given /^I haven't made any RTSP requests$/ do
2
+ RTSP::Client.configure { |config| config.log = false }
3
+ end
4
+
5
+ Given /^I have set up a stream$/ do
6
+ @url = "rtsp://fake-rtsp-server/some_path"
7
+ @client = RTSP::Client.new(@url) do |connection|
8
+ connection.socket = @fake_server
9
+ connection.timeout = 3
10
+ end
11
+ @client.setup @url
12
+ @client.session_state.should == :ready
13
+ end
14
+
15
+ Given /^I have started (playing|recording) a stream$/ do |method|
16
+ if method == "playing"
17
+ @client.setup @url
18
+ @client.play @url
19
+ elsif method == "recording"
20
+ @client.record @url
21
+ end
22
+ @client.session_state.should == method.to_sym
23
+ end
24
+
25
+ When /^I issue an "([^"]*)" request with "([^"]*)"$/ do |request_type, params|
26
+ unless @client
27
+ url = "rtsp://fake-rtsp-server/some_path"
28
+
29
+ @client = RTSP::Client.new(url) do |connection|
30
+ connection.socket = @fake_server
31
+ connection.timeout = 3
32
+ end
33
+ end
34
+
35
+ @initial_state = @client.session_state
36
+ params = params.empty? ? {} : params
37
+
38
+ if request_type == 'play'
39
+ @client.setup(url)
40
+ @client.play(params)
41
+ else
42
+ @client.send(request_type.to_sym, params)
43
+ end
44
+ end
45
+
46
+ Then /^the state stays the same$/ do
47
+ @client.session_state.should == @initial_state
48
+ end
49
+
50
+ Then /^the state changes to "([^"]*)"$/ do |new_state|
51
+ @client.session_state.should == new_state.to_sym
52
+ end
@@ -0,0 +1,68 @@
1
+ Given /^a known RTSP server$/ do
2
+ @server_url = "rtsp://64.202.98.91:554/sa.sdp"
3
+
4
+ @client = RTSP::Client.new(@server_url) do |connection|
5
+ connection.socket = @fake_server
6
+ connection.timeout = 3
7
+ end
8
+ end
9
+
10
+ When /^I make a "([^"]*)" request$/ do |method|
11
+ @response = if method == 'announce'
12
+ @client.setup(@server_url)
13
+ @client.announce(@server_url, @client.describe)
14
+ else
15
+ @client.send(method.to_sym)
16
+ end
17
+ end
18
+
19
+ When /^I make a "([^"]*)" request with headers:$/ do |method, headers_table|
20
+ # table is a Cucumber::Ast::Table
21
+ headers = {}
22
+
23
+ headers_table.hashes.each do |hash|
24
+ header_type = hash["header"].to_sym
25
+ headers[header_type] = hash["value"]
26
+ end
27
+
28
+ @response = if method == 'setup'
29
+ @client.setup(@server_url, headers)
30
+ else
31
+ @client.send(method.to_sym, headers)
32
+ end
33
+ end
34
+
35
+ Then /^I should receive an RTSP response to that OPTIONS request$/ do
36
+ @response.should be_a RTSP::Response
37
+ @response.code.should == 200
38
+ @response.message.should == "OK"
39
+ @response.cseq.should == 1
40
+ @response.public.should == "DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE"
41
+ @response.body.should be_empty
42
+ end
43
+
44
+ Then /^I should receive an RTSP response to that DESCRIBE request$/ do
45
+ @response.should be_a RTSP::Response
46
+ @response.code.should == 200
47
+ @response.message.should == "OK"
48
+ @response.server.should == "DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )"
49
+ @response.cseq.should == 1
50
+ @response.body.should be_a SDP::Description
51
+ @response.body.username.should == "-"
52
+ end
53
+
54
+ Then /^I should receive an RTSP response to that ANNOUNCE request$/ do
55
+ @response.should be_a RTSP::Response
56
+ @response.code.should == 200
57
+ @response.message.should == "OK"
58
+ @response.cseq.should == 2
59
+ end
60
+
61
+ Then /^I should receive an RTSP response to that SETUP request$/ do
62
+ @response.should be_a RTSP::Response
63
+ @response.code.should == 200
64
+ @response.message.should == "OK"
65
+ @response.cseq.should == 1
66
+ @response.transport.should match(/RTP\/AVP;unicast;destination=\S+;source=\S+;client_port=\d+-\d+;server_port=\d+-\d+/)
67
+ end
68
+
@@ -0,0 +1,34 @@
1
+ Given /^an RTSP server at "([^"]*)" and port (\d+)$/ do |ip_address, port|
2
+ @rtp_port = port.to_i
3
+ @client = RTSP::Client.new(ip_address) do |connection, capturer|
4
+ capturer.rtp_port = @rtp_port
5
+ end
6
+ end
7
+
8
+ Given /^an RTSP server at "([^"]*)" and port (\d+) and URL "([^"]*)"$/ do |ip_address, port, path|
9
+ uri = "rtsp://#{ip_address}:#{port}#{path}"
10
+ @rtp_port = port
11
+ @client = RTSP::Client.new(uri) do |connection, capturer|
12
+ capturer.rtp_port = @rtp_port
13
+ end
14
+ end
15
+
16
+ When /^I play a stream from that server$/ do
17
+ @play_result = lambda { @client.play }
18
+ end
19
+
20
+ Then /^I should not receive any errors$/ do
21
+ @play_result.should_not raise_error
22
+ end
23
+
24
+ Then /^I should receive data on the same port$/ do
25
+ @client.capturer.rtp_file.should_not be_empty
26
+ end
27
+
28
+ Given /^I know what the describe response looks like$/ do
29
+ @response_text = @fake_server.describe
30
+ end
31
+
32
+ When /^I ask the server to describe$/ do
33
+ puts @client.describe
34
+ end