|
1 /* |
|
2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: RTP/TCP streamer for RTSP source.* |
|
15 */ |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 // INCLUDE FILES |
|
21 #include "CCRRtpTcpStreamer.h" |
|
22 #include "CCRRtpTcpObserver.h" |
|
23 #include "CCRRtpTcpStream.h" |
|
24 #include "CRRTSPCommon.h" |
|
25 #include <es_sock.h> |
|
26 #include "videoserviceutilsLogger.h" |
|
27 |
|
28 // CONSTANTS |
|
29 const TInt KCRRtpTcpHeaderLength( 4 ); |
|
30 const TInt KCRRtpTcpStartMark( 0x24 ); |
|
31 |
|
32 // ============================ MEMBER FUNCTIONS =============================== |
|
33 |
|
34 // ----------------------------------------------------------------------------- |
|
35 // CCRRtpTcpStreamer::NewL |
|
36 // ----------------------------------------------------------------------------- |
|
37 CCRRtpTcpStreamer* CCRRtpTcpStreamer::NewL( MCRRtpTcpObserver& aObserver ) |
|
38 { |
|
39 CCRRtpTcpStreamer* self = new( ELeave ) CCRRtpTcpStreamer( aObserver ); |
|
40 CleanupStack::PushL( self ); |
|
41 self->ConstructL(); |
|
42 CleanupStack::Pop( self ); |
|
43 return self; |
|
44 } |
|
45 |
|
46 // ----------------------------------------------------------------------------- |
|
47 // CCRRtpTcpStreamer::CCRRtpTcpStreamer |
|
48 // ----------------------------------------------------------------------------- |
|
49 // |
|
50 CCRRtpTcpStreamer::CCRRtpTcpStreamer( MCRRtpTcpObserver& aObserver ) |
|
51 : iObserver( aObserver ), |
|
52 iMoreExpected( KErrNotFound ), |
|
53 iIpData( NULL ) |
|
54 { |
|
55 // None |
|
56 } |
|
57 |
|
58 // ----------------------------------------------------------------------------- |
|
59 // CCRRtpTcpStreamer::ConstructL |
|
60 // ----------------------------------------------------------------------------- |
|
61 // |
|
62 void CCRRtpTcpStreamer::ConstructL() |
|
63 { |
|
64 // Construct streams |
|
65 for ( TInt i( 0 ); i < KCRRtpTcpStreamCount; i++ ) |
|
66 { |
|
67 iStreams[i] = CCRRtpTcpStream::NewL( iObserver ); |
|
68 } |
|
69 } |
|
70 |
|
71 // ----------------------------------------------------------------------------- |
|
72 // CCRRtpTcpStreamer::~CCRRtpTcpStreamer |
|
73 // ----------------------------------------------------------------------------- |
|
74 CCRRtpTcpStreamer::~CCRRtpTcpStreamer() |
|
75 { |
|
76 // Buffers |
|
77 if ( iIpData ) |
|
78 { |
|
79 delete iIpData; iIpData = NULL; |
|
80 } |
|
81 if ( iRtspData ) |
|
82 { |
|
83 delete iRtspData; iRtspData = NULL; |
|
84 } |
|
85 |
|
86 // Delete streams |
|
87 for ( TInt i( 0 ); i < KCRRtpTcpStreamCount; i++ ) |
|
88 { |
|
89 if ( iStreams[i] ) |
|
90 { |
|
91 delete iStreams[i]; iStreams[i] = NULL; |
|
92 } |
|
93 } |
|
94 } |
|
95 |
|
96 // ----------------------------------------------------------------------------- |
|
97 // CCRRtpTcpStreamer::DataAvailable |
|
98 // ----------------------------------------------------------------------------- |
|
99 // |
|
100 void CCRRtpTcpStreamer::DataAvailable( |
|
101 const TDesC8& aIpData, |
|
102 const TBool& aInterleaved ) |
|
103 { |
|
104 TPtrC8 data( aIpData ); |
|
105 if ( iMoreExpected > KErrNotFound && iIpData != NULL ) |
|
106 { |
|
107 // More data expected |
|
108 if ( HandleMoreExpected( data ) ) |
|
109 { |
|
110 return; // Need more |
|
111 } |
|
112 } |
|
113 |
|
114 // Can't be existing IP data at this point |
|
115 delete iIpData; iIpData = NULL; |
|
116 iMoreExpected = KErrNotFound; |
|
117 |
|
118 // Find out next packet |
|
119 do |
|
120 { |
|
121 // Search for $ (0x24) sign |
|
122 TBool tcp( EFalse ); |
|
123 for ( TInt i( 0 ); aInterleaved && tcp == EFalse && |
|
124 i < data.Length() && i < KCRRtpTcpHeaderLength; i++ ) |
|
125 { |
|
126 if ( data[i] == KCRRtpTcpStartMark ) |
|
127 { |
|
128 tcp = ETrue; |
|
129 data.Set( data.Mid( i ) ); |
|
130 |
|
131 // Received less than full interleved header (4 bytes) |
|
132 if ( data.Length() < KCRRtpTcpHeaderLength ) |
|
133 { |
|
134 iMoreExpected = KCRRtpTcpHeaderLength - data.Length(); |
|
135 iIpData = data.Alloc(); |
|
136 LOG1( "CCRRtpTcpStreamer::DataAvailable(), No interleave header, len: %d", data.Length() ); |
|
137 return; // Need more |
|
138 } |
|
139 } |
|
140 } |
|
141 |
|
142 if ( tcp ) |
|
143 { |
|
144 // TCP packet |
|
145 if ( HandleTcpPacket( data ) ) |
|
146 { |
|
147 return; // Need more |
|
148 } |
|
149 } |
|
150 else |
|
151 { |
|
152 // RTSP response |
|
153 if ( HandleRtspResponse( data, aInterleaved ) ) |
|
154 { |
|
155 return; // Need more |
|
156 } |
|
157 |
|
158 delete iRtspData; iRtspData = NULL; |
|
159 } |
|
160 } |
|
161 while ( data.Length() > 0 ); |
|
162 } |
|
163 |
|
164 // ----------------------------------------------------------------------------- |
|
165 // CCRRtpTcpStreamer::HandleMoreExpected |
|
166 // ----------------------------------------------------------------------------- |
|
167 // |
|
168 TBool CCRRtpTcpStreamer::HandleMoreExpected( TPtrC8& aData ) |
|
169 { |
|
170 TInt len( aData.Length() ); |
|
171 int used( len ); |
|
172 if ( len >= iMoreExpected || iMoreExpected == KMaxTInt ) |
|
173 { |
|
174 if ( iMoreExpected >= KCRRtpTcpHeaderLength || |
|
175 iIpData->Des()[0] != KCRRtpTcpStartMark || |
|
176 iIpData->Length() >= KCRRtpTcpHeaderLength ) |
|
177 { |
|
178 // KMaxTInt is indication of unknow length in RTSP response |
|
179 if ( iMoreExpected < KMaxTInt ) |
|
180 { |
|
181 used = iMoreExpected; |
|
182 iMoreExpected = KErrNotFound; |
|
183 } |
|
184 else |
|
185 { |
|
186 // Combine datas and try find out RTSP response |
|
187 delete iRtspData; iRtspData = NULL; |
|
188 iRtspData = HBufC8::New( iIpData->Length() + len ); |
|
189 TPtr8 ptr( iRtspData->Des() ); |
|
190 ptr.Copy( iIpData->Des() ); |
|
191 ptr.Append( aData ); |
|
192 aData.Set( iRtspData->Des() ); |
|
193 return EFalse; // Continue |
|
194 } |
|
195 } |
|
196 else |
|
197 { |
|
198 // Fill interleave header |
|
199 iIpData = iIpData->ReAlloc( iIpData->Length() + iMoreExpected ); |
|
200 TPtr8 ptr( iIpData->Des() ); |
|
201 ptr.Append( aData.Mid( 0, iMoreExpected ) ); |
|
202 aData.Set( aData.Mid( iMoreExpected ) ); |
|
203 len = aData.Length(); |
|
204 used = len; |
|
205 // Find real wanted packet length |
|
206 iMoreExpected = ( TInt )BigEndian::Get16( ptr.Ptr() + 2 ); |
|
207 if ( len == 0 ) |
|
208 { |
|
209 return ETrue; // Need more |
|
210 } |
|
211 if ( len >= iMoreExpected ) |
|
212 { |
|
213 used = iMoreExpected; |
|
214 iMoreExpected = KErrNotFound; |
|
215 } |
|
216 } |
|
217 } |
|
218 |
|
219 // Add new data to iIpData |
|
220 iIpData = iIpData->ReAlloc( iIpData->Length() + used ); |
|
221 TPtr8 ptr( iIpData->Des() ); |
|
222 ptr.Append( aData.Mid( 0, used ) ); |
|
223 aData.Set( aData.Mid( used ) ); |
|
224 if ( iMoreExpected == KErrNotFound ) |
|
225 { |
|
226 ForwardPacket( ptr ); |
|
227 if ( used == len ) |
|
228 { |
|
229 delete iIpData; iIpData = NULL; |
|
230 return ETrue; // All handled |
|
231 } |
|
232 } |
|
233 else |
|
234 { |
|
235 iMoreExpected -= used; |
|
236 return ETrue; // Need more |
|
237 } |
|
238 |
|
239 return EFalse; // Continue |
|
240 } |
|
241 |
|
242 // ----------------------------------------------------------------------------- |
|
243 // CCRRtpTcpStreamer::HandleTcpPacket |
|
244 // ----------------------------------------------------------------------------- |
|
245 // |
|
246 TBool CCRRtpTcpStreamer::HandleTcpPacket( TPtrC8& aData ) |
|
247 { |
|
248 const TInt length( KCRRtpTcpHeaderLength + |
|
249 ( TInt )BigEndian::Get16( aData.Ptr() + 2 ) ); |
|
250 if ( aData.Length() >= length ) |
|
251 { |
|
252 MakePacket( aData, length ); |
|
253 } |
|
254 else |
|
255 { |
|
256 // Need more data |
|
257 iMoreExpected = length - aData.Length(); |
|
258 iIpData = aData.Alloc(); |
|
259 return ETrue; // Need more |
|
260 } |
|
261 |
|
262 return EFalse; // Continue |
|
263 } |
|
264 |
|
265 // ----------------------------------------------------------------------------- |
|
266 // CCRRtpTcpStreamer::HandleRtspResponse |
|
267 // ----------------------------------------------------------------------------- |
|
268 // |
|
269 TBool CCRRtpTcpStreamer::HandleRtspResponse( |
|
270 TPtrC8& aData, |
|
271 const TBool& aInterleaved ) |
|
272 { |
|
273 TInt point( aData.FindC( KCRRTSPReplyHeader ) ); |
|
274 if ( point > KErrNotFound ) |
|
275 { |
|
276 aData.Set( aData.Mid( point ) ); |
|
277 |
|
278 // Search for double CRLF combination |
|
279 TInt crlf2( aData.FindC( KCR2NewLines ) ); |
|
280 if ( crlf2 > KErrNotFound ) |
|
281 { |
|
282 crlf2 += KCR2NewLines().Length(); |
|
283 } |
|
284 |
|
285 // Content length |
|
286 point = aData.FindC( KCRRTSPContentLength() ); |
|
287 if ( point > KErrNotFound && crlf2 > KErrNotFound ) |
|
288 { |
|
289 point += KCRRTSPContentLength().Length(); |
|
290 TInt contentLen( KErrNotFound ); |
|
291 TLex8 contentLenLex( aData.Mid( point, 5 ) ); |
|
292 if ( contentLenLex.Val( contentLen ) < KErrNone ) |
|
293 { |
|
294 LOG1( "CCRRtpTcpStreamer::HandleRtspResponse(), Content length parse failed, Dumped %d bytes !", aData.Length() ); |
|
295 return ETrue; |
|
296 } |
|
297 |
|
298 LOG1( "CCRRtspCommon::HandleRtspResponse(), contentLen %d", contentLen ); |
|
299 // Verify that enought data in IP packet |
|
300 if ( aData.Length() >= ( crlf2 + contentLen ) ) |
|
301 { |
|
302 MakePacket( aData, crlf2 + contentLen ); |
|
303 } |
|
304 else |
|
305 { |
|
306 // Need more |
|
307 iIpData = aData.Alloc(); |
|
308 iMoreExpected = crlf2 + contentLen - aData.Length(); |
|
309 return ETrue; |
|
310 } |
|
311 } |
|
312 else |
|
313 { |
|
314 // Content length not defined, RTSP command should end to double CRLF |
|
315 if ( crlf2 > KErrNotFound ) |
|
316 { |
|
317 MakePacket( aData, crlf2 ); |
|
318 } |
|
319 else |
|
320 { |
|
321 LOG( "CCRRtpTcpStreamer::HandleRtspResponse(), No double CRLF.." ); |
|
322 |
|
323 // Look for single CRLF |
|
324 point = aData.FindC( KCRNewLine ); |
|
325 if ( point > KErrNotFound ) |
|
326 { |
|
327 // If not interleaved, all data belongs to RTSP response |
|
328 if ( !aInterleaved ) |
|
329 { |
|
330 if ( aData.Mid( aData.Length() - KCR2NewLines().Length() ). |
|
331 FindF( KCRNewLine ) > KErrNotFound ) |
|
332 { |
|
333 ForwardPacket( aData ); |
|
334 return ETrue; |
|
335 } |
|
336 |
|
337 // Not complete but total length unknown |
|
338 LOG( "CCRRtpTcpStreamer::HandleRtspResponse(), Need more without known length.." ); |
|
339 iIpData = aData.Alloc(); |
|
340 iMoreExpected = KMaxTInt; |
|
341 return ETrue; |
|
342 } |
|
343 |
|
344 // Only one CRLF after RTSP response, find last |
|
345 point += KCRNewLine().Length(); |
|
346 for ( TInt i( point ); i < aData.Length(); ) |
|
347 { |
|
348 TInt next( aData.Mid( point ).FindC( KCRNewLine ) ); |
|
349 if ( next > KErrNotFound ) |
|
350 { |
|
351 point += ( next + KCRNewLine().Length() ); |
|
352 i = point; |
|
353 } |
|
354 else |
|
355 { |
|
356 i = aData.Length(); |
|
357 } |
|
358 } |
|
359 |
|
360 LOG1( "CCRRtpTcpStreamer::HandleRtspResponse(), Last CRLF at index: %d", point ); |
|
361 MakePacket( aData, point ); |
|
362 } |
|
363 else |
|
364 { |
|
365 // Not any CRLF, can not be RTSP response |
|
366 LOG1( "CCRRtpTcpStreamer::HandleRtspResponse(), No CRLF, Dumped %d bytes !", aData.Length() ); |
|
367 return ETrue; |
|
368 } |
|
369 } |
|
370 } |
|
371 } |
|
372 else |
|
373 { |
|
374 LOG1( "CCRRtpTcpStreamer::HandleRtspResponse(), Not RTSP message, Dumped %d bytes !", aData.Length() ); |
|
375 return ETrue; |
|
376 } |
|
377 |
|
378 return EFalse; |
|
379 } |
|
380 |
|
381 // ----------------------------------------------------------------------------- |
|
382 // CCRRtpTcpStreamer::MakePacket |
|
383 // ----------------------------------------------------------------------------- |
|
384 // |
|
385 void CCRRtpTcpStreamer::MakePacket( TPtrC8& aData, const TInt aLength ) |
|
386 { |
|
387 ForwardPacket( aData.Mid( 0, aLength ) ); |
|
388 aData.Set( aData.Mid( aLength ) ); |
|
389 } |
|
390 |
|
391 // ----------------------------------------------------------------------------- |
|
392 // CCRRtpTcpStreamer::ForwardPacket |
|
393 // ----------------------------------------------------------------------------- |
|
394 // |
|
395 void CCRRtpTcpStreamer::ForwardPacket( const TDesC8& aPacket ) |
|
396 { |
|
397 if ( aPacket[0] == KCRRtpTcpStartMark ) |
|
398 { |
|
399 // 1. Forward (actually return or signal reception of) packet to user |
|
400 const TInt channel( ( TInt )aPacket[1] ); |
|
401 iObserver.RtpTcpPacketAvailable( |
|
402 channel, aPacket.Mid( KCRRtpTcpHeaderLength ) ); |
|
403 |
|
404 // 2. Map channel to internal stream, ignore non audio or video |
|
405 const TInt streamId( channel / 2 ); |
|
406 if ( streamId >= 0 && streamId < KCRRtpTcpStreamCount ) |
|
407 { |
|
408 iStreams[streamId]->PacketAvailable( channel ); |
|
409 } |
|
410 } |
|
411 else |
|
412 { |
|
413 // RTSP |
|
414 iObserver.RtspMsgAvailable( aPacket ); |
|
415 } |
|
416 } |
|
417 |
|
418 // End of File |