|
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: RTSP Client impl.* |
|
15 */ |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 // INCLUDE FILES |
|
21 #include "CCRRtspPacketSource.h" |
|
22 #include "CCRPunchPacketSender.h" |
|
23 #include "CCRRtpTcpStreamer.h" |
|
24 #include "CCRRtspCommand.h" |
|
25 #include "CCRPacketBuffer.h" |
|
26 #include <ipvideo/CDvrSdpParser.h> |
|
27 #include "CCRTimer.h" |
|
28 #include <Uri16.h> |
|
29 #include <e32msgqueue.h> |
|
30 #include <centralrepository.h> |
|
31 #include <WebUtilsInternalCRKeys.h> |
|
32 #include <mmf/common/mmferrors.h> // ROP error codes |
|
33 |
|
34 // DATA TYPES |
|
35 // ###################################################### |
|
36 // WARNING: JUMBOJET-SIZED KLUDGE AHEAD: |
|
37 // ###################################################### |
|
38 #define private public |
|
39 // Explanation: timestamp getter in rtcp sender report |
|
40 // class is broken beyond repair. It may be fixed but the |
|
41 // broken version is already shipped to millions of phones |
|
42 // around the world. The broken getter method can't |
|
43 // be overridden as it requires access to private part |
|
44 // of sender reports instance variables. The item we |
|
45 // need (ntp timestamp) is there intact in private instance |
|
46 // variables but there is useless getter for that. |
|
47 #include <rtcp.h> |
|
48 |
|
49 /* sender report (SR) */ |
|
50 class TRtcpSRPart |
|
51 { |
|
52 public: |
|
53 TUint32 ssrc; /**< sender generating this report */ |
|
54 TUint32 ntp_sec; /**< NTP timestamp */ |
|
55 TUint32 ntp_frac; /**< Fractal seconds */ |
|
56 TUint32 rtp_ts; /**< RTP timestamp */ |
|
57 TUint32 psent; /**< packets sent */ |
|
58 TUint32 osent; /**< octets sent */ |
|
59 }; |
|
60 #undef private |
|
61 // ###################################################### |
|
62 // Major kludge ends here. |
|
63 // ###################################################### |
|
64 |
|
65 // CONSTANTS |
|
66 const TInt KCRPortNumberBase( 16670 ); |
|
67 const TInt KCSeqForRtspNegoation( 42 ); |
|
68 const TInt KRtspPortNumber( 554 ); |
|
69 const TInt KRtpPacketVersion( 2 ); |
|
70 const TUint KSenderReportPacketType( 0xC8 ); // 200 decimal |
|
71 const TInt KDVR10Seconds( 10000000 ); |
|
72 |
|
73 // The number of sequential packets that must be received |
|
74 // before a stream is considered good. 1 means no delay, start |
|
75 // from very first packet |
|
76 const TInt KDVRMinSequential( 1 ); |
|
77 // The maximum number of dropped packets to be considered a |
|
78 // dropout, as opposed to an ended and restarted stream. |
|
79 const TInt KDVRMaxMisorder( 50 ); |
|
80 // The maximum number of packets by which a packet can be delayed |
|
81 // before it is considered dropped. |
|
82 const TInt KDVRMaxDropOut( 3000 ); |
|
83 _LIT( KRtspPortString, "554" ); |
|
84 _LIT8( KCRCName, "N++ " ); |
|
85 // Timeout for RTP/UDP reception before switching to TCP mode |
|
86 const TTimeIntervalMicroSeconds32 KCRRtspRtpUdpTimeout( 10 * 1e6 ); |
|
87 // Timeout for waiting for server response to any RTSP command |
|
88 const TTimeIntervalMicroSeconds32 KCRRtspResponseTimeout( 15 * 1e6 ); |
|
89 // Timeout for waiting for server response to TIERDOWN command |
|
90 const TTimeIntervalMicroSeconds32 KCRRtspTierdownTimeout( 3 * 1e6 ); |
|
91 |
|
92 // ============================ MEMBER FUNCTIONS =============================== |
|
93 |
|
94 // ----------------------------------------------------------------------------- |
|
95 // CCRRtspPacketSource::NewL |
|
96 // Two-phased constructor. |
|
97 // ----------------------------------------------------------------------------- |
|
98 // |
|
99 CCRRtspPacketSource* CCRRtspPacketSource::NewL( |
|
100 const SCRRtspParams& aParams, |
|
101 CCRConnection& aConnection, |
|
102 RSocketServ& aSockServer, |
|
103 MCRStreamObserver& aSessionObs, |
|
104 CCRStreamingSession& aOwningSession ) |
|
105 { |
|
106 CCRRtspPacketSource* self = new( ELeave ) |
|
107 CCRRtspPacketSource( aConnection, aSockServer, aSessionObs, aOwningSession ); |
|
108 CleanupStack::PushL( self ); |
|
109 self->ConstructL( aParams ); |
|
110 CleanupStack::Pop( self ); |
|
111 return self; |
|
112 } |
|
113 |
|
114 // ----------------------------------------------------------------------------- |
|
115 // CCRRtspPacketSource::CCRRtspPacketSource |
|
116 // C++ default constructor can NOT contain any code, that might leave. |
|
117 // ----------------------------------------------------------------------------- |
|
118 // |
|
119 CCRRtspPacketSource::CCRRtspPacketSource( |
|
120 CCRConnection& aConnection, |
|
121 RSocketServ& aSockServer, |
|
122 MCRStreamObserver& aSessionObs, |
|
123 CCRStreamingSession& aOwningSession ) |
|
124 : CCRPacketSourceBase( aOwningSession, CCRStreamingSession::ECRRtspSourceId ), |
|
125 iSockServer( aSockServer ), |
|
126 iConnection( aConnection ), |
|
127 iStage( ERTSPInit ), |
|
128 iCSeq( KCSeqForRtspNegoation ), |
|
129 iClientPort( KCRPortNumberBase ), |
|
130 iSessionId(NULL, 0 ), |
|
131 iReadyToPlay(EFalse), |
|
132 iSessionObs( aSessionObs ), |
|
133 iStartPos( KRealZero ), |
|
134 iEndPos( KRealMinusOne ), |
|
135 iUdpFound( EFalse ), |
|
136 iTrafficFound( EFalse ) |
|
137 { |
|
138 // None |
|
139 } |
|
140 |
|
141 // ----------------------------------------------------------------------------- |
|
142 // CCRRtspPacketSource::ConstructL |
|
143 // Symbian 2nd phase constructor can leave. |
|
144 // ----------------------------------------------------------------------------- |
|
145 // |
|
146 void CCRRtspPacketSource::ConstructL( const SCRRtspParams& aParams ) |
|
147 { |
|
148 LOG( "CCRRtspPacketSource::ConstructL() in" ); |
|
149 if ( aParams.iUrl.Length() == 0 ) |
|
150 { |
|
151 User::Leave ( KErrArgument ); |
|
152 } |
|
153 |
|
154 iSentData = HBufC8::NewL ( KCROptionsReply().Length() + KMaxInfoName ); |
|
155 iRtpTcpStreamer = CCRRtpTcpStreamer::NewL( *this ); |
|
156 iRtspUri = aParams.iUrl.AllocL(); |
|
157 iRtspUri8 = HBufC8::NewL( aParams.iUrl.Length()); |
|
158 iRtspUri8->Des().Copy( aParams.iUrl ); |
|
159 iUserName = aParams.iUserName.AllocL(); |
|
160 iPassword = aParams.iPassword.AllocL(); |
|
161 User::LeaveIfError( iConnection.RegisterObserver( this ) ); |
|
162 iUdpReceptionTimer = CCRTimer::NewL( EPriorityLow, *this ); |
|
163 iProxyServerAddr = aParams.iProxyServerAddr; |
|
164 iProxyServerPort = aParams.iProxyServerPort; |
|
165 DoConnectL(); // Makes no sense to construct without immediately connecting |
|
166 |
|
167 LOG( "CCRRtspPacketSource::ConstructL() out" ); |
|
168 } |
|
169 |
|
170 // ----------------------------------------------------------------------------- |
|
171 // CCRRtspPacketSource::~CCRRtspPacketSource |
|
172 // Destructor. |
|
173 // ----------------------------------------------------------------------------- |
|
174 // |
|
175 CCRRtspPacketSource::~CCRRtspPacketSource() |
|
176 { |
|
177 LOG( "CCRRtspPacketSource::~CCRRtspPacketSource() in" ); |
|
178 // Deletes everything related to session |
|
179 CleanUp(); |
|
180 delete iRtspTimeout; |
|
181 delete iSentData; |
|
182 delete iAuthType; |
|
183 delete iRtspUri8; |
|
184 delete iUserName; |
|
185 delete iPassword; |
|
186 delete iNonce; |
|
187 delete iOpaque; |
|
188 delete iRealm; |
|
189 delete iRtpTcpStreamer; |
|
190 delete iUdpReceptionTimer; |
|
191 iReceiveStreams.Reset(); |
|
192 iObserver = NULL; |
|
193 iConnection.UnregisterObserver( this ); |
|
194 LOG( "CCRRtspPacketSource::~CCRRtspPacketSource() out" ); |
|
195 } |
|
196 |
|
197 // ----------------------------------------------------------------------------- |
|
198 // CCRRtspPacketSource::CleanUp |
|
199 // Callback method called from cleanup-cidle that just calls the actual |
|
200 // cleanup method. |
|
201 // ----------------------------------------------------------------------------- |
|
202 // |
|
203 void CCRRtspPacketSource::CleanUp() |
|
204 { |
|
205 LOG( "CCRRtspPacketSource::CleanUp() in" ); |
|
206 if ( iUdpReceptionTimer ) |
|
207 { |
|
208 iUdpReceptionTimer->Cancel(); |
|
209 } |
|
210 delete iRtspPingTimer; |
|
211 iRtspPingTimer = NULL; |
|
212 |
|
213 iRtpRecvSrcAudio.Close(); |
|
214 iRtpRecvSrcVideo.Close(); |
|
215 iAudioSession.Close(); |
|
216 iVideoSession.Close(); |
|
217 iReadyToPlay = EFalse; |
|
218 delete iSdpParser; iSdpParser = NULL; |
|
219 delete iRtspUri; iRtspUri = NULL; |
|
220 delete iRtspSock; iRtspSock = NULL; |
|
221 |
|
222 for ( TInt i( 0 ); i < ERTPMaxSockets; i++ ) |
|
223 { |
|
224 delete iRTPSockArr[i]; |
|
225 iRTPSockArr[i] = NULL; |
|
226 } |
|
227 for ( TInt i( 0 ); i < ERTSPLastStage; i++ ) |
|
228 { |
|
229 delete iPrevCommands[i]; |
|
230 iPrevCommands[i] = NULL; |
|
231 delete iResponses[i]; |
|
232 iResponses[i] = NULL; |
|
233 } |
|
234 |
|
235 iSessionId.Set( NULL, 0 ); |
|
236 delete iPunchPacketSenderAudio; iPunchPacketSenderAudio = NULL; |
|
237 delete iPunchPacketSenderVideo; iPunchPacketSenderVideo = NULL; |
|
238 delete iUserAgent; iUserAgent = NULL; |
|
239 delete iWapProfile; iWapProfile = NULL; |
|
240 iStartPos = KRealZero; |
|
241 iEndPos = KRealMinusOne; |
|
242 |
|
243 LOG( "CCRRtspPacketSource::CleanUp() out" ); |
|
244 } |
|
245 |
|
246 // ----------------------------------------------------------------------------- |
|
247 // CCRRtspPacketSource::DoConnectL |
|
248 // ----------------------------------------------------------------------------- |
|
249 // |
|
250 void CCRRtspPacketSource::DoConnectL( void ) |
|
251 { |
|
252 if ( !iRtspUri ) |
|
253 { |
|
254 User::Leave( KErrNotReady ); |
|
255 } |
|
256 if ( iRtspSock ) |
|
257 { |
|
258 delete iRtspSock; iRtspSock = NULL; |
|
259 } |
|
260 |
|
261 iRtspSock = CCRSock::NewL( *this, ERTPControl, iConnection.Connection(), |
|
262 iSockServer, ETrue, ETrue ); |
|
263 TUriParser uriParser; |
|
264 User::LeaveIfError( uriParser.Parse( iRtspUri->Des() ) ); |
|
265 iRtspUriHost.Set( uriParser.Extract( EUriHost ) ); |
|
266 TPtrC portString( KRtspPortString ); |
|
267 if ( uriParser.IsPresent( EUriPort ) ) |
|
268 { |
|
269 portString.Set( uriParser.Extract( EUriPort ) ); |
|
270 } |
|
271 |
|
272 TLex portLex( portString ); |
|
273 TInt port( KRtspPortNumber ); |
|
274 if ( portLex.Val( port ) != KErrNone ) |
|
275 { |
|
276 User::Leave( KErrMMInvalidURL ); |
|
277 } |
|
278 if ( iProxyServerAddr.Length() && iProxyServerPort ) |
|
279 { |
|
280 LOG2( "CCRRtspPacketSource::DoConnectL(), Proxy: %S port: %d", |
|
281 &iProxyServerAddr, iProxyServerPort ); |
|
282 User::LeaveIfError( iRtspSock->ConnectSock( iProxyServerAddr, iProxyServerPort ) ); |
|
283 } |
|
284 else |
|
285 { |
|
286 User::LeaveIfError(iRtspSock->ConnectSock( iRtspUriHost, port ) ); |
|
287 } |
|
288 iCSeq = KCSeqForRtspNegoation; |
|
289 |
|
290 TTime now; |
|
291 now.UniversalTime(); |
|
292 iClientPort = |
|
293 KCRPortNumberBase + ( ( now.DateTime().MicroSecond() / 1000 ) * 2 ); |
|
294 |
|
295 // Get transport method from connection heuristics |
|
296 iTransport = ( iConnection.GetHeuristic( |
|
297 CCRConnection::EUdpStreamingBlocked ) )? ERTPOverTCP: ERTPOverUDP; |
|
298 LOG1( "CCRRtspPacketSource::DoConnectL(), RTP transport: %d (0=UDP, 1=TCP)", iTransport ); |
|
299 |
|
300 // Get user agent, bandwidth and wap profile based on connection bearer (3G or not) |
|
301 TConnMonBearerType bearer = iConnection.BearerType(); |
|
302 TBool is3g( iConnection.IsBearerWLANor3G( bearer ) ); |
|
303 |
|
304 // Fetch wap profile from WebUtils repository |
|
305 if ( !iWapProfile ) |
|
306 { |
|
307 CRepository* repository = CRepository::NewLC( KCRUidWebUtils ); |
|
308 TUint32 profilekey = ( is3g )? KWebUtilsUaProf3G: KWebUtilsUaProf; |
|
309 TFileName profilebuf( KNullDesC ); |
|
310 if ( !repository->Get( profilekey, profilebuf ) ) |
|
311 { |
|
312 iWapProfile = HBufC8::NewL( profilebuf.Length() ); |
|
313 iWapProfile->Des().Copy( profilebuf ); |
|
314 } |
|
315 |
|
316 CleanupStack::PopAndDestroy( repository ); |
|
317 LOG1( "CCRRtspPacketSource::DoConnectL(), iWapProfile: %S", &profilebuf ); |
|
318 } |
|
319 |
|
320 // Fetch user agent |
|
321 // Should we add version information to user agent string? |
|
322 delete iUserAgent; iUserAgent = NULL; |
|
323 iUserAgent = KCRRTSPDefaultUserAgent().AllocL(); |
|
324 |
|
325 // Get bandwidth from connection |
|
326 iBandwidth = iConnection.MaximumBandwidth(); |
|
327 |
|
328 LOG( "CCRRtspPacketSource::DoConnectL out" ); |
|
329 } |
|
330 |
|
331 // ----------------------------------------------------------------------------- |
|
332 // CCRRtspPacketSource::URI |
|
333 // ----------------------------------------------------------------------------- |
|
334 // |
|
335 TPtr CCRRtspPacketSource::URI(void) |
|
336 { |
|
337 __ASSERT_DEBUG( iRtspUri != NULL , User::Panic( _L( "RTSP source" ), KErrBadHandle ) ); |
|
338 TPtr retval ( NULL , 0 ); |
|
339 if ( iRtspUri ) |
|
340 { |
|
341 retval.Set( iRtspUri->Des() ); |
|
342 } |
|
343 else |
|
344 { |
|
345 LOG( "CCRRtspPacketSource::URI iRtspUri was NULL !!!!!!!!!! " ); |
|
346 } |
|
347 return retval; |
|
348 } |
|
349 |
|
350 // ----------------------------------------------------------------------------- |
|
351 // CCRRtspPacketSource::GetSdp |
|
352 // ----------------------------------------------------------------------------- |
|
353 // |
|
354 TInt CCRRtspPacketSource::GetSdp( TPtrC8& aSdp ) |
|
355 { |
|
356 TInt retval( KErrNotReady ); |
|
357 if ( iSdpParser ) |
|
358 { |
|
359 return iSdpParser->GetSdp( aSdp ); |
|
360 } |
|
361 |
|
362 return retval; |
|
363 } |
|
364 |
|
365 // ----------------------------------------------------------------------------- |
|
366 // CCRRtspPacketSource::SeqAndTS |
|
367 // ----------------------------------------------------------------------------- |
|
368 // |
|
369 TInt CCRRtspPacketSource::SeqAndTS( |
|
370 TUint& aAudioSeq, |
|
371 TUint& aAudioTS, |
|
372 TUint& aVideoSeq, |
|
373 TUint& aVideoTS ) |
|
374 { |
|
375 TInt retval( KErrNotReady ); |
|
376 if ( iSeqFromRtpInfoForVideo != 0 || iSeqFromRtpInfoForAudio != 0 ) |
|
377 { |
|
378 aAudioSeq = iSeqFromRtpInfoForAudio; |
|
379 aAudioTS = iRTPTimeStampAudio; |
|
380 aVideoSeq = iSeqFromRtpInfoForVideo; |
|
381 aVideoTS = iRTPTimeStampVideo; |
|
382 retval = KErrNone; |
|
383 } |
|
384 |
|
385 return retval; |
|
386 } |
|
387 |
|
388 // ----------------------------------------------------------------------------- |
|
389 // CCRRtspPacketSource::PostActionL |
|
390 // ----------------------------------------------------------------------------- |
|
391 // |
|
392 void CCRRtspPacketSource::PostActionL() |
|
393 { |
|
394 LOG1( "CCRRtspPacketSource::PostActionL(), SDP will be handled, iSdpParser: %d", |
|
395 iSdpParser ); |
|
396 User::LeaveIfNull( iSdpParser ); |
|
397 iSessionObs.StatusChanged( MCRPacketSource::ERtpStateSdpAvailable ); |
|
398 } |
|
399 |
|
400 // ----------------------------------------------------------------------------- |
|
401 // CCRRtspPacketSource::Play |
|
402 // ----------------------------------------------------------------------------- |
|
403 // |
|
404 TInt CCRRtspPacketSource::Play( const TReal& aStartPos, const TReal& aEndPos ) |
|
405 { |
|
406 LOG2( "CCRRtspPacketSource::Play(), aStartPos: %f, aEndPos: %f", |
|
407 aStartPos, aEndPos ); |
|
408 LOG2( "CCRRtspPacketSource::Play(), sent seq: %d, rec: %d", |
|
409 iCSeq, iLastReceivedSeq ); |
|
410 iReadyToPlay = ETrue; |
|
411 iStartPos = aStartPos; |
|
412 iEndPos = aEndPos; |
|
413 ResetStreamFlags(); |
|
414 |
|
415 // In xps case we never get startpos with this method. |
|
416 // instead setposition will be called |
|
417 if ( iBuffer ) |
|
418 { |
|
419 iBuffer->ResetBuffer(); |
|
420 } |
|
421 |
|
422 // If both audio and video sessions are closed, we |
|
423 // need to open at least one of them: |
|
424 TInt err( KErrNone ); |
|
425 if ( iStage == ERTSPReadyToPlay || iStage == ERTSPPauseSent ) |
|
426 { |
|
427 if ( iStage == ERTSPReadyToPlay || iCSeq == ( iLastReceivedSeq + 1 ) ) |
|
428 { |
|
429 TRAP( err, SendPlayCommandL() ); |
|
430 } |
|
431 else |
|
432 { |
|
433 // We have a fast-fingered user in charge; play has been issued |
|
434 // but the previous pause has not been completed yet: postpone this |
|
435 // operation |
|
436 iPostPonedPlay = ETrue; |
|
437 } |
|
438 } |
|
439 |
|
440 return err; |
|
441 } |
|
442 |
|
443 // ----------------------------------------------------------------------------- |
|
444 // CCRRtspPacketSource::Pause |
|
445 // ----------------------------------------------------------------------------- |
|
446 // |
|
447 TInt CCRRtspPacketSource::Pause() |
|
448 { |
|
449 LOG1( "CCRRTSPPacketSource::Pause() stage %d", iStage ); |
|
450 TInt err( KErrNotReady ); |
|
451 if ( iStage == ERTSPPlaying ) |
|
452 { |
|
453 if ( iResponses[ERTSPPlaySent]->IsLiveStream() || iSdpParser->IsLiveStream() ) |
|
454 { |
|
455 err = KErrNotSupported; |
|
456 } |
|
457 else |
|
458 { |
|
459 TRAP( err, SendPauseCommandL() ); |
|
460 } |
|
461 } |
|
462 if ( iStage == ERTSPPauseSent ) |
|
463 { |
|
464 err = KErrNone; |
|
465 } |
|
466 return err; |
|
467 } |
|
468 |
|
469 // ----------------------------------------------------------------------------- |
|
470 // CCRRtspPacketSource::Stop |
|
471 // ----------------------------------------------------------------------------- |
|
472 // |
|
473 TInt CCRRtspPacketSource::Stop() |
|
474 { |
|
475 LOG( "CCRRtspPacketSource::Stop()" ); |
|
476 |
|
477 iReadyToPlay = EFalse; |
|
478 iPostPonedPlay = EFalse; |
|
479 iStartPos = KRealZero; |
|
480 TInt err( KErrDisconnected ); |
|
481 |
|
482 if ( iStage == ERTSPPlaySent || iStage == ERTSPPlaying || |
|
483 iStage == ERTSPPauseSent || iStage == ERTSPSetupAudioSent || |
|
484 iStage == ERTSPSetupVideoSent ) |
|
485 { |
|
486 err = KErrNone; |
|
487 if ( iRtspSock ) |
|
488 { |
|
489 iRtspSock->Cancel(); |
|
490 } |
|
491 |
|
492 TRAP_IGNORE( SendTearDownCommandL() ); // if this fails, we don't care |
|
493 iStage = ERTSPTearDownSent; |
|
494 StartRtspTimeout( KCRRtspTierdownTimeout ); |
|
495 } |
|
496 |
|
497 return err; |
|
498 } |
|
499 |
|
500 // ----------------------------------------------------------------------------- |
|
501 // CCRRtspPacketSource::SetPosition |
|
502 // ----------------------------------------------------------------------------- |
|
503 |
|
504 TInt CCRRtspPacketSource::SetPosition( const TInt64 aPosition ) |
|
505 { |
|
506 LOG1( "CCRRtspPacketSource::SetPosition(), iStartPos: %f", iStartPos ); |
|
507 |
|
508 if ( aPosition == -2 ) |
|
509 { |
|
510 if ( iStage != ERTSPPlaySent && iObserver ) |
|
511 { |
|
512 iObserver->ConnectionStatusChange( |
|
513 iOwningSession.SourceChecksum(), |
|
514 ECRReadyToSeek, KErrNone ); |
|
515 } |
|
516 } |
|
517 return KErrNone; |
|
518 } |
|
519 |
|
520 // ----------------------------------------------------------------------------- |
|
521 // CCRRtspPacketSource::GetRange |
|
522 // ----------------------------------------------------------------------------- |
|
523 void CCRRtspPacketSource::GetRange( TReal& aLower, TReal& aUpper ) |
|
524 { |
|
525 aLower = KRealZero; |
|
526 aUpper = KRealMinusOne; |
|
527 |
|
528 if ( ( iStage == ERTSPPlaySent || iStage == ERTSPPlaying ) && |
|
529 iResponses[ERTSPPlaySent] ) |
|
530 { |
|
531 iResponses[ERTSPPlaySent]->GetRange(aLower,aUpper); |
|
532 } |
|
533 } |
|
534 |
|
535 // ----------------------------------------------------------------------------- |
|
536 // CCRRtspPacketSource::DataReceived |
|
537 // This is called when data is received from socket. |
|
538 // ----------------------------------------------------------------------------- |
|
539 // |
|
540 void CCRRtspPacketSource::DataReceived( TInt /*aSockId*/, const TDesC8& aData ) |
|
541 { |
|
542 // Find out RTCP message or RTP packet from IP packet |
|
543 iRtpTcpStreamer->DataAvailable( aData, ( iTransport == ERTPOverTCP ) ); |
|
544 } |
|
545 |
|
546 // ----------------------------------------------------------------------------- |
|
547 // CCRRtspPacketSource::RtspMsgAvailable |
|
548 // This is called when data is received from socket. |
|
549 // ----------------------------------------------------------------------------- |
|
550 // |
|
551 void CCRRtspPacketSource::RtspMsgAvailable( const TDesC8& aData ) |
|
552 { |
|
553 #if defined ( LIVE_TV_FILE_TRACE ) || defined ( LIVE_TV_RDEBUG_TRACE ) |
|
554 if ( aData.Length() > 0 ) |
|
555 { |
|
556 LOG1( "CCRRtspPacketSource::RtspMsgAvailable(), aData len: %d", aData.Length() ); |
|
557 TName d( KNullDesC ); |
|
558 for( TInt i( 0 ); i < aData.Length(); i++ ) |
|
559 { |
|
560 TChar c = aData[i]; |
|
561 d.Append( c ); |
|
562 if ( ( i > 0 ) && ( i % 80 ) == 0 ) |
|
563 { |
|
564 LOG1( ">%S<", &d ); |
|
565 d.Zero(); |
|
566 } |
|
567 } |
|
568 |
|
569 LOG1( ">%S<", &d ); |
|
570 } |
|
571 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
572 |
|
573 TRAPD( err, ProcessRtspResponseL( aData ) ); |
|
574 if ( err ) |
|
575 { |
|
576 LOG1( "CCRRtspPacketSource::RtspMsgAvailable(), ProcessRtspResponseL Leaved, err: %d", err ); |
|
577 if ( err == KErrNotSupported ) |
|
578 { |
|
579 // The response did not look like rtsp response at all. |
|
580 // some servers decide to send rtsp commands to us so lets |
|
581 // try interpreting it as a command |
|
582 err = KErrNone; |
|
583 TRAP( err, ProcessRTSPCommandL( aData ) ) |
|
584 if ( err ) |
|
585 { |
|
586 iOwningSession.SourceStop(); |
|
587 } |
|
588 } |
|
589 else |
|
590 { |
|
591 iOwningSession.SourceStop(); |
|
592 } |
|
593 } |
|
594 } |
|
595 |
|
596 // ----------------------------------------------------------------------------- |
|
597 // CCRRtspPacketSource::SockStatusChange |
|
598 // This is called when socket status changes. |
|
599 // ----------------------------------------------------------------------------- |
|
600 // |
|
601 void CCRRtspPacketSource::SockStatusChange( |
|
602 TInt aSockId, |
|
603 CCRSock::TCRSockStatus aStatus, |
|
604 TInt aError ) |
|
605 { |
|
606 #if defined ( LIVE_TV_FILE_TRACE ) || defined ( LIVE_TV_RDEBUG_TRACE ) |
|
607 if ( aStatus == CCRSock::EFailed ) |
|
608 { |
|
609 LOG3( "CCRRtspPacketSource::SockStatusChange(), aSockId: %d, aStatus: %d, aError: %d", |
|
610 aSockId, aStatus, aError ); |
|
611 } |
|
612 #else // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
613 ( void )aSockId; |
|
614 ( void )aError; |
|
615 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
616 |
|
617 if ( aStatus == CCRSock::EFailed ) |
|
618 { |
|
619 // Ask session to perform cleanup |
|
620 iOwningSession.SourceStop(); |
|
621 |
|
622 if ( iStage == ERTSPInit && aSockId == ERTPControl && aError == KErrCouldNotConnect ) |
|
623 { |
|
624 // map error to different error id, so we can know that showing reconnect query is pointless. |
|
625 aError = KErrEof; |
|
626 } |
|
627 |
|
628 // Inform the observer that there is a problem. Exclude case where we're closing |
|
629 // and the error is KErrEof |
|
630 if ( ! ( iStage == ERTSPTearDownSent && aError == KErrEof ) ) |
|
631 { |
|
632 if ( iObserver ) |
|
633 { |
|
634 iObserver->ConnectionStatusChange( |
|
635 iOwningSession.SourceChecksum(), ECRConnectionError, aError ); |
|
636 } |
|
637 } |
|
638 else |
|
639 { |
|
640 LOG( "CCRRtspPacketSource::SockStatusChange(), eof in closing: normal" ); |
|
641 } |
|
642 } |
|
643 else if ( aSockId == ERTPControl && aStatus == CCRSock::EIdle && |
|
644 iStage == ERTSPInit ) |
|
645 { |
|
646 // Called once from here for lifetime of this object |
|
647 TRAPD( err, SendRtspCommandL() ); |
|
648 if ( err ) |
|
649 { |
|
650 LOG1( "CCRRtspPacketSource::SockStatusChange(), SendRtspCommandL Leaved: %d", err ); |
|
651 |
|
652 // Ask session to perform cleanup |
|
653 iOwningSession.SourceStop(); |
|
654 } |
|
655 } |
|
656 } |
|
657 |
|
658 // ----------------------------------------------------------------------------- |
|
659 // CCRRtspPacketSource::RtpTcpPacketAvailable |
|
660 // ----------------------------------------------------------------------------- |
|
661 // |
|
662 void CCRRtspPacketSource::RtpTcpPacketAvailable( |
|
663 TInt aChannel, |
|
664 const TDesC8& aPacket ) |
|
665 { |
|
666 // Map embedded TCP channel to streamid: |
|
667 // video: channel=(0,1) --> id=(2,3) |
|
668 // audio: channel=(2,3) --> id=(0,1) when video present |
|
669 // audio: channel=(0,1) --> id=(0,1) when audio only |
|
670 TInt mappedChannel( ( iSdpParser->VideoControlAddr().Length() )? |
|
671 ( aChannel + 2 ) % 4: aChannel ); |
|
672 MCRPacketSource::TCRPacketStreamId streamid( |
|
673 ( MCRPacketSource::TCRPacketStreamId )( mappedChannel ) ); |
|
674 |
|
675 iBuffer->AddPacket( streamid, aPacket ); |
|
676 } |
|
677 |
|
678 // ----------------------------------------------------------------------------- |
|
679 // CCRRtspPacketSource::ForwardRtpTcpChunk |
|
680 // ----------------------------------------------------------------------------- |
|
681 // |
|
682 void CCRRtspPacketSource::ForwardRtpTcpChunck( const TDesC8& aChunk ) |
|
683 { |
|
684 if ( iRtspSock ) |
|
685 { |
|
686 iRtspSock->SendData( aChunk ); |
|
687 } |
|
688 } |
|
689 |
|
690 // ----------------------------------------------------------------------------- |
|
691 // CCRRtspPacketSource::TimerExpired |
|
692 // ----------------------------------------------------------------------------- |
|
693 // |
|
694 void CCRRtspPacketSource::TimerExpired( CCRTimer* ) |
|
695 { |
|
696 LOG( "CCRRtspPacketSource::TimerExpired: RTP/UDP timer expired, switching to RTP/TCP" ); |
|
697 |
|
698 if ( !iUdpFound ) |
|
699 { |
|
700 // Signal heuristic for TCP streaming |
|
701 LOG( "CCRRtspPacketSource::TimerExpired - Switch to TCP" ); |
|
702 iConnection.SetHeuristic( CCRConnection::EUdpStreamingBlocked, ETrue ); |
|
703 } |
|
704 else |
|
705 { |
|
706 // We had UDP before in this session but now it is lost for some reason. |
|
707 // Try UDP again. |
|
708 |
|
709 // Flag UDP found away |
|
710 iUdpFound = EFalse; |
|
711 iTrafficFound = EFalse; |
|
712 |
|
713 // Clear stream followup |
|
714 iReceiveStreams.Reset(); |
|
715 |
|
716 LOG( "CCRRtspPacketSource::TimerExpired - Trying UDP again" ); |
|
717 } |
|
718 |
|
719 // Notify client to close us and start a new session |
|
720 if ( iObserver ) |
|
721 { |
|
722 // Notify client |
|
723 iObserver->ConnectionStatusChange( |
|
724 iOwningSession.SourceChecksum(), ECRSwitchingToTcp, KErrNone ); |
|
725 } |
|
726 else |
|
727 { |
|
728 // If no client observer, teardown and cleanup ourselves |
|
729 iPostPonedPlay = EFalse; |
|
730 TRAPD( err, SendTearDownCommandL() ); |
|
731 if ( err != KErrNone ) |
|
732 { |
|
733 LOG1( "CCRRtspPacketSource::TimerExpired() Send TEARDOWN failed: %d", err ); |
|
734 } |
|
735 |
|
736 CleanUp(); |
|
737 iSessionObs.StatusChanged( MCRPacketSource::ERtpStateClosing ); |
|
738 } |
|
739 } |
|
740 |
|
741 // ----------------------------------------------------------------------------- |
|
742 // CCRRtspPacketSource::ProcessRTSPCommandL |
|
743 // ----------------------------------------------------------------------------- |
|
744 // |
|
745 void CCRRtspPacketSource::ProcessRTSPCommandL( const TDesC8& aData ) |
|
746 { |
|
747 LOG1( "CCRRtspPacketSource::ProcessRTSPCommandL(), iStage: %d", ( int )iStage ); |
|
748 |
|
749 CCRRtspCommand* cmd = CCRRtspCommand::NewL(); |
|
750 CleanupStack::PushL( cmd ); |
|
751 cmd->TryParseL( aData ); |
|
752 |
|
753 switch ( cmd->Command() ) |
|
754 { |
|
755 case CCRRtspCommand::ERTSPCommandOPTIONS: |
|
756 iSentData->Des().Format( KCROptionsReply, cmd->CSeq() ); |
|
757 iRtspSock->SendData( iSentData->Des() ); |
|
758 break; |
|
759 |
|
760 default: |
|
761 // Server sent us a command and it is not options. |
|
762 // for sure they want us to stop ; is there |
|
763 iOwningSession.SourceStop(); |
|
764 break; |
|
765 } |
|
766 |
|
767 CleanupStack::PopAndDestroy( cmd ); |
|
768 } |
|
769 |
|
770 // ----------------------------------------------------------------------------- |
|
771 // CCRRtspPacketSource::ProcessRtspResponseL |
|
772 // ----------------------------------------------------------------------------- |
|
773 // |
|
774 void CCRRtspPacketSource::ProcessRtspResponseL( const TDesC8& aData ) |
|
775 { |
|
776 LOG1( "CCRRtspPacketSource::ProcessRtspResponseL(), iStage: %d", iStage ); |
|
777 |
|
778 // Cancel timeout timer |
|
779 if ( iRtspTimeout ) |
|
780 { |
|
781 iRtspTimeout->Cancel(); |
|
782 } |
|
783 |
|
784 // The server responded to our TEARDOWN command. No need to parse the response |
|
785 // since we don't care what the server said. Ask session to clean us up. |
|
786 if ( iStage == ERTSPTearDownSent ) |
|
787 { |
|
788 iOwningSession.SourceStop(); |
|
789 return; |
|
790 } |
|
791 |
|
792 // First parse response |
|
793 CCRRtspResponse* resp = CCRRtspResponse::NewL(); |
|
794 CleanupStack::PushL( resp ); |
|
795 resp->TryParseL( aData ); |
|
796 |
|
797 // Then find the command that this resp is associated with: |
|
798 iLastReceivedSeq = resp->CSeq(); |
|
799 TBool commandFound( EFalse ); |
|
800 for ( TInt i( 0 ); i < ERTSPLastStage && !commandFound; i++ ) |
|
801 { |
|
802 LOG2( "CCRRtspPacketSource:: prevcommand stage: %d cseq: %d", |
|
803 i, ( iPrevCommands[i] )? iPrevCommands[i]->CSeq(): KErrNotFound ); |
|
804 |
|
805 if ( iPrevCommands[i] && ( iPrevCommands[i]->CSeq() == resp->CSeq() ) ) |
|
806 { |
|
807 LOG1( "CCRRtspPacketSource::ProcessRtspResponseL(), matching command: %d", i ); |
|
808 LOG1( "CCRRtspPacketSource::ProcessRtspResponseL(), cseq was: %d", resp->CSeq() ); |
|
809 delete iResponses[i]; |
|
810 CleanupStack::Pop( resp ); |
|
811 iResponses[i] = resp; |
|
812 commandFound = ETrue; |
|
813 if ( i == ERTSPOptSent ) |
|
814 { |
|
815 // Process options no further, used only for ping here |
|
816 return; |
|
817 } |
|
818 } |
|
819 } |
|
820 |
|
821 // Delete response if sequency not match |
|
822 if ( !commandFound ) |
|
823 { |
|
824 CleanupStack::PopAndDestroy( resp ); |
|
825 LOG1( "CCRRtspPacketSource::ProcessRtspResponseL(), Command not found, cseq: %d", resp->CSeq() ); |
|
826 } |
|
827 else |
|
828 { |
|
829 if ( iResponses[iStage]->StatusCode() == CCRRtspResponse::ERTSPRespOK || // 200 |
|
830 iResponses[iStage]->StatusCode() == CCRRtspResponse::ERTSPRespCreated ) // 201 |
|
831 { |
|
832 // Extract useful information from response depending on stage: |
|
833 switch ( iStage ) |
|
834 { |
|
835 case ERTSPSetupAudioSent: // From setups take session id |
|
836 case ERTSPSetupVideoSent: |
|
837 if ( !iSessionId.Ptr() ) |
|
838 { |
|
839 iResponses[iStage]->SessionId( iSessionId ); |
|
840 } |
|
841 // Check for sdp parser and send punch packets for UDP transport |
|
842 // (TCP or multicast: session setup and PLAY in SendRTSPCommand) |
|
843 if ( iSdpParser && iTransport == ERTPOverUDP ) |
|
844 { |
|
845 // If we see that we don't need to send further setups, |
|
846 // do send punch packets now. |
|
847 if ( ( iSdpParser->VideoControlAddr().Length() && // if we have video |
|
848 iResponses[ERTSPSetupVideoSent] && // and we have video se tup |
|
849 iSdpParser->AudioControlAddr().Length() && // and we have audio |
|
850 iResponses[ERTSPSetupAudioSent] ) || // and we have audio set up or... |
|
851 ( !iSdpParser->VideoControlAddr().Length() && // if we have no video |
|
852 !iResponses[ERTSPSetupVideoSent] && // and we've video not set up |
|
853 iSdpParser->AudioControlAddr().Length() && // and it shows we have audio |
|
854 iResponses[ERTSPSetupAudioSent] ) || // and we've audio set up or... |
|
855 ( iSdpParser->VideoControlAddr().Length() && // if we have video |
|
856 iResponses[ERTSPSetupVideoSent] && // and we have video set up |
|
857 !iSdpParser->AudioControlAddr().Length() && // and we have no audio |
|
858 !iResponses[ERTSPSetupAudioSent] ) ) // and we have no audio set up |
|
859 { |
|
860 SendPunchPacketsL(); |
|
861 } |
|
862 } |
|
863 |
|
864 // Notify sink that SETUP repply received |
|
865 iSessionObs.StatusChanged( |
|
866 MCRPacketSource::ERtpStateSetupRepply ); |
|
867 break; |
|
868 |
|
869 case ERTSPDescSent: // From desc take sdp |
|
870 if ( iObserver && iResponses[iStage]->ContentLen() <= 0 ) |
|
871 { |
|
872 // This should not happen |
|
873 if ( iObserver ) |
|
874 { |
|
875 iObserver->ConnectionStatusChange( |
|
876 iOwningSession.SourceChecksum(), ECRConnectionError, KErrUnderflow ); |
|
877 } |
|
878 iOwningSession.SourceStop(); |
|
879 } |
|
880 else |
|
881 { |
|
882 delete iSdpParser; iSdpParser = NULL; |
|
883 iSdpParser = CDvrSdpParser::NewL(); |
|
884 if ( iResponses[iStage]->ContentBase().Length() ) |
|
885 { |
|
886 iSdpParser->TryParseL( iResponses[iStage]->Content(), |
|
887 iResponses[iStage]->ContentBase() ); |
|
888 } |
|
889 else |
|
890 { |
|
891 iSdpParser->TryParseL( iResponses[iStage]->Content(), |
|
892 iRtspUri8->Des() ); |
|
893 } |
|
894 // Check for multicast address in SDP |
|
895 if ( iSdpParser->IsMultiCastSdp() ) |
|
896 { |
|
897 iTransport = ERTPOverMulticast; |
|
898 } |
|
899 if ( iObserver && iSdpParser->IsRealMediaContent() ) |
|
900 { |
|
901 iObserver->ConnectionStatusChange( |
|
902 iOwningSession.SourceChecksum(), |
|
903 ECRStreamIsRealMedia, KErrNotSupported ); |
|
904 iOwningSession.SourceStop(); |
|
905 return; // Make sure we don't continue with SETUP commands |
|
906 } |
|
907 else // do not send realmedia sdp to sinks |
|
908 { |
|
909 if ( iObserver && iSdpParser->IsLiveStream() ) |
|
910 { |
|
911 iObserver->ConnectionStatusChange( |
|
912 iOwningSession.SourceChecksum(), |
|
913 ECRStreamIsLiveStream, KErrNone ); |
|
914 } |
|
915 |
|
916 // then check for bandwidth requirements even before we start: |
|
917 if ( iObserver ) |
|
918 { |
|
919 // Unknown bitrate or bandwidth are returned as zero. |
|
920 // Bitrates in kbit/s |
|
921 TInt bitrate( iSdpParser->VideoBitrate() + |
|
922 iSdpParser->AudioBitrate() ); |
|
923 TInt bandwidth( iConnection.MaximumBandwidth() / 1000 ); |
|
924 if ( bitrate && bandwidth && bandwidth < bitrate ) |
|
925 { |
|
926 LOG2( "CCRRtspPacketSource::ProcessRtspResponseL(), bitrate:%d, bandwidth: %d -> NotEnoughBandwidth", |
|
927 bitrate, bandwidth); |
|
928 iObserver->ConnectionStatusChange( |
|
929 iOwningSession.SourceChecksum(), |
|
930 ECRNotEnoughBandwidth, KErrNone ); |
|
931 return; // Make sure we don't tell sinks anything about |
|
932 // sdp that has too high bitrate for our network bearer |
|
933 } |
|
934 } |
|
935 |
|
936 // But if we didn't have realmedia stream and the bandwidth check |
|
937 // is also all right, then go on and tell the sinks -> |
|
938 iSessionObs.StatusChanged( |
|
939 MCRPacketSource::ERtpStateSdpAvailable ); |
|
940 } |
|
941 } |
|
942 break; |
|
943 |
|
944 case ERTSPPlaySent: |
|
945 { |
|
946 CCRRtspResponse::SRTPInfoHeader rtpInfo; |
|
947 iResponses[ERTSPPlaySent]->RTPInfoHeader( rtpInfo ); |
|
948 |
|
949 TPtrC8 videoAddr ( NULL, 0 ); |
|
950 if ( iSdpParser->VideoControlAddr().Length() ) |
|
951 { |
|
952 videoAddr.Set ( iSdpParser->VideoControlAddr() ); |
|
953 } |
|
954 TPtrC8 audioAddr ( NULL , 0 ); |
|
955 if ( iSdpParser->AudioControlAddr().Length() ) |
|
956 { |
|
957 audioAddr.Set ( iSdpParser->AudioControlAddr() ); |
|
958 } |
|
959 |
|
960 if ( iSdpParser->VideoControlAddr().Length() && |
|
961 rtpInfo.iFirstURL.Length() && |
|
962 videoAddr.Find( rtpInfo.iFirstURL ) >= 0 ) |
|
963 { |
|
964 iRTPTimeStampVideo = rtpInfo.iFirstTS ? rtpInfo.iFirstTS : 1; |
|
965 iSeqFromRtpInfoForVideo = rtpInfo.iFirstSeq; |
|
966 } |
|
967 if ( iSdpParser->VideoControlAddr().Length() && |
|
968 rtpInfo.iSecondURL.Length() && |
|
969 videoAddr.Find( rtpInfo.iSecondURL ) >= 0 ) |
|
970 { |
|
971 iRTPTimeStampVideo = rtpInfo.iSecondTS ? rtpInfo.iSecondTS : 1; |
|
972 iSeqFromRtpInfoForVideo = rtpInfo.iSecondSeq; |
|
973 } |
|
974 if ( iSdpParser->AudioControlAddr().Length() && |
|
975 rtpInfo.iFirstURL.Length() && |
|
976 audioAddr.Find( rtpInfo.iFirstURL) >= 0 ) |
|
977 { |
|
978 iRTPTimeStampAudio = rtpInfo.iFirstTS ? rtpInfo.iFirstTS : 1; |
|
979 iSeqFromRtpInfoForAudio = rtpInfo.iFirstSeq; |
|
980 } |
|
981 if ( iSdpParser->AudioControlAddr().Length() && |
|
982 rtpInfo.iSecondURL.Length() && |
|
983 audioAddr.Find( rtpInfo.iSecondURL) >= 0 ) |
|
984 { |
|
985 iRTPTimeStampAudio = rtpInfo.iSecondTS ? rtpInfo.iSecondTS : 1; |
|
986 iSeqFromRtpInfoForAudio = rtpInfo.iSecondSeq; |
|
987 } |
|
988 |
|
989 // ok, if we don't have rtp-info header, we don't know yet. |
|
990 if ( rtpInfo.iFirstURL.Length() == 0 && |
|
991 rtpInfo.iSecondURL.Length() == 0 ) |
|
992 { |
|
993 iNoRtpInfoHeader++; |
|
994 } |
|
995 else |
|
996 { |
|
997 // We have RTP-info, so control stream is no longer mandatory |
|
998 // Mark control streams as "found" |
|
999 StreamFound( EAudioControlStream ); |
|
1000 StreamFound( EVideoControlStream ); |
|
1001 //StreamFound( ESubTitleControlStream ); |
|
1002 |
|
1003 iSessionObs.StatusChanged( |
|
1004 MCRPacketSource::ERtpStateSeqAndTSAvailable ); |
|
1005 } |
|
1006 |
|
1007 // Live state |
|
1008 if ( iResponses[ERTSPPlaySent]->IsLiveStream() || iSdpParser->IsLiveStream() ) |
|
1009 { |
|
1010 if ( iObserver ) |
|
1011 { |
|
1012 iObserver->ConnectionStatusChange( |
|
1013 iOwningSession.SourceChecksum(), |
|
1014 ECRStreamIsLiveStream, KErrNone ); |
|
1015 } |
|
1016 } |
|
1017 |
|
1018 // Notify seeking |
|
1019 if ( iObserver ) |
|
1020 { |
|
1021 iObserver->ConnectionStatusChange( |
|
1022 iOwningSession.SourceChecksum(), |
|
1023 ECRReadyToSeek, KErrNone ); |
|
1024 } |
|
1025 } |
|
1026 break; |
|
1027 |
|
1028 default: |
|
1029 // by default extract no information |
|
1030 break; |
|
1031 } |
|
1032 |
|
1033 // Then continue with business: |
|
1034 SendRtspCommandL(); // will change iStage also |
|
1035 } |
|
1036 |
|
1037 // Authentication needed.. |
|
1038 else if ( iResponses[iStage]->StatusCode() == |
|
1039 CCRRtspResponse::ERTSPRespUnauthorized || // 401 |
|
1040 iResponses[iStage]->StatusCode() == |
|
1041 CCRRtspResponse::ERTSPRespProxyAuthenticationRequired ) // 407 |
|
1042 { |
|
1043 iAuthFailedCount++; |
|
1044 if ( iUserName && |
|
1045 iUserName->Length() && |
|
1046 iPassword && |
|
1047 iAuthFailedCount == 1 ) |
|
1048 { |
|
1049 iAuthenticationNeeded = ETrue; |
|
1050 iAuthType = iResponses[iStage]->AuthenticationTypeL().AllocL(); |
|
1051 iRealm = iResponses[iStage]->RealmL().AllocL(); |
|
1052 iOpaque = iResponses[iStage]->OpaqueL().AllocL(); |
|
1053 iNonce = iResponses[iStage]->NonceL().AllocL(); |
|
1054 SendAuthDescribeL(); |
|
1055 } |
|
1056 else |
|
1057 { |
|
1058 iAuthFailedCount = 0; |
|
1059 LOG( "CCRRtspPacketSource::ProcessRtspResponseL() Authentication failure !" ); |
|
1060 |
|
1061 // Cleanup |
|
1062 iOwningSession.SourceStop(); |
|
1063 if ( iObserver ) |
|
1064 { |
|
1065 iObserver->ConnectionStatusChange( |
|
1066 iOwningSession.SourceChecksum(), |
|
1067 ECRAuthenticationNeeded, KErrNone ); |
|
1068 } |
|
1069 } |
|
1070 } |
|
1071 else if ( iResponses[iStage]->StatusCode() == CCRRtspResponse::ERTSPRespUnsupportedTransport ) // 461 |
|
1072 { |
|
1073 LOG1( "CCRRtspPacketSource::ProcessRtspResponseL() - Unsupported Transport: %d", iTransport ); |
|
1074 |
|
1075 if ( iConnection.GetHeuristic( CCRConnection::EUdpStreamingBlocked ) ) |
|
1076 { |
|
1077 // Using TCP, change to UDP |
|
1078 LOG( "CCRRtspPacketSource::ProcessRtspResponseL() - Change TCP to UDP" ); |
|
1079 iConnection.SetHeuristic( CCRConnection::EUdpStreamingBlocked, EFalse ); |
|
1080 // Notify observer at client side: |
|
1081 ProcessRtspErrorResponseL( iResponses[iStage]->StatusCode() ); |
|
1082 } |
|
1083 else |
|
1084 { |
|
1085 // Using UDP, change to TCP |
|
1086 LOG( "CCRRtspPacketSource::ProcessRtspResponseL() - Change UDP to TCP"); |
|
1087 iConnection.SetHeuristic( CCRConnection::EUdpStreamingBlocked, ETrue ); |
|
1088 // Notify observer at client side: |
|
1089 ProcessRtspErrorResponseL( iResponses[iStage]->StatusCode() ); |
|
1090 } |
|
1091 } |
|
1092 else |
|
1093 { |
|
1094 // before doing cleanup, notify observer at client side: |
|
1095 ProcessRtspErrorResponseL( iResponses[iStage]->StatusCode() ); |
|
1096 } |
|
1097 } |
|
1098 } |
|
1099 |
|
1100 // ----------------------------------------------------------------------------- |
|
1101 // CCRRtspPacketSource::ProcessRtspErrorResponseL |
|
1102 // ----------------------------------------------------------------------------- |
|
1103 // |
|
1104 void CCRRtspPacketSource::ProcessRtspErrorResponseL( |
|
1105 CCRRtspResponse::TResponseCode aErrorCode ) |
|
1106 { |
|
1107 SCRQueueEntry entry; |
|
1108 entry.iMsg = ECRMsgQueueConnectionError; |
|
1109 |
|
1110 switch ( aErrorCode ) |
|
1111 { |
|
1112 case CCRRtspResponse::ERTSPRespLowOnStorageSpace: |
|
1113 entry.iErr = KErrGeneral; |
|
1114 break; |
|
1115 |
|
1116 case CCRRtspResponse::ERTSPRespMultipleChoices: |
|
1117 entry.iErr = KErrGeneral; |
|
1118 break; |
|
1119 |
|
1120 case CCRRtspResponse::ERTSPRespMovedPermanently: |
|
1121 entry.iErr = KErrNotFound; |
|
1122 break; |
|
1123 |
|
1124 case CCRRtspResponse::ERTSPRespMovedTemporarily: |
|
1125 entry.iErr = KErrNotFound; |
|
1126 break; |
|
1127 |
|
1128 case CCRRtspResponse::ERTSPRespSeeOther: |
|
1129 entry.iErr = KErrGeneral; |
|
1130 break; |
|
1131 |
|
1132 case CCRRtspResponse::ERTSPRespNotModified: |
|
1133 entry.iErr = KErrGeneral; |
|
1134 break; |
|
1135 |
|
1136 case CCRRtspResponse::ERTSPRespUseProxy: |
|
1137 entry.iErr = KErrGeneral; |
|
1138 break; |
|
1139 |
|
1140 case CCRRtspResponse::ERTSPRespBadRequest: |
|
1141 entry.iErr = KErrGeneral; |
|
1142 break; |
|
1143 |
|
1144 case CCRRtspResponse::ERTSPRespPaymentRequired: |
|
1145 entry.iErr = KErrGeneral; |
|
1146 break; |
|
1147 |
|
1148 case CCRRtspResponse::ERTSPRespForbidden: |
|
1149 entry.iErr = KErrGeneral; |
|
1150 break; |
|
1151 |
|
1152 case CCRRtspResponse::ERTSPRespGone: |
|
1153 case CCRRtspResponse::ERTSPRespConferenceNotFound: |
|
1154 case CCRRtspResponse::ERTSPRespNotFound: |
|
1155 entry.iErr = KErrNotFound; |
|
1156 break; |
|
1157 |
|
1158 case CCRRtspResponse::ERTSPRespMethodNotAllowed: |
|
1159 entry.iErr = KErrGeneral; |
|
1160 break; |
|
1161 |
|
1162 case CCRRtspResponse::ERTSPRespNotAcceptable: |
|
1163 entry.iErr = KErrGeneral; |
|
1164 break; |
|
1165 |
|
1166 case CCRRtspResponse::ERTSPRespRequestTimeOut: |
|
1167 entry.iErr = KErrTimedOut; |
|
1168 break; |
|
1169 |
|
1170 case CCRRtspResponse::ERTSPRespLengthRequired: |
|
1171 entry.iErr = KErrGeneral; |
|
1172 break; |
|
1173 |
|
1174 case CCRRtspResponse::ERTSPRespPreconditionFailed: |
|
1175 entry.iErr = KErrGeneral; |
|
1176 break; |
|
1177 |
|
1178 case CCRRtspResponse::ERTSPRespRequestEntityTooLarge: |
|
1179 entry.iErr = KErrGeneral; |
|
1180 break; |
|
1181 |
|
1182 case CCRRtspResponse::ERTSPRespRequestURITooLarge: |
|
1183 entry.iErr = KErrGeneral; |
|
1184 break; |
|
1185 |
|
1186 case CCRRtspResponse::ERTSPRespParameterNotUnderstood: |
|
1187 entry.iErr = KErrArgument; |
|
1188 break; |
|
1189 |
|
1190 case CCRRtspResponse::ERTSPRespNotEnoughBandwidth: |
|
1191 entry.iErr = KErrGeneral; |
|
1192 break; |
|
1193 |
|
1194 case CCRRtspResponse::ERTSPRespSessionNotFound: |
|
1195 entry.iErr = KErrCouldNotConnect; |
|
1196 break; |
|
1197 |
|
1198 case CCRRtspResponse::ERTSPRespMethodNotValidInThisState: |
|
1199 entry.iErr = KErrGeneral; |
|
1200 break; |
|
1201 |
|
1202 case CCRRtspResponse::ERTSPRespHeaderFieldNotValidForResource: |
|
1203 entry.iErr = KErrGeneral; |
|
1204 break; |
|
1205 |
|
1206 case CCRRtspResponse::ERTSPRespInvalidRange: |
|
1207 entry.iErr = KErrGeneral; |
|
1208 break; |
|
1209 |
|
1210 case CCRRtspResponse::ERTSPRespParameterIsReadOnly: |
|
1211 entry.iErr = KErrGeneral; |
|
1212 break; |
|
1213 |
|
1214 case CCRRtspResponse::ERTSPRespAggregateOperationNotAllowed: |
|
1215 entry.iErr = KErrGeneral; |
|
1216 break; |
|
1217 |
|
1218 case CCRRtspResponse::ERTSPRespOnlyAggregateOperationAllowed: |
|
1219 entry.iErr = KErrGeneral; |
|
1220 break; |
|
1221 |
|
1222 case CCRRtspResponse::ERTSPRespUnsupportedTransport: |
|
1223 entry.iErr = KErrCouldNotConnect; |
|
1224 break; |
|
1225 |
|
1226 case CCRRtspResponse::ERTSPRespDestinationUnreachable: |
|
1227 entry.iErr = KErrCouldNotConnect; |
|
1228 break; |
|
1229 |
|
1230 case CCRRtspResponse::ERTSPRespInternalServerError: |
|
1231 entry.iErr = KErrGeneral; |
|
1232 break; |
|
1233 |
|
1234 case CCRRtspResponse::ERTSPRespNotImplemented: |
|
1235 entry.iErr = KErrGeneral; |
|
1236 break; |
|
1237 |
|
1238 case CCRRtspResponse::ERTSPRespBadGateway: |
|
1239 entry.iErr = KErrGeneral; |
|
1240 break; |
|
1241 |
|
1242 case CCRRtspResponse::ERTSPRespServiceUnavailable: |
|
1243 entry.iErr = KErrCouldNotConnect; |
|
1244 break; |
|
1245 |
|
1246 case CCRRtspResponse::ERTSPRespGatewayTimeOut: |
|
1247 entry.iErr = KErrGeneral; |
|
1248 break; |
|
1249 |
|
1250 case CCRRtspResponse::ERTSPRespUnsupportedMediaType: |
|
1251 case CCRRtspResponse::ERTSPRespOptionNotSupported: |
|
1252 case CCRRtspResponse::ERTSPRespRTSPVersionNotSupported: |
|
1253 entry.iErr = KErrNotSupported; |
|
1254 break; |
|
1255 |
|
1256 default: |
|
1257 entry.iErr = KErrGeneral; |
|
1258 break; |
|
1259 } |
|
1260 |
|
1261 if ( iObserver ) |
|
1262 { |
|
1263 iObserver->ConnectionStatusChange( |
|
1264 iOwningSession.SourceChecksum(), ECRConnectionError, entry.iErr ); |
|
1265 } |
|
1266 |
|
1267 // Try tear down first |
|
1268 if ( Stop() == KErrDisconnected ) |
|
1269 { |
|
1270 iOwningSession.SourceStop(); |
|
1271 } |
|
1272 } |
|
1273 |
|
1274 // ----------------------------------------------------------------------------- |
|
1275 // CCRRtspPacketSource::StartRtspTimeout |
|
1276 // Starts RTSP command response timeout. |
|
1277 // ----------------------------------------------------------------------------- |
|
1278 // |
|
1279 void CCRRtspPacketSource::StartRtspTimeout( TTimeIntervalMicroSeconds32 aTime ) |
|
1280 { |
|
1281 // Start a timeout timer to wait for the server to respond. |
|
1282 // If the server doesn't respond in time, cleanup will be initialized. |
|
1283 if ( !iRtspTimeout ) |
|
1284 { |
|
1285 TRAPD( err, iRtspTimeout = |
|
1286 CPeriodic::NewL( CActive::EPriorityStandard ) ); |
|
1287 if ( err != KErrNone ) |
|
1288 { |
|
1289 // Timer creation failed, start cleanup immediately |
|
1290 iOwningSession.SourceStop(); |
|
1291 } |
|
1292 } |
|
1293 else |
|
1294 { |
|
1295 iRtspTimeout->Cancel(); |
|
1296 } |
|
1297 |
|
1298 // Start timeout timer |
|
1299 iRtspTimeout->Start( |
|
1300 aTime, |
|
1301 aTime, |
|
1302 TCallBack( RtspTimeoutCallback, this ) ); |
|
1303 } |
|
1304 |
|
1305 // ----------------------------------------------------------------------------- |
|
1306 // CCRRtspPacketSource::RtspTimeoutCallback |
|
1307 // Callback for RTSP response timeout. Just ask session to start cleanup |
|
1308 // ----------------------------------------------------------------------------- |
|
1309 // |
|
1310 TInt CCRRtspPacketSource::RtspTimeoutCallback( TAny* aPtr ) |
|
1311 { |
|
1312 LOG( "CCRRtspPacketSource::RtspTimeoutCallback()" ); |
|
1313 |
|
1314 CCRRtspPacketSource* self = static_cast<CCRRtspPacketSource*>( aPtr ); |
|
1315 self->iRtspTimeout->Cancel(); |
|
1316 self->iOwningSession.SourceStop(); |
|
1317 return 0; |
|
1318 } |
|
1319 |
|
1320 // ----------------------------------------------------------------------------- |
|
1321 // CCRRtspPacketSource::SendRtspCommandL |
|
1322 // ----------------------------------------------------------------------------- |
|
1323 // |
|
1324 void CCRRtspPacketSource::SendRtspCommandL() |
|
1325 { |
|
1326 LOG1( "CCRRtspPacketSource::SendRtspCommandL(), iStage: %d", iStage ); |
|
1327 |
|
1328 if ( iPostPonedPlay ) |
|
1329 { |
|
1330 iPostPonedPlay = EFalse; |
|
1331 Play( iStartPos, iEndPos ); |
|
1332 } |
|
1333 else |
|
1334 { |
|
1335 switch ( iStage ) |
|
1336 { |
|
1337 case ERTSPInit: |
|
1338 case ERTSPOptSent: |
|
1339 { |
|
1340 delete iPrevCommands[ERTSPDescSent]; |
|
1341 iPrevCommands[ERTSPDescSent] = NULL; |
|
1342 iPrevCommands[ERTSPDescSent] = CCRRtspCommand::NewL(); |
|
1343 iPrevCommands[ERTSPDescSent]->SetCommand( |
|
1344 CCRRtspCommand::ERTSPCommandDESCRIBE ); |
|
1345 |
|
1346 TPtrC8 uriDes ( iRtspUri8->Des() ); |
|
1347 iPrevCommands[ERTSPDescSent]->SetURL( uriDes ); |
|
1348 iPrevCommands[ERTSPDescSent]->SetCSeq( iCSeq++ ); |
|
1349 if ( iUserAgent ) |
|
1350 { |
|
1351 iPrevCommands[ERTSPDescSent]->SetUserAgentL( *iUserAgent ); |
|
1352 } |
|
1353 if ( iWapProfile ) |
|
1354 { |
|
1355 iPrevCommands[ERTSPDescSent]->SetWapProfileL( *iWapProfile ); |
|
1356 } |
|
1357 if ( iBandwidth ) |
|
1358 { |
|
1359 iPrevCommands[ERTSPDescSent]->SetBandwidth( iBandwidth ); |
|
1360 } |
|
1361 |
|
1362 if ( iRtspSock ) |
|
1363 { |
|
1364 iRtspSock->SendData( iPrevCommands[ERTSPDescSent]->ProduceL() ); |
|
1365 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
1366 iStage = ERTSPDescSent; |
|
1367 } |
|
1368 } |
|
1369 break; |
|
1370 |
|
1371 case ERTSPDescSent: |
|
1372 if ( iSdpParser ) |
|
1373 { |
|
1374 const TInt audio( iSdpParser->MediaIdentifierAudio() ); |
|
1375 const TInt video( iSdpParser->MediaIdentifierVideo() ); |
|
1376 TBool videoExists( iSdpParser->VideoControlAddr().Length() > 0 ); |
|
1377 TBool audioExists( iSdpParser->AudioControlAddr().Length() > 0 ); |
|
1378 |
|
1379 /* If both medias are reported with dynamic payload |
|
1380 * type and audio stream is reported with lower |
|
1381 * payload type, then some servers don't work correctly |
|
1382 * if the SETUP commands are not in correct order, ie. |
|
1383 * we need to first SETUP the audio stream here. |
|
1384 */ |
|
1385 const TBool audioBeforeVideo( |
|
1386 audioExists && audio >= 96 && video >= 96 && audio < video ); |
|
1387 |
|
1388 if ( videoExists && !audioBeforeVideo ) |
|
1389 { |
|
1390 SendSetupCommandL( iSdpParser->VideoControlAddr(), EFalse ); |
|
1391 iStage = ERTSPSetupVideoSent; |
|
1392 } |
|
1393 else if ( audioExists ) |
|
1394 { |
|
1395 SendSetupCommandL( iSdpParser->AudioControlAddr(), ETrue ); |
|
1396 iStage = ERTSPSetupAudioSent; |
|
1397 } |
|
1398 else |
|
1399 { |
|
1400 LOG1( "CCRRtspPacketSource::SendRtspCommand stag %d have no audio nor video", |
|
1401 ( TInt )iStage ); |
|
1402 // no audio, no video, el panique grande |
|
1403 iOwningSession.SourceStop(); |
|
1404 } |
|
1405 } |
|
1406 break; |
|
1407 |
|
1408 case ERTSPSetupAudioSent: |
|
1409 { |
|
1410 const TInt audio( iSdpParser->MediaIdentifierAudio() ); |
|
1411 const TInt video( iSdpParser->MediaIdentifierVideo() ); |
|
1412 |
|
1413 if ( audio >= 96 && video >= 96 && audio < video && |
|
1414 iSdpParser && iSdpParser->VideoControlAddr().Length() ) |
|
1415 { |
|
1416 // Video exists also and has not been setup before, so |
|
1417 // let's setup it now. |
|
1418 |
|
1419 TPtrC8 ctrlAddr ( iSdpParser->VideoControlAddr() ); |
|
1420 SendSetupCommandL( ctrlAddr, EFalse ); |
|
1421 iStage = ERTSPSetupVideoSent; |
|
1422 } |
|
1423 else |
|
1424 { |
|
1425 ConditionallySetupMultiCastOrTcpStreamingL(); |
|
1426 } |
|
1427 } |
|
1428 break; |
|
1429 |
|
1430 case ERTSPSetupVideoSent: |
|
1431 { |
|
1432 const TInt audio( iSdpParser->MediaIdentifierAudio() ); |
|
1433 const TInt video( iSdpParser->MediaIdentifierVideo() ); |
|
1434 |
|
1435 // Check explanation for this in case ERTSPDescSent above. |
|
1436 const TBool audioBeforeVideo( |
|
1437 audio >= 96 && video >= 96 && audio < video ); |
|
1438 |
|
1439 // Then send audio, if applicable: |
|
1440 if ( iSdpParser && iSdpParser->AudioControlAddr().Length() && |
|
1441 !audioBeforeVideo ) |
|
1442 { |
|
1443 TPtrC8 ctrlAddr ( iSdpParser->AudioControlAddr() ); |
|
1444 SendSetupCommandL( ctrlAddr, ETrue ); |
|
1445 iStage = ERTSPSetupAudioSent; |
|
1446 } |
|
1447 else |
|
1448 { |
|
1449 // there is no audio that need setup so lets check also multicast+tcp |
|
1450 ConditionallySetupMultiCastOrTcpStreamingL(); |
|
1451 } |
|
1452 } |
|
1453 break; |
|
1454 |
|
1455 case ERTSPPauseSent: |
|
1456 // If we're paused, do zero the buffer, in tcp streaming case |
|
1457 // some servers seem to send packets even after play.. |
|
1458 break; |
|
1459 |
|
1460 case ERTSPReadyToPlay: |
|
1461 // In these stages send no further commands |
|
1462 break; |
|
1463 |
|
1464 case ERTSPPlaySent: |
|
1465 // Start timer for UDP reception and start streaming |
|
1466 if ( iTransport == ERTPOverUDP ) |
|
1467 { |
|
1468 iUdpReceptionTimer->Cancel(); |
|
1469 iUdpReceptionTimer->After( KCRRtspRtpUdpTimeout ); |
|
1470 } |
|
1471 |
|
1472 iStage = ERTSPPlaying; |
|
1473 if ( !iNoRtpInfoHeader ) |
|
1474 { |
|
1475 iSessionObs.StatusChanged( MCRPacketSource::ERtpStatePlaying ); |
|
1476 } |
|
1477 break; |
|
1478 |
|
1479 case ERTSPPlaying: |
|
1480 // None |
|
1481 break; |
|
1482 |
|
1483 case ERTSPTearDownSent: |
|
1484 iPostPonedPlay = EFalse; |
|
1485 iOwningSession.SourceStop(); |
|
1486 break; |
|
1487 |
|
1488 default: |
|
1489 // By default send no further commands |
|
1490 break; |
|
1491 } |
|
1492 } |
|
1493 } |
|
1494 |
|
1495 // ----------------------------------------------------------------------------- |
|
1496 // CCRRtspPacketSource::SendPlayCommandL |
|
1497 // ----------------------------------------------------------------------------- |
|
1498 // |
|
1499 void CCRRtspPacketSource::SendPlayCommandL(void) |
|
1500 { |
|
1501 delete iPrevCommands[ERTSPPlaySent]; |
|
1502 iPrevCommands[ERTSPPlaySent] = NULL; |
|
1503 iPrevCommands[ERTSPPlaySent] = CCRRtspCommand::NewL(); |
|
1504 iPrevCommands[ERTSPPlaySent]->SetCommand ( CCRRtspCommand::ERTSPCommandPLAY ); |
|
1505 TPtrC8 uriDes( iRtspUri8->Des() ); |
|
1506 iPrevCommands[ERTSPPlaySent]->SetURL( uriDes ); |
|
1507 iPrevCommands[ERTSPPlaySent]->SetCSeq( iCSeq ++ ); |
|
1508 iPrevCommands[ERTSPPlaySent]->SetRange( iStartPos , iEndPos ); |
|
1509 |
|
1510 if ( iUserAgent ) |
|
1511 { |
|
1512 iPrevCommands[ERTSPPlaySent]->SetUserAgentL( *iUserAgent ); |
|
1513 } |
|
1514 if ( iSessionId.Ptr() ) |
|
1515 { |
|
1516 iPrevCommands[ERTSPPlaySent]->SetSessionId( iSessionId ); |
|
1517 } |
|
1518 if ( iAuthenticationNeeded ) |
|
1519 { |
|
1520 AddAuthenticationL( ERTSPPlaySent ); |
|
1521 } |
|
1522 |
|
1523 if ( iRtspSock ) |
|
1524 { |
|
1525 iRtspSock->SendData( iPrevCommands[ERTSPPlaySent]->ProduceL() ); |
|
1526 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
1527 iStage = ERTSPPlaySent; |
|
1528 } |
|
1529 |
|
1530 iStartPos = KRealZero; |
|
1531 iEndPos = KRealMinusOne; |
|
1532 } |
|
1533 |
|
1534 // ----------------------------------------------------------------------------- |
|
1535 // CCRRtspPacketSource::SendPauseCommandL |
|
1536 // ----------------------------------------------------------------------------- |
|
1537 // |
|
1538 void CCRRtspPacketSource::SendPauseCommandL(void) |
|
1539 { |
|
1540 delete iPrevCommands[ERTSPPauseSent]; |
|
1541 iPrevCommands[ERTSPPauseSent] = NULL; |
|
1542 iPrevCommands[ERTSPPauseSent] = CCRRtspCommand::NewL(); |
|
1543 iPrevCommands[ERTSPPauseSent]->SetCommand ( CCRRtspCommand::ERTSPCommandPAUSE ); |
|
1544 TPtrC8 uriDes( iRtspUri8->Des() ); |
|
1545 iPrevCommands[ERTSPPauseSent]->SetURL( uriDes ); |
|
1546 iPrevCommands[ERTSPPauseSent]->SetCSeq( iCSeq ++ ); |
|
1547 |
|
1548 if ( iUserAgent ) |
|
1549 { |
|
1550 iPrevCommands[ERTSPPauseSent]->SetUserAgentL( *iUserAgent ); |
|
1551 } |
|
1552 if ( iSessionId.Ptr() ) |
|
1553 { |
|
1554 iPrevCommands[ERTSPPauseSent]->SetSessionId( iSessionId ); |
|
1555 } |
|
1556 if ( iAuthenticationNeeded ) |
|
1557 { |
|
1558 AddAuthenticationL( ERTSPPauseSent ); |
|
1559 } |
|
1560 |
|
1561 if ( iRtspSock ) |
|
1562 { |
|
1563 iRtspSock->SendData( iPrevCommands[ERTSPPauseSent]->ProduceL() ); |
|
1564 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
1565 iStage = ERTSPPauseSent; |
|
1566 } |
|
1567 } |
|
1568 |
|
1569 // ----------------------------------------------------------------------------- |
|
1570 // CCRRtspPacketSource::SendSetupCommandL |
|
1571 // ----------------------------------------------------------------------------- |
|
1572 // |
|
1573 TInt CCRRtspPacketSource::SendSetupCommandL( |
|
1574 const TDesC8& aControlAddr, |
|
1575 TBool aForAudio ) |
|
1576 { |
|
1577 TCRRTSPStage newStage = aForAudio ? ERTSPSetupAudioSent : ERTSPSetupVideoSent; |
|
1578 |
|
1579 delete iPrevCommands[newStage]; |
|
1580 iPrevCommands[newStage] = NULL; |
|
1581 iPrevCommands[newStage] = CCRRtspCommand::NewL(); |
|
1582 iPrevCommands[newStage]->SetCommand ( CCRRtspCommand::ERTSPCommandSETUP ); |
|
1583 iPrevCommands[newStage]->SetURL( aControlAddr ); |
|
1584 iPrevCommands[newStage]->SetCSeq( iCSeq ++ ); |
|
1585 iPrevCommands[newStage]->SetTransport( iTransport ); |
|
1586 |
|
1587 // Map stream to port number (when streaming over UDP) or channel (over TCP) |
|
1588 // base: iClientPort for UDP, 0 for TCP |
|
1589 // video: (base+0, base+1) |
|
1590 // audio: (base+2, base+3) or (base+0, base+1) when audio only |
|
1591 TInt portbase( ( iTransport == ERTPOverUDP )? iClientPort: 0 ); |
|
1592 TInt portoffset( ( aForAudio && iSdpParser->VideoControlAddr().Length() )? 2: 0 ); |
|
1593 iPrevCommands[newStage]->SetClientPort( portbase + portoffset ); |
|
1594 |
|
1595 if ( iSessionId.Ptr() ) |
|
1596 { |
|
1597 iPrevCommands[newStage]->SetSessionId ( iSessionId ); |
|
1598 } |
|
1599 if ( iAuthenticationNeeded ) |
|
1600 { |
|
1601 AddAuthenticationL( newStage ); |
|
1602 } |
|
1603 if ( iUserAgent ) |
|
1604 { |
|
1605 iPrevCommands[newStage]->SetUserAgentL( *iUserAgent ); |
|
1606 } |
|
1607 if ( iWapProfile ) |
|
1608 { |
|
1609 iPrevCommands[newStage]->SetWapProfileL( *iWapProfile ); |
|
1610 } |
|
1611 |
|
1612 if ( iRtspSock ) |
|
1613 { |
|
1614 iRtspSock->SendData( iPrevCommands[newStage]->ProduceL() ); |
|
1615 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
1616 } |
|
1617 |
|
1618 return KErrNone; |
|
1619 } |
|
1620 |
|
1621 // ----------------------------------------------------------------------------- |
|
1622 // CCRRtspPacketSource::SendTearDownCommandL |
|
1623 // ----------------------------------------------------------------------------- |
|
1624 // |
|
1625 void CCRRtspPacketSource::SendTearDownCommandL() |
|
1626 { |
|
1627 CCRRtspCommand*& teardowncmd = iPrevCommands[ERTSPTearDownSent]; |
|
1628 iPostPonedPlay = EFalse; |
|
1629 if ( teardowncmd ) |
|
1630 { |
|
1631 delete teardowncmd; teardowncmd = NULL; |
|
1632 } |
|
1633 |
|
1634 teardowncmd = CCRRtspCommand::NewL(); |
|
1635 teardowncmd->SetCommand( CCRRtspCommand::ERTSPCommandTEARDOWN ); |
|
1636 TPtrC8 uri( iRtspUri8->Des() ); |
|
1637 teardowncmd->SetURL( uri ); |
|
1638 teardowncmd->SetCSeq( iCSeq++ ); |
|
1639 |
|
1640 if ( iSessionId.Ptr() ) |
|
1641 { |
|
1642 teardowncmd->SetSessionId( iSessionId ); |
|
1643 } |
|
1644 if ( iUserAgent ) |
|
1645 { |
|
1646 teardowncmd->SetUserAgentL( *iUserAgent ); |
|
1647 } |
|
1648 if ( iAuthenticationNeeded ) |
|
1649 { |
|
1650 AddAuthenticationL( ERTSPTearDownSent ); |
|
1651 } |
|
1652 |
|
1653 if ( iRtspSock ) |
|
1654 { |
|
1655 iRtspSock->SendData( teardowncmd->ProduceL() ); |
|
1656 } |
|
1657 } |
|
1658 |
|
1659 // ----------------------------------------------------------------------------- |
|
1660 // CCRRtspPacketSource::SendOptionsCommandL |
|
1661 // ----------------------------------------------------------------------------- |
|
1662 // |
|
1663 void CCRRtspPacketSource::SendOptionsCommandL(void) |
|
1664 { |
|
1665 delete iPrevCommands[ERTSPOptSent]; |
|
1666 iPrevCommands[ERTSPOptSent] = NULL; |
|
1667 iPrevCommands[ERTSPOptSent] = CCRRtspCommand::NewL(); |
|
1668 iPrevCommands[ERTSPOptSent]->SetCommand ( CCRRtspCommand::ERTSPCommandOPTIONS ); |
|
1669 TPtrC8 uriDes ( iRtspUri8->Des() ); |
|
1670 iPrevCommands[ERTSPOptSent]->SetURL ( uriDes ); |
|
1671 iPrevCommands[ERTSPOptSent]->SetCSeq ( iCSeq ++ ); |
|
1672 |
|
1673 if ( iUserAgent ) |
|
1674 { |
|
1675 iPrevCommands[ERTSPOptSent]->SetUserAgentL( *iUserAgent ); |
|
1676 } |
|
1677 if ( iSessionId.Ptr() ) |
|
1678 { |
|
1679 iPrevCommands[ERTSPOptSent]->SetSessionId ( iSessionId ); |
|
1680 } |
|
1681 if ( iAuthenticationNeeded ) |
|
1682 { |
|
1683 AddAuthenticationL( ERTSPOptSent ); |
|
1684 } |
|
1685 |
|
1686 if ( iRtspSock ) |
|
1687 { |
|
1688 iRtspSock->SendData( iPrevCommands[ERTSPOptSent]->ProduceL() ); |
|
1689 } |
|
1690 // Sending options ping does not change our state |
|
1691 } |
|
1692 |
|
1693 // ----------------------------------------------------------------------------- |
|
1694 // CCRRtspPacketSource::SetupRTPSessions |
|
1695 // ----------------------------------------------------------------------------- |
|
1696 // |
|
1697 TInt CCRRtspPacketSource::SetupRTPSessions( void ) |
|
1698 { |
|
1699 TInt retval( KErrNone ); |
|
1700 if ( !iRtspSock ) |
|
1701 { |
|
1702 retval = KErrNotReady; |
|
1703 } |
|
1704 else |
|
1705 { |
|
1706 TInetAddr localAddr( iRtspSock->LocalAddr() ); |
|
1707 TInetAddr remoteAddr( iRtspSock->ConnectedAddr() ); |
|
1708 |
|
1709 // Clear used streams |
|
1710 iReceiveStreams.Reset(); |
|
1711 iTrafficFound = EFalse; |
|
1712 |
|
1713 // First audio: |
|
1714 if ( iRtspSock && iResponses[ERTSPSetupAudioSent] ) |
|
1715 { |
|
1716 if ( iTransport == ERTPOverMulticast ) |
|
1717 { |
|
1718 retval = CreateMulticastSocket( ERTPAudioSend1, |
|
1719 iResponses[ERTSPSetupAudioSent]->Destination(), |
|
1720 iResponses[ERTSPSetupAudioSent]->ClientPort() ); |
|
1721 if ( retval == KErrNone ) |
|
1722 { |
|
1723 retval = CreateMulticastSocket( ERTPAudioSend2, |
|
1724 iResponses[ERTSPSetupAudioSent]->Destination(), |
|
1725 iResponses[ERTSPSetupAudioSent]->ClientPort()+1 ); |
|
1726 } |
|
1727 } |
|
1728 else |
|
1729 { |
|
1730 localAddr.SetPort( iResponses[ERTSPSetupAudioSent]->ClientPort() ); |
|
1731 remoteAddr.SetPort( iResponses[ERTSPSetupAudioSent]->ServerPort() ); |
|
1732 |
|
1733 #if defined ( LIVE_TV_FILE_TRACE ) || defined ( LIVE_TV_RDEBUG_TRACE ) |
|
1734 TName _addr; |
|
1735 localAddr.Output( _addr ); |
|
1736 LOG2( "localaddr for video is %S:%d", &_addr, localAddr.Port() ); |
|
1737 remoteAddr.Output( _addr ); |
|
1738 LOG2( "remoteAddr for video is %S:%d", &_addr, remoteAddr.Port() ); |
|
1739 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
1740 |
|
1741 retval = CreateUnicastSocket( ERTPAudioSend1, localAddr, remoteAddr ); |
|
1742 if ( retval == KErrNone ) |
|
1743 { |
|
1744 localAddr.SetPort( localAddr.Port()+1 ); |
|
1745 remoteAddr.SetPort( remoteAddr.Port()+1 ); |
|
1746 retval = CreateUnicastSocket( ERTPAudioSend2, localAddr, remoteAddr ); |
|
1747 } |
|
1748 } |
|
1749 |
|
1750 if ( retval == KErrNone ) |
|
1751 { |
|
1752 TRAP( retval, iAudioSession.OpenL( |
|
1753 iRTPSockArr[ERTPAudioSend1]->Socket(), |
|
1754 KAverageExpectedRtpPacketMaxSize, |
|
1755 iRTPSockArr[ERTPAudioSend2]->Socket(), |
|
1756 EPriorityNormal, KCRCName() ) ); |
|
1757 } |
|
1758 |
|
1759 LOG1( "CCRRtspPacketSource::SetupRTPSessions audio sess open: %d", retval ); |
|
1760 if ( !retval ) |
|
1761 { |
|
1762 SetRtpSession( iAudioSession , iSdpParser->AudioTimerGranularity() ); |
|
1763 iAudioSession.SetBandwidth( iSdpParser->AudioBitrate() * 1000 ); |
|
1764 TRAP( retval, iAudioSession.PrivRegisterEventCallbackL( ERtpNewSource, |
|
1765 ( TRtpCallbackFunction )CCRRtspPacketSource::AudioRTPCallBack, this ) ); |
|
1766 |
|
1767 TReceiveStream audioDataStream; |
|
1768 audioDataStream.iStreamType = EAudioStream; |
|
1769 audioDataStream.iDataReceived = EFalse; |
|
1770 iReceiveStreams.Append( audioDataStream ); |
|
1771 LOG( "CCRRtspPacketSource::SetupRTPSessions - AudioStream found" ); |
|
1772 TReceiveStream audioControlStream; |
|
1773 audioControlStream.iStreamType = EAudioControlStream; |
|
1774 audioControlStream.iDataReceived = EFalse; |
|
1775 LOG( "CCRRtspPacketSource::SetupRTPSessions - AudioControlStream found" ); |
|
1776 iReceiveStreams.Append( audioControlStream ); |
|
1777 |
|
1778 LOG2( "CCRRtspPacketSource::SetupRTPSessions audio stat: %d, ts: %u", |
|
1779 retval, ( TUint )iRTPTimeStampAudio ); |
|
1780 } |
|
1781 else |
|
1782 { |
|
1783 if ( iObserver ) |
|
1784 { |
|
1785 iObserver->ConnectionStatusChange( |
|
1786 iOwningSession.SourceChecksum(), |
|
1787 ECRConnectionError, retval ); |
|
1788 } |
|
1789 iOwningSession.SourceStop(); |
|
1790 } |
|
1791 } |
|
1792 |
|
1793 // Then video |
|
1794 if ( retval == KErrNone && iRtspSock && iResponses[ERTSPSetupVideoSent] ) |
|
1795 { |
|
1796 if ( iTransport==ERTPOverMulticast ) |
|
1797 { |
|
1798 retval = CreateMulticastSocket( ERTPVideoSend1, |
|
1799 iResponses[ERTSPSetupVideoSent]->Destination(), |
|
1800 iResponses[ERTSPSetupVideoSent]->ClientPort() ); |
|
1801 if ( retval==KErrNone ) |
|
1802 { |
|
1803 retval = CreateMulticastSocket( ERTPVideoSend2, |
|
1804 iResponses[ERTSPSetupVideoSent]->Destination(), |
|
1805 iResponses[ERTSPSetupVideoSent]->ClientPort()+1 ); |
|
1806 } |
|
1807 } |
|
1808 else |
|
1809 { |
|
1810 localAddr.SetPort( iResponses[ERTSPSetupVideoSent]->ClientPort() ); |
|
1811 remoteAddr.SetPort( iResponses[ERTSPSetupVideoSent]->ServerPort() ); |
|
1812 |
|
1813 #if defined ( LIVE_TV_FILE_TRACE ) || defined ( LIVE_TV_RDEBUG_TRACE ) |
|
1814 TName _addr; |
|
1815 localAddr.Output( _addr ); |
|
1816 LOG2( "localaddr for video is %S:%d", &_addr, localAddr.Port() ); |
|
1817 remoteAddr.Output( _addr ); |
|
1818 LOG2( "remoteAddr for video is %S:%d", &_addr, remoteAddr.Port() ); |
|
1819 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
1820 |
|
1821 retval = CreateUnicastSocket( ERTPVideoSend1, localAddr, remoteAddr ); |
|
1822 if ( retval == KErrNone ) |
|
1823 { |
|
1824 localAddr.SetPort( localAddr.Port() + 1 ); |
|
1825 remoteAddr.SetPort( remoteAddr.Port() + 1 ); |
|
1826 retval = CreateUnicastSocket( ERTPVideoSend2, localAddr, remoteAddr ); |
|
1827 } |
|
1828 } |
|
1829 |
|
1830 if ( retval == KErrNone ) |
|
1831 { |
|
1832 TRAP( retval, iVideoSession.OpenL( iRTPSockArr[ERTPVideoSend1]->Socket(), |
|
1833 KAverageExpectedRtpPacketMaxSize, iRTPSockArr[ERTPVideoSend2]->Socket(), |
|
1834 EPriorityNormal, KCRCName() ) ); |
|
1835 } |
|
1836 |
|
1837 LOG1( "CCRRtspPacketSource::SetupRTPSessions video sess open: %d", retval ); |
|
1838 if ( !retval ) |
|
1839 { |
|
1840 SetRtpSession( iVideoSession , iSdpParser->VideoTimerGranularity() ); |
|
1841 iVideoSession.SetBandwidth( iSdpParser->VideoBitrate() * 1000 ); |
|
1842 TRAP( retval, iVideoSession.PrivRegisterEventCallbackL( ERtpNewSource, |
|
1843 ( TRtpCallbackFunction )CCRRtspPacketSource::VideoRTPCallBack, this ) ); |
|
1844 |
|
1845 TReceiveStream videoDataStream; |
|
1846 videoDataStream.iStreamType = EVideoStream; |
|
1847 videoDataStream.iDataReceived = EFalse; |
|
1848 LOG( "CCRRtspPacketSource::SetupRTPSessions - VideoStream found" ); |
|
1849 iReceiveStreams.Append( videoDataStream ); |
|
1850 TReceiveStream videoControlStream; |
|
1851 videoControlStream.iStreamType = EVideoControlStream; |
|
1852 videoControlStream.iDataReceived = EFalse; |
|
1853 LOG( "CCRRtspPacketSource::SetupRTPSessions - VideoControlStream found" ); |
|
1854 iReceiveStreams.Append( videoControlStream ); |
|
1855 |
|
1856 LOG2( "CCRRtspPacketSource::SetupRTPSessions video stat: %d, ts: %u", |
|
1857 retval, ( TUint )iRTPTimeStampVideo ); |
|
1858 } |
|
1859 else |
|
1860 { |
|
1861 if ( iObserver ) |
|
1862 { |
|
1863 iObserver->ConnectionStatusChange( |
|
1864 iOwningSession.SourceChecksum(), |
|
1865 ECRConnectionError, retval ); |
|
1866 } |
|
1867 iOwningSession.SourceStop(); |
|
1868 } |
|
1869 } |
|
1870 } |
|
1871 |
|
1872 return retval; |
|
1873 } |
|
1874 |
|
1875 // ----------------------------------------------------------------------------- |
|
1876 // CCRRtspPacketSource::CreateMulticastSocket |
|
1877 // ----------------------------------------------------------------------------- |
|
1878 // |
|
1879 TInt CCRRtspPacketSource::CreateMulticastSocket( |
|
1880 TCRRTPSockId aSockId, |
|
1881 const TInetAddr& aGroupAddr, |
|
1882 TInt aPort ) |
|
1883 { |
|
1884 // Alias for socket being created |
|
1885 CCRSock*& sock = iRTPSockArr[aSockId]; |
|
1886 |
|
1887 // Delete if already existing |
|
1888 if ( sock ) |
|
1889 { |
|
1890 delete sock; |
|
1891 sock = NULL; |
|
1892 } |
|
1893 |
|
1894 // Create socket |
|
1895 TRAPD( err, sock = CCRSock::NewL( *this, aSockId, iConnection.Connection(), |
|
1896 iSockServer, EFalse, EFalse) ); |
|
1897 if ( err != KErrNone ) |
|
1898 { |
|
1899 LOG2( "CCRRtspPacketSource::CreateMulticastSocket: CCRSock::NewL FAILED, sockId: %d, err: %d", |
|
1900 aSockId, err ); |
|
1901 return err; |
|
1902 } |
|
1903 |
|
1904 // Bind socket to local UDP port, issue no reads -> handled by RRtpSession |
|
1905 err = sock->ListenPort( aPort ); |
|
1906 if ( err != KErrNone ) |
|
1907 { |
|
1908 LOG2( "CCRRtspPacketSource::CreateMulticastSocket: ListenPort FAILED, port: %d, err: %d", |
|
1909 aPort, err ); |
|
1910 return err; |
|
1911 } |
|
1912 |
|
1913 err = sock->JoinGroup( aGroupAddr ); |
|
1914 if ( err != KErrNone ) |
|
1915 { |
|
1916 LOG1( "CCRRtspPacketSource::CreateMulticastSocket: JoinGroup FAILED, err: %d", err ); |
|
1917 return err; |
|
1918 } |
|
1919 |
|
1920 #if defined(LIVE_TV_FILE_TRACE) || defined(LIVE_TV_RDEBUG_TRACE) |
|
1921 TName group; |
|
1922 aGroupAddr.Output( group ); |
|
1923 LOG3( "CCRRtspPacketSource::CreateMulticastSocket: sockid: %d, group: '%S', port: %d OK", |
|
1924 aSockId, &group, aPort ); |
|
1925 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
1926 |
|
1927 return KErrNone; |
|
1928 } |
|
1929 |
|
1930 // ----------------------------------------------------------------------------- |
|
1931 // CCRRtspPacketSource::CreateUnicastSocket |
|
1932 // ----------------------------------------------------------------------------- |
|
1933 TInt CCRRtspPacketSource::CreateUnicastSocket( |
|
1934 TCRRTPSockId aSockId, |
|
1935 const TInetAddr& aLocalAddr, |
|
1936 const TInetAddr& /*aRemoteAddr*/ ) |
|
1937 { |
|
1938 // Alias for socket being created |
|
1939 CCRSock*& sock = iRTPSockArr[aSockId]; |
|
1940 |
|
1941 // Delete if already existing |
|
1942 if ( sock ) |
|
1943 { |
|
1944 delete sock; |
|
1945 sock = NULL; |
|
1946 } |
|
1947 |
|
1948 // Create socket: EFalse=UDP, EFalse=issue no read (handled by RRtpSession) |
|
1949 TRAPD( err, sock = CCRSock::NewL( *this,aSockId, iConnection.Connection(), |
|
1950 iSockServer, EFalse, EFalse ) ); |
|
1951 if ( err != KErrNone ) |
|
1952 { |
|
1953 LOG2( "CCRRtspPacketSource::CreateUnicastSocket: CCRSock::NewL FAILED, sockId: %d, err: %d", |
|
1954 aSockId, err ); |
|
1955 return err; |
|
1956 } |
|
1957 |
|
1958 // Bind to local port, ignore remote address and port |
|
1959 TInt port = aLocalAddr.Port(); |
|
1960 err = sock->ListenPort( port ); |
|
1961 if ( err != KErrNone ) |
|
1962 { |
|
1963 LOG2( "CCRRtspPacketSource::CreateUnicastSocket: ListenPort FAILED, port: %d, err: %d", |
|
1964 port, err ); |
|
1965 return err; |
|
1966 } |
|
1967 |
|
1968 #if defined(LIVE_TV_FILE_TRACE) || defined(LIVE_TV_RDEBUG_TRACE) |
|
1969 LOG2( "CCRRtspPacketSource::CreateUnicastSocket: sockid: %d, port: %d OK", |
|
1970 aSockId, port ); |
|
1971 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
1972 |
|
1973 return KErrNone; |
|
1974 } |
|
1975 |
|
1976 // ----------------------------------------------------------------------------- |
|
1977 // CCRRtspPacketSource::RTPPayloadProcessor |
|
1978 // This is called from audio and video callbacks when real payload packet |
|
1979 // is received from rtp stack. |
|
1980 // ----------------------------------------------------------------------------- |
|
1981 // |
|
1982 void CCRRtspPacketSource::RTPPayloadProcessor( |
|
1983 const TRtpEvent& aEvent, |
|
1984 const TBool aIsAudio ) |
|
1985 { |
|
1986 // If udp traffic hasn't been flagged as found |
|
1987 // keep marking streams as found |
|
1988 if ( !iTrafficFound ) |
|
1989 { |
|
1990 if ( aIsAudio ) |
|
1991 { |
|
1992 StreamFound( EAudioStream ); |
|
1993 } |
|
1994 else |
|
1995 { |
|
1996 StreamFound( EVideoStream ); |
|
1997 } |
|
1998 |
|
1999 // Cancel UDP timer, so as not to trigger TCP streaming |
|
2000 if ( CheckReceiveOfStreams() ) |
|
2001 { |
|
2002 // We have traffic from all needed streams, cancel reception timer |
|
2003 // and set UDP flag. |
|
2004 iUdpReceptionTimer->Cancel(); |
|
2005 iUdpFound = ETrue; |
|
2006 iTrafficFound = ETrue; |
|
2007 } |
|
2008 } |
|
2009 |
|
2010 // Here process packet |
|
2011 RRtpReceivePacket p = aEvent.ReceiveSource().Packet(); |
|
2012 TUint32 flag( 0 ); |
|
2013 BigEndian::Put32( ( TUint8* )&flag, p.Flags() ); |
|
2014 |
|
2015 // Header |
|
2016 TCRRtpMessageHeader packetHeader; |
|
2017 memcpy( &packetHeader, &flag, sizeof( flag ) ); |
|
2018 BigEndian::Put32( ( TUint8* )&packetHeader.iTimestamp, p.Timestamp() ); |
|
2019 BigEndian::Put32( ( TUint8* )&packetHeader.iSSRC, p.SSRC() ); |
|
2020 TPtrC8 rtpHeader( ( TUint8* )&packetHeader, sizeof( packetHeader ) ); |
|
2021 |
|
2022 if ( iNoRtpInfoHeader ) |
|
2023 { |
|
2024 ConstructSeqAndTsForSink( |
|
2025 aIsAudio ? MCRPacketSource::EAudioStream : MCRPacketSource::EVideoStream, |
|
2026 0 /*nop*/, 0 /*nop*/, 0 /*nop*/, p.SequenceNumber() ); |
|
2027 } |
|
2028 |
|
2029 // Stream |
|
2030 MCRPacketSource::TCRPacketStreamId stream( |
|
2031 ( aIsAudio )? MCRPacketSource::EAudioStream : |
|
2032 MCRPacketSource::EVideoStream ); |
|
2033 iBuffer->AddPacket( stream, rtpHeader, p.Payload() ); |
|
2034 |
|
2035 // Count of packets |
|
2036 if ( aIsAudio ) |
|
2037 { |
|
2038 iAudioBytes += p.Payload( ).Length(); |
|
2039 iAudioPackets ++; |
|
2040 } |
|
2041 else |
|
2042 { |
|
2043 iVideoBytes += p.Payload( ).Length(); |
|
2044 iVideoPackets ++; |
|
2045 } |
|
2046 |
|
2047 p.Close(); |
|
2048 } |
|
2049 |
|
2050 // ----------------------------------------------------------------------------- |
|
2051 // CCRRtspPacketSource::AudioRTPCallBack |
|
2052 // ----------------------------------------------------------------------------- |
|
2053 // |
|
2054 void CCRRtspPacketSource::AudioRTPCallBack( |
|
2055 CCRRtspPacketSource* aPtr, |
|
2056 const TRtpEvent& aEvent ) |
|
2057 { |
|
2058 switch ( aEvent.Type() ) |
|
2059 { |
|
2060 case ERtpPacketReceived: |
|
2061 static_cast<CCRRtspPacketSource*>( aPtr )-> |
|
2062 RTPPayloadProcessor( aEvent, ETrue ); |
|
2063 break; |
|
2064 |
|
2065 // RTCP |
|
2066 case ERtpSR: |
|
2067 { |
|
2068 // We have audio control traffic |
|
2069 if ( !aPtr->iTrafficFound ) |
|
2070 { |
|
2071 aPtr->StreamFound( EAudioControlStream ); |
|
2072 if ( aPtr->CheckReceiveOfStreams() ) |
|
2073 { |
|
2074 // Cancel UDP timer, so as not to trigger TCP streaming |
|
2075 aPtr->iUdpReceptionTimer->Cancel(); |
|
2076 aPtr->iUdpFound = ETrue; |
|
2077 aPtr->iTrafficFound = ETrue; |
|
2078 } |
|
2079 } |
|
2080 |
|
2081 // Sender report |
|
2082 SenderReport( aPtr, aEvent, MCRPacketSource::EAudioControlStream ); |
|
2083 } |
|
2084 break; |
|
2085 |
|
2086 case ERtpNewSource: |
|
2087 { |
|
2088 // Handle audio |
|
2089 TRAPD( err, HandleNewSourceL( aPtr, aPtr->iRtpRecvSrcAudio, aEvent, |
|
2090 ( TRtpCallbackFunction )CCRRtspPacketSource::AudioRTPCallBack ) ); |
|
2091 if ( err ) |
|
2092 { |
|
2093 LOG1( "CCRRtspPacketSource::AudioRTPCallBack(), HandleNewSourceL Leaved: %d", err ); |
|
2094 aPtr->iOwningSession.SourceStop(); |
|
2095 } |
|
2096 } |
|
2097 break; |
|
2098 |
|
2099 case ERtpSessionFail: |
|
2100 case ERtpSourceFail: |
|
2101 LOG( "CCRRtspPacketSource::VideoRTPCallBack(), source/session fail" ); |
|
2102 aPtr->iOwningSession.SourceStop(); |
|
2103 if ( aPtr->iObserver ) |
|
2104 { |
|
2105 aPtr->iObserver->ConnectionStatusChange( |
|
2106 aPtr->iOwningSession.SourceChecksum(), |
|
2107 ECRNormalEndOfStream, KErrSessionClosed ); |
|
2108 } |
|
2109 break; |
|
2110 |
|
2111 case ERtpBYE: |
|
2112 LOG( "CCRRtspPacketSource::AudioRTPCallBack(), ERtpBYE" ); |
|
2113 if ( aPtr->iObserver ) |
|
2114 { |
|
2115 aPtr->iObserver->ConnectionStatusChange( |
|
2116 aPtr->iOwningSession.SourceChecksum(), |
|
2117 ECRNormalEndOfStream, KErrNone ); |
|
2118 } |
|
2119 break; |
|
2120 |
|
2121 default: |
|
2122 LOG1( "CCRRtspPacketSource::AudioRTPCallBack default case, type 0x%x", |
|
2123 ( TUint )( aEvent.Type() ) ); |
|
2124 // by do nothing |
|
2125 break; |
|
2126 } |
|
2127 } |
|
2128 |
|
2129 // ----------------------------------------------------------------------------- |
|
2130 // CCRRtspPacketSource::VideoRTPCallBack |
|
2131 // ----------------------------------------------------------------------------- |
|
2132 // |
|
2133 void CCRRtspPacketSource::VideoRTPCallBack( |
|
2134 CCRRtspPacketSource* aPtr, |
|
2135 const TRtpEvent& aEvent ) |
|
2136 { |
|
2137 switch ( aEvent.Type() ) |
|
2138 { |
|
2139 case ERtpPacketReceived: |
|
2140 static_cast<CCRRtspPacketSource*>( aPtr )-> |
|
2141 RTPPayloadProcessor( aEvent, EFalse ); |
|
2142 break; |
|
2143 |
|
2144 // RTCP |
|
2145 case ERtpSR: |
|
2146 { |
|
2147 // We have video control traffic |
|
2148 if ( !aPtr->iTrafficFound ) |
|
2149 { |
|
2150 aPtr->StreamFound( EVideoControlStream ); |
|
2151 if ( aPtr->CheckReceiveOfStreams() ) |
|
2152 { |
|
2153 // Cancel UDP timer, so as not to trigger TCP streaming |
|
2154 aPtr->iUdpReceptionTimer->Cancel(); |
|
2155 aPtr->iUdpFound = ETrue; |
|
2156 aPtr->iTrafficFound = ETrue; |
|
2157 } |
|
2158 } |
|
2159 |
|
2160 // Sender report |
|
2161 SenderReport( aPtr, aEvent, MCRPacketSource::EVideoControlStream ); |
|
2162 } |
|
2163 break; |
|
2164 |
|
2165 case ERtpNewSource: |
|
2166 { |
|
2167 // Handle video |
|
2168 TRAPD( err, HandleNewSourceL( aPtr, aPtr->iRtpRecvSrcVideo, aEvent, |
|
2169 ( TRtpCallbackFunction )CCRRtspPacketSource::VideoRTPCallBack ) ); |
|
2170 if ( err ) |
|
2171 { |
|
2172 LOG1( "CCRRtspPacketSource::VideoRTPCallBack(), HandleNewSourceL Leaved: %d", err ); |
|
2173 aPtr->iOwningSession.SourceStop(); |
|
2174 } |
|
2175 } |
|
2176 break; |
|
2177 |
|
2178 case ERtpSessionFail: |
|
2179 case ERtpSourceFail: |
|
2180 LOG( "CCRRtspPacketSource::VideoRTPCallBack(), Source/session fail" ); |
|
2181 aPtr->iOwningSession.SourceStop(); |
|
2182 if ( aPtr->iObserver ) |
|
2183 { |
|
2184 aPtr->iObserver->ConnectionStatusChange( |
|
2185 aPtr->iOwningSession.SourceChecksum(), |
|
2186 ECRNormalEndOfStream, KErrSessionClosed ); |
|
2187 } |
|
2188 break; |
|
2189 |
|
2190 case ERtpBYE: |
|
2191 LOG( "CCRRtspPacketSource::VideoRTPCallBack(), ERtpBYE" ); |
|
2192 if ( aPtr->iObserver ) |
|
2193 { |
|
2194 aPtr->iObserver->ConnectionStatusChange( |
|
2195 aPtr->iOwningSession.SourceChecksum(), |
|
2196 ECRNormalEndOfStream, KErrNone ); |
|
2197 } |
|
2198 break; |
|
2199 |
|
2200 default: |
|
2201 LOG1( "CCRRtspPacketSource::VideoRTPCallBack default case, type 0x%x", |
|
2202 ( TUint )( aEvent.Type() ) ); |
|
2203 // By do nothing |
|
2204 break; |
|
2205 } |
|
2206 } |
|
2207 |
|
2208 // ----------------------------------------------------------------------------- |
|
2209 // CCRRtspPacketSource::SenderReport |
|
2210 // rfc-1305: |
|
2211 // NTP timestamps are represented as a 64-bit unsigned fixed- |
|
2212 // point number, in seconds relative to 0h on 1 January 1900. |
|
2213 // The integer part is in the first 32 bits and the fraction |
|
2214 // part in the last 32 bits. |
|
2215 // ----------------------------------------------------------------------------- |
|
2216 // |
|
2217 void CCRRtspPacketSource::SenderReport( |
|
2218 CCRRtspPacketSource* aPtr, |
|
2219 const TRtpEvent& aEvent, |
|
2220 MCRPacketSource::TCRPacketStreamId aStreamId ) |
|
2221 { |
|
2222 TCRRtpSRReportHeader srReport; |
|
2223 srReport.iVersion = KRtpPacketVersion; // value is 2 |
|
2224 srReport.iPadding = 0; |
|
2225 srReport.iReportCount = 0; |
|
2226 srReport.iPacketType = KSenderReportPacketType; |
|
2227 RRtpReceiveSource source( aEvent.ReceiveSource() ); |
|
2228 BigEndian::Put16( ( TUint8* )&srReport.iLength, 6 ); |
|
2229 BigEndian::Put32( ( TUint8* )&srReport.iSenderSSRC, |
|
2230 source.SSRC() ); |
|
2231 BigEndian::Put32( ( TUint8* )&srReport.iMSWTimestamp, |
|
2232 source.GetSR().iSrPtr.ntp_sec ); |
|
2233 BigEndian::Put32( ( TUint8* )&srReport.iLSWTimestamp, |
|
2234 source.GetSR().iSrPtr.ntp_frac ); |
|
2235 BigEndian::Put32( ( TUint8* )&srReport.iRTPTimestamp, |
|
2236 source.GetSR().RTPTimestamp() ); |
|
2237 BigEndian::Put32( ( TUint8* )&srReport.iSenderPacketCount, |
|
2238 aPtr->iAudioPackets ); |
|
2239 BigEndian::Put32( ( TUint8* )&srReport.iSenderOctetCount, |
|
2240 aPtr->iAudioBytes ); |
|
2241 TPtrC8 rtcpHeader( ( TUint8* )&srReport, sizeof( srReport ) ); |
|
2242 aPtr->iBuffer->AddPacket( aStreamId, rtcpHeader ); |
|
2243 |
|
2244 // Verify Seq and Ts |
|
2245 if ( aPtr->iNoRtpInfoHeader ) |
|
2246 { |
|
2247 aPtr->ConstructSeqAndTsForSink ( |
|
2248 aStreamId, |
|
2249 source.GetSR().iSrPtr.ntp_sec, |
|
2250 source.GetSR().iSrPtr.ntp_frac, |
|
2251 source.GetSR().RTPTimestamp(), |
|
2252 0 ); // 0 not used |
|
2253 } |
|
2254 } |
|
2255 |
|
2256 // ----------------------------------------------------------------------------- |
|
2257 // CCRRtspPacketSource::HandleNewSourceL |
|
2258 // ----------------------------------------------------------------------------- |
|
2259 // |
|
2260 void CCRRtspPacketSource::HandleNewSourceL( |
|
2261 CCRRtspPacketSource* aPtr, |
|
2262 RRtpReceiveSource& aSource, |
|
2263 const TRtpEvent& aEvent, |
|
2264 TRtpCallbackFunction aCallback ) |
|
2265 { |
|
2266 // Cancel UDP timer, so as not to trigger TCP streaming |
|
2267 aPtr->iUdpReceptionTimer->Cancel(); |
|
2268 delete aPtr->iPunchPacketSenderAudio; |
|
2269 aPtr->iPunchPacketSenderAudio = NULL; |
|
2270 if ( aSource.IsOpen() ) |
|
2271 { |
|
2272 aSource.Close(); |
|
2273 } |
|
2274 |
|
2275 // Source |
|
2276 aSource = aEvent.Session().NewReceiveSourceL(); |
|
2277 aSource.PrivRegisterEventCallbackL( ERtpPacketReceived, aCallback, aPtr ); |
|
2278 aSource.PrivRegisterEventCallbackL( ERtpSR, aCallback, aPtr ); |
|
2279 aSource.PrivRegisterEventCallbackL( ERtpBYE, aCallback, aPtr ); |
|
2280 aSource.PrivRegisterEventCallbackL( ERtpSessionFail, aCallback, aPtr ); |
|
2281 aSource.PrivRegisterEventCallbackL( ERtpSourceFail, aCallback, aPtr ); |
|
2282 |
|
2283 // Ping Timer |
|
2284 if ( !aPtr->iRtspPingTimer ) |
|
2285 { |
|
2286 aPtr->iRtspPingTimer = CPeriodic::NewL( CActive::EPriorityLow ); |
|
2287 aPtr->iRtspPingTimer->Start( |
|
2288 KDVR10Seconds, 2 * KDVR10Seconds, TCallBack( SendRtspPing, aPtr ) ); |
|
2289 } |
|
2290 |
|
2291 aEvent.Session().SendAPPL( KCRCName() ); |
|
2292 aEvent.Session().SetRTCPAutoSend( ETrue ); |
|
2293 } |
|
2294 |
|
2295 // ----------------------------------------------------------------------------- |
|
2296 // CCRRtspPacketSource::SendAuthDescribeL |
|
2297 // ----------------------------------------------------------------------------- |
|
2298 // |
|
2299 void CCRRtspPacketSource::SendAuthDescribeL( ) |
|
2300 { |
|
2301 delete iPrevCommands[ERTSPDescSent]; |
|
2302 iPrevCommands[ERTSPDescSent] = NULL; |
|
2303 iPrevCommands[ERTSPDescSent] = CCRRtspCommand::NewL(); |
|
2304 iPrevCommands[ERTSPDescSent]->SetCommand ( |
|
2305 CCRRtspCommand::ERTSPCommandDESCRIBE ); |
|
2306 TPtrC8 uriDes ( iRtspUri8->Des() ); |
|
2307 iPrevCommands[ERTSPDescSent]->SetURL ( uriDes ); |
|
2308 iPrevCommands[ERTSPDescSent]->SetCSeq ( iCSeq ++ ); |
|
2309 |
|
2310 if ( iAuthType ) |
|
2311 { |
|
2312 iPrevCommands[ERTSPDescSent]->SetAuthenticationTypeL( iAuthType->Des() ); |
|
2313 } |
|
2314 if ( iNonce ) |
|
2315 { |
|
2316 iPrevCommands[ERTSPDescSent]->SetNonceL( iNonce->Des() ); |
|
2317 } |
|
2318 if ( iRealm ) |
|
2319 { |
|
2320 iPrevCommands[ERTSPDescSent]->SetRealmL( iRealm->Des() ); |
|
2321 } |
|
2322 if ( iOpaque ) |
|
2323 { |
|
2324 iPrevCommands[ERTSPDescSent]->SetOpaqueL( iOpaque->Des() ); |
|
2325 } |
|
2326 if ( iUserAgent ) |
|
2327 { |
|
2328 iPrevCommands[ERTSPDescSent]->SetUserAgentL( *iUserAgent ); |
|
2329 } |
|
2330 if ( iWapProfile ) |
|
2331 { |
|
2332 iPrevCommands[ERTSPDescSent]->SetWapProfileL( *iWapProfile ); |
|
2333 } |
|
2334 if ( iBandwidth ) |
|
2335 { |
|
2336 iPrevCommands[ERTSPDescSent]->SetBandwidth( iBandwidth ); |
|
2337 } |
|
2338 |
|
2339 iPrevCommands[ERTSPDescSent]->SetUserNameL( iUserName->Des() ); |
|
2340 iPrevCommands[ERTSPDescSent]->SetPassWdL( iPassword->Des() ); |
|
2341 iPrevCommands[ERTSPDescSent]->SetRtspUriL( iRtspUri->Des() ); |
|
2342 iPrevCommands[ERTSPDescSent]->SetAuthentication ( iAuthenticationNeeded ); |
|
2343 if ( iRtspSock ) |
|
2344 { |
|
2345 iRtspSock->SendData( iPrevCommands[ERTSPDescSent]->ProduceL() ); |
|
2346 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
2347 } |
|
2348 iStage = ERTSPDescSent; |
|
2349 } |
|
2350 |
|
2351 // ----------------------------------------------------------------------------- |
|
2352 // CCRRtspPacketSource::AddAuthenticationL |
|
2353 // ----------------------------------------------------------------------------- |
|
2354 // |
|
2355 void CCRRtspPacketSource::AddAuthenticationL( TInt aCommand ) |
|
2356 { |
|
2357 if ( iPrevCommands[aCommand] && iNonce && |
|
2358 iOpaque && iUserName && iPassword ) |
|
2359 { |
|
2360 iPrevCommands[aCommand]->SetAuthenticationTypeL( iAuthType->Des() ); |
|
2361 iPrevCommands[aCommand]->SetNonceL( iNonce->Des() ); |
|
2362 iPrevCommands[aCommand]->SetRealmL( iRealm->Des() ); |
|
2363 iPrevCommands[aCommand]->SetOpaqueL( iOpaque->Des() ); |
|
2364 iPrevCommands[aCommand]->SetUserNameL( iUserName->Des() ); |
|
2365 iPrevCommands[aCommand]->SetPassWdL( iPassword->Des() ); |
|
2366 iPrevCommands[aCommand]->SetRtspUriL( iRtspUri->Des() ); |
|
2367 iPrevCommands[aCommand]->SetAuthentication ( iAuthenticationNeeded ); |
|
2368 } |
|
2369 } |
|
2370 |
|
2371 // ----------------------------------------------------------------------------- |
|
2372 // CCRRtspPacketSource::PunchPacketsSent |
|
2373 // ----------------------------------------------------------------------------- |
|
2374 // |
|
2375 void CCRRtspPacketSource::PunchPacketsSent( CCRPunchPacketSender* aPuncher ) |
|
2376 { |
|
2377 if ( iPunchPacketSenderVideo && aPuncher == iPunchPacketSenderVideo ) |
|
2378 { |
|
2379 iPunchPacketSentForVideo = ETrue; |
|
2380 } |
|
2381 if ( iPunchPacketSenderAudio && aPuncher == iPunchPacketSenderAudio ) |
|
2382 { |
|
2383 iPunchPacketSentForAudio = ETrue; |
|
2384 } |
|
2385 if ( ( iPunchPacketSenderVideo && !iPunchPacketSenderAudio && |
|
2386 iPunchPacketSentForVideo ) || |
|
2387 ( !iPunchPacketSenderVideo && iPunchPacketSenderAudio && |
|
2388 iPunchPacketSentForAudio ) || |
|
2389 ( iPunchPacketSenderVideo && iPunchPacketSenderAudio && |
|
2390 iPunchPacketSentForVideo && iPunchPacketSentForAudio ) ) |
|
2391 { |
|
2392 LOG1( "PunchPacketsSent, play readiness: %d", iReadyToPlay ); |
|
2393 SetupSessionsAndPlay(); |
|
2394 } |
|
2395 } |
|
2396 |
|
2397 // ----------------------------------------------------------------------------- |
|
2398 // CCRRtspPacketSource::SetupSessionsAndPlay |
|
2399 // ----------------------------------------------------------------------------- |
|
2400 // |
|
2401 void CCRRtspPacketSource::SetupSessionsAndPlay() |
|
2402 { |
|
2403 // all needed punch packets are sent: |
|
2404 if ( SetupRTPSessions() != KErrNone ) |
|
2405 { |
|
2406 iOwningSession.SourceStop(); |
|
2407 } |
|
2408 else |
|
2409 { |
|
2410 // if we're ready to play, play |
|
2411 if ( iReadyToPlay ) |
|
2412 { |
|
2413 TRAPD( err, SendPlayCommandL() ); |
|
2414 if ( err != KErrNone ) |
|
2415 { |
|
2416 iOwningSession.SourceStop(); |
|
2417 } |
|
2418 } |
|
2419 else |
|
2420 { |
|
2421 iStage = ERTSPReadyToPlay; |
|
2422 } |
|
2423 } |
|
2424 } |
|
2425 |
|
2426 // ----------------------------------------------------------------------------- |
|
2427 // CCRRtspPacketSource::SendPunchPackets |
|
2428 // ----------------------------------------------------------------------------- |
|
2429 // |
|
2430 void CCRRtspPacketSource::SendPunchPacketsL( void ) |
|
2431 { |
|
2432 LOG( "CCRRtspPacketSource::SendPunchPacketsL in" ); |
|
2433 delete iPunchPacketSenderAudio; |
|
2434 iPunchPacketSenderAudio = NULL; |
|
2435 delete iPunchPacketSenderVideo; |
|
2436 iPunchPacketSenderVideo = NULL; |
|
2437 |
|
2438 if ( iSdpParser &&iRtspSock && iResponses[ERTSPSetupVideoSent] ) |
|
2439 { |
|
2440 TInetAddr localAddr = iRtspSock->LocalAddr(); |
|
2441 TInetAddr remoteAddr = iRtspSock->ConnectedAddr(); |
|
2442 localAddr.SetPort(iResponses[ERTSPSetupVideoSent]->ClientPort()); |
|
2443 remoteAddr.SetPort(iResponses[ERTSPSetupVideoSent]->ServerPort()); |
|
2444 iPunchPacketSenderVideo = CCRPunchPacketSender::NewL( |
|
2445 iConnection.Connection(), iSockServer, |
|
2446 localAddr, remoteAddr, 0, *this ); |
|
2447 } |
|
2448 if ( iSdpParser && iRtspSock && iResponses[ERTSPSetupAudioSent] ) |
|
2449 { |
|
2450 TInetAddr localAddr = iRtspSock->LocalAddr(); |
|
2451 TInetAddr remoteAddr = iRtspSock->ConnectedAddr(); |
|
2452 localAddr.SetPort(iResponses[ERTSPSetupAudioSent]->ClientPort()); |
|
2453 remoteAddr.SetPort(iResponses[ERTSPSetupAudioSent]->ServerPort()); |
|
2454 iPunchPacketSenderAudio = CCRPunchPacketSender::NewL( |
|
2455 iConnection.Connection(), iSockServer, |
|
2456 localAddr, remoteAddr, 0, *this ); |
|
2457 } |
|
2458 } |
|
2459 |
|
2460 // ----------------------------------------------------------------------------- |
|
2461 // CCRRtspPacketSource::ConnectionStatusChange |
|
2462 // ----------------------------------------------------------------------------- |
|
2463 // |
|
2464 void CCRRtspPacketSource::ConnectionStatusChange( |
|
2465 TInt /*aSessionId*/, |
|
2466 TCRConnectionStatus aStatus, |
|
2467 TInt /* aErr */ ) |
|
2468 { |
|
2469 switch( aStatus ) |
|
2470 { |
|
2471 // Connection has gone up or bearer has changed -> check bandwidth |
|
2472 case ECRBearerChanged: |
|
2473 { |
|
2474 LOG( "CCRRtspPacketSource::ConnectionStatusChange: IapUp or IapUp2G" ); |
|
2475 if ( iSdpParser && iObserver ) |
|
2476 { |
|
2477 // Unknown bitrate or bandwidth are returned as zero. Bitrates in kbit/s |
|
2478 TInt bitrate( iSdpParser->VideoBitrate() + |
|
2479 iSdpParser->AudioBitrate() ); |
|
2480 TInt bandwidth( iConnection.MaximumBandwidth() / 1000 ); |
|
2481 if ( bitrate > 0 && bandwidth > 0 && bandwidth < bitrate ) |
|
2482 { |
|
2483 LOG2( "CCRRtspPacketSource::ConnectionStatusChange: clip_bitrate: %d, connection_bandwidth: %d -> NotEnoughBandwidth", |
|
2484 bitrate, bandwidth ); |
|
2485 iObserver->ConnectionStatusChange( |
|
2486 iOwningSession.SourceChecksum(), ECRNotEnoughBandwidth, KErrNone ); |
|
2487 } |
|
2488 } |
|
2489 break; |
|
2490 } |
|
2491 |
|
2492 // Connection has gone down or error occured -> switch back to RTP/UDP transport |
|
2493 case ECRConnectionError: |
|
2494 case ECRIapDown: |
|
2495 { |
|
2496 LOG( "CCRRtspPacketSource::ConnectionStatusChange: IapDown or ConnectionError -> switch to RTP/UDP streaming" ); |
|
2497 iConnection.SetHeuristic( CCRConnection::EUdpStreamingBlocked, EFalse ); |
|
2498 break; |
|
2499 } |
|
2500 |
|
2501 // Nothing to do for: |
|
2502 // ECRConnecting |
|
2503 // ECRAuthenticationNeeded |
|
2504 // ECRNotEnoughBandwidth |
|
2505 // ECRNormalEndOfStream |
|
2506 default: |
|
2507 { |
|
2508 LOG1( "CCRRtspPacketSource::ConnectionStatusChange: unhandled status: %d", aStatus ); |
|
2509 break; |
|
2510 } |
|
2511 } |
|
2512 } |
|
2513 |
|
2514 // ----------------------------------------------------------------------------- |
|
2515 // CCRRtspPacketSource::RegisterConnectionObs |
|
2516 // ----------------------------------------------------------------------------- |
|
2517 // |
|
2518 void CCRRtspPacketSource::RegisterConnectionObs( MCRConnectionObserver* aObserver ) |
|
2519 { |
|
2520 iObserver = aObserver; |
|
2521 } |
|
2522 |
|
2523 // ----------------------------------------------------------------------------- |
|
2524 // CCRRtspPacketSource::UnregisterConnectionObs |
|
2525 // ----------------------------------------------------------------------------- |
|
2526 // |
|
2527 void CCRRtspPacketSource::UnregisterConnectionObs( ) |
|
2528 { |
|
2529 iObserver = NULL; |
|
2530 } |
|
2531 |
|
2532 // ----------------------------------------------------------------------------- |
|
2533 // CCRRtspPacketSource::SetRtpSession |
|
2534 // ----------------------------------------------------------------------------- |
|
2535 // |
|
2536 void CCRRtspPacketSource::SetRtpSession( |
|
2537 RRtpSession& aSession, |
|
2538 TReal aGranularity ) |
|
2539 { |
|
2540 // Unit is 1/second |
|
2541 __ASSERT_DEBUG( iSdpParser != NULL, User::Panic( _L( "RTSP source" ), KErrBadHandle ) ); |
|
2542 TUint32 howManyNanoSecondsIsOneTick( |
|
2543 ( TUint32 )( TReal( 1000000000.0L ) / aGranularity ) ); |
|
2544 LOG1( "CCRRtspPacketSource::SetRtpSession clock tick: %u", howManyNanoSecondsIsOneTick ); |
|
2545 aSession.SetRTPTimeConversion( 0, howManyNanoSecondsIsOneTick ); |
|
2546 aSession.SetRtpStreamParameters( KDVRMinSequential, // 1 |
|
2547 KDVRMaxMisorder, // 50 |
|
2548 KDVRMaxDropOut ); // 3000 |
|
2549 } |
|
2550 |
|
2551 // ----------------------------------------------------------------------------- |
|
2552 // CCRRtspPacketSource::SendRtspPing |
|
2553 // ----------------------------------------------------------------------------- |
|
2554 // |
|
2555 TInt CCRRtspPacketSource::SendRtspPing( TAny* aSelfPtr ) |
|
2556 { |
|
2557 CCRRtspPacketSource* ptr = static_cast<CCRRtspPacketSource*> ( aSelfPtr ); |
|
2558 TRAPD( err, ptr->SendOptionsCommandL() ); |
|
2559 return err; |
|
2560 } |
|
2561 |
|
2562 // ----------------------------------------------------------------------------- |
|
2563 // CCRRtspPacketSource::ConstructSeqAndTsForSink |
|
2564 // ----------------------------------------------------------------------------- |
|
2565 // |
|
2566 void CCRRtspPacketSource::ConstructSeqAndTsForSink ( |
|
2567 MCRPacketSource::TCRPacketStreamId aStreamId, |
|
2568 TUint32 aMSWTimestamp, |
|
2569 TUint32 aLSWTimestamp, |
|
2570 TUint32 aRTPTimestamp, |
|
2571 TUint aSeq ) |
|
2572 { |
|
2573 switch ( aStreamId ) |
|
2574 { |
|
2575 case EAudioStream: |
|
2576 if ( iRTPTimeStampAudio ) |
|
2577 { |
|
2578 iSeqFromRtpInfoForAudio = aSeq; |
|
2579 if ( iSeqFromRtpInfoForAudio == 0 ) |
|
2580 { |
|
2581 iSeqFromRtpInfoForAudio++; |
|
2582 } |
|
2583 LOG1( "CCRRtspPacketSource::ConstructSeqAndTsForSink(), Audio seq: %d ", ( int )aSeq ); |
|
2584 // We may declare that we have seq+ts if we're here and have only audio or |
|
2585 // if we're here and have both audio and video and have also seq for video |
|
2586 if ( ( iSdpParser->SupportedContent() == CDvrSdpParser::EDvrAudioOnly ) || |
|
2587 ( iSdpParser->SupportedContent() == CDvrSdpParser::EDvrBothAudioAndVideo && |
|
2588 iSeqFromRtpInfoForVideo && iRTPTimeStampVideo ) ) |
|
2589 { |
|
2590 iSessionObs.StatusChanged( |
|
2591 MCRPacketSource::ERtpStateSeqAndTSAvailable ); |
|
2592 iNoRtpInfoHeader = EFalse; |
|
2593 if ( iStage == ERTSPPlaying ) |
|
2594 { |
|
2595 iSessionObs.StatusChanged( |
|
2596 MCRPacketSource::ERtpStatePlaying ); |
|
2597 } |
|
2598 } |
|
2599 } |
|
2600 break; |
|
2601 |
|
2602 case EAudioControlStream: |
|
2603 if ( !iMSWTimestamp ) |
|
2604 { // no wall clock time yet set |
|
2605 iMSWTimestamp = aMSWTimestamp; |
|
2606 iLSWTimestamp = aLSWTimestamp; |
|
2607 iRTPTimeStampAudio = aRTPTimestamp; |
|
2608 if ( iRTPTimeStampAudio == 0 ) |
|
2609 { |
|
2610 iRTPTimeStampAudio++; |
|
2611 } |
|
2612 } |
|
2613 else |
|
2614 { |
|
2615 // Sync audio with video |
|
2616 TInt64 wallClockOfVideo = MAKE_TINT64 ( iMSWTimestamp , iLSWTimestamp ); |
|
2617 TInt64 wallClockOfAudio = MAKE_TINT64 ( aMSWTimestamp , aLSWTimestamp ); |
|
2618 // Then figure out the difference. unit is now difficult ; upper |
|
2619 // 32 bits contain whole seconds, lower contains fraction |
|
2620 TInt64 wallClockDifference( wallClockOfVideo - wallClockOfAudio ); |
|
2621 // Now, the aRTPTimestamp has different scale, declared in SDP. |
|
2622 // first make one second that has same scale as wallClockDifference |
|
2623 TInt64 granularity( MAKE_TINT64( 1, 0 ) ); |
|
2624 // Then divide that one second with the given granularity. variable |
|
2625 // granularity will now contain in its low 32 bits the fraction of the |
|
2626 // second that re-presents one clock tick (e.g. 1/90000 sec for video) |
|
2627 granularity = granularity / static_cast<TInt64>( |
|
2628 iSdpParser->AudioTimerGranularity() ); |
|
2629 // Then divide our difference with this fraction of second |
|
2630 TInt64 wallClockDifferenceGranular = wallClockDifference / granularity; |
|
2631 // unit of wallClockDifferenceGranular is now 2^32 / granularity |
|
2632 TInt32 wallClockDifferenceGranular32 = wallClockDifferenceGranular; |
|
2633 LOG2( "CCRRtspPacketSource::ConstructSeqAndTsForSink(), Audio ts: %u adjust by: %d", |
|
2634 aRTPTimestamp , wallClockDifferenceGranular32 ); |
|
2635 iRTPTimeStampAudio = aRTPTimestamp + wallClockDifferenceGranular32; |
|
2636 if ( iRTPTimeStampAudio == 0 ) |
|
2637 { |
|
2638 iRTPTimeStampAudio++; |
|
2639 } |
|
2640 } |
|
2641 break; |
|
2642 |
|
2643 case EVideoStream: |
|
2644 if ( iRTPTimeStampVideo ) |
|
2645 { |
|
2646 iSeqFromRtpInfoForVideo = aSeq; |
|
2647 if ( iSeqFromRtpInfoForVideo == 0 ) |
|
2648 { |
|
2649 iSeqFromRtpInfoForVideo++; |
|
2650 } |
|
2651 LOG1( "CCRRtspPacketSource::ConstructSeqAndTsForSink(), Video seq: %d ", |
|
2652 ( int )aSeq ); |
|
2653 |
|
2654 // We may declare that we have seq+ts if we're here and have only video or |
|
2655 // if we're here and have both and have also seq for video |
|
2656 if ( ( iSdpParser->SupportedContent() == CDvrSdpParser::EDvrVideoOnly ) || |
|
2657 ( iSdpParser->SupportedContent() == CDvrSdpParser::EDvrBothAudioAndVideo && |
|
2658 iSeqFromRtpInfoForAudio && iRTPTimeStampAudio ) ) |
|
2659 { |
|
2660 iSessionObs.StatusChanged( |
|
2661 MCRPacketSource::ERtpStateSeqAndTSAvailable ); |
|
2662 iNoRtpInfoHeader = EFalse; |
|
2663 if ( iStage == ERTSPPlaying ) |
|
2664 { |
|
2665 iSessionObs.StatusChanged( |
|
2666 MCRPacketSource::ERtpStatePlaying ); |
|
2667 } |
|
2668 } |
|
2669 } |
|
2670 break; |
|
2671 |
|
2672 case EVideoControlStream: |
|
2673 if ( !iMSWTimestamp ) |
|
2674 { // No wall clock time yet set |
|
2675 iMSWTimestamp = aMSWTimestamp; |
|
2676 iLSWTimestamp = aLSWTimestamp; |
|
2677 iRTPTimeStampVideo = aRTPTimestamp; |
|
2678 if ( iRTPTimeStampVideo == 0 ) |
|
2679 { |
|
2680 iRTPTimeStampVideo++; |
|
2681 } |
|
2682 } |
|
2683 else |
|
2684 { |
|
2685 // Sync audio with video |
|
2686 TInt64 wallClockOfAudio = MAKE_TINT64 ( iMSWTimestamp , iLSWTimestamp ); |
|
2687 TInt64 wallClockOfVideo = MAKE_TINT64 ( aMSWTimestamp , aLSWTimestamp ); |
|
2688 // Then figure out the difference. unit is now difficult ; upper |
|
2689 // 32 bits contain whole seconds, lower contains fraction |
|
2690 TInt64 wallClockDifference( wallClockOfAudio - wallClockOfVideo ); |
|
2691 // Now, the aRTPTimestamp has different scale, declared in SDP. |
|
2692 // first make one second that has same scale as wallClockDifference |
|
2693 TInt64 granularity( MAKE_TINT64( 1, 0 ) ); |
|
2694 // Then divide that one second with the given granularity. variable |
|
2695 // granularity will now contain in its low 32 bits the fraction of the |
|
2696 // second that re-presents one clock tick (e.g. 1/90000 sec for video) |
|
2697 granularity = granularity / static_cast<TInt64>( |
|
2698 iSdpParser->VideoTimerGranularity()); |
|
2699 // Then divide our difference with this fraction of second |
|
2700 TInt64 wallClockDifferenceGranular = wallClockDifference / granularity; |
|
2701 // Unit of wallClockDifferenceGranular is now 2^32 / granularity |
|
2702 TInt32 wallClockDifferenceGranular32 = wallClockDifferenceGranular; |
|
2703 LOG2( "CCRRtspPacketSource::ConstructSeqAndTsForSink(), Video ts: %u adjust by: %d", |
|
2704 aRTPTimestamp , wallClockDifferenceGranular32 ); |
|
2705 iRTPTimeStampVideo = aRTPTimestamp + wallClockDifferenceGranular32; |
|
2706 if ( iRTPTimeStampVideo == 0 ) |
|
2707 { |
|
2708 iRTPTimeStampVideo++; |
|
2709 } |
|
2710 } |
|
2711 break; |
|
2712 |
|
2713 default: |
|
2714 // no thing |
|
2715 break; |
|
2716 } |
|
2717 } |
|
2718 |
|
2719 // ----------------------------------------------------------------------------- |
|
2720 // CCRRtspPacketSource::ConditionallySetupMultiCastOrTcpStreamingL |
|
2721 // ----------------------------------------------------------------------------- |
|
2722 // |
|
2723 void CCRRtspPacketSource::ConditionallySetupMultiCastOrTcpStreamingL ( void ) |
|
2724 { |
|
2725 // UDP: Punch packets or play sent in ProcessRTSPResponseL, so do nothing. |
|
2726 if ( iTransport == ERTPOverUDP ) |
|
2727 { |
|
2728 } |
|
2729 // Multicast: no punch packets needed but session setup yes |
|
2730 else if ( iTransport == ERTPOverMulticast ) |
|
2731 { |
|
2732 SetupSessionsAndPlay(); |
|
2733 } |
|
2734 |
|
2735 // TCP: no punch packets or session, just send PLAY .. but wait for UI |
|
2736 else if ( iTransport == ERTPOverTCP ) |
|
2737 { |
|
2738 if ( iReadyToPlay ) |
|
2739 { |
|
2740 SendPlayCommandL(); |
|
2741 } |
|
2742 else |
|
2743 { |
|
2744 iStage = ERTSPReadyToPlay; |
|
2745 } |
|
2746 } |
|
2747 } |
|
2748 |
|
2749 // ----------------------------------------------------------------------------- |
|
2750 // CCRRtspPacketSource::CheckReceiveOfStreams |
|
2751 // ----------------------------------------------------------------------------- |
|
2752 // |
|
2753 TBool CCRRtspPacketSource::CheckReceiveOfStreams() |
|
2754 { |
|
2755 TBool retVal( ETrue ); |
|
2756 |
|
2757 // Go through all streams and check that all streams have receive flag on, |
|
2758 // if not return false. |
|
2759 for ( TInt i = 0 ; i < iReceiveStreams.Count() ; i++ ) |
|
2760 { |
|
2761 if ( iReceiveStreams[i].iDataReceived == EFalse ) |
|
2762 { |
|
2763 LOG1( "CCRRtspPacketSource::CheckReceiveOfStreams - Missing atleast stream %d", iReceiveStreams[i].iStreamType ); |
|
2764 retVal = EFalse; |
|
2765 break; |
|
2766 } |
|
2767 } |
|
2768 |
|
2769 if ( retVal ) |
|
2770 { |
|
2771 LOG( "CCRRtspPacketSource::CheckReceiveOfStreams - Receiving from all streams!" ); |
|
2772 } |
|
2773 |
|
2774 return retVal; |
|
2775 } |
|
2776 |
|
2777 // ----------------------------------------------------------------------------- |
|
2778 // CCRRtspPacketSource::StreamFound |
|
2779 // ----------------------------------------------------------------------------- |
|
2780 // |
|
2781 void CCRRtspPacketSource::StreamFound( TCRPacketStreamId aStreamType ) |
|
2782 { |
|
2783 // Go through streams and find correct stream to set the receive flag. |
|
2784 for ( TInt i = 0 ; i < iReceiveStreams.Count(); i++ ) |
|
2785 { |
|
2786 if ( iReceiveStreams[i].iStreamType == aStreamType ) |
|
2787 { |
|
2788 iReceiveStreams[i].iDataReceived = ETrue; |
|
2789 LOG1( "CCRRtspPacketSource::StreamFound - Stream %d found", iReceiveStreams[i].iStreamType ); |
|
2790 break; |
|
2791 } |
|
2792 } |
|
2793 } |
|
2794 |
|
2795 // ----------------------------------------------------------------------------- |
|
2796 // CCRRtspPacketSource::ResetStreamFlags |
|
2797 // ----------------------------------------------------------------------------- |
|
2798 // |
|
2799 void CCRRtspPacketSource::ResetStreamFlags( ) |
|
2800 { |
|
2801 // Go through streams and clear receiving flag. |
|
2802 for ( TInt i = 0 ; i < iReceiveStreams.Count() ; i++ ) |
|
2803 { |
|
2804 iReceiveStreams[i].iDataReceived = EFalse; |
|
2805 } |
|
2806 |
|
2807 // We have to check receive again |
|
2808 iTrafficFound = EFalse; |
|
2809 } |
|
2810 |
|
2811 #if defined ( LIVE_TV_FILE_TRACE ) || defined ( LIVE_TV_RDEBUG_TRACE ) |
|
2812 // ----------------------------------------------------------------------------- |
|
2813 // CCRRtspPacketSource::ShowHeader |
|
2814 // ----------------------------------------------------------------------------- |
|
2815 // |
|
2816 void CCRRtspPacketSource::ShowHeader( |
|
2817 const TDesC8& aRtcpHeader, |
|
2818 const TCRRtpSRReportHeader& aSrReport ) |
|
2819 { |
|
2820 TBuf<100> b( KNullDesC ); |
|
2821 LOG1( "CCRRtspPacketSource::TCP control packet len: %d", aRtcpHeader.Length() ); |
|
2822 for ( TInt j( 0 ); j < 32 && j < aRtcpHeader.Length(); j++ ) |
|
2823 { |
|
2824 b.AppendFormat( _L( "%2X " ), ( unsigned )( aRtcpHeader[j] ) ); |
|
2825 if ( j > 0 && ( ( j % 16 ) == 0 ) ) |
|
2826 { |
|
2827 LOG2( "%d -> %S", j, &b ); |
|
2828 b.Zero(); |
|
2829 } |
|
2830 } |
|
2831 |
|
2832 LOG1( "iVersion %u", ( unsigned )aSrReport.iVersion ); |
|
2833 LOG1( "iPadding %u", ( unsigned )aSrReport.iPadding ); |
|
2834 LOG1( "iReportCount %u",( unsigned )aSrReport.iReportCount ); |
|
2835 LOG1( "iPacketType %u", ( unsigned )aSrReport.iPacketType ); |
|
2836 LOG1( "iLength %u", |
|
2837 ( unsigned)BigEndian::Get16( ( const TUint8* )&aSrReport.iLength ) ); |
|
2838 LOG1( "iSenderSSRC %u", |
|
2839 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iSenderSSRC ) ); |
|
2840 LOG1( "iMSWTimestamp %u", |
|
2841 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iMSWTimestamp) ); |
|
2842 LOG1( "iLSWTimestamp %u", |
|
2843 ( unsigned)BigEndian::Get32( ( const TUint8* )&aSrReport.iLSWTimestamp ) ); |
|
2844 LOG1( "iRTPTimestamp %u", |
|
2845 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iRTPTimestamp ) ); |
|
2846 LOG1( "iSenderPacketCount %u", |
|
2847 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iSenderPacketCount) ); |
|
2848 LOG1( "iSenderOctetCount %u", |
|
2849 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iSenderOctetCount ) ); |
|
2850 |
|
2851 } |
|
2852 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
2853 |
|
2854 // End of File |