rtsp 0.3.0 → 0.4.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.
- data/ChangeLog.rdoc +19 -0
- data/README.rdoc +7 -7
- data/features/control_streams_as_client.feature +1 -1
- data/features/step_definitions/client_changes_state_steps.rb +7 -1
- data/features/step_definitions/client_requests_steps.rb +19 -25
- data/features/support/env.rb +11 -0
- data/lib/rtsp/client.rb +8 -8
- data/lib/rtsp/message.rb +11 -11
- data/lib/rtsp/response.rb +15 -3
- data/lib/rtsp/transport_parser.rb +49 -17
- data/lib/rtsp/version.rb +1 -1
- data/rtsp.gemspec +1 -1
- data/spec/rtsp/client_spec.rb +6 -6
- data/spec/rtsp/message_spec.rb +36 -36
- data/spec/rtsp/response_spec.rb +73 -42
- data/spec/rtsp/transport_parser_spec.rb +109 -26
- data/spec/rtsp_spec.rb +2 -2
- data/spec/spec_helper.rb +60 -53
- metadata +25 -25
data/spec/rtsp/message_spec.rb
CHANGED
@@ -3,31 +3,31 @@ require_relative '../spec_helper'
|
|
3
3
|
require 'rtsp/message'
|
4
4
|
|
5
5
|
describe "RTSP::Message" do
|
6
|
-
|
7
|
-
@stream = "rtsp://1.2.3.4/stream1"
|
8
|
-
end
|
6
|
+
let(:stream) { "rtsp://1.2.3.4/stream1" }
|
9
7
|
|
10
8
|
it "raises if the header type isn't a Symbol" do
|
11
|
-
message = RTSP::Message.options(
|
12
|
-
|
9
|
+
message = RTSP::Message.options(stream)
|
10
|
+
|
11
|
+
lambda {
|
12
|
+
message.header "hi", "everyone"
|
13
13
|
}.should raise_error RTSP::Error
|
14
14
|
end
|
15
15
|
|
16
16
|
RTSP::Message.instance_variable_get(:@message_types).each do |method|
|
17
17
|
it "adds a User-Agent header to the #{method} method" do
|
18
|
-
message = RTSP::Message.send(method,
|
18
|
+
message = RTSP::Message.send(method, stream)
|
19
19
|
message.to_s.should include "User-Agent: RubyRTSP/"
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
context "builds an OPTIONS string" do
|
24
24
|
it "with default sequence number" do
|
25
|
-
message = RTSP::Message.options(
|
25
|
+
message = RTSP::Message.options(stream)
|
26
26
|
message.to_s.should == "OPTIONS rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\nCSeq: 1\r\nUser-Agent: RubyRTSP/#{RTSP::VERSION} (Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})\r\n\r\n"
|
27
27
|
end
|
28
28
|
|
29
29
|
it "with new sequence number" do
|
30
|
-
message = RTSP::Message.options(
|
30
|
+
message = RTSP::Message.options(stream)
|
31
31
|
message.header :cseq, 2345
|
32
32
|
message.to_s.should == "OPTIONS rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\nCSeq: 2345\r\nUser-Agent: RubyRTSP/#{RTSP::VERSION} (Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})\r\n\r\n"
|
33
33
|
end
|
@@ -35,7 +35,7 @@ describe "RTSP::Message" do
|
|
35
35
|
|
36
36
|
context "builds a DESCRIBE string" do
|
37
37
|
it "with default sequence and accept values" do
|
38
|
-
message = RTSP::Message.describe(
|
38
|
+
message = RTSP::Message.describe(stream)
|
39
39
|
message.to_s.should match(/^DESCRIBE rtsp:/)
|
40
40
|
message.to_s.should include "DESCRIBE rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
41
41
|
message.to_s.should include "CSeq: 1\r\n"
|
@@ -44,7 +44,7 @@ describe "RTSP::Message" do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it "with default sequence value" do
|
47
|
-
message = RTSP::Message.describe(
|
47
|
+
message = RTSP::Message.describe(stream).with_headers({
|
48
48
|
accept: 'application/sdp, application/rtsl' })
|
49
49
|
message.to_s.should match(/^DESCRIBE rtsp:/)
|
50
50
|
message.to_s.should include "DESCRIBE rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -54,7 +54,7 @@ describe "RTSP::Message" do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it "with new sequence and accept values" do
|
57
|
-
message = RTSP::Message.describe(
|
57
|
+
message = RTSP::Message.describe(stream).with_headers({
|
58
58
|
accept: 'application/sdp, application/rtsl',
|
59
59
|
cseq: 2345 })
|
60
60
|
|
@@ -68,7 +68,7 @@ describe "RTSP::Message" do
|
|
68
68
|
|
69
69
|
context "builds a ANNOUNCE string" do
|
70
70
|
it "with default sequence, content type, but no body" do
|
71
|
-
message = RTSP::Message.announce(
|
71
|
+
message = RTSP::Message.announce(stream).with_headers({ session: 123456789 })
|
72
72
|
|
73
73
|
message.to_s.should match(/^ANNOUNCE rtsp:/)
|
74
74
|
message.to_s.should include "ANNOUNCE rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -79,7 +79,7 @@ describe "RTSP::Message" do
|
|
79
79
|
end
|
80
80
|
|
81
81
|
it "with passed-in session and content type but no body" do
|
82
|
-
message = RTSP::Message.announce(
|
82
|
+
message = RTSP::Message.announce(stream).with_headers({
|
83
83
|
session: 123456789,
|
84
84
|
content_type: 'application/sdp, application/rtsl' })
|
85
85
|
|
@@ -92,7 +92,7 @@ describe "RTSP::Message" do
|
|
92
92
|
end
|
93
93
|
|
94
94
|
it "with passed-in sequence, session, content-type, but no body " do
|
95
|
-
message = RTSP::Message.announce(
|
95
|
+
message = RTSP::Message.announce(stream).with_headers({
|
96
96
|
session: 123456789,
|
97
97
|
content_type: 'application/sdp, application/rtsl',
|
98
98
|
cseq: 2345 })
|
@@ -110,7 +110,7 @@ describe "RTSP::Message" do
|
|
110
110
|
sdp.protocol_version = 1
|
111
111
|
sdp.username = 'bobo'
|
112
112
|
|
113
|
-
message = RTSP::Message.announce(
|
113
|
+
message = RTSP::Message.announce(stream).with_headers({
|
114
114
|
session: 123456789,
|
115
115
|
content_type: 'application/sdp',
|
116
116
|
cseq: 2345 })
|
@@ -128,7 +128,7 @@ describe "RTSP::Message" do
|
|
128
128
|
|
129
129
|
context "builds a SETUP string" do
|
130
130
|
it "with default sequence, client_port, and routing values" do
|
131
|
-
message = RTSP::Message.setup(
|
131
|
+
message = RTSP::Message.setup(stream)
|
132
132
|
|
133
133
|
message.to_s.should match(/^SETUP rtsp/)
|
134
134
|
message.to_s.should include "SETUP rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -137,7 +137,7 @@ describe "RTSP::Message" do
|
|
137
137
|
end
|
138
138
|
|
139
139
|
it "with default sequence, transport, and client_port values" do
|
140
|
-
message = RTSP::Message.setup(
|
140
|
+
message = RTSP::Message.setup(stream).with_headers({
|
141
141
|
transport: ["RTP/AVP", "multicast", { :client_port => "9000-9001" }] })
|
142
142
|
|
143
143
|
message.to_s.should match(/^SETUP rtsp/)
|
@@ -148,7 +148,7 @@ describe "RTSP::Message" do
|
|
148
148
|
end
|
149
149
|
|
150
150
|
it "with default transport, client_port, and routing values" do
|
151
|
-
message = RTSP::Message.setup(
|
151
|
+
message = RTSP::Message.setup(stream).with_headers({
|
152
152
|
transport: ["RTP/AVP", "multicast", { :client_port => "9000-9001" }],
|
153
153
|
cseq: 2345 })
|
154
154
|
|
@@ -162,7 +162,7 @@ describe "RTSP::Message" do
|
|
162
162
|
|
163
163
|
context "builds a PLAY string" do
|
164
164
|
it "with default sequence and range values" do
|
165
|
-
message = RTSP::Message.play(
|
165
|
+
message = RTSP::Message.play(stream).with_headers({
|
166
166
|
session: 123456789 })
|
167
167
|
|
168
168
|
message.to_s.should match(/^PLAY rtsp/)
|
@@ -174,7 +174,7 @@ describe "RTSP::Message" do
|
|
174
174
|
end
|
175
175
|
|
176
176
|
it "with default sequence value" do
|
177
|
-
message = RTSP::Message.play(
|
177
|
+
message = RTSP::Message.play(stream).with_headers({
|
178
178
|
session: 123456789,
|
179
179
|
range: { :npt => "0.000-1.234" } })
|
180
180
|
|
@@ -189,7 +189,7 @@ describe "RTSP::Message" do
|
|
189
189
|
|
190
190
|
context "builds a PAUSE string" do
|
191
191
|
it "with required Request values" do
|
192
|
-
message = RTSP::Message.pause(
|
192
|
+
message = RTSP::Message.pause(stream)
|
193
193
|
|
194
194
|
message.to_s.should match(/^PAUSE rtsp/)
|
195
195
|
message.to_s.should include "PAUSE rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -198,7 +198,7 @@ describe "RTSP::Message" do
|
|
198
198
|
end
|
199
199
|
|
200
200
|
it "with session and range headers" do
|
201
|
-
message = RTSP::Message.pause(
|
201
|
+
message = RTSP::Message.pause(stream).with_headers({
|
202
202
|
session: 123456789,
|
203
203
|
range: { :npt => "0.000" } })
|
204
204
|
|
@@ -213,7 +213,7 @@ describe "RTSP::Message" do
|
|
213
213
|
|
214
214
|
context "builds a TEARDOWN string" do
|
215
215
|
it "with required Request values" do
|
216
|
-
message = RTSP::Message.teardown(
|
216
|
+
message = RTSP::Message.teardown(stream)
|
217
217
|
|
218
218
|
message.to_s.should match(/^TEARDOWN rtsp/)
|
219
219
|
message.to_s.should include "TEARDOWN rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -222,7 +222,7 @@ describe "RTSP::Message" do
|
|
222
222
|
end
|
223
223
|
|
224
224
|
it "with session and range headers" do
|
225
|
-
message = RTSP::Message.teardown(
|
225
|
+
message = RTSP::Message.teardown(stream).with_headers({
|
226
226
|
session: 123456789 })
|
227
227
|
|
228
228
|
message.to_s.should match(/^TEARDOWN rtsp/)
|
@@ -235,7 +235,7 @@ describe "RTSP::Message" do
|
|
235
235
|
|
236
236
|
context "builds a GET_PARAMETER string" do
|
237
237
|
it "with required Request values" do
|
238
|
-
message = RTSP::Message.get_parameter(
|
238
|
+
message = RTSP::Message.get_parameter(stream)
|
239
239
|
|
240
240
|
message.to_s.should match(/^GET_PARAMETER rtsp/)
|
241
241
|
message.to_s.should include "GET_PARAMETER rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -246,7 +246,7 @@ describe "RTSP::Message" do
|
|
246
246
|
it "with cseq, content type, session headers, and text body" do
|
247
247
|
the_body = "packets_received\r\njitter\r\n"
|
248
248
|
|
249
|
-
message = RTSP::Message.get_parameter(
|
249
|
+
message = RTSP::Message.get_parameter(stream).with_headers({
|
250
250
|
cseq: 431,
|
251
251
|
content_type: 'text/parameters',
|
252
252
|
session: 123456789 })
|
@@ -266,7 +266,7 @@ describe "RTSP::Message" do
|
|
266
266
|
|
267
267
|
context "builds a SET_PARAMETER string" do
|
268
268
|
it "with required Request values" do
|
269
|
-
message = RTSP::Message.set_parameter(
|
269
|
+
message = RTSP::Message.set_parameter(stream)
|
270
270
|
|
271
271
|
message.to_s.should match(/^SET_PARAMETER rtsp/)
|
272
272
|
message.to_s.should include "SET_PARAMETER rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -277,7 +277,7 @@ describe "RTSP::Message" do
|
|
277
277
|
it "with cseq, content type, session headers, and text body" do
|
278
278
|
the_body = "barparam: barstuff\r\n"
|
279
279
|
|
280
|
-
message = RTSP::Message.set_parameter(
|
280
|
+
message = RTSP::Message.set_parameter(stream).with_headers({
|
281
281
|
cseq: 431,
|
282
282
|
content_type: 'text/parameters',
|
283
283
|
session: 123456789 })
|
@@ -296,7 +296,7 @@ describe "RTSP::Message" do
|
|
296
296
|
|
297
297
|
context "builds a REDIRECT string" do
|
298
298
|
it "with required Request values" do
|
299
|
-
message = RTSP::Message.redirect(
|
299
|
+
message = RTSP::Message.redirect(stream)
|
300
300
|
|
301
301
|
message.to_s.should match(/^REDIRECT rtsp/)
|
302
302
|
message.to_s.should include "REDIRECT rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -305,7 +305,7 @@ describe "RTSP::Message" do
|
|
305
305
|
end
|
306
306
|
|
307
307
|
it "with cseq, location, and range headers" do
|
308
|
-
message = RTSP::Message.redirect(
|
308
|
+
message = RTSP::Message.redirect(stream).with_headers({
|
309
309
|
cseq: 732,
|
310
310
|
location: "rtsp://bigserver.com:8001",
|
311
311
|
range: { :clock => "19960213T143205Z-" } })
|
@@ -321,7 +321,7 @@ describe "RTSP::Message" do
|
|
321
321
|
|
322
322
|
context "builds a RECORD string" do
|
323
323
|
it "with required Request values" do
|
324
|
-
message = RTSP::Message.record(
|
324
|
+
message = RTSP::Message.record(stream)
|
325
325
|
|
326
326
|
message.to_s.should match(/^RECORD rtsp/)
|
327
327
|
message.to_s.should include "RECORD rtsp://1.2.3.4:554/stream1 RTSP/1.0\r\n"
|
@@ -330,7 +330,7 @@ describe "RTSP::Message" do
|
|
330
330
|
end
|
331
331
|
|
332
332
|
it "with cseq, session, and conference headers" do
|
333
|
-
message = RTSP::Message.record(
|
333
|
+
message = RTSP::Message.record(stream).with_headers({
|
334
334
|
cseq: 954,
|
335
335
|
session: 12345678,
|
336
336
|
conference: "128.16.64.19/32492374" })
|
@@ -346,7 +346,7 @@ describe "RTSP::Message" do
|
|
346
346
|
|
347
347
|
context "#to_s turns a Hash into an String of header strings" do
|
348
348
|
it "single header, non-hyphenated name, hash value" do
|
349
|
-
message = RTSP::Message.play(
|
349
|
+
message = RTSP::Message.play(stream).with_headers({
|
350
350
|
range: { npt: "0.000-" }
|
351
351
|
})
|
352
352
|
|
@@ -356,7 +356,7 @@ describe "RTSP::Message" do
|
|
356
356
|
end
|
357
357
|
|
358
358
|
it "single header, hyphenated, non-hash value" do
|
359
|
-
message = RTSP::Message.play(
|
359
|
+
message = RTSP::Message.play(stream).with_headers({
|
360
360
|
:if_modified_since => "Sat, 29 Oct 1994 19:43:31 GMT"
|
361
361
|
})
|
362
362
|
|
@@ -366,7 +366,7 @@ describe "RTSP::Message" do
|
|
366
366
|
end
|
367
367
|
|
368
368
|
it "two headers, mixed hyphenated, array & hash values" do
|
369
|
-
message = RTSP::Message.redirect(
|
369
|
+
message = RTSP::Message.redirect(stream).with_headers({
|
370
370
|
:cache_control => ["no-cache", { :max_age => 12345 }],
|
371
371
|
:content_type => ['application/sdp', 'application/x-rtsp-mh']
|
372
372
|
})
|
@@ -380,7 +380,7 @@ describe "RTSP::Message" do
|
|
380
380
|
|
381
381
|
describe "#with_headers" do
|
382
382
|
it "returns an RTSP::Message" do
|
383
|
-
message = RTSP::Message.options(
|
383
|
+
message = RTSP::Message.options(stream)
|
384
384
|
result = message.with_headers({ test: "test" })
|
385
385
|
result.class.should == RTSP::Message
|
386
386
|
end
|
data/spec/rtsp/response_spec.rb
CHANGED
@@ -4,28 +4,59 @@ require 'rtsp/response'
|
|
4
4
|
describe RTSP::Response do
|
5
5
|
describe "#initialize" do
|
6
6
|
it "expects a non-nil string on" do
|
7
|
-
|
7
|
+
expect { RTSP::Response.new(nil) }.to raise_exception RTSP::Error
|
8
8
|
end
|
9
9
|
|
10
10
|
it "expects a non-empty string on" do
|
11
|
-
|
11
|
+
expect { RTSP::Response.new("") }.to raise_exception RTSP::Error
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
describe "#parse_head" do
|
16
|
+
let(:head) do
|
17
|
+
head = double "head"
|
18
|
+
head.stub(:split).and_return(['', session_line])
|
19
|
+
head.stub(:each_with_index).and_yield
|
20
|
+
|
21
|
+
head
|
22
|
+
end
|
23
|
+
|
24
|
+
context "Session header contains session-id and timeout" do
|
25
|
+
let(:session_line) { "Session: 118;timeout=49" }
|
26
|
+
subject { RTSP::Response.new SETUP_RESPONSE_WITH_SESSION_TIMEOUT }
|
27
|
+
|
28
|
+
it "creates a :session reader with value being a Hash with key/value" do
|
29
|
+
subject.stub(:extract_status_line)
|
30
|
+
subject.should_receive(:create_reader).with("session",
|
31
|
+
{ session_id: 118, timeout: 49 })
|
32
|
+
subject.parse_head(head)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "Session header contains just session-id" do
|
37
|
+
let(:session_line) { "Session: 118" }
|
38
|
+
subject { RTSP::Response.new SETUP_RESPONSE_WITH_SESSION_TIMEOUT }
|
39
|
+
|
40
|
+
it "creates a :session reader with value being a Hash with key/value" do
|
41
|
+
subject.stub(:extract_status_line)
|
42
|
+
subject.should_receive(:create_reader).with("session",
|
43
|
+
{ session_id: 118 })
|
44
|
+
subject.parse_head(head)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
subject { RTSP::Response.new OPTIONS_RESPONSE }
|
49
|
+
|
16
50
|
it "raises when RTSP version is corrupted" do
|
17
|
-
|
18
|
-
lambda { response.parse_head "RTSP/ 200 OK\r\n" }.should raise_error RTSP::Error
|
51
|
+
expect { subject.parse_head "RTSP/ 200 OK\r\n" }.to raise_error RTSP::Error
|
19
52
|
end
|
20
53
|
|
21
54
|
it "raises when the response code is corrupted" do
|
22
|
-
|
23
|
-
lambda { response.parse_head "RTSP/1.0 2 OK\r\n" }.should raise_error RTSP::Error
|
55
|
+
expect { subject.parse_head "RTSP/1.0 2 OK\r\n" }.to raise_error RTSP::Error
|
24
56
|
end
|
25
57
|
|
26
58
|
it "raises when the response message is corrupted" do
|
27
|
-
|
28
|
-
lambda { response.parse_head "RTSP/1.0 200 \r\n" }.should raise_error RTSP::Error
|
59
|
+
expect { subject.parse_head "RTSP/1.0 200 \r\n" }.to raise_error RTSP::Error
|
29
60
|
end
|
30
61
|
end
|
31
62
|
|
@@ -150,7 +181,7 @@ describe RTSP::Response do
|
|
150
181
|
end
|
151
182
|
|
152
183
|
it "returns the session" do
|
153
|
-
@response.session.should == 118
|
184
|
+
@response.session[:session_id].should == 118
|
154
185
|
end
|
155
186
|
end
|
156
187
|
|
@@ -176,7 +207,7 @@ describe RTSP::Response do
|
|
176
207
|
end
|
177
208
|
|
178
209
|
it "returns the session" do
|
179
|
-
@response.session.should == 118
|
210
|
+
@response.session[:session_id].should == 118
|
180
211
|
end
|
181
212
|
|
182
213
|
it "returns the rtp_info" do
|
@@ -231,44 +262,44 @@ describe RTSP::Response do
|
|
231
262
|
it "splits responses with headers and no body" do
|
232
263
|
response = RTSP::Response.new OPTIONS_RESPONSE
|
233
264
|
head_and_body = response.split_head_and_body_from OPTIONS_RESPONSE
|
234
|
-
head_and_body.first.should == %Q{RTSP/1.0 200 OK\r
|
235
|
-
CSeq: 1\r
|
236
|
-
Date: Fri, Jan 28 2011 01:14:42 GMT\r
|
237
|
-
Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r
|
265
|
+
head_and_body.first.should == %Q{RTSP/1.0 200 OK\r
|
266
|
+
CSeq: 1\r
|
267
|
+
Date: Fri, Jan 28 2011 01:14:42 GMT\r
|
268
|
+
Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r
|
238
269
|
}
|
239
270
|
end
|
240
271
|
|
241
272
|
it "splits responses with headers and body" do
|
242
273
|
response = RTSP::Response.new DESCRIBE_RESPONSE
|
243
274
|
head_and_body = response.split_head_and_body_from DESCRIBE_RESPONSE
|
244
|
-
head_and_body.first.should == %{RTSP/1.0 200 OK\r
|
245
|
-
Server: DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )\r
|
246
|
-
Cseq: 1\r
|
247
|
-
Cache-Control: no-cache\r
|
248
|
-
Content-length: 406\r
|
249
|
-
Date: Sun, 23 Jan 2011 00:36:45 GMT\r
|
250
|
-
Expires: Sun, 23 Jan 2011 00:36:45 GMT\r
|
251
|
-
Content-Type: application/sdp\r
|
252
|
-
x-Accept-Retransmit: our-retransmit\r
|
253
|
-
x-Accept-Dynamic-Rate: 1\r
|
254
|
-
Content-Base: rtsp://64.202.98.91:554/gs.sdp
|
255
|
-
|
256
|
-
head_and_body.last.should == %{
|
257
|
-
v=0
|
258
|
-
o=- 545877020 467920391 IN IP4 127.0.0.1
|
259
|
-
s=Groove Salad from SomaFM [aacPlus]
|
260
|
-
i=Downtempo Ambient Groove
|
261
|
-
c=IN IP4 0.0.0.0
|
262
|
-
t=0 0
|
263
|
-
a=x-qt-text-cmt:Orban Opticodec-PC
|
264
|
-
a=x-qt-text-nam:Groove Salad from SomaFM [aacPlus]
|
265
|
-
a=x-qt-text-inf:Downtempo Ambient Groove
|
266
|
-
a=control
|
267
|
-
m=audio 0 RTP/AVP 96
|
268
|
-
b=AS:48
|
269
|
-
a=rtpmap:96 MP4A-LATM/44100/2
|
270
|
-
a=fmtp:96 cpresent=0;config=400027200000
|
271
|
-
a=control:trackID=1
|
275
|
+
head_and_body.first.should == %{RTSP/1.0 200 OK\r
|
276
|
+
Server: DSS/5.5 (Build/489.7; Platform/Linux; Release/Darwin; )\r
|
277
|
+
Cseq: 1\r
|
278
|
+
Cache-Control: no-cache\r
|
279
|
+
Content-length: 406\r
|
280
|
+
Date: Sun, 23 Jan 2011 00:36:45 GMT\r
|
281
|
+
Expires: Sun, 23 Jan 2011 00:36:45 GMT\r
|
282
|
+
Content-Type: application/sdp\r
|
283
|
+
x-Accept-Retransmit: our-retransmit\r
|
284
|
+
x-Accept-Dynamic-Rate: 1\r
|
285
|
+
Content-Base: rtsp://64.202.98.91:554/gs.sdp/}
|
286
|
+
|
287
|
+
head_and_body.last.should == %{\r
|
288
|
+
v=0\r
|
289
|
+
o=- 545877020 467920391 IN IP4 127.0.0.1\r
|
290
|
+
s=Groove Salad from SomaFM [aacPlus]\r
|
291
|
+
i=Downtempo Ambient Groove\r
|
292
|
+
c=IN IP4 0.0.0.0\r
|
293
|
+
t=0 0\r
|
294
|
+
a=x-qt-text-cmt:Orban Opticodec-PC\r
|
295
|
+
a=x-qt-text-nam:Groove Salad from SomaFM [aacPlus]\r
|
296
|
+
a=x-qt-text-inf:Downtempo Ambient Groove\r
|
297
|
+
a=control:*\r
|
298
|
+
m=audio 0 RTP/AVP 96\r
|
299
|
+
b=AS:48\r
|
300
|
+
a=rtpmap:96 MP4A-LATM/44100/2\r
|
301
|
+
a=fmtp:96 cpresent=0;config=400027200000\r
|
302
|
+
a=control:trackID=1\r
|
272
303
|
}
|
273
304
|
end
|
274
305
|
end
|
@@ -2,53 +2,136 @@ require_relative '../spec_helper'
|
|
2
2
|
require 'rtsp/transport_parser'
|
3
3
|
|
4
4
|
describe RTSP::TransportParser do
|
5
|
-
|
6
|
-
|
5
|
+
let(:result) { subject.parse transport }
|
6
|
+
|
7
|
+
describe :transport_specifier do
|
8
|
+
context "RTP/AVP" do
|
9
|
+
let(:transport) { "RTP/AVP" }
|
10
|
+
specify { result[:streaming_protocol].should == 'RTP' }
|
11
|
+
specify { result[:profile].should == 'AVP' }
|
12
|
+
end
|
13
|
+
|
14
|
+
context "RTP/AVP/TCP" do
|
15
|
+
let(:transport) { "RTP/AVP/TCP" }
|
16
|
+
specify { result[:streaming_protocol].should == 'RTP' }
|
17
|
+
specify { result[:profile].should == 'AVP' }
|
18
|
+
specify { result[:transport_protocol].should == 'TCP' }
|
19
|
+
end
|
20
|
+
|
21
|
+
context "rtp/avp/tcp" do
|
22
|
+
let(:transport) { "rtp/avp/tcp" }
|
23
|
+
specify { result[:streaming_protocol].should == 'rtp' }
|
24
|
+
specify { result[:profile].should == 'avp' }
|
25
|
+
specify { result[:transport_protocol].should == 'tcp' }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe :broadcast_type do
|
30
|
+
context "RTP/AVP;unicast" do
|
31
|
+
let(:transport) { "RTP/AVP;unicast" }
|
32
|
+
specify { result[:broadcast_type].should == 'unicast' }
|
33
|
+
end
|
34
|
+
|
35
|
+
context "RTP/AVP;multicast" do
|
36
|
+
let(:transport) { "RTP/AVP;multicast" }
|
37
|
+
specify { result[:broadcast_type].should == 'multicast' }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe :destination do
|
42
|
+
context "RTP/AVP;multicast;destination=224.2.0.1" do
|
43
|
+
let(:transport) { "RTP/AVP;multicast;destination=224.2.0.1" }
|
44
|
+
specify { result[:destination].should == '224.2.0.1' }
|
45
|
+
end
|
7
46
|
end
|
8
47
|
|
9
|
-
describe
|
10
|
-
|
11
|
-
transport
|
12
|
-
|
48
|
+
describe :source do
|
49
|
+
context "RTP/AVP;multicast;destination=22.2.0.1;source=10.0.0.10" do
|
50
|
+
let(:transport) { "RTP/AVP;multicast;destination=22.2.0.1;source=10.0.0.10" }
|
51
|
+
specify { result[:source].should == '10.0.0.10' }
|
13
52
|
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe :client_port do
|
56
|
+
context "RTP/AVP;unicast;client_port=9000-9001" do
|
57
|
+
let(:transport) { "RTP/AVP;unicast;client_port=9000-9001" }
|
58
|
+
specify { result[:client_port][:rtp].should == '9000' }
|
59
|
+
specify { result[:client_port][:rtcp].should == '9001' }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe :server_port do
|
64
|
+
context "RTP/AVP/UCP;unicast;client_port=3058-3059;server_port=5002-5003" do
|
65
|
+
let(:transport) { "RTP/AVP/UCP;unicast;client_port=3058-3059;server_port=5002-5003" }
|
66
|
+
specify { result[:server_port][:rtp].should == "5002" }
|
67
|
+
specify { result[:server_port][:rtcp].should == "5003" }
|
68
|
+
end
|
69
|
+
end
|
14
70
|
|
15
|
-
|
16
|
-
|
71
|
+
describe :interleaved do
|
72
|
+
context "RTP/AVP/TCP;unicast;interleaved=0-1" do
|
73
|
+
let(:transport) { "RTP/AVP/TCP;unicast;interleaved=0-1" }
|
74
|
+
specify { result[:interleaved][:rtp_channel].should == '0' }
|
75
|
+
specify { result[:interleaved][:rtcp_channel].should == '1' }
|
17
76
|
end
|
77
|
+
end
|
18
78
|
|
19
|
-
|
20
|
-
|
79
|
+
describe :ttl do
|
80
|
+
context 'RTP/AVP;unicast;ttl=127' do
|
81
|
+
let(:transport) { 'RTP/AVP;unicast;ttl=127' }
|
82
|
+
specify { result[:ttl].should == "127" }
|
21
83
|
end
|
84
|
+
end
|
22
85
|
|
23
|
-
|
24
|
-
|
86
|
+
describe :port do
|
87
|
+
context 'RTP/AVP;unicast;port=1234' do
|
88
|
+
let(:transport) { 'RTP/AVP;unicast;port=1234' }
|
89
|
+
specify { result[:port][:rtp].should == "1234" }
|
90
|
+
specify { result[:port][:rtcp].should be_nil }
|
25
91
|
end
|
26
92
|
|
27
|
-
|
28
|
-
|
93
|
+
context 'RTP/AVP;unicast;port=1234-1235' do
|
94
|
+
let(:transport) { 'RTP/AVP;unicast;port=1234-1235' }
|
95
|
+
specify { result[:port][:rtp].should == "1234" }
|
96
|
+
specify { result[:port][:rtcp].should == "1235" }
|
29
97
|
end
|
98
|
+
end
|
30
99
|
|
31
|
-
|
32
|
-
|
100
|
+
describe :ssrc do
|
101
|
+
context 'RTP/AVP;unicast;ssrc=ABCD1234' do
|
102
|
+
let(:transport) { 'RTP/AVP;unicast;ssrc=ABCD1234' }
|
103
|
+
specify { result[:ssrc].should == "ABCD1234" }
|
33
104
|
end
|
34
105
|
end
|
35
106
|
|
36
|
-
describe
|
37
|
-
|
38
|
-
transport
|
39
|
-
|
107
|
+
describe :channel do
|
108
|
+
context 'RTP/AVP;unicast;channel=RTP' do
|
109
|
+
let(:transport) { 'RTP/AVP;unicast;channel=RTP' }
|
110
|
+
specify { result[:channel].should == "RTP" }
|
40
111
|
end
|
112
|
+
end
|
41
113
|
|
42
|
-
|
43
|
-
|
114
|
+
describe :address do
|
115
|
+
context 'RTP/AVP;unicast;address=192.168.14.18' do
|
116
|
+
let(:transport) { 'RTP/AVP;unicast;address=192.168.14.18' }
|
117
|
+
specify { result[:address].should == "192.168.14.18" }
|
44
118
|
end
|
45
119
|
|
46
|
-
|
47
|
-
|
120
|
+
context 'RTP/AVP;unicast;address=mycomputer.com' do
|
121
|
+
let(:transport) { 'RTP/AVP;unicast;address=mycomputer.com' }
|
122
|
+
specify { result[:address].should == "mycomputer.com" }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe :mode do
|
127
|
+
context 'RTP/AVP;unicast;mode="PLAY"' do
|
128
|
+
let(:transport) { 'RTP/AVP;unicast;mode="PLAY"' }
|
129
|
+
specify { result[:mode].should == "PLAY" }
|
48
130
|
end
|
49
131
|
|
50
|
-
|
51
|
-
|
132
|
+
context 'with ttl=127;mode=RECORD' do
|
133
|
+
let(:transport) { 'RTP/AVP;unicast;mode=RECORD' }
|
134
|
+
specify { result[:mode].should == "RECORD" }
|
52
135
|
end
|
53
136
|
end
|
54
137
|
end
|