rtsp 0.0.1.alpha → 0.1.0

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 (57) hide show
  1. data/.document +3 -0
  2. data/.infinity_test +1 -1
  3. data/.yardopts +4 -0
  4. data/ChangeLog.rdoc +9 -0
  5. data/Gemfile +15 -6
  6. data/Gemfile.lock +78 -40
  7. data/LICENSE.rdoc +20 -0
  8. data/PostInstall.txt +0 -3
  9. data/README.rdoc +85 -36
  10. data/Rakefile +33 -49
  11. data/bin/rtsp_client +129 -0
  12. data/features/client_changes_state.feature +58 -0
  13. data/features/client_requests.feature +27 -0
  14. data/features/control_streams_as_client.feature +26 -0
  15. data/features/step_definitions/client_changes_state_steps.rb +46 -0
  16. data/features/step_definitions/client_requests_steps.rb +74 -0
  17. data/features/step_definitions/control_streams_as_client_steps.rb +34 -0
  18. data/features/support/env.rb +31 -29
  19. data/features/support/hooks.rb +3 -0
  20. data/gemspec.yml +30 -0
  21. data/lib/ext/logger.rb +8 -0
  22. data/lib/rtsp.rb +3 -6
  23. data/lib/rtsp/capturer.rb +105 -0
  24. data/lib/rtsp/client.rb +446 -204
  25. data/lib/rtsp/error.rb +6 -0
  26. data/lib/rtsp/global.rb +63 -0
  27. data/lib/rtsp/helpers.rb +28 -0
  28. data/lib/rtsp/message.rb +270 -0
  29. data/lib/rtsp/response.rb +89 -29
  30. data/lib/rtsp/transport_parser.rb +64 -0
  31. data/lib/rtsp/version.rb +4 -0
  32. data/nsm_test.rb +26 -0
  33. data/rtsp.gemspec +284 -0
  34. data/sarix_test.rb +23 -0
  35. data/soma_test.rb +39 -0
  36. data/spec/rtsp/client_spec.rb +302 -27
  37. data/spec/rtsp/helpers_spec.rb +53 -0
  38. data/spec/rtsp/message_spec.rb +420 -0
  39. data/spec/rtsp/response_spec.rb +144 -58
  40. data/spec/rtsp/transport_parser_spec.rb +54 -0
  41. data/spec/rtsp_spec.rb +3 -3
  42. data/spec/spec_helper.rb +66 -7
  43. data/spec/support/fake_rtsp_server.rb +123 -0
  44. data/tasks/metrics.rake +27 -0
  45. data/tasks/roodi_config.yml +14 -0
  46. data/tasks/stats.rake +12 -0
  47. metadata +174 -183
  48. data/.autotest +0 -23
  49. data/History.txt +0 -4
  50. data/Manifest.txt +0 -26
  51. data/bin/rtsp +0 -121
  52. data/features/step_definitions/stream_steps.rb +0 -50
  53. data/features/stream.feature +0 -17
  54. data/features/support/common.rb +0 -1
  55. data/features/support/world.rb +0 -1
  56. data/lib/rtsp/request_messages.rb +0 -104
  57. data/lib/rtsp/status_code.rb +0 -7
data/bin/rtsp_client ADDED
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'tempfile'
5
+ require 'optparse'
6
+
7
+ $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib/')
8
+ require 'rtsp/client'
9
+
10
+ optparse = OptionParser.new do |opts|
11
+ opts.banner = "Usage: #{__FILE__} [options] url"
12
+
13
+ #----------------------------------------------------------------------------
14
+ # Turn on logging
15
+ RTSP::Client.configure { |c| c.log = false }
16
+ opts.on('-d', '--debug', "Turn on RTSP::Client logging.") do
17
+ RTSP::Client.configure { |c| c.log = true }
18
+ end
19
+
20
+ #----------------------------------------------------------------------------
21
+ # Get description
22
+ opts.on('--describe [URL]', "Get description from the given URL.") do |url|
23
+ if url.nil?
24
+ puts "Must pass in a URL."
25
+ exit
26
+ end
27
+
28
+ rtsp_client = RTSP::Client.new(url)
29
+ p rtsp_client.describe.body.inspect
30
+ exit
31
+ end
32
+
33
+ #----------------------------------------------------------------------------
34
+ # Show available tracks
35
+ opts.on('--show-tracks [URL]', "Show available tracks from the given URL.") do |url|
36
+ if url.nil?
37
+ puts "Must pass in a URL."
38
+ exit
39
+ end
40
+
41
+ rtsp_client = RTSP::Client.new(url)
42
+ rtsp_client.describe
43
+ puts "Aggregate control track: #{rtsp_client.aggregate_control_track}"
44
+ puts "Media control tracks: #{rtsp_client.media_control_tracks}"
45
+ exit
46
+ end
47
+
48
+ #----------------------------------------------------------------------------
49
+ # Stream
50
+ opts.on('--stream [URL]', "Show available tracks from the given URL.") do |url|
51
+ if url.nil?
52
+ puts "Must pass in a URL."
53
+ exit
54
+ end
55
+
56
+ rtsp_client = RTSP::Client.new(url) do |connection, capturer|
57
+ capturer.rtp_file = File.open("#{Dir.pwd}/rtsp_client_stream.rtp", "wb")
58
+ end
59
+
60
+ begin
61
+ puts "Getting server options..."
62
+ response = rtsp_client.options
63
+ puts "\tServer: #{response.server}"
64
+ puts "\tSupported methods: #{response.public}"
65
+ puts ""
66
+
67
+ puts "Getting description..."
68
+ response = rtsp_client.describe
69
+ puts "\tcache_control: #{response.cache_control}" if response.respond_to? "cache_control"
70
+ puts "\tdate: #{response.date}"
71
+ puts "\texpires: #{response.expires}" if response.respond_to? "expires"
72
+ puts "\tcontent_type: #{response.content_type}"
73
+ puts "\tcontent_base: #{response.content_base}"
74
+ puts "\tAggregate control track: #{rtsp_client.aggregate_control_track}"
75
+ puts "\tMedia control tracks: #{rtsp_client.media_control_tracks}"
76
+ puts ""
77
+
78
+ puts "Setting up #{rtsp_client.media_control_tracks.first}"
79
+ response = rtsp_client.setup rtsp_client.media_control_tracks.first
80
+ puts "\ttransport: #{response.transport}"
81
+ puts ""
82
+
83
+ if response.message == "OK"
84
+ puts "Playing #{rtsp_client.aggregate_control_track}"
85
+ r = rtsp_client.play rtsp_client.aggregate_control_track
86
+ puts "\trange: #{r.range}"
87
+ puts "\trtp_info: #{r.rtp_info}"
88
+ puts ""
89
+
90
+
91
+ 1...5.times do
92
+ print "."
93
+ sleep 1
94
+ end
95
+ puts ""
96
+
97
+ if rtsp_client.capturer.rtp_file.size.zero?
98
+ puts "Captured 0 bytes. Your firewall might be blocking the RTP traffic on port #{rtsp_client.capturer.rtp_port}."
99
+ else
100
+ puts "RTP data captured to file: #{rtsp_client.capturer.rtp_file}"
101
+ end
102
+
103
+ puts "Tearing down..."
104
+ r2 = rtsp_client.teardown(rtsp_client.aggregate_control_track)
105
+ puts "\tconnection: #{r2.connection}" if r2.respond_to? "connection"
106
+ else
107
+ puts "Play call returned: #{response.message}. Exiting."
108
+ exit
109
+ end
110
+ rescue RTSP::Error => ex
111
+ puts ex.backtrace
112
+ puts ex.message
113
+ end
114
+ end
115
+
116
+ #----------------------------------------------------------------------------
117
+ # Help
118
+ opts.on('-h', '--help', "You're looking at it.") do
119
+ puts opts
120
+ exit
121
+ end
122
+ end
123
+
124
+ if ARGV.size.zero?
125
+ puts optparse.help if ARGV.size.zero?
126
+ exit
127
+ end
128
+ optparse.parse!
129
+
@@ -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,46 @@
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
+ @client = RTSP::Client.new(url) do |connection|
29
+ connection.socket = @fake_server
30
+ connection.timeout = 3
31
+ end
32
+ end
33
+
34
+ @initial_state = @client.session_state
35
+ params = params.empty? ? {} : params
36
+
37
+ @client.send(request_type.to_sym, params)
38
+ end
39
+
40
+ Then /^the state stays the same$/ do
41
+ @client.session_state.should == @initial_state
42
+ end
43
+
44
+ Then /^the state changes to "([^"]*)"$/ do |new_state|
45
+ @client.session_state.should == new_state.to_sym
46
+ end
@@ -0,0 +1,74 @@
1
+ Given /^a known RTSP server$/ do
2
+ @server_url = "rtsp://64.202.98.91:554/sa.sdp"
3
+ @client = RTSP::Client.new(@server_url) do |connection|
4
+ connection.socket = @fake_server
5
+ connection.timeout = 3
6
+ end
7
+ end
8
+
9
+ When /^I make a "([^"]*)" request$/ do |method|
10
+ =begin
11
+ @response = RTSP::Request.execute({
12
+ :method => method.to_sym,
13
+ :resource_url => @server_url }
14
+ )
15
+ =end
16
+ @response = @client.send(method.to_sym)
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
+ =begin
29
+ @response = RTSP::Request.execute({
30
+ :method => method.to_sym,
31
+ :headers => headers,
32
+ :resource_url => @server_url }
33
+ )
34
+ =end
35
+ @response = @client.send(method.to_sym, headers)
36
+ end
37
+
38
+ Then /^I should receive an RTSP response to that OPTIONS request$/ do
39
+ @response.is_a?(RTSP::Response).should be_true
40
+ @response.code.should == 200
41
+ @response.message.should == "OK"
42
+ @response.cseq.should == 1
43
+ @response.public.should == "DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE"
44
+ @response.body.should be_nil
45
+ end
46
+
47
+ Then /^I should receive an RTSP response to that DESCRIBE request$/ do
48
+ @response.is_a?(RTSP::Response).should be_true
49
+ @response.code.should == 200
50
+ @response.message.should == "OK"
51
+ @response.server.should == "DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )"
52
+ @response.cseq.should == 1
53
+ @response.body.is_a?(SDP::Description).should be_true
54
+ @response.body.protocol_version.should == "0"
55
+ @response.body.username.should == "-"
56
+ end
57
+
58
+ Then /^I should receive an RTSP response to that ANNOUNCE request$/ do
59
+ @response.is_a?(RTSP::Response).should be_true
60
+ @response.code.should == 200
61
+ @response.message.should == "OK"
62
+ @response.server.should == "DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )"
63
+ @response.cseq.should == 1
64
+ end
65
+
66
+ Then /^I should receive an RTSP response to that SETUP request$/ do
67
+ @response.is_a?(RTSP::Response).should be_true
68
+ @response.code.should == 200
69
+ @response.message.should == "OK"
70
+ @response.server.should == "DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )"
71
+ @response.cseq.should == 1
72
+ @response.transport.should == ""
73
+ end
74
+
@@ -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
@@ -1,37 +1,39 @@
1
1
  require 'rubygems'
2
2
  require 'socket'
3
3
  require 'timeout'
4
+ require 'cucumber/rspec/doubles'
4
5
 
5
6
  $:.unshift(File.dirname(__FILE__) + '/../../lib')
6
7
  require 'rtsp/client'
7
8
 
9
+ $:.unshift(File.dirname(__FILE__) + '/../../spec/support')
10
+ require 'fake_rtsp_server'
8
11
 
9
- DESCRIBE_RESPONSE = <<-RESP
10
- RTSP/1.0 200 OK
11
- Server: DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )
12
- Cseq: 1
13
- Cache-Control: no-cache
14
- Content-length: 406
15
- Date: Sun, 23 Jan 2011 00:36:45 GMT
16
- Expires: Sun, 23 Jan 2011 00:36:45 GMT
17
- Content-Type: application/sdp
18
- x-Accept-Retransmit: our-retransmit
19
- x-Accept-Dynamic-Rate: 1
20
- Content-Base: rtsp://64.202.98.91:554/gs.sdp/
21
-
22
- v=0
23
- o=- 545877020 467920391 IN IP4 127.0.0.1
24
- s=Groove Salad from SomaFM [aacPlus]
25
- i=Downtempo Ambient Groove
26
- c=IN IP4 0.0.0.0
27
- t=0 0
28
- a=x-qt-text-cmt:Orban Opticodec-PC
29
- a=x-qt-text-nam:Groove Salad from SomaFM [aacPlus]
30
- a=x-qt-text-inf:Downtempo Ambient Groove
31
- a=control:*
32
- m=audio 0 RTP/AVP 96
33
- b=AS:48
34
- a=rtpmap:96 MP4A-LATM/44100/2
35
- a=fmtp:96 cpresent=0;config=400027200000
36
- a=control:trackID=1
37
- RESP
12
+ DESCRIBE_RESPONSE = %Q{ RTSP/1.0 200 OK\r
13
+ Server: DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )\r
14
+ Cseq: 2\r
15
+ Cache-Control: no-cache\r
16
+ Content-length: 406\r
17
+ Date: Sun, 23 Jan 2011 00:36:45 GMT\r
18
+ Expires: Sun, 23 Jan 2011 00:36:45 GMT\r
19
+ Content-Type: application/sdp\r
20
+ x-Accept-Retransmit: our-retransmit\r
21
+ x-Accept-Dynamic-Rate: 1\r
22
+ Content-Base: rtsp://64.202.98.91:554/gs.sdp/\r
23
+ \r\n\r
24
+ v=0\r
25
+ o=- 545877020 467920391 IN IP4 127.0.0.1\r
26
+ s=Groove Salad from SomaFM [aacPlus]\r
27
+ i=Downtempo Ambient Groove\r
28
+ c=IN IP4 0.0.0.0\r
29
+ t=0 0\r
30
+ a=x-qt-text-cmt:Orban Opticodec-PC\r\n
31
+ a=x-qt-text-nam:Groove Salad from SomaFM [aacPlus]\r
32
+ a=x-qt-text-inf:Downtempo Ambient Groove\r
33
+ a=control:*\r
34
+ m=audio 0 RTP/AVP 96\r
35
+ b=AS:48\r
36
+ a=rtpmap:96 MP4A-LATM/44100/2\r
37
+ a=fmtp:96 cpresent=0;config=400027200000\r
38
+ a=control:trackID=1\r
39
+ \r\n}