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.
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 +311 -0
  27. data/lib/rtsp/socat_streaming.rb +320 -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 +44 -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
@@ -0,0 +1,96 @@
1
+ require 'parslet'
2
+
3
+ module RTSP
4
+
5
+ # Used for parsing the Transport header--mainly as the response from the
6
+ # SETUP request. The values from this are used to determine what to use for
7
+ # other requests.
8
+ class TransportParser < Parslet::Parser
9
+ rule(:transport_specifier) do
10
+ match('[A-Za-z]').repeat(3).as(:streaming_protocol) >> forward_slash >>
11
+ match('[A-Za-z]').repeat(3).as(:profile) >>
12
+ (forward_slash >> match('[A-Za-z]').repeat(3).as(:transport_protocol)).maybe
13
+ end
14
+
15
+ rule(:broadcast_type) do
16
+ str('unicast') | str('multicast')
17
+ end
18
+
19
+ rule(:destination) do
20
+ str('destination=') >> ip_address.as(:destination)
21
+ end
22
+
23
+ rule(:source) do
24
+ str('source=') >> ip_address.as(:source)
25
+ end
26
+
27
+ rule(:client_port) do
28
+ str('client_port=') >> number.as(:rtp) >> dash >> number.as(:rtcp)
29
+ end
30
+
31
+ rule(:server_port) do
32
+ str('server_port=') >> number.as(:rtp) >> dash >> number.as(:rtcp)
33
+ end
34
+
35
+ rule(:interleaved) do
36
+ str('interleaved=') >> number.as(:rtp_channel) >> dash >>
37
+ number.as(:rtcp_channel)
38
+ end
39
+
40
+ rule(:ttl) do
41
+ str('ttl=') >> match('[\d]').repeat(1,3).as(:ttl)
42
+ end
43
+
44
+ rule(:port) do
45
+ str('port=') >> match('[\d]').repeat(1,5).as(:rtp) >>
46
+ dash.maybe >> match('[\d]').repeat(1,5).as(:rtcp).maybe
47
+ end
48
+
49
+ rule(:ssrc) do
50
+ str('ssrc=') >> match('[0-9A-Fa-f]').repeat(8).as(:ssrc)
51
+ end
52
+
53
+ rule(:channel) do
54
+ str('channel=') >> match('[\w]').repeat(1,3).as(:channel)
55
+ end
56
+
57
+ rule(:address) do
58
+ str('address=') >> match('[\S]').repeat.as(:address)
59
+ end
60
+
61
+ rule(:mode) do
62
+ str('mode=') >> str('"').maybe >> match('[A-Za-z]').repeat.as(:mode) >>
63
+ str('"').maybe
64
+ end
65
+
66
+ rule(:ip_address) do
67
+ match('[\d]').repeat(1,3) >> str('.') >>
68
+ match('[\d]').repeat(1,3) >> str('.') >>
69
+ match('[\d]').repeat(1,3) >> str('.') >>
70
+ match('[\d]').repeat(1,3)
71
+ end
72
+
73
+ rule(:number) { match('[\d]').repeat }
74
+ rule(:forward_slash) { match('[/]') }
75
+ rule(:semi_colon) { match('[;]') }
76
+ rule(:dash) { match('[-]') }
77
+
78
+ rule(:header_field) do
79
+ transport_specifier >>
80
+ (semi_colon >> broadcast_type.as(:broadcast_type)).maybe >>
81
+ (semi_colon >> destination).maybe >>
82
+ (semi_colon >> source).maybe >>
83
+ (semi_colon >> client_port.as(:client_port)).maybe >>
84
+ (semi_colon >> server_port.as(:server_port)).maybe >>
85
+ (semi_colon >> interleaved.as(:interleaved)).maybe >>
86
+ (semi_colon >> ttl).maybe >>
87
+ (semi_colon >> port.as(:port)).maybe >>
88
+ (semi_colon >> ssrc).maybe >>
89
+ (semi_colon >> channel).maybe >>
90
+ (semi_colon >> address).maybe >>
91
+ (semi_colon >> mode).maybe
92
+ end
93
+
94
+ root :header_field
95
+ end
96
+ end
@@ -0,0 +1,4 @@
1
+ module RTSP
2
+ # rtsp version
3
+ VERSION = "0.0.2"
4
+ end
data/lib/rtsp.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'pathname'
2
+ require_relative 'rtsp/version'
3
+
4
+ # This base module simply defines properties about the library. See child
5
+ # classes/modules for the meat.
6
+ module RTSP; end
data/rtsp.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('lib/', File.dirname(__FILE__))
3
+ $:.unshift lib unless $:.include?(lib)
4
+
5
+ require 'rtsp/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "rtsp_server"
9
+ s.version = RTSP::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.platform = Gem::Platform.new(['universal', 'java']) if RUBY_PLATFORM == "java"
12
+
13
+ s.homepage = %q{https://github.com/turboladen/rtsp}
14
+ s.authors = ["Steve Loveless, Mike Kirby", "Sujin Philip"]
15
+ s.summary = %q{Library to allow RTSP streaming from RTSP-enabled devices.}
16
+ s.description = %q{This library intends to follow the RTSP RFC document (2326)
17
+ to allow for working with RTSP servers. At this point, it's up to you to parse
18
+ the data from a play call, but we'll get there. ...eventually.
19
+ For more information see: http://www.ietf.org/rfc/rfc2326.txt}
20
+ s.email = %w{steve.loveless@gmail.com}
21
+ s.licenses = %w{MIT}
22
+
23
+ s.executables = %w{rtsp_client}
24
+ s.files = Dir.glob("{lib,bin,spec,tasks}/**/*") + Dir.glob("*.rdoc") +
25
+ %w(.gemtest rtsp.gemspec Gemfile Rakefile)
26
+ s.extra_rdoc_files = %w{ChangeLog.rdoc LICENSE.rdoc README.rdoc}
27
+ s.require_paths = %w{lib}
28
+ s.rubygems_version = %q{1.7.2}
29
+ s.test_files = Dir.glob("{spec,features}/**/*")
30
+
31
+ s.add_runtime_dependency(%q<parslet>, [">= 1.1.0"])
32
+ s.add_runtime_dependency(%q<rtp>, [">= 0.0.1"])
33
+ s.add_runtime_dependency(%q<sdp>, ["~> 0.2.6"])
34
+ s.add_runtime_dependency(%q<sys-proctable>, ["> 0"])
35
+
36
+ s.add_development_dependency(%q<bundler>)
37
+ s.add_development_dependency(%q<code_statistics>, ["~> 0.2.13"])
38
+ s.add_development_dependency(%q<cucumber>, [">= 1.1.0"])
39
+ s.add_development_dependency(%q<roodi>, [">= 2.1.0"])
40
+ s.add_development_dependency(%q<rake>, [">= 0.8.7"])
41
+ s.add_development_dependency(%q<rspec>, [">= 2.5.0"])
42
+ s.add_development_dependency(%q<simplecov>, [">= 0.4.0"])
43
+ s.add_development_dependency(%q<yard>, [">= 0.6.0"])
44
+ end
@@ -0,0 +1,326 @@
1
+ require 'sdp'
2
+ require_relative '../spec_helper'
3
+ require 'rtsp/client'
4
+ require_relative '../support/fake_rtsp_server'
5
+
6
+ describe RTSP::Client do
7
+ def setup_client_at(url)
8
+ fake_rtsp_server = FakeRTSPServer.new
9
+ mock_logger = double 'MockLogger', :send => nil
10
+
11
+ client = RTSP::Client.new(url) do |connection|
12
+ connection.socket = fake_rtsp_server
13
+ end
14
+
15
+ RTSP::Client.reset_config!
16
+ RTSP::Client.configure { |config| config.log = false }
17
+ client.logger = mock_logger
18
+
19
+ client
20
+ end
21
+
22
+ before do
23
+ RTP::Receiver.any_instance.stub(:run)
24
+ RTP::Receiver.any_instance.stub(:stop)
25
+ end
26
+
27
+ describe "#initialize" do
28
+ before :each do
29
+ mock_socket = double 'MockSocket'
30
+ @client = RTSP::Client.new("rtsp://localhost") do |connection|
31
+ connection.socket = mock_socket
32
+ end
33
+ end
34
+
35
+ it "sets @cseq to 1" do
36
+ @client.instance_variable_get(:@cseq).should == 1
37
+ end
38
+
39
+ it "sets @session_state to :init" do
40
+ @client.instance_variable_get(:@session_state).should == :init
41
+ end
42
+
43
+ it "sets @server_uri to be a URI containing the first init param + 554" do
44
+ @client.instance_variable_get(:@server_uri).should be_a(URI)
45
+ @client.instance_variable_get(:@server_uri).to_s.should ==
46
+ "rtsp://localhost:554"
47
+ end
48
+ end
49
+
50
+ describe ".configure" do
51
+ around do |example|
52
+ RTSP::Client.reset_config!
53
+ example.run
54
+ RTSP::Client.reset_config!
55
+ RTSP::Client.log = false
56
+ end
57
+
58
+ before :each do
59
+ mock_socket = double 'MockSocket'
60
+
61
+ @client = RTSP::Client.new("rtsp://localhost") do |connection|
62
+ connection.socket = mock_socket
63
+ end
64
+ end
65
+
66
+ describe "log" do
67
+ it "should default to true" do
68
+ RTSP::Client.log?.should be_true
69
+ end
70
+
71
+ it "should set whether to log RTSP requests/responses" do
72
+ RTSP::Client.configure { |config| config.log = false }
73
+ RTSP::Client.log?.should be_false
74
+ end
75
+ end
76
+
77
+ describe "logger" do
78
+ it "should set the logger to use" do
79
+ MyLogger = Class.new
80
+ RTSP::Client.configure { |config| config.logger = MyLogger }
81
+ RTSP::Client.logger.should == MyLogger
82
+ end
83
+
84
+ it "should default to Logger writing to STDOUT" do
85
+ RTSP::Client.logger.should be_a(Logger)
86
+ end
87
+ end
88
+
89
+ describe "log_level" do
90
+ it "should default to :debug" do
91
+ RTSP::Client.log_level.should == :debug
92
+ end
93
+
94
+ it "should set the log level to use" do
95
+ RTSP::Client.configure { |config| config.log_level = :info }
96
+ RTSP::Client.log_level.should == :info
97
+ end
98
+ end
99
+ end
100
+
101
+ it "handles empty non-existent CSeq header" do
102
+ pending
103
+ end
104
+
105
+ context "#server_url" do
106
+ before :each do
107
+ @client = setup_client_at "rtsp://localhost"
108
+ end
109
+
110
+ it "allows for changing the server URL on the fly" do
111
+ @client.server_uri.to_s.should == "rtsp://localhost:554"
112
+ @client.server_url = "rtsp://localhost:8080"
113
+ @client.server_uri.to_s.should == "rtsp://localhost:8080"
114
+ end
115
+
116
+ it "raises when passing in something other than a String" do
117
+ @client.server_uri.to_s.should == "rtsp://localhost:554"
118
+ lambda { @client.server_url = [] }.should raise_error
119
+ end
120
+ end
121
+
122
+ describe "#options" do
123
+ before :each do
124
+ @client = setup_client_at "rtsp://localhost"
125
+ end
126
+
127
+ it "extracts the server's supported methods" do
128
+ @client.options
129
+ @client.supported_methods.should ==
130
+ [:describe, :setup, :teardown, :play, :pause]
131
+ end
132
+
133
+ it "returns a Response" do
134
+ response = @client.options
135
+ response.is_a?(RTSP::Response).should be_true
136
+ end
137
+ end
138
+
139
+ describe "#describe" do
140
+ before do
141
+ @client = setup_client_at "rtsp://localhost"
142
+ @response = @client.describe
143
+ end
144
+
145
+ it "extracts the aggregate control track" do
146
+ @client.aggregate_control_track.should == "rtsp://64.202.98.91:554/sa.sdp/"
147
+ end
148
+
149
+ it "extracts the media control tracks" do
150
+ @client.media_control_tracks.should == ["rtsp://64.202.98.91:554/sa.sdp/trackID=1"]
151
+ end
152
+
153
+ it "extracts the SDP object" do
154
+ @client.instance_variable_get(:@session_description).should ==
155
+ @response.body
156
+ end
157
+
158
+ it "extracts the Content-Base header" do
159
+ @client.instance_variable_get(:@content_base).should ==
160
+ URI.parse("rtsp://64.202.98.91:554/sa.sdp/")
161
+ end
162
+
163
+ it "returns a Response" do
164
+ @response.is_a?(RTSP::Response).should be_true
165
+ end
166
+ end
167
+
168
+ describe "#announce" do
169
+ it "returns a Response" do
170
+ client = setup_client_at "rtsp://localhost"
171
+ sdp = SDP::Description.new
172
+ client.setup("rtsp://localhost/another_track")
173
+ response = client.announce("rtsp://localhost/another_track", sdp)
174
+ response.is_a?(RTSP::Response).should be_true
175
+ end
176
+ end
177
+
178
+ describe "#setup" do
179
+ before :each do
180
+ @client = setup_client_at "rtsp://localhost"
181
+ end
182
+
183
+ it "extracts the session number" do
184
+ @client.session.should be_empty
185
+ @client.setup("rtsp://localhost/some_track")
186
+ @client.session[:session_id].should == 1234567890
187
+ end
188
+
189
+ it "changes the session_state to :ready" do
190
+ @client.setup("rtsp://localhost/some_track")
191
+ @client.session_state.should == :ready
192
+ end
193
+
194
+ it "extracts the transport header info" do
195
+ @client.instance_variable_get(:@transport).should be_nil
196
+ @client.setup("rtsp://localhost/some_track")
197
+ @client.instance_variable_get(:@transport).should_not be_nil
198
+ end
199
+
200
+ it "returns a Response" do
201
+ response = @client.setup("rtsp://localhost/some_track")
202
+ response.is_a?(RTSP::Response).should be_true
203
+ end
204
+ end
205
+
206
+ describe "#play" do
207
+ before :each do
208
+ @client = setup_client_at "rtsp://localhost"
209
+ end
210
+
211
+ after :each do
212
+ @client.teardown "rtsp://localhost"
213
+ end
214
+
215
+ it "changes the session_state to :playing" do
216
+ @client.setup("rtsp://localhost/some_track")
217
+ @client.play("rtsp://localhost/some_track")
218
+ @client.session_state.should == :playing
219
+ end
220
+
221
+ it "returns a Response" do
222
+ @client.setup("rtsp://localhost/some_track")
223
+ response = @client.play("rtsp://localhost/some_track")
224
+ response.is_a?(RTSP::Response).should be_true
225
+ end
226
+ end
227
+
228
+ describe "#pause" do
229
+ before :each do
230
+ @client = setup_client_at "rtsp://localhost"
231
+ @client.setup("rtsp://localhost/some_track")
232
+ end
233
+
234
+ after :each do
235
+ @client.teardown "rtsp://localhost"
236
+ end
237
+
238
+ it "changes the session_state from :playing to :ready" do
239
+ @client.play("rtsp://localhost/some_track")
240
+ @client.pause("rtsp://localhost/some_track")
241
+ @client.session_state.should == :ready
242
+ end
243
+
244
+ it "changes the session_state from :recording to :ready" do
245
+ @client.record("rtsp://localhost/some_track")
246
+ @client.pause("rtsp://localhost/some_track")
247
+ @client.session_state.should == :ready
248
+ end
249
+
250
+ it "returns a Response" do
251
+ response = @client.pause("rtsp://localhost/some_track")
252
+ response.is_a?(RTSP::Response).should be_true
253
+ end
254
+ end
255
+
256
+ describe "#teardown" do
257
+ before :each do
258
+ @client = setup_client_at "rtsp://localhost"
259
+ @client.setup("rtsp://localhost/some_track")
260
+ end
261
+
262
+ it "changes the session_state to :init" do
263
+ @client.session_state.should_not == :init
264
+ @client.teardown("rtsp://localhost/some_track")
265
+ @client.session_state.should == :init
266
+ end
267
+
268
+ it "changes the session_id back to 0" do
269
+ @client.session.should_not be_empty
270
+ @client.teardown("rtsp://localhost/some_track")
271
+ @client.session.should be_empty
272
+ end
273
+
274
+ it "returns a Response" do
275
+ response = @client.teardown("rtsp://localhost/some_track")
276
+ response.is_a?(RTSP::Response).should be_true
277
+ end
278
+ end
279
+
280
+ describe "#get_parameter" do
281
+ before :each do
282
+ @client = setup_client_at "rtsp://localhost"
283
+ end
284
+
285
+ it "returns a Response" do
286
+ response = @client.get_parameter("rtsp://localhost/some_track", "ping!")
287
+ response.is_a?(RTSP::Response).should be_true
288
+ end
289
+ end
290
+
291
+ describe "#set_parameter" do
292
+ before :each do
293
+ @client = setup_client_at "rtsp://localhost"
294
+ end
295
+
296
+ it "returns a Response" do
297
+ response = @client.set_parameter("rtsp://localhost/some_track", "ping!")
298
+ response.is_a?(RTSP::Response).should be_true
299
+ end
300
+ end
301
+
302
+ describe "#record" do
303
+ before :each do
304
+ @client = setup_client_at "rtsp://localhost"
305
+ @client.setup("rtsp://localhost/some_track")
306
+ end
307
+
308
+ it "returns a Response" do
309
+ response = @client.record("rtsp://localhost/some_track")
310
+ response.is_a?(RTSP::Response).should be_true
311
+ end
312
+
313
+ it "changes the session_state to :recording" do
314
+ @client.session_state.should == :ready
315
+ @client.record("rtsp://localhost/some_track")
316
+ @client.session_state.should == :recording
317
+ end
318
+ end
319
+
320
+ describe "#send_message" do
321
+ it "raises if the send takes longer than the timeout" do
322
+ pending "until I figure out how to test the time out raises"
323
+ @client = setup_client_at "rtsp://localhost"
324
+ end
325
+ end
326
+ end
@@ -0,0 +1,53 @@
1
+ require_relative '../spec_helper'
2
+ require 'rtsp/helpers'
3
+
4
+ class HelperTest
5
+ include RTSP::Helpers
6
+ end
7
+
8
+ describe RTSP::Helpers do
9
+ describe "#build_resource_uri_from" do
10
+ before do
11
+ @my_object = HelperTest.new
12
+ end
13
+
14
+ context "parses the resource URL to a URI" do
15
+ it "with scheme, IP, path; port defaults to 554" do
16
+ uri = @my_object.build_resource_uri_from "rtsp://64.202.98.91/sa.sdp"
17
+ uri.scheme.should == "rtsp"
18
+ uri.host.should == "64.202.98.91"
19
+ uri.port.should == 554
20
+ uri.path.should == "/sa.sdp"
21
+ end
22
+
23
+ it "with IP, path; port defaults to 554; scheme defaults to 'rtsp'" do
24
+ uri = @my_object.build_resource_uri_from "64.202.98.91/sa.sdp"
25
+ uri.scheme.should == "rtsp"
26
+ uri.host.should == "64.202.98.91"
27
+ uri.port.should == 554
28
+ uri.path.should == "/sa.sdp"
29
+ end
30
+
31
+ it "with scheme, IP, port" do
32
+ uri = @my_object.build_resource_uri_from "rtsp://64.202.98.91"
33
+ uri.scheme.should == "rtsp"
34
+ uri.host.should == "64.202.98.91"
35
+ uri.port.should == 554
36
+ uri.path.should == ""
37
+ uri.to_s.should == "rtsp://64.202.98.91:554"
38
+ end
39
+
40
+ it "handles passing in a URI" do
41
+ uri = @my_object.build_resource_uri_from "rtsp://64.202.98.91"
42
+ lambda { @my_object.build_resource_uri_from uri
43
+ }.should raise_error
44
+ end
45
+
46
+ it "raises if not given a String" do
47
+ lambda do
48
+ @my_object.build_resource_uri_from URI.parse "rtsp://64.202.98.91"
49
+ end.should raise_exception RTSP::Error
50
+ end
51
+ end
52
+ end
53
+ end