rtsp_server 0.0.2-universal-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/ChangeLog.rdoc +74 -0
- data/Gemfile +3 -0
- data/LICENSE.rdoc +20 -0
- data/README.rdoc +152 -0
- data/Rakefile +23 -0
- data/bin/rtsp_client +133 -0
- data/features/client_changes_state.feature +58 -0
- data/features/client_requests.feature +27 -0
- data/features/control_streams_as_client.feature +26 -0
- data/features/step_definitions/client_changes_state_steps.rb +52 -0
- data/features/step_definitions/client_requests_steps.rb +68 -0
- data/features/step_definitions/control_streams_as_client_steps.rb +34 -0
- data/features/support/env.rb +50 -0
- data/features/support/hooks.rb +3 -0
- data/lib/ext/logger.rb +8 -0
- data/lib/rtsp/client.rb +520 -0
- data/lib/rtsp/common.rb +148 -0
- data/lib/rtsp/error.rb +6 -0
- data/lib/rtsp/global.rb +63 -0
- data/lib/rtsp/helpers.rb +28 -0
- data/lib/rtsp/message.rb +272 -0
- data/lib/rtsp/request.rb +39 -0
- data/lib/rtsp/response.rb +47 -0
- data/lib/rtsp/server.rb +311 -0
- data/lib/rtsp/socat_streaming.rb +320 -0
- data/lib/rtsp/stream_server.rb +37 -0
- data/lib/rtsp/transport_parser.rb +96 -0
- data/lib/rtsp/version.rb +4 -0
- data/lib/rtsp.rb +6 -0
- data/rtsp.gemspec +44 -0
- data/spec/rtsp/client_spec.rb +326 -0
- data/spec/rtsp/helpers_spec.rb +53 -0
- data/spec/rtsp/message_spec.rb +420 -0
- data/spec/rtsp/response_spec.rb +306 -0
- data/spec/rtsp/transport_parser_spec.rb +137 -0
- data/spec/rtsp_spec.rb +27 -0
- data/spec/spec_helper.rb +88 -0
- data/spec/support/fake_rtsp_server.rb +123 -0
- data/tasks/roodi.rake +9 -0
- data/tasks/roodi_config.yaml +14 -0
- data/tasks/stats.rake +12 -0
- metadata +280 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ccad9e4be96987634a8df45e84603cc6786161d5
|
4
|
+
data.tar.gz: cda5810ec70b56bcf2a7c2389874c64720bbef17
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: eb3a7f4b3a46c19bcd4f2a60c6ec99e1685fcb9bcb1cd0b73d1bec612b0833bf615d3277de7956405f383fc7ed73be0efdb74fd4c2d11d599219d704d0e108e8
|
7
|
+
data.tar.gz: 54080420cc181b44cfe6bd87da00ec0852259a9b3686b869dc61ed123167772426fcba69ba2e3a2a5d01d640995cf6e721f1d8a584f3c064ab3a18d7a65c5b24
|
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
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
|