Skip to content

Commit 1352727

Browse files
feature: renew RTSP session
1 parent 7471103 commit 1352727

File tree

5 files changed

+66
-1
lines changed

5 files changed

+66
-1
lines changed

lib/components/rtsp-session/rtspsession-component.js

+24
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ class RtspSessionComponent extends Component {
135135
this._callHistory = []
136136
this._state = IDLE
137137
this._waiting = false
138+
if (this._renewSessionInterval) {
139+
clearInterval(this._renewSessionInterval)
140+
}
141+
this._renewSessionInterval = null
138142

139143
this._contentBase = null
140144
this._sessionId = null
@@ -157,7 +161,23 @@ class RtspSessionComponent extends Component {
157161
if (!this._sessionId && !ended) {
158162
// Response on first SETUP
159163
this._sessionId = Rtsp.sessionId(msg.data)
164+
const sessionTimeout = Rtsp.sessionTimeout(msg.data)
165+
if (sessionTimeout !== null) {
166+
// The server specified that sessions will timeout if not renewed.
167+
// In order to keep it alive we need periodically send a RTSP_OPTIONS message
168+
if (this._renewSessionInterval) {
169+
clearInterval(this._renewSessionInterval)
170+
}
171+
this._renewSessionInterval = setInterval(
172+
() => {
173+
this._enqueue({ method: RTSP_OPTIONS })
174+
this._dequeue()
175+
},
176+
(sessionTimeout - 5) * 1000 // timeout minus 5 seconds.
177+
)
178+
}
160179
}
180+
161181
if (!this._contentBase) {
162182
this._contentBase = Rtsp.contentBase(msg.data)
163183
}
@@ -290,6 +310,10 @@ class RtspSessionComponent extends Component {
290310
this._callStack = []
291311
}
292312
this._state = IDLE
313+
if (this._renewSessionInterval) {
314+
clearInterval(this._renewSessionInterval)
315+
this._renewSessionInterval = null
316+
}
293317
this._dequeue()
294318
}
295319

lib/components/rtsp-session/rtspsession-component.test.js

+2
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,11 @@ describe('session', () => {
135135
test('should get the session from a Response containing session info', () => {
136136
const s = new RtspSessionComponent({ uri: 'whatever' })
137137
expect(s._sessionId).toEqual(null)
138+
expect(s._renewSessionInterval).toBeNull()
138139
const res = Buffer.from(setupResponse)
139140
s.incoming.write({ data: res, type: RTSP })
140141
expect(s._sessionId).toEqual('Bk48Ak7wjcWaAgRD')
142+
expect(s._renewSessionInterval).not.toBeNull()
141143
})
142144

143145
test('should emit a Request using SETUP command', (done) => {

lib/utils/protocols/fixtures.js

+10
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ Date: Wed, 03 Jun 2015 14:23:42 GMT
7878
7979
`.split('\n').join('\r\n');
8080

81+
exports.setupResponseNoTimeout = `RTSP/1.0 200 OK
82+
CSeq: 5
83+
RTP-Info: url=rtsp://192.168.0.3/axis-media/media.amp/stream=0?resolution=176x144&fps=1;seq=10176;rtptime=2419713327
84+
Range: npt=now-
85+
Server: GStreamer RTSP server
86+
Session: Bk48Ak7wjcWaAgRD
87+
Date: Wed, 03 Jun 2015 14:23:42 GMT
88+
89+
`.split('\n').join('\r\n');
90+
8191
exports.teardownResponse = `RTSP/1.0 200 OK
8292
CSeq: 5
8393
Server: GStreamer RTSP server

lib/utils/protocols/rtsp.js

+17
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ const sessionId = (buffer) => {
3535
return val ? val.split(';')[0] : null
3636
}
3737

38+
const sessionTimeout = (buffer) => {
39+
const val = extractHeaderValue(buffer, 'Session')
40+
if (val === null) {
41+
return null
42+
}
43+
const timeoutToken = 'timeout='
44+
const timeoutPosition = val.indexOf(timeoutToken)
45+
if (timeoutPosition !== -1) {
46+
let timeoutVal = val.substring(timeoutPosition + timeoutToken.length)
47+
timeoutVal = timeoutVal.split(';')[0]
48+
let parsedTimeout = parseInt(timeoutVal)
49+
return (isNaN(parsedTimeout)) ? null : parsedTimeout
50+
}
51+
return null
52+
}
53+
3854
const statusCode = (buffer) => {
3955
return Number(buffer.toString('ascii', 9, 12))
4056
}
@@ -86,6 +102,7 @@ const bodyOffset = (chunk) => {
86102
module.exports = {
87103
sequence,
88104
sessionId,
105+
sessionTimeout,
89106
statusCode,
90107
contentBase,
91108
connectionEnded,

lib/utils/protocols/rtsp.test.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const Rtsp = require('./rtsp')
2-
const { sdpResponse, sdpResponseLive555, setupResponse, teardownResponse } =
2+
const { sdpResponse, sdpResponseLive555, setupResponse, setupResponseNoTimeout, teardownResponse } =
33
require('./fixtures')
44

55
describe('Rtsp', () => {
@@ -21,6 +21,18 @@ describe('Rtsp', () => {
2121
})
2222
})
2323

24+
describe('sessionTimeout', () => {
25+
it('should be null before SETUP', () => {
26+
expect(Rtsp.sessionTimeout(Buffer.from(sdpResponse))).toBeNull()
27+
})
28+
it('should be extracted correctly when in a SETUP response', () => {
29+
expect(Rtsp.sessionTimeout(Buffer.from(setupResponse))).toEqual(60)
30+
})
31+
it('should be null when not specified in a SETUP response', () => {
32+
expect(Rtsp.sessionTimeout(Buffer.from(setupResponseNoTimeout))).toBeNull()
33+
})
34+
})
35+
2436
describe('statusCode', () => {
2537
it('should return an integer', () => {
2638
expect(Rtsp.statusCode(Buffer.from(sdpResponseLive555))).toEqual(200)

0 commit comments

Comments
 (0)