rtsp 0.0.1.alpha → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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}