|
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 // If we see that we don't need to send further setups, |
|
842 // do send punch packets now. |
|
843 if ( iSdpParser && // if we have sdp parser |
|
844 ( iSdpParser->VideoControlAddr().Length() && // and it shows we have video |
|
845 iResponses[ERTSPSetupVideoSent] && // and we have video se tup |
|
846 iSdpParser->AudioControlAddr().Length() && // and it shows we have audio |
|
847 iResponses[ERTSPSetupAudioSent] ) || // and we have audio set up |
|
848 ( !iSdpParser->VideoControlAddr().Length() && // or it shows we have no video |
|
849 !iResponses[ERTSPSetupVideoSent] && // and we've video not set up |
|
850 iSdpParser->AudioControlAddr().Length() && // and it shows we have audio |
|
851 iResponses[ERTSPSetupAudioSent] ) || // and we've audio set up |
|
852 ( iSdpParser->VideoControlAddr().Length() && // or it shows we've video |
|
853 iResponses[ERTSPSetupVideoSent] && // and we have video set up |
|
854 !iSdpParser->AudioControlAddr().Length() && // and we have no audio |
|
855 !iResponses[ERTSPSetupAudioSent] ) )// and we have no audio set up |
|
856 { |
|
857 // Only send punch packets for UDP transport |
|
858 // TCP or multicast: session setup and PLAY in SendRTSPCommand |
|
859 if ( iTransport == ERTPOverUDP ) |
|
860 { |
|
861 SendPunchPacketsL(); |
|
862 } |
|
863 } |
|
864 |
|
865 // Notify sink that SETUP repply received |
|
866 iSessionObs.StatusChanged( |
|
867 MCRPacketSource::ERtpStateSetupRepply ); |
|
868 break; |
|
869 |
|
870 case ERTSPDescSent: // From desc take sdp |
|
871 if ( iObserver && iResponses[iStage]->ContentLen() <= 0 ) |
|
872 { |
|
873 // This should not happen |
|
874 if ( iObserver ) |
|
875 { |
|
876 iObserver->ConnectionStatusChange( |
|
877 iOwningSession.SourceChecksum(), ECRConnectionError, KErrUnderflow ); |
|
878 } |
|
879 iOwningSession.SourceStop(); |
|
880 } |
|
881 else |
|
882 { |
|
883 delete iSdpParser; iSdpParser = NULL; |
|
884 iSdpParser = CDvrSdpParser::NewL(); |
|
885 if ( iResponses[iStage]->ContentBase().Length() ) |
|
886 { |
|
887 iSdpParser->TryParseL( iResponses[iStage]->Content(), |
|
888 iResponses[iStage]->ContentBase() ); |
|
889 } |
|
890 else |
|
891 { |
|
892 iSdpParser->TryParseL( iResponses[iStage]->Content(), |
|
893 iRtspUri8->Des() ); |
|
894 } |
|
895 // Check for multicast address in SDP |
|
896 if ( iSdpParser->IsMultiCastSdp() ) |
|
897 { |
|
898 iTransport = ERTPOverMulticast; |
|
899 } |
|
900 if ( iObserver && iSdpParser->IsRealMediaContent() ) |
|
901 { |
|
902 iObserver->ConnectionStatusChange( |
|
903 iOwningSession.SourceChecksum(), |
|
904 ECRStreamIsRealMedia, KErrNotSupported ); |
|
905 iOwningSession.SourceStop(); |
|
906 return; // Make sure we don't continue with SETUP commands |
|
907 } |
|
908 else // do not send realmedia sdp to sinks |
|
909 { |
|
910 if ( iObserver && iSdpParser->IsLiveStream() ) |
|
911 { |
|
912 iObserver->ConnectionStatusChange( |
|
913 iOwningSession.SourceChecksum(), |
|
914 ECRStreamIsLiveStream, KErrNone ); |
|
915 } |
|
916 |
|
917 // then check for bandwidth requirements even before we start: |
|
918 if ( iObserver ) |
|
919 { |
|
920 // Unknown bitrate or bandwidth are returned as zero. |
|
921 // Bitrates in kbit/s |
|
922 TInt bitrate( iSdpParser->VideoBitrate() + |
|
923 iSdpParser->AudioBitrate() ); |
|
924 TInt bandwidth( iConnection.MaximumBandwidth() / 1000 ); |
|
925 if ( bitrate && bandwidth && bandwidth < bitrate ) |
|
926 { |
|
927 LOG2( "CCRRtspPacketSource::ProcessRtspResponseL(), bitrate:%d, bandwidth: %d -> NotEnoughBandwidth", |
|
928 bitrate, bandwidth); |
|
929 iObserver->ConnectionStatusChange( |
|
930 iOwningSession.SourceChecksum(), |
|
931 ECRNotEnoughBandwidth, KErrNone ); |
|
932 return; // Make sure we don't tell sinks anything about |
|
933 // sdp that has too high bitrate for our network bearer |
|
934 } |
|
935 } |
|
936 |
|
937 // But if we didn't have realmedia stream and the bandwidth check |
|
938 // is also all right, then go on and tell the sinks -> |
|
939 iSessionObs.StatusChanged( |
|
940 MCRPacketSource::ERtpStateSdpAvailable ); |
|
941 } |
|
942 } |
|
943 break; |
|
944 |
|
945 case ERTSPPlaySent: |
|
946 { |
|
947 CCRRtspResponse::SRTPInfoHeader rtpInfo; |
|
948 iResponses[ERTSPPlaySent]->RTPInfoHeader( rtpInfo ); |
|
949 |
|
950 TPtrC8 videoAddr ( NULL, 0 ); |
|
951 if ( iSdpParser->VideoControlAddr().Length() ) |
|
952 { |
|
953 videoAddr.Set ( iSdpParser->VideoControlAddr() ); |
|
954 } |
|
955 TPtrC8 audioAddr ( NULL , 0 ); |
|
956 if ( iSdpParser->AudioControlAddr().Length() ) |
|
957 { |
|
958 audioAddr.Set ( iSdpParser->AudioControlAddr() ); |
|
959 } |
|
960 |
|
961 if ( iSdpParser->VideoControlAddr().Length() && |
|
962 rtpInfo.iFirstURL.Length() && |
|
963 videoAddr.Find( rtpInfo.iFirstURL ) >= 0 ) |
|
964 { |
|
965 iRTPTimeStampVideo = rtpInfo.iFirstTS ? rtpInfo.iFirstTS : 1; |
|
966 iSeqFromRtpInfoForVideo = rtpInfo.iFirstSeq; |
|
967 } |
|
968 if ( iSdpParser->VideoControlAddr().Length() && |
|
969 rtpInfo.iSecondURL.Length() && |
|
970 videoAddr.Find( rtpInfo.iSecondURL ) >= 0 ) |
|
971 { |
|
972 iRTPTimeStampVideo = rtpInfo.iSecondTS ? rtpInfo.iSecondTS : 1; |
|
973 iSeqFromRtpInfoForVideo = rtpInfo.iSecondSeq; |
|
974 } |
|
975 if ( iSdpParser->AudioControlAddr().Length() && |
|
976 rtpInfo.iFirstURL.Length() && |
|
977 audioAddr.Find( rtpInfo.iFirstURL) >= 0 ) |
|
978 { |
|
979 iRTPTimeStampAudio = rtpInfo.iFirstTS ? rtpInfo.iFirstTS : 1; |
|
980 iSeqFromRtpInfoForAudio = rtpInfo.iFirstSeq; |
|
981 } |
|
982 if ( iSdpParser->AudioControlAddr().Length() && |
|
983 rtpInfo.iSecondURL.Length() && |
|
984 audioAddr.Find( rtpInfo.iSecondURL) >= 0 ) |
|
985 { |
|
986 iRTPTimeStampAudio = rtpInfo.iSecondTS ? rtpInfo.iSecondTS : 1; |
|
987 iSeqFromRtpInfoForAudio = rtpInfo.iSecondSeq; |
|
988 } |
|
989 |
|
990 // ok, if we don't have rtp-info header, we don't know yet. |
|
991 if ( rtpInfo.iFirstURL.Length() == 0 && |
|
992 rtpInfo.iSecondURL.Length() == 0 ) |
|
993 { |
|
994 iNoRtpInfoHeader++; |
|
995 } |
|
996 else |
|
997 { |
|
998 // We have RTP-info, so control stream is no longer mandatory |
|
999 // Mark control streams as "found" |
|
1000 StreamFound( EAudioControlStream ); |
|
1001 StreamFound( EVideoControlStream ); |
|
1002 //StreamFound( ESubTitleControlStream ); |
|
1003 |
|
1004 iSessionObs.StatusChanged( |
|
1005 MCRPacketSource::ERtpStateSeqAndTSAvailable ); |
|
1006 } |
|
1007 |
|
1008 // Live state |
|
1009 if ( iResponses[ERTSPPlaySent]->IsLiveStream() || iSdpParser->IsLiveStream() ) |
|
1010 { |
|
1011 if ( iObserver ) |
|
1012 { |
|
1013 iObserver->ConnectionStatusChange( |
|
1014 iOwningSession.SourceChecksum(), |
|
1015 ECRStreamIsLiveStream, KErrNone ); |
|
1016 } |
|
1017 } |
|
1018 |
|
1019 // Notify seeking |
|
1020 if ( iObserver ) |
|
1021 { |
|
1022 iObserver->ConnectionStatusChange( |
|
1023 iOwningSession.SourceChecksum(), |
|
1024 ECRReadyToSeek, KErrNone ); |
|
1025 } |
|
1026 } |
|
1027 break; |
|
1028 |
|
1029 default: |
|
1030 // by default extract no information |
|
1031 break; |
|
1032 } |
|
1033 |
|
1034 // Then continue with business: |
|
1035 SendRtspCommandL(); // will change iStage also |
|
1036 } |
|
1037 |
|
1038 // Authentication needed.. |
|
1039 else if ( iResponses[iStage]->StatusCode() == |
|
1040 CCRRtspResponse::ERTSPRespUnauthorized || // 401 |
|
1041 iResponses[iStage]->StatusCode() == |
|
1042 CCRRtspResponse::ERTSPRespProxyAuthenticationRequired ) // 407 |
|
1043 { |
|
1044 iAuthFailedCount++; |
|
1045 if ( iUserName && |
|
1046 iUserName->Length() && |
|
1047 iPassword && |
|
1048 iAuthFailedCount == 1 ) |
|
1049 { |
|
1050 iAuthenticationNeeded = ETrue; |
|
1051 iAuthType = iResponses[iStage]->AuthenticationTypeL().AllocL(); |
|
1052 iRealm = iResponses[iStage]->RealmL().AllocL(); |
|
1053 iOpaque = iResponses[iStage]->OpaqueL().AllocL(); |
|
1054 iNonce = iResponses[iStage]->NonceL().AllocL(); |
|
1055 SendAuthDescribeL(); |
|
1056 } |
|
1057 else |
|
1058 { |
|
1059 iAuthFailedCount = 0; |
|
1060 LOG( "CCRRtspPacketSource::ProcessRtspResponseL() Authentication failure !" ); |
|
1061 |
|
1062 // Cleanup |
|
1063 iOwningSession.SourceStop(); |
|
1064 if ( iObserver ) |
|
1065 { |
|
1066 iObserver->ConnectionStatusChange( |
|
1067 iOwningSession.SourceChecksum(), |
|
1068 ECRAuthenticationNeeded, KErrNone ); |
|
1069 } |
|
1070 } |
|
1071 } |
|
1072 else if ( iResponses[iStage]->StatusCode() == CCRRtspResponse::ERTSPRespUnsupportedTransport ) // 461 |
|
1073 { |
|
1074 LOG1( "CCRRtspPacketSource::ProcessRtspResponseL() - Unsupported Transport: %d", iTransport ); |
|
1075 |
|
1076 if ( iConnection.GetHeuristic( CCRConnection::EUdpStreamingBlocked ) ) |
|
1077 { |
|
1078 // Using TCP, change to UDP |
|
1079 LOG( "CCRRtspPacketSource::ProcessRtspResponseL() - Change TCP to UDP" ); |
|
1080 iConnection.SetHeuristic( CCRConnection::EUdpStreamingBlocked, EFalse ); |
|
1081 // Notify observer at client side: |
|
1082 ProcessRtspErrorResponseL( iResponses[iStage]->StatusCode() ); |
|
1083 } |
|
1084 else |
|
1085 { |
|
1086 // Using UDP, change to TCP |
|
1087 LOG( "CCRRtspPacketSource::ProcessRtspResponseL() - Change UDP to TCP"); |
|
1088 iConnection.SetHeuristic( CCRConnection::EUdpStreamingBlocked, ETrue ); |
|
1089 // Notify observer at client side: |
|
1090 ProcessRtspErrorResponseL( iResponses[iStage]->StatusCode() ); |
|
1091 } |
|
1092 } |
|
1093 else |
|
1094 { |
|
1095 // before doing cleanup, notify observer at client side: |
|
1096 ProcessRtspErrorResponseL( iResponses[iStage]->StatusCode() ); |
|
1097 } |
|
1098 } |
|
1099 } |
|
1100 |
|
1101 // ----------------------------------------------------------------------------- |
|
1102 // CCRRtspPacketSource::ProcessRtspErrorResponseL |
|
1103 // ----------------------------------------------------------------------------- |
|
1104 // |
|
1105 void CCRRtspPacketSource::ProcessRtspErrorResponseL( |
|
1106 CCRRtspResponse::TResponseCode aErrorCode ) |
|
1107 { |
|
1108 SCRQueueEntry entry; |
|
1109 entry.iMsg = ECRMsgQueueConnectionError; |
|
1110 |
|
1111 switch ( aErrorCode ) |
|
1112 { |
|
1113 case CCRRtspResponse::ERTSPRespLowOnStorageSpace: |
|
1114 entry.iErr = KErrGeneral; |
|
1115 break; |
|
1116 |
|
1117 case CCRRtspResponse::ERTSPRespMultipleChoices: |
|
1118 entry.iErr = KErrGeneral; |
|
1119 break; |
|
1120 |
|
1121 case CCRRtspResponse::ERTSPRespMovedPermanently: |
|
1122 entry.iErr = KErrNotFound; |
|
1123 break; |
|
1124 |
|
1125 case CCRRtspResponse::ERTSPRespMovedTemporarily: |
|
1126 entry.iErr = KErrNotFound; |
|
1127 break; |
|
1128 |
|
1129 case CCRRtspResponse::ERTSPRespSeeOther: |
|
1130 entry.iErr = KErrGeneral; |
|
1131 break; |
|
1132 |
|
1133 case CCRRtspResponse::ERTSPRespNotModified: |
|
1134 entry.iErr = KErrGeneral; |
|
1135 break; |
|
1136 |
|
1137 case CCRRtspResponse::ERTSPRespUseProxy: |
|
1138 entry.iErr = KErrGeneral; |
|
1139 break; |
|
1140 |
|
1141 case CCRRtspResponse::ERTSPRespBadRequest: |
|
1142 entry.iErr = KErrGeneral; |
|
1143 break; |
|
1144 |
|
1145 case CCRRtspResponse::ERTSPRespPaymentRequired: |
|
1146 entry.iErr = KErrGeneral; |
|
1147 break; |
|
1148 |
|
1149 case CCRRtspResponse::ERTSPRespForbidden: |
|
1150 entry.iErr = KErrGeneral; |
|
1151 break; |
|
1152 |
|
1153 case CCRRtspResponse::ERTSPRespGone: |
|
1154 case CCRRtspResponse::ERTSPRespConferenceNotFound: |
|
1155 case CCRRtspResponse::ERTSPRespNotFound: |
|
1156 entry.iErr = KErrNotFound; |
|
1157 break; |
|
1158 |
|
1159 case CCRRtspResponse::ERTSPRespMethodNotAllowed: |
|
1160 entry.iErr = KErrGeneral; |
|
1161 break; |
|
1162 |
|
1163 case CCRRtspResponse::ERTSPRespNotAcceptable: |
|
1164 entry.iErr = KErrGeneral; |
|
1165 break; |
|
1166 |
|
1167 case CCRRtspResponse::ERTSPRespRequestTimeOut: |
|
1168 entry.iErr = KErrTimedOut; |
|
1169 break; |
|
1170 |
|
1171 case CCRRtspResponse::ERTSPRespLengthRequired: |
|
1172 entry.iErr = KErrGeneral; |
|
1173 break; |
|
1174 |
|
1175 case CCRRtspResponse::ERTSPRespPreconditionFailed: |
|
1176 entry.iErr = KErrGeneral; |
|
1177 break; |
|
1178 |
|
1179 case CCRRtspResponse::ERTSPRespRequestEntityTooLarge: |
|
1180 entry.iErr = KErrGeneral; |
|
1181 break; |
|
1182 |
|
1183 case CCRRtspResponse::ERTSPRespRequestURITooLarge: |
|
1184 entry.iErr = KErrGeneral; |
|
1185 break; |
|
1186 |
|
1187 case CCRRtspResponse::ERTSPRespParameterNotUnderstood: |
|
1188 entry.iErr = KErrArgument; |
|
1189 break; |
|
1190 |
|
1191 case CCRRtspResponse::ERTSPRespNotEnoughBandwidth: |
|
1192 entry.iErr = KErrGeneral; |
|
1193 break; |
|
1194 |
|
1195 case CCRRtspResponse::ERTSPRespSessionNotFound: |
|
1196 entry.iErr = KErrCouldNotConnect; |
|
1197 break; |
|
1198 |
|
1199 case CCRRtspResponse::ERTSPRespMethodNotValidInThisState: |
|
1200 entry.iErr = KErrGeneral; |
|
1201 break; |
|
1202 |
|
1203 case CCRRtspResponse::ERTSPRespHeaderFieldNotValidForResource: |
|
1204 entry.iErr = KErrGeneral; |
|
1205 break; |
|
1206 |
|
1207 case CCRRtspResponse::ERTSPRespInvalidRange: |
|
1208 entry.iErr = KErrGeneral; |
|
1209 break; |
|
1210 |
|
1211 case CCRRtspResponse::ERTSPRespParameterIsReadOnly: |
|
1212 entry.iErr = KErrGeneral; |
|
1213 break; |
|
1214 |
|
1215 case CCRRtspResponse::ERTSPRespAggregateOperationNotAllowed: |
|
1216 entry.iErr = KErrGeneral; |
|
1217 break; |
|
1218 |
|
1219 case CCRRtspResponse::ERTSPRespOnlyAggregateOperationAllowed: |
|
1220 entry.iErr = KErrGeneral; |
|
1221 break; |
|
1222 |
|
1223 case CCRRtspResponse::ERTSPRespUnsupportedTransport: |
|
1224 entry.iErr = KErrCouldNotConnect; |
|
1225 break; |
|
1226 |
|
1227 case CCRRtspResponse::ERTSPRespDestinationUnreachable: |
|
1228 entry.iErr = KErrCouldNotConnect; |
|
1229 break; |
|
1230 |
|
1231 case CCRRtspResponse::ERTSPRespInternalServerError: |
|
1232 entry.iErr = KErrGeneral; |
|
1233 break; |
|
1234 |
|
1235 case CCRRtspResponse::ERTSPRespNotImplemented: |
|
1236 entry.iErr = KErrGeneral; |
|
1237 break; |
|
1238 |
|
1239 case CCRRtspResponse::ERTSPRespBadGateway: |
|
1240 entry.iErr = KErrGeneral; |
|
1241 break; |
|
1242 |
|
1243 case CCRRtspResponse::ERTSPRespServiceUnavailable: |
|
1244 entry.iErr = KErrCouldNotConnect; |
|
1245 break; |
|
1246 |
|
1247 case CCRRtspResponse::ERTSPRespGatewayTimeOut: |
|
1248 entry.iErr = KErrGeneral; |
|
1249 break; |
|
1250 |
|
1251 case CCRRtspResponse::ERTSPRespUnsupportedMediaType: |
|
1252 case CCRRtspResponse::ERTSPRespOptionNotSupported: |
|
1253 case CCRRtspResponse::ERTSPRespRTSPVersionNotSupported: |
|
1254 entry.iErr = KErrNotSupported; |
|
1255 break; |
|
1256 |
|
1257 default: |
|
1258 entry.iErr = KErrGeneral; |
|
1259 break; |
|
1260 } |
|
1261 |
|
1262 if ( iObserver ) |
|
1263 { |
|
1264 iObserver->ConnectionStatusChange( |
|
1265 iOwningSession.SourceChecksum(), ECRConnectionError, entry.iErr ); |
|
1266 } |
|
1267 |
|
1268 // Try tear down first |
|
1269 if ( Stop() == KErrDisconnected ) |
|
1270 { |
|
1271 iOwningSession.SourceStop(); |
|
1272 } |
|
1273 } |
|
1274 |
|
1275 // ----------------------------------------------------------------------------- |
|
1276 // CCRRtspPacketSource::StartRtspTimeout |
|
1277 // Starts RTSP command response timeout. |
|
1278 // ----------------------------------------------------------------------------- |
|
1279 // |
|
1280 void CCRRtspPacketSource::StartRtspTimeout( TTimeIntervalMicroSeconds32 aTime ) |
|
1281 { |
|
1282 // Start a timeout timer to wait for the server to respond. |
|
1283 // If the server doesn't respond in time, cleanup will be initialized. |
|
1284 if ( !iRtspTimeout ) |
|
1285 { |
|
1286 TRAPD( err, iRtspTimeout = |
|
1287 CPeriodic::NewL( CActive::EPriorityStandard ) ); |
|
1288 if ( err != KErrNone ) |
|
1289 { |
|
1290 // Timer creation failed, start cleanup immediately |
|
1291 iOwningSession.SourceStop(); |
|
1292 } |
|
1293 } |
|
1294 else |
|
1295 { |
|
1296 iRtspTimeout->Cancel(); |
|
1297 } |
|
1298 |
|
1299 // Start timeout timer |
|
1300 iRtspTimeout->Start( |
|
1301 aTime, |
|
1302 aTime, |
|
1303 TCallBack( RtspTimeoutCallback, this ) ); |
|
1304 } |
|
1305 |
|
1306 // ----------------------------------------------------------------------------- |
|
1307 // CCRRtspPacketSource::RtspTimeoutCallback |
|
1308 // Callback for RTSP response timeout. Just ask session to start cleanup |
|
1309 // ----------------------------------------------------------------------------- |
|
1310 // |
|
1311 TInt CCRRtspPacketSource::RtspTimeoutCallback( TAny* aPtr ) |
|
1312 { |
|
1313 LOG( "CCRRtspPacketSource::RtspTimeoutCallback()" ); |
|
1314 |
|
1315 CCRRtspPacketSource* self = static_cast<CCRRtspPacketSource*>( aPtr ); |
|
1316 self->iRtspTimeout->Cancel(); |
|
1317 self->iOwningSession.SourceStop(); |
|
1318 return 0; |
|
1319 } |
|
1320 |
|
1321 // ----------------------------------------------------------------------------- |
|
1322 // CCRRtspPacketSource::SendRtspCommandL |
|
1323 // ----------------------------------------------------------------------------- |
|
1324 // |
|
1325 void CCRRtspPacketSource::SendRtspCommandL() |
|
1326 { |
|
1327 LOG1( "CCRRtspPacketSource::SendRtspCommandL(), iStage: %d", iStage ); |
|
1328 |
|
1329 if ( iPostPonedPlay ) |
|
1330 { |
|
1331 iPostPonedPlay = EFalse; |
|
1332 Play( iStartPos, iEndPos ); |
|
1333 } |
|
1334 else |
|
1335 { |
|
1336 switch ( iStage ) |
|
1337 { |
|
1338 case ERTSPInit: |
|
1339 case ERTSPOptSent: |
|
1340 { |
|
1341 delete iPrevCommands[ERTSPDescSent]; |
|
1342 iPrevCommands[ERTSPDescSent] = NULL; |
|
1343 iPrevCommands[ERTSPDescSent] = CCRRtspCommand::NewL(); |
|
1344 iPrevCommands[ERTSPDescSent]->SetCommand( |
|
1345 CCRRtspCommand::ERTSPCommandDESCRIBE ); |
|
1346 |
|
1347 TPtrC8 uriDes ( iRtspUri8->Des() ); |
|
1348 iPrevCommands[ERTSPDescSent]->SetURL( uriDes ); |
|
1349 iPrevCommands[ERTSPDescSent]->SetCSeq( iCSeq++ ); |
|
1350 if ( iUserAgent ) |
|
1351 { |
|
1352 iPrevCommands[ERTSPDescSent]->SetUserAgentL( *iUserAgent ); |
|
1353 } |
|
1354 if ( iWapProfile ) |
|
1355 { |
|
1356 iPrevCommands[ERTSPDescSent]->SetWapProfileL( *iWapProfile ); |
|
1357 } |
|
1358 if ( iBandwidth ) |
|
1359 { |
|
1360 iPrevCommands[ERTSPDescSent]->SetBandwidth( iBandwidth ); |
|
1361 } |
|
1362 |
|
1363 if ( iRtspSock ) |
|
1364 { |
|
1365 iRtspSock->SendData( iPrevCommands[ERTSPDescSent]->ProduceL() ); |
|
1366 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
1367 iStage = ERTSPDescSent; |
|
1368 } |
|
1369 } |
|
1370 break; |
|
1371 |
|
1372 case ERTSPDescSent: |
|
1373 if ( iSdpParser ) |
|
1374 { |
|
1375 const TInt audio( iSdpParser->MediaIdentifierAudio() ); |
|
1376 const TInt video( iSdpParser->MediaIdentifierVideo() ); |
|
1377 TBool videoExists( iSdpParser->VideoControlAddr().Length() > 0 ); |
|
1378 TBool audioExists( iSdpParser->AudioControlAddr().Length() > 0 ); |
|
1379 |
|
1380 /* If both medias are reported with dynamic payload |
|
1381 * type and audio stream is reported with lower |
|
1382 * payload type, then some servers don't work correctly |
|
1383 * if the SETUP commands are not in correct order, ie. |
|
1384 * we need to first SETUP the audio stream here. |
|
1385 */ |
|
1386 const TBool audioBeforeVideo( |
|
1387 audioExists && audio >= 96 && video >= 96 && audio < video ); |
|
1388 |
|
1389 if ( videoExists && !audioBeforeVideo ) |
|
1390 { |
|
1391 SendSetupCommandL( iSdpParser->VideoControlAddr(), EFalse ); |
|
1392 iStage = ERTSPSetupVideoSent; |
|
1393 } |
|
1394 else if ( audioExists ) |
|
1395 { |
|
1396 SendSetupCommandL( iSdpParser->AudioControlAddr(), ETrue ); |
|
1397 iStage = ERTSPSetupAudioSent; |
|
1398 } |
|
1399 else |
|
1400 { |
|
1401 LOG1( "CCRRtspPacketSource::SendRtspCommand stag %d have no audio nor video", |
|
1402 ( TInt )iStage ); |
|
1403 // no audio, no video, el panique grande |
|
1404 iOwningSession.SourceStop(); |
|
1405 } |
|
1406 } |
|
1407 break; |
|
1408 |
|
1409 case ERTSPSetupAudioSent: |
|
1410 { |
|
1411 const TInt audio( iSdpParser->MediaIdentifierAudio() ); |
|
1412 const TInt video( iSdpParser->MediaIdentifierVideo() ); |
|
1413 |
|
1414 if ( audio >= 96 && video >= 96 && audio < video && |
|
1415 iSdpParser && iSdpParser->VideoControlAddr().Length() ) |
|
1416 { |
|
1417 // Video exists also and has not been setup before, so |
|
1418 // let's setup it now. |
|
1419 |
|
1420 TPtrC8 ctrlAddr ( iSdpParser->VideoControlAddr() ); |
|
1421 SendSetupCommandL( ctrlAddr, EFalse ); |
|
1422 iStage = ERTSPSetupVideoSent; |
|
1423 } |
|
1424 else |
|
1425 { |
|
1426 ConditionallySetupMultiCastOrTcpStreamingL(); |
|
1427 } |
|
1428 } |
|
1429 break; |
|
1430 |
|
1431 case ERTSPSetupVideoSent: |
|
1432 { |
|
1433 const TInt audio( iSdpParser->MediaIdentifierAudio() ); |
|
1434 const TInt video( iSdpParser->MediaIdentifierVideo() ); |
|
1435 |
|
1436 // Check explanation for this in case ERTSPDescSent above. |
|
1437 const TBool audioBeforeVideo( |
|
1438 audio >= 96 && video >= 96 && audio < video ); |
|
1439 |
|
1440 // Then send audio, if applicable: |
|
1441 if ( iSdpParser && iSdpParser->AudioControlAddr().Length() && |
|
1442 !audioBeforeVideo ) |
|
1443 { |
|
1444 TPtrC8 ctrlAddr ( iSdpParser->AudioControlAddr() ); |
|
1445 SendSetupCommandL( ctrlAddr, ETrue ); |
|
1446 iStage = ERTSPSetupAudioSent; |
|
1447 } |
|
1448 else |
|
1449 { |
|
1450 // there is no audio that need setup so lets check also multicast+tcp |
|
1451 ConditionallySetupMultiCastOrTcpStreamingL(); |
|
1452 } |
|
1453 } |
|
1454 break; |
|
1455 |
|
1456 case ERTSPPauseSent: |
|
1457 // If we're paused, do zero the buffer, in tcp streaming case |
|
1458 // some servers seem to send packets even after play.. |
|
1459 break; |
|
1460 |
|
1461 case ERTSPReadyToPlay: |
|
1462 // In these stages send no further commands |
|
1463 break; |
|
1464 |
|
1465 case ERTSPPlaySent: |
|
1466 // Start timer for UDP reception and start streaming |
|
1467 if ( iTransport == ERTPOverUDP ) |
|
1468 { |
|
1469 iUdpReceptionTimer->Cancel(); |
|
1470 iUdpReceptionTimer->After( KCRRtspRtpUdpTimeout ); |
|
1471 } |
|
1472 |
|
1473 iStage = ERTSPPlaying; |
|
1474 if ( !iNoRtpInfoHeader ) |
|
1475 { |
|
1476 iSessionObs.StatusChanged( MCRPacketSource::ERtpStatePlaying ); |
|
1477 } |
|
1478 break; |
|
1479 |
|
1480 case ERTSPPlaying: |
|
1481 // None |
|
1482 break; |
|
1483 |
|
1484 case ERTSPTearDownSent: |
|
1485 iPostPonedPlay = EFalse; |
|
1486 iOwningSession.SourceStop(); |
|
1487 break; |
|
1488 |
|
1489 default: |
|
1490 // By default send no further commands |
|
1491 break; |
|
1492 } |
|
1493 } |
|
1494 } |
|
1495 |
|
1496 // ----------------------------------------------------------------------------- |
|
1497 // CCRRtspPacketSource::SendPlayCommandL |
|
1498 // ----------------------------------------------------------------------------- |
|
1499 // |
|
1500 void CCRRtspPacketSource::SendPlayCommandL(void) |
|
1501 { |
|
1502 delete iPrevCommands[ERTSPPlaySent]; |
|
1503 iPrevCommands[ERTSPPlaySent] = NULL; |
|
1504 iPrevCommands[ERTSPPlaySent] = CCRRtspCommand::NewL(); |
|
1505 iPrevCommands[ERTSPPlaySent]->SetCommand ( CCRRtspCommand::ERTSPCommandPLAY ); |
|
1506 TPtrC8 uriDes( iRtspUri8->Des() ); |
|
1507 iPrevCommands[ERTSPPlaySent]->SetURL( uriDes ); |
|
1508 iPrevCommands[ERTSPPlaySent]->SetCSeq( iCSeq ++ ); |
|
1509 iPrevCommands[ERTSPPlaySent]->SetRange( iStartPos , iEndPos ); |
|
1510 |
|
1511 if ( iUserAgent ) |
|
1512 { |
|
1513 iPrevCommands[ERTSPPlaySent]->SetUserAgentL( *iUserAgent ); |
|
1514 } |
|
1515 if ( iSessionId.Ptr() ) |
|
1516 { |
|
1517 iPrevCommands[ERTSPPlaySent]->SetSessionId( iSessionId ); |
|
1518 } |
|
1519 if ( iAuthenticationNeeded ) |
|
1520 { |
|
1521 AddAuthenticationL( ERTSPPlaySent ); |
|
1522 } |
|
1523 |
|
1524 if ( iRtspSock ) |
|
1525 { |
|
1526 iRtspSock->SendData( iPrevCommands[ERTSPPlaySent]->ProduceL() ); |
|
1527 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
1528 iStage = ERTSPPlaySent; |
|
1529 } |
|
1530 |
|
1531 iStartPos = KRealZero; |
|
1532 iEndPos = KRealMinusOne; |
|
1533 } |
|
1534 |
|
1535 // ----------------------------------------------------------------------------- |
|
1536 // CCRRtspPacketSource::SendPauseCommandL |
|
1537 // ----------------------------------------------------------------------------- |
|
1538 // |
|
1539 void CCRRtspPacketSource::SendPauseCommandL(void) |
|
1540 { |
|
1541 delete iPrevCommands[ERTSPPauseSent]; |
|
1542 iPrevCommands[ERTSPPauseSent] = NULL; |
|
1543 iPrevCommands[ERTSPPauseSent] = CCRRtspCommand::NewL(); |
|
1544 iPrevCommands[ERTSPPauseSent]->SetCommand ( CCRRtspCommand::ERTSPCommandPAUSE ); |
|
1545 TPtrC8 uriDes( iRtspUri8->Des() ); |
|
1546 iPrevCommands[ERTSPPauseSent]->SetURL( uriDes ); |
|
1547 iPrevCommands[ERTSPPauseSent]->SetCSeq( iCSeq ++ ); |
|
1548 |
|
1549 if ( iUserAgent ) |
|
1550 { |
|
1551 iPrevCommands[ERTSPPauseSent]->SetUserAgentL( *iUserAgent ); |
|
1552 } |
|
1553 if ( iSessionId.Ptr() ) |
|
1554 { |
|
1555 iPrevCommands[ERTSPPauseSent]->SetSessionId( iSessionId ); |
|
1556 } |
|
1557 if ( iAuthenticationNeeded ) |
|
1558 { |
|
1559 AddAuthenticationL( ERTSPPauseSent ); |
|
1560 } |
|
1561 |
|
1562 if ( iRtspSock ) |
|
1563 { |
|
1564 iRtspSock->SendData( iPrevCommands[ERTSPPauseSent]->ProduceL() ); |
|
1565 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
1566 iStage = ERTSPPauseSent; |
|
1567 } |
|
1568 } |
|
1569 |
|
1570 // ----------------------------------------------------------------------------- |
|
1571 // CCRRtspPacketSource::SendSetupCommandL |
|
1572 // ----------------------------------------------------------------------------- |
|
1573 // |
|
1574 TInt CCRRtspPacketSource::SendSetupCommandL( |
|
1575 const TDesC8& aControlAddr, |
|
1576 TBool aForAudio ) |
|
1577 { |
|
1578 TCRRTSPStage newStage = aForAudio ? ERTSPSetupAudioSent : ERTSPSetupVideoSent; |
|
1579 |
|
1580 delete iPrevCommands[newStage]; |
|
1581 iPrevCommands[newStage] = NULL; |
|
1582 iPrevCommands[newStage] = CCRRtspCommand::NewL(); |
|
1583 iPrevCommands[newStage]->SetCommand ( CCRRtspCommand::ERTSPCommandSETUP ); |
|
1584 iPrevCommands[newStage]->SetURL( aControlAddr ); |
|
1585 iPrevCommands[newStage]->SetCSeq( iCSeq ++ ); |
|
1586 iPrevCommands[newStage]->SetTransport( iTransport ); |
|
1587 |
|
1588 // Map stream to port number (when streaming over UDP) or channel (over TCP) |
|
1589 // base: iClientPort for UDP, 0 for TCP |
|
1590 // video: (base+0, base+1) |
|
1591 // audio: (base+2, base+3) or (base+0, base+1) when audio only |
|
1592 TInt portbase( ( iTransport == ERTPOverUDP )? iClientPort: 0 ); |
|
1593 TInt portoffset( ( aForAudio && iSdpParser->VideoControlAddr().Length() )? 2: 0 ); |
|
1594 iPrevCommands[newStage]->SetClientPort( portbase + portoffset ); |
|
1595 |
|
1596 if ( iSessionId.Ptr() ) |
|
1597 { |
|
1598 iPrevCommands[newStage]->SetSessionId ( iSessionId ); |
|
1599 } |
|
1600 if ( iAuthenticationNeeded ) |
|
1601 { |
|
1602 AddAuthenticationL( newStage ); |
|
1603 } |
|
1604 if ( iUserAgent ) |
|
1605 { |
|
1606 iPrevCommands[newStage]->SetUserAgentL( *iUserAgent ); |
|
1607 } |
|
1608 if ( iWapProfile ) |
|
1609 { |
|
1610 iPrevCommands[newStage]->SetWapProfileL( *iWapProfile ); |
|
1611 } |
|
1612 |
|
1613 if ( iRtspSock ) |
|
1614 { |
|
1615 iRtspSock->SendData( iPrevCommands[newStage]->ProduceL() ); |
|
1616 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
1617 } |
|
1618 |
|
1619 return KErrNone; |
|
1620 } |
|
1621 |
|
1622 // ----------------------------------------------------------------------------- |
|
1623 // CCRRtspPacketSource::SendTearDownCommandL |
|
1624 // ----------------------------------------------------------------------------- |
|
1625 // |
|
1626 void CCRRtspPacketSource::SendTearDownCommandL() |
|
1627 { |
|
1628 CCRRtspCommand*& teardowncmd = iPrevCommands[ERTSPTearDownSent]; |
|
1629 iPostPonedPlay = EFalse; |
|
1630 if ( teardowncmd ) |
|
1631 { |
|
1632 delete teardowncmd; teardowncmd = NULL; |
|
1633 } |
|
1634 |
|
1635 teardowncmd = CCRRtspCommand::NewL(); |
|
1636 teardowncmd->SetCommand( CCRRtspCommand::ERTSPCommandTEARDOWN ); |
|
1637 TPtrC8 uri( iRtspUri8->Des() ); |
|
1638 teardowncmd->SetURL( uri ); |
|
1639 teardowncmd->SetCSeq( iCSeq++ ); |
|
1640 |
|
1641 if ( iSessionId.Ptr() ) |
|
1642 { |
|
1643 teardowncmd->SetSessionId( iSessionId ); |
|
1644 } |
|
1645 if ( iUserAgent ) |
|
1646 { |
|
1647 teardowncmd->SetUserAgentL( *iUserAgent ); |
|
1648 } |
|
1649 if ( iAuthenticationNeeded ) |
|
1650 { |
|
1651 AddAuthenticationL( ERTSPTearDownSent ); |
|
1652 } |
|
1653 |
|
1654 if ( iRtspSock ) |
|
1655 { |
|
1656 iRtspSock->SendData( teardowncmd->ProduceL() ); |
|
1657 } |
|
1658 } |
|
1659 |
|
1660 // ----------------------------------------------------------------------------- |
|
1661 // CCRRtspPacketSource::SendOptionsCommandL |
|
1662 // ----------------------------------------------------------------------------- |
|
1663 // |
|
1664 void CCRRtspPacketSource::SendOptionsCommandL(void) |
|
1665 { |
|
1666 delete iPrevCommands[ERTSPOptSent]; |
|
1667 iPrevCommands[ERTSPOptSent] = NULL; |
|
1668 iPrevCommands[ERTSPOptSent] = CCRRtspCommand::NewL(); |
|
1669 iPrevCommands[ERTSPOptSent]->SetCommand ( CCRRtspCommand::ERTSPCommandOPTIONS ); |
|
1670 TPtrC8 uriDes ( iRtspUri8->Des() ); |
|
1671 iPrevCommands[ERTSPOptSent]->SetURL ( uriDes ); |
|
1672 iPrevCommands[ERTSPOptSent]->SetCSeq ( iCSeq ++ ); |
|
1673 |
|
1674 if ( iUserAgent ) |
|
1675 { |
|
1676 iPrevCommands[ERTSPOptSent]->SetUserAgentL( *iUserAgent ); |
|
1677 } |
|
1678 if ( iSessionId.Ptr() ) |
|
1679 { |
|
1680 iPrevCommands[ERTSPOptSent]->SetSessionId ( iSessionId ); |
|
1681 } |
|
1682 if ( iAuthenticationNeeded ) |
|
1683 { |
|
1684 AddAuthenticationL( ERTSPOptSent ); |
|
1685 } |
|
1686 |
|
1687 if ( iRtspSock ) |
|
1688 { |
|
1689 iRtspSock->SendData( iPrevCommands[ERTSPOptSent]->ProduceL() ); |
|
1690 } |
|
1691 // Sending options ping does not change our state |
|
1692 } |
|
1693 |
|
1694 // ----------------------------------------------------------------------------- |
|
1695 // CCRRtspPacketSource::SetupRTPSessions |
|
1696 // ----------------------------------------------------------------------------- |
|
1697 // |
|
1698 TInt CCRRtspPacketSource::SetupRTPSessions( void ) |
|
1699 { |
|
1700 TInt retval( KErrNone ); |
|
1701 if ( !iRtspSock ) |
|
1702 { |
|
1703 retval = KErrNotReady; |
|
1704 } |
|
1705 else |
|
1706 { |
|
1707 TInetAddr localAddr( iRtspSock->LocalAddr() ); |
|
1708 TInetAddr remoteAddr( iRtspSock->ConnectedAddr() ); |
|
1709 |
|
1710 // Clear used streams |
|
1711 iReceiveStreams.Reset(); |
|
1712 iTrafficFound = EFalse; |
|
1713 |
|
1714 // First audio: |
|
1715 if ( iRtspSock && iResponses[ERTSPSetupAudioSent] ) |
|
1716 { |
|
1717 if ( iTransport == ERTPOverMulticast ) |
|
1718 { |
|
1719 retval = CreateMulticastSocket( ERTPAudioSend1, |
|
1720 iResponses[ERTSPSetupAudioSent]->Destination(), |
|
1721 iResponses[ERTSPSetupAudioSent]->ClientPort() ); |
|
1722 if ( retval == KErrNone ) |
|
1723 { |
|
1724 retval = CreateMulticastSocket( ERTPAudioSend2, |
|
1725 iResponses[ERTSPSetupAudioSent]->Destination(), |
|
1726 iResponses[ERTSPSetupAudioSent]->ClientPort()+1 ); |
|
1727 } |
|
1728 } |
|
1729 else |
|
1730 { |
|
1731 localAddr.SetPort( iResponses[ERTSPSetupAudioSent]->ClientPort() ); |
|
1732 remoteAddr.SetPort( iResponses[ERTSPSetupAudioSent]->ServerPort() ); |
|
1733 |
|
1734 #if defined ( LIVE_TV_FILE_TRACE ) || defined ( LIVE_TV_RDEBUG_TRACE ) |
|
1735 TName _addr; |
|
1736 localAddr.Output( _addr ); |
|
1737 LOG2( "localaddr for video is %S:%d", &_addr, localAddr.Port() ); |
|
1738 remoteAddr.Output( _addr ); |
|
1739 LOG2( "remoteAddr for video is %S:%d", &_addr, remoteAddr.Port() ); |
|
1740 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
1741 |
|
1742 retval = CreateUnicastSocket( ERTPAudioSend1, localAddr, remoteAddr ); |
|
1743 if ( retval == KErrNone ) |
|
1744 { |
|
1745 localAddr.SetPort( localAddr.Port()+1 ); |
|
1746 remoteAddr.SetPort( remoteAddr.Port()+1 ); |
|
1747 retval = CreateUnicastSocket( ERTPAudioSend2, localAddr, remoteAddr ); |
|
1748 } |
|
1749 } |
|
1750 |
|
1751 if ( retval == KErrNone ) |
|
1752 { |
|
1753 TRAP( retval, iAudioSession.OpenL( |
|
1754 iRTPSockArr[ERTPAudioSend1]->Socket(), |
|
1755 KAverageExpectedRtpPacketMaxSize, |
|
1756 iRTPSockArr[ERTPAudioSend2]->Socket(), |
|
1757 EPriorityNormal, KCRCName() ) ); |
|
1758 } |
|
1759 |
|
1760 LOG1( "CCRRtspPacketSource::SetupRTPSessions audio sess open: %d", retval ); |
|
1761 if ( !retval ) |
|
1762 { |
|
1763 SetRtpSession( iAudioSession , iSdpParser->AudioTimerGranularity() ); |
|
1764 iAudioSession.SetBandwidth( iSdpParser->AudioBitrate() * 1000 ); |
|
1765 TRAP( retval, iAudioSession.PrivRegisterEventCallbackL( ERtpNewSource, |
|
1766 ( TRtpCallbackFunction )CCRRtspPacketSource::AudioRTPCallBack, this ) ); |
|
1767 |
|
1768 TReceiveStream audioDataStream; |
|
1769 audioDataStream.iStreamType = EAudioStream; |
|
1770 audioDataStream.iDataReceived = EFalse; |
|
1771 iReceiveStreams.Append( audioDataStream ); |
|
1772 LOG( "CCRRtspPacketSource::SetupRTPSessions - AudioStream found" ); |
|
1773 TReceiveStream audioControlStream; |
|
1774 audioControlStream.iStreamType = EAudioControlStream; |
|
1775 audioControlStream.iDataReceived = EFalse; |
|
1776 LOG( "CCRRtspPacketSource::SetupRTPSessions - AudioControlStream found" ); |
|
1777 iReceiveStreams.Append( audioControlStream ); |
|
1778 |
|
1779 LOG2( "CCRRtspPacketSource::SetupRTPSessions audio stat: %d, ts: %u", |
|
1780 retval, ( TUint )iRTPTimeStampAudio ); |
|
1781 } |
|
1782 else |
|
1783 { |
|
1784 if ( iObserver ) |
|
1785 { |
|
1786 iObserver->ConnectionStatusChange( |
|
1787 iOwningSession.SourceChecksum(), |
|
1788 ECRConnectionError, retval ); |
|
1789 } |
|
1790 iOwningSession.SourceStop(); |
|
1791 } |
|
1792 } |
|
1793 |
|
1794 // Then video |
|
1795 if ( retval == KErrNone && iRtspSock && iResponses[ERTSPSetupVideoSent] ) |
|
1796 { |
|
1797 if ( iTransport==ERTPOverMulticast ) |
|
1798 { |
|
1799 retval = CreateMulticastSocket( ERTPVideoSend1, |
|
1800 iResponses[ERTSPSetupVideoSent]->Destination(), |
|
1801 iResponses[ERTSPSetupVideoSent]->ClientPort() ); |
|
1802 if ( retval==KErrNone ) |
|
1803 { |
|
1804 retval = CreateMulticastSocket( ERTPVideoSend2, |
|
1805 iResponses[ERTSPSetupVideoSent]->Destination(), |
|
1806 iResponses[ERTSPSetupVideoSent]->ClientPort()+1 ); |
|
1807 } |
|
1808 } |
|
1809 else |
|
1810 { |
|
1811 localAddr.SetPort( iResponses[ERTSPSetupVideoSent]->ClientPort() ); |
|
1812 remoteAddr.SetPort( iResponses[ERTSPSetupVideoSent]->ServerPort() ); |
|
1813 |
|
1814 #if defined ( LIVE_TV_FILE_TRACE ) || defined ( LIVE_TV_RDEBUG_TRACE ) |
|
1815 TName _addr; |
|
1816 localAddr.Output( _addr ); |
|
1817 LOG2( "localaddr for video is %S:%d", &_addr, localAddr.Port() ); |
|
1818 remoteAddr.Output( _addr ); |
|
1819 LOG2( "remoteAddr for video is %S:%d", &_addr, remoteAddr.Port() ); |
|
1820 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
1821 |
|
1822 retval = CreateUnicastSocket( ERTPVideoSend1, localAddr, remoteAddr ); |
|
1823 if ( retval == KErrNone ) |
|
1824 { |
|
1825 localAddr.SetPort( localAddr.Port() + 1 ); |
|
1826 remoteAddr.SetPort( remoteAddr.Port() + 1 ); |
|
1827 retval = CreateUnicastSocket( ERTPVideoSend2, localAddr, remoteAddr ); |
|
1828 } |
|
1829 } |
|
1830 |
|
1831 if ( retval == KErrNone ) |
|
1832 { |
|
1833 TRAP( retval, iVideoSession.OpenL( iRTPSockArr[ERTPVideoSend1]->Socket(), |
|
1834 KAverageExpectedRtpPacketMaxSize, iRTPSockArr[ERTPVideoSend2]->Socket(), |
|
1835 EPriorityNormal, KCRCName() ) ); |
|
1836 } |
|
1837 |
|
1838 LOG1( "CCRRtspPacketSource::SetupRTPSessions video sess open: %d", retval ); |
|
1839 if ( !retval ) |
|
1840 { |
|
1841 SetRtpSession( iVideoSession , iSdpParser->VideoTimerGranularity() ); |
|
1842 iVideoSession.SetBandwidth( iSdpParser->VideoBitrate() * 1000 ); |
|
1843 TRAP( retval, iVideoSession.PrivRegisterEventCallbackL( ERtpNewSource, |
|
1844 ( TRtpCallbackFunction )CCRRtspPacketSource::VideoRTPCallBack, this ) ); |
|
1845 |
|
1846 TReceiveStream videoDataStream; |
|
1847 videoDataStream.iStreamType = EVideoStream; |
|
1848 videoDataStream.iDataReceived = EFalse; |
|
1849 LOG( "CCRRtspPacketSource::SetupRTPSessions - VideoStream found" ); |
|
1850 iReceiveStreams.Append( videoDataStream ); |
|
1851 TReceiveStream videoControlStream; |
|
1852 videoControlStream.iStreamType = EVideoControlStream; |
|
1853 videoControlStream.iDataReceived = EFalse; |
|
1854 LOG( "CCRRtspPacketSource::SetupRTPSessions - VideoControlStream found" ); |
|
1855 iReceiveStreams.Append( videoControlStream ); |
|
1856 |
|
1857 LOG2( "CCRRtspPacketSource::SetupRTPSessions video stat: %d, ts: %u", |
|
1858 retval, ( TUint )iRTPTimeStampVideo ); |
|
1859 } |
|
1860 else |
|
1861 { |
|
1862 if ( iObserver ) |
|
1863 { |
|
1864 iObserver->ConnectionStatusChange( |
|
1865 iOwningSession.SourceChecksum(), |
|
1866 ECRConnectionError, retval ); |
|
1867 } |
|
1868 iOwningSession.SourceStop(); |
|
1869 } |
|
1870 } |
|
1871 } |
|
1872 |
|
1873 return retval; |
|
1874 } |
|
1875 |
|
1876 // ----------------------------------------------------------------------------- |
|
1877 // CCRRtspPacketSource::CreateMulticastSocket |
|
1878 // ----------------------------------------------------------------------------- |
|
1879 // |
|
1880 TInt CCRRtspPacketSource::CreateMulticastSocket( |
|
1881 TCRRTPSockId aSockId, |
|
1882 const TInetAddr& aGroupAddr, |
|
1883 TInt aPort ) |
|
1884 { |
|
1885 // Alias for socket being created |
|
1886 CCRSock*& sock = iRTPSockArr[aSockId]; |
|
1887 |
|
1888 // Delete if already existing |
|
1889 if ( sock ) |
|
1890 { |
|
1891 delete sock; |
|
1892 sock = NULL; |
|
1893 } |
|
1894 |
|
1895 // Create socket |
|
1896 TRAPD( err, sock = CCRSock::NewL( *this, aSockId, iConnection.Connection(), |
|
1897 iSockServer, EFalse, EFalse) ); |
|
1898 if ( err != KErrNone ) |
|
1899 { |
|
1900 LOG2( "CCRRtspPacketSource::CreateMulticastSocket: CCRSock::NewL FAILED, sockId: %d, err: %d", |
|
1901 aSockId, err ); |
|
1902 return err; |
|
1903 } |
|
1904 |
|
1905 // Bind socket to local UDP port, issue no reads -> handled by RRtpSession |
|
1906 err = sock->ListenPort( aPort ); |
|
1907 if ( err != KErrNone ) |
|
1908 { |
|
1909 LOG2( "CCRRtspPacketSource::CreateMulticastSocket: ListenPort FAILED, port: %d, err: %d", |
|
1910 aPort, err ); |
|
1911 return err; |
|
1912 } |
|
1913 |
|
1914 err = sock->JoinGroup( aGroupAddr ); |
|
1915 if ( err != KErrNone ) |
|
1916 { |
|
1917 LOG1( "CCRRtspPacketSource::CreateMulticastSocket: JoinGroup FAILED, err: %d", err ); |
|
1918 return err; |
|
1919 } |
|
1920 |
|
1921 #if defined(LIVE_TV_FILE_TRACE) || defined(LIVE_TV_RDEBUG_TRACE) |
|
1922 TName group; |
|
1923 aGroupAddr.Output( group ); |
|
1924 LOG3( "CCRRtspPacketSource::CreateMulticastSocket: sockid: %d, group: '%S', port: %d OK", |
|
1925 aSockId, &group, aPort ); |
|
1926 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
1927 |
|
1928 return KErrNone; |
|
1929 } |
|
1930 |
|
1931 // ----------------------------------------------------------------------------- |
|
1932 // CCRRtspPacketSource::CreateUnicastSocket |
|
1933 // ----------------------------------------------------------------------------- |
|
1934 TInt CCRRtspPacketSource::CreateUnicastSocket( |
|
1935 TCRRTPSockId aSockId, |
|
1936 const TInetAddr& aLocalAddr, |
|
1937 const TInetAddr& /*aRemoteAddr*/ ) |
|
1938 { |
|
1939 // Alias for socket being created |
|
1940 CCRSock*& sock = iRTPSockArr[aSockId]; |
|
1941 |
|
1942 // Delete if already existing |
|
1943 if ( sock ) |
|
1944 { |
|
1945 delete sock; |
|
1946 sock = NULL; |
|
1947 } |
|
1948 |
|
1949 // Create socket: EFalse=UDP, EFalse=issue no read (handled by RRtpSession) |
|
1950 TRAPD( err, sock = CCRSock::NewL( *this,aSockId, iConnection.Connection(), |
|
1951 iSockServer, EFalse, EFalse ) ); |
|
1952 if ( err != KErrNone ) |
|
1953 { |
|
1954 LOG2( "CCRRtspPacketSource::CreateUnicastSocket: CCRSock::NewL FAILED, sockId: %d, err: %d", |
|
1955 aSockId, err ); |
|
1956 return err; |
|
1957 } |
|
1958 |
|
1959 // Bind to local port, ignore remote address and port |
|
1960 TInt port = aLocalAddr.Port(); |
|
1961 err = sock->ListenPort( port ); |
|
1962 if ( err != KErrNone ) |
|
1963 { |
|
1964 LOG2( "CCRRtspPacketSource::CreateUnicastSocket: ListenPort FAILED, port: %d, err: %d", |
|
1965 port, err ); |
|
1966 return err; |
|
1967 } |
|
1968 |
|
1969 #if defined(LIVE_TV_FILE_TRACE) || defined(LIVE_TV_RDEBUG_TRACE) |
|
1970 LOG2( "CCRRtspPacketSource::CreateUnicastSocket: sockid: %d, port: %d OK", |
|
1971 aSockId, port ); |
|
1972 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
1973 |
|
1974 return KErrNone; |
|
1975 } |
|
1976 |
|
1977 // ----------------------------------------------------------------------------- |
|
1978 // CCRRtspPacketSource::RTPPayloadProcessor |
|
1979 // This is called from audio and video callbacks when real payload packet |
|
1980 // is received from rtp stack. |
|
1981 // ----------------------------------------------------------------------------- |
|
1982 // |
|
1983 void CCRRtspPacketSource::RTPPayloadProcessor( |
|
1984 const TRtpEvent& aEvent, |
|
1985 const TBool aIsAudio ) |
|
1986 { |
|
1987 // If udp traffic hasn't been flagged as found |
|
1988 // keep marking streams as found |
|
1989 if ( !iTrafficFound ) |
|
1990 { |
|
1991 if ( aIsAudio ) |
|
1992 { |
|
1993 StreamFound( EAudioStream ); |
|
1994 } |
|
1995 else |
|
1996 { |
|
1997 StreamFound( EVideoStream ); |
|
1998 } |
|
1999 |
|
2000 // Cancel UDP timer, so as not to trigger TCP streaming |
|
2001 if ( CheckReceiveOfStreams() ) |
|
2002 { |
|
2003 // We have traffic from all needed streams, cancel reception timer |
|
2004 // and set UDP flag. |
|
2005 iUdpReceptionTimer->Cancel(); |
|
2006 iUdpFound = ETrue; |
|
2007 iTrafficFound = ETrue; |
|
2008 } |
|
2009 } |
|
2010 |
|
2011 // Here process packet |
|
2012 RRtpReceivePacket p = aEvent.ReceiveSource().Packet(); |
|
2013 TUint32 flag( 0 ); |
|
2014 BigEndian::Put32( ( TUint8* )&flag, p.Flags() ); |
|
2015 |
|
2016 // Header |
|
2017 TCRRtpMessageHeader packetHeader; |
|
2018 memcpy( &packetHeader, &flag, sizeof( flag ) ); |
|
2019 BigEndian::Put32( ( TUint8* )&packetHeader.iTimestamp, p.Timestamp() ); |
|
2020 BigEndian::Put32( ( TUint8* )&packetHeader.iSSRC, p.SSRC() ); |
|
2021 TPtrC8 rtpHeader( ( TUint8* )&packetHeader, sizeof( packetHeader ) ); |
|
2022 |
|
2023 if ( iNoRtpInfoHeader ) |
|
2024 { |
|
2025 ConstructSeqAndTsForSink( |
|
2026 aIsAudio ? MCRPacketSource::EAudioStream : MCRPacketSource::EVideoStream, |
|
2027 0 /*nop*/, 0 /*nop*/, 0 /*nop*/, p.SequenceNumber() ); |
|
2028 } |
|
2029 |
|
2030 // Stream |
|
2031 MCRPacketSource::TCRPacketStreamId stream( |
|
2032 ( aIsAudio )? MCRPacketSource::EAudioStream : |
|
2033 MCRPacketSource::EVideoStream ); |
|
2034 iBuffer->AddPacket( stream, rtpHeader, p.Payload() ); |
|
2035 |
|
2036 // Count of packets |
|
2037 if ( aIsAudio ) |
|
2038 { |
|
2039 iAudioBytes += p.Payload( ).Length(); |
|
2040 iAudioPackets ++; |
|
2041 } |
|
2042 else |
|
2043 { |
|
2044 iVideoBytes += p.Payload( ).Length(); |
|
2045 iVideoPackets ++; |
|
2046 } |
|
2047 |
|
2048 p.Close(); |
|
2049 } |
|
2050 |
|
2051 // ----------------------------------------------------------------------------- |
|
2052 // CCRRtspPacketSource::AudioRTPCallBack |
|
2053 // ----------------------------------------------------------------------------- |
|
2054 // |
|
2055 void CCRRtspPacketSource::AudioRTPCallBack( |
|
2056 CCRRtspPacketSource* aPtr, |
|
2057 const TRtpEvent& aEvent ) |
|
2058 { |
|
2059 switch ( aEvent.Type() ) |
|
2060 { |
|
2061 case ERtpPacketReceived: |
|
2062 static_cast<CCRRtspPacketSource*>( aPtr )-> |
|
2063 RTPPayloadProcessor( aEvent, ETrue ); |
|
2064 break; |
|
2065 |
|
2066 // RTCP |
|
2067 case ERtpSR: |
|
2068 { |
|
2069 // We have audio control traffic |
|
2070 if ( !aPtr->iTrafficFound ) |
|
2071 { |
|
2072 aPtr->StreamFound( EAudioControlStream ); |
|
2073 if ( aPtr->CheckReceiveOfStreams() ) |
|
2074 { |
|
2075 // Cancel UDP timer, so as not to trigger TCP streaming |
|
2076 aPtr->iUdpReceptionTimer->Cancel(); |
|
2077 aPtr->iUdpFound = ETrue; |
|
2078 aPtr->iTrafficFound = ETrue; |
|
2079 } |
|
2080 } |
|
2081 |
|
2082 // Sender report |
|
2083 SenderReport( aPtr, aEvent, MCRPacketSource::EAudioControlStream ); |
|
2084 } |
|
2085 break; |
|
2086 |
|
2087 case ERtpNewSource: |
|
2088 { |
|
2089 // Handle audio |
|
2090 TRAPD( err, HandleNewSourceL( aPtr, aPtr->iRtpRecvSrcAudio, aEvent, |
|
2091 ( TRtpCallbackFunction )CCRRtspPacketSource::AudioRTPCallBack ) ); |
|
2092 if ( err ) |
|
2093 { |
|
2094 LOG1( "CCRRtspPacketSource::AudioRTPCallBack(), HandleNewSourceL Leaved: %d", err ); |
|
2095 aPtr->iOwningSession.SourceStop(); |
|
2096 } |
|
2097 } |
|
2098 break; |
|
2099 |
|
2100 case ERtpSessionFail: |
|
2101 case ERtpSourceFail: |
|
2102 LOG( "CCRRtspPacketSource::VideoRTPCallBack(), source/session fail" ); |
|
2103 aPtr->iOwningSession.SourceStop(); |
|
2104 if ( aPtr->iObserver ) |
|
2105 { |
|
2106 aPtr->iObserver->ConnectionStatusChange( |
|
2107 aPtr->iOwningSession.SourceChecksum(), |
|
2108 ECRNormalEndOfStream, KErrSessionClosed ); |
|
2109 } |
|
2110 break; |
|
2111 |
|
2112 case ERtpBYE: |
|
2113 LOG( "CCRRtspPacketSource::AudioRTPCallBack(), ERtpBYE" ); |
|
2114 if ( aPtr->iObserver ) |
|
2115 { |
|
2116 aPtr->iObserver->ConnectionStatusChange( |
|
2117 aPtr->iOwningSession.SourceChecksum(), |
|
2118 ECRNormalEndOfStream, KErrNone ); |
|
2119 } |
|
2120 break; |
|
2121 |
|
2122 default: |
|
2123 LOG1( "CCRRtspPacketSource::AudioRTPCallBack default case, type 0x%x", |
|
2124 ( TUint )( aEvent.Type() ) ); |
|
2125 // by do nothing |
|
2126 break; |
|
2127 } |
|
2128 } |
|
2129 |
|
2130 // ----------------------------------------------------------------------------- |
|
2131 // CCRRtspPacketSource::VideoRTPCallBack |
|
2132 // ----------------------------------------------------------------------------- |
|
2133 // |
|
2134 void CCRRtspPacketSource::VideoRTPCallBack( |
|
2135 CCRRtspPacketSource* aPtr, |
|
2136 const TRtpEvent& aEvent ) |
|
2137 { |
|
2138 switch ( aEvent.Type() ) |
|
2139 { |
|
2140 case ERtpPacketReceived: |
|
2141 static_cast<CCRRtspPacketSource*>( aPtr )-> |
|
2142 RTPPayloadProcessor( aEvent, EFalse ); |
|
2143 break; |
|
2144 |
|
2145 // RTCP |
|
2146 case ERtpSR: |
|
2147 { |
|
2148 // We have video control traffic |
|
2149 if ( !aPtr->iTrafficFound ) |
|
2150 { |
|
2151 aPtr->StreamFound( EVideoControlStream ); |
|
2152 if ( aPtr->CheckReceiveOfStreams() ) |
|
2153 { |
|
2154 // Cancel UDP timer, so as not to trigger TCP streaming |
|
2155 aPtr->iUdpReceptionTimer->Cancel(); |
|
2156 aPtr->iUdpFound = ETrue; |
|
2157 aPtr->iTrafficFound = ETrue; |
|
2158 } |
|
2159 } |
|
2160 |
|
2161 // Sender report |
|
2162 SenderReport( aPtr, aEvent, MCRPacketSource::EVideoControlStream ); |
|
2163 } |
|
2164 break; |
|
2165 |
|
2166 case ERtpNewSource: |
|
2167 { |
|
2168 // Handle video |
|
2169 TRAPD( err, HandleNewSourceL( aPtr, aPtr->iRtpRecvSrcVideo, aEvent, |
|
2170 ( TRtpCallbackFunction )CCRRtspPacketSource::VideoRTPCallBack ) ); |
|
2171 if ( err ) |
|
2172 { |
|
2173 LOG1( "CCRRtspPacketSource::VideoRTPCallBack(), HandleNewSourceL Leaved: %d", err ); |
|
2174 aPtr->iOwningSession.SourceStop(); |
|
2175 } |
|
2176 } |
|
2177 break; |
|
2178 |
|
2179 case ERtpSessionFail: |
|
2180 case ERtpSourceFail: |
|
2181 LOG( "CCRRtspPacketSource::VideoRTPCallBack(), Source/session fail" ); |
|
2182 aPtr->iOwningSession.SourceStop(); |
|
2183 if ( aPtr->iObserver ) |
|
2184 { |
|
2185 aPtr->iObserver->ConnectionStatusChange( |
|
2186 aPtr->iOwningSession.SourceChecksum(), |
|
2187 ECRNormalEndOfStream, KErrSessionClosed ); |
|
2188 } |
|
2189 break; |
|
2190 |
|
2191 case ERtpBYE: |
|
2192 LOG( "CCRRtspPacketSource::VideoRTPCallBack(), ERtpBYE" ); |
|
2193 if ( aPtr->iObserver ) |
|
2194 { |
|
2195 aPtr->iObserver->ConnectionStatusChange( |
|
2196 aPtr->iOwningSession.SourceChecksum(), |
|
2197 ECRNormalEndOfStream, KErrNone ); |
|
2198 } |
|
2199 break; |
|
2200 |
|
2201 default: |
|
2202 LOG1( "CCRRtspPacketSource::VideoRTPCallBack default case, type 0x%x", |
|
2203 ( TUint )( aEvent.Type() ) ); |
|
2204 // By do nothing |
|
2205 break; |
|
2206 } |
|
2207 } |
|
2208 |
|
2209 // ----------------------------------------------------------------------------- |
|
2210 // CCRRtspPacketSource::SenderReport |
|
2211 // rfc-1305: |
|
2212 // NTP timestamps are represented as a 64-bit unsigned fixed- |
|
2213 // point number, in seconds relative to 0h on 1 January 1900. |
|
2214 // The integer part is in the first 32 bits and the fraction |
|
2215 // part in the last 32 bits. |
|
2216 // ----------------------------------------------------------------------------- |
|
2217 // |
|
2218 void CCRRtspPacketSource::SenderReport( |
|
2219 CCRRtspPacketSource* aPtr, |
|
2220 const TRtpEvent& aEvent, |
|
2221 MCRPacketSource::TCRPacketStreamId aStreamId ) |
|
2222 { |
|
2223 TCRRtpSRReportHeader srReport; |
|
2224 srReport.iVersion = KRtpPacketVersion; // value is 2 |
|
2225 srReport.iPadding = 0; |
|
2226 srReport.iReportCount = 0; |
|
2227 srReport.iPacketType = KSenderReportPacketType; |
|
2228 RRtpReceiveSource source( aEvent.ReceiveSource() ); |
|
2229 BigEndian::Put16( ( TUint8* )&srReport.iLength, 6 ); |
|
2230 BigEndian::Put32( ( TUint8* )&srReport.iSenderSSRC, |
|
2231 source.SSRC() ); |
|
2232 BigEndian::Put32( ( TUint8* )&srReport.iMSWTimestamp, |
|
2233 source.GetSR().iSrPtr.ntp_sec ); |
|
2234 BigEndian::Put32( ( TUint8* )&srReport.iLSWTimestamp, |
|
2235 source.GetSR().iSrPtr.ntp_frac ); |
|
2236 BigEndian::Put32( ( TUint8* )&srReport.iRTPTimestamp, |
|
2237 source.GetSR().RTPTimestamp() ); |
|
2238 BigEndian::Put32( ( TUint8* )&srReport.iSenderPacketCount, |
|
2239 aPtr->iAudioPackets ); |
|
2240 BigEndian::Put32( ( TUint8* )&srReport.iSenderOctetCount, |
|
2241 aPtr->iAudioBytes ); |
|
2242 TPtrC8 rtcpHeader( ( TUint8* )&srReport, sizeof( srReport ) ); |
|
2243 aPtr->iBuffer->AddPacket( aStreamId, rtcpHeader ); |
|
2244 |
|
2245 // Verify Seq and Ts |
|
2246 if ( aPtr->iNoRtpInfoHeader ) |
|
2247 { |
|
2248 aPtr->ConstructSeqAndTsForSink ( |
|
2249 aStreamId, |
|
2250 source.GetSR().iSrPtr.ntp_sec, |
|
2251 source.GetSR().iSrPtr.ntp_frac, |
|
2252 source.GetSR().RTPTimestamp(), |
|
2253 0 ); // 0 not used |
|
2254 } |
|
2255 } |
|
2256 |
|
2257 // ----------------------------------------------------------------------------- |
|
2258 // CCRRtspPacketSource::HandleNewSourceL |
|
2259 // ----------------------------------------------------------------------------- |
|
2260 // |
|
2261 void CCRRtspPacketSource::HandleNewSourceL( |
|
2262 CCRRtspPacketSource* aPtr, |
|
2263 RRtpReceiveSource& aSource, |
|
2264 const TRtpEvent& aEvent, |
|
2265 TRtpCallbackFunction aCallback ) |
|
2266 { |
|
2267 // Cancel UDP timer, so as not to trigger TCP streaming |
|
2268 aPtr->iUdpReceptionTimer->Cancel(); |
|
2269 delete aPtr->iPunchPacketSenderAudio; |
|
2270 aPtr->iPunchPacketSenderAudio = NULL; |
|
2271 if ( aSource.IsOpen() ) |
|
2272 { |
|
2273 aSource.Close(); |
|
2274 } |
|
2275 |
|
2276 // Source |
|
2277 aSource = aEvent.Session().NewReceiveSourceL(); |
|
2278 aSource.PrivRegisterEventCallbackL( ERtpPacketReceived, aCallback, aPtr ); |
|
2279 aSource.PrivRegisterEventCallbackL( ERtpSR, aCallback, aPtr ); |
|
2280 aSource.PrivRegisterEventCallbackL( ERtpBYE, aCallback, aPtr ); |
|
2281 aSource.PrivRegisterEventCallbackL( ERtpSessionFail, aCallback, aPtr ); |
|
2282 aSource.PrivRegisterEventCallbackL( ERtpSourceFail, aCallback, aPtr ); |
|
2283 |
|
2284 // Ping Timer |
|
2285 if ( !aPtr->iRtspPingTimer ) |
|
2286 { |
|
2287 aPtr->iRtspPingTimer = CPeriodic::NewL( CActive::EPriorityLow ); |
|
2288 aPtr->iRtspPingTimer->Start( |
|
2289 KDVR10Seconds, 2 * KDVR10Seconds, TCallBack( SendRtspPing, aPtr ) ); |
|
2290 } |
|
2291 |
|
2292 aEvent.Session().SendAPPL( KCRCName() ); |
|
2293 aEvent.Session().SetRTCPAutoSend( ETrue ); |
|
2294 } |
|
2295 |
|
2296 // ----------------------------------------------------------------------------- |
|
2297 // CCRRtspPacketSource::SendAuthDescribeL |
|
2298 // ----------------------------------------------------------------------------- |
|
2299 // |
|
2300 void CCRRtspPacketSource::SendAuthDescribeL( ) |
|
2301 { |
|
2302 delete iPrevCommands[ERTSPDescSent]; |
|
2303 iPrevCommands[ERTSPDescSent] = NULL; |
|
2304 iPrevCommands[ERTSPDescSent] = CCRRtspCommand::NewL(); |
|
2305 iPrevCommands[ERTSPDescSent]->SetCommand ( |
|
2306 CCRRtspCommand::ERTSPCommandDESCRIBE ); |
|
2307 TPtrC8 uriDes ( iRtspUri8->Des() ); |
|
2308 iPrevCommands[ERTSPDescSent]->SetURL ( uriDes ); |
|
2309 iPrevCommands[ERTSPDescSent]->SetCSeq ( iCSeq ++ ); |
|
2310 |
|
2311 if ( iAuthType ) |
|
2312 { |
|
2313 iPrevCommands[ERTSPDescSent]->SetAuthenticationTypeL( iAuthType->Des() ); |
|
2314 } |
|
2315 if ( iNonce ) |
|
2316 { |
|
2317 iPrevCommands[ERTSPDescSent]->SetNonceL( iNonce->Des() ); |
|
2318 } |
|
2319 if ( iRealm ) |
|
2320 { |
|
2321 iPrevCommands[ERTSPDescSent]->SetRealmL( iRealm->Des() ); |
|
2322 } |
|
2323 if ( iOpaque ) |
|
2324 { |
|
2325 iPrevCommands[ERTSPDescSent]->SetOpaqueL( iOpaque->Des() ); |
|
2326 } |
|
2327 if ( iUserAgent ) |
|
2328 { |
|
2329 iPrevCommands[ERTSPDescSent]->SetUserAgentL( *iUserAgent ); |
|
2330 } |
|
2331 if ( iWapProfile ) |
|
2332 { |
|
2333 iPrevCommands[ERTSPDescSent]->SetWapProfileL( *iWapProfile ); |
|
2334 } |
|
2335 if ( iBandwidth ) |
|
2336 { |
|
2337 iPrevCommands[ERTSPDescSent]->SetBandwidth( iBandwidth ); |
|
2338 } |
|
2339 |
|
2340 iPrevCommands[ERTSPDescSent]->SetUserNameL( iUserName->Des() ); |
|
2341 iPrevCommands[ERTSPDescSent]->SetPassWdL( iPassword->Des() ); |
|
2342 iPrevCommands[ERTSPDescSent]->SetRtspUriL( iRtspUri->Des() ); |
|
2343 iPrevCommands[ERTSPDescSent]->SetAuthentication ( iAuthenticationNeeded ); |
|
2344 if ( iRtspSock ) |
|
2345 { |
|
2346 iRtspSock->SendData( iPrevCommands[ERTSPDescSent]->ProduceL() ); |
|
2347 StartRtspTimeout( KCRRtspResponseTimeout ); |
|
2348 } |
|
2349 iStage = ERTSPDescSent; |
|
2350 } |
|
2351 |
|
2352 // ----------------------------------------------------------------------------- |
|
2353 // CCRRtspPacketSource::AddAuthenticationL |
|
2354 // ----------------------------------------------------------------------------- |
|
2355 // |
|
2356 void CCRRtspPacketSource::AddAuthenticationL( TInt aCommand ) |
|
2357 { |
|
2358 if ( iPrevCommands[aCommand] && iNonce && |
|
2359 iOpaque && iUserName && iPassword ) |
|
2360 { |
|
2361 iPrevCommands[aCommand]->SetAuthenticationTypeL( iAuthType->Des() ); |
|
2362 iPrevCommands[aCommand]->SetNonceL( iNonce->Des() ); |
|
2363 iPrevCommands[aCommand]->SetRealmL( iRealm->Des() ); |
|
2364 iPrevCommands[aCommand]->SetOpaqueL( iOpaque->Des() ); |
|
2365 iPrevCommands[aCommand]->SetUserNameL( iUserName->Des() ); |
|
2366 iPrevCommands[aCommand]->SetPassWdL( iPassword->Des() ); |
|
2367 iPrevCommands[aCommand]->SetRtspUriL( iRtspUri->Des() ); |
|
2368 iPrevCommands[aCommand]->SetAuthentication ( iAuthenticationNeeded ); |
|
2369 } |
|
2370 } |
|
2371 |
|
2372 // ----------------------------------------------------------------------------- |
|
2373 // CCRRtspPacketSource::PunchPacketsSent |
|
2374 // ----------------------------------------------------------------------------- |
|
2375 // |
|
2376 void CCRRtspPacketSource::PunchPacketsSent( CCRPunchPacketSender* aPuncher ) |
|
2377 { |
|
2378 if ( iPunchPacketSenderVideo && aPuncher == iPunchPacketSenderVideo ) |
|
2379 { |
|
2380 iPunchPacketSentForVideo = ETrue; |
|
2381 } |
|
2382 if ( iPunchPacketSenderAudio && aPuncher == iPunchPacketSenderAudio ) |
|
2383 { |
|
2384 iPunchPacketSentForAudio = ETrue; |
|
2385 } |
|
2386 if ( ( iPunchPacketSenderVideo && !iPunchPacketSenderAudio && |
|
2387 iPunchPacketSentForVideo ) || |
|
2388 ( !iPunchPacketSenderVideo && iPunchPacketSenderAudio && |
|
2389 iPunchPacketSentForAudio ) || |
|
2390 ( iPunchPacketSenderVideo && iPunchPacketSenderAudio && |
|
2391 iPunchPacketSentForVideo && iPunchPacketSentForAudio ) ) |
|
2392 { |
|
2393 LOG1( "PunchPacketsSent, play readiness: %d", iReadyToPlay ); |
|
2394 SetupSessionsAndPlay(); |
|
2395 } |
|
2396 } |
|
2397 |
|
2398 // ----------------------------------------------------------------------------- |
|
2399 // CCRRtspPacketSource::SetupSessionsAndPlay |
|
2400 // ----------------------------------------------------------------------------- |
|
2401 // |
|
2402 void CCRRtspPacketSource::SetupSessionsAndPlay() |
|
2403 { |
|
2404 // all needed punch packets are sent: |
|
2405 if ( SetupRTPSessions() != KErrNone ) |
|
2406 { |
|
2407 iOwningSession.SourceStop(); |
|
2408 } |
|
2409 else |
|
2410 { |
|
2411 // if we're ready to play, play |
|
2412 if ( iReadyToPlay ) |
|
2413 { |
|
2414 TRAPD( err, SendPlayCommandL() ); |
|
2415 if ( err != KErrNone ) |
|
2416 { |
|
2417 iOwningSession.SourceStop(); |
|
2418 } |
|
2419 } |
|
2420 else |
|
2421 { |
|
2422 iStage = ERTSPReadyToPlay; |
|
2423 } |
|
2424 } |
|
2425 } |
|
2426 |
|
2427 // ----------------------------------------------------------------------------- |
|
2428 // CCRRtspPacketSource::SendPunchPackets |
|
2429 // ----------------------------------------------------------------------------- |
|
2430 // |
|
2431 void CCRRtspPacketSource::SendPunchPacketsL( void ) |
|
2432 { |
|
2433 LOG( "CCRRtspPacketSource::SendPunchPacketsL in" ); |
|
2434 delete iPunchPacketSenderAudio; |
|
2435 iPunchPacketSenderAudio = NULL; |
|
2436 delete iPunchPacketSenderVideo; |
|
2437 iPunchPacketSenderVideo = NULL; |
|
2438 |
|
2439 if ( iSdpParser &&iRtspSock && iResponses[ERTSPSetupVideoSent] ) |
|
2440 { |
|
2441 TInetAddr localAddr = iRtspSock->LocalAddr(); |
|
2442 TInetAddr remoteAddr = iRtspSock->ConnectedAddr(); |
|
2443 localAddr.SetPort(iResponses[ERTSPSetupVideoSent]->ClientPort()); |
|
2444 remoteAddr.SetPort(iResponses[ERTSPSetupVideoSent]->ServerPort()); |
|
2445 iPunchPacketSenderVideo = CCRPunchPacketSender::NewL( |
|
2446 iConnection.Connection(), iSockServer, |
|
2447 localAddr, remoteAddr, 0, *this ); |
|
2448 } |
|
2449 if ( iSdpParser && iRtspSock && iResponses[ERTSPSetupAudioSent] ) |
|
2450 { |
|
2451 TInetAddr localAddr = iRtspSock->LocalAddr(); |
|
2452 TInetAddr remoteAddr = iRtspSock->ConnectedAddr(); |
|
2453 localAddr.SetPort(iResponses[ERTSPSetupAudioSent]->ClientPort()); |
|
2454 remoteAddr.SetPort(iResponses[ERTSPSetupAudioSent]->ServerPort()); |
|
2455 iPunchPacketSenderAudio = CCRPunchPacketSender::NewL( |
|
2456 iConnection.Connection(), iSockServer, |
|
2457 localAddr, remoteAddr, 0, *this ); |
|
2458 } |
|
2459 } |
|
2460 |
|
2461 // ----------------------------------------------------------------------------- |
|
2462 // CCRRtspPacketSource::ConnectionStatusChange |
|
2463 // ----------------------------------------------------------------------------- |
|
2464 // |
|
2465 void CCRRtspPacketSource::ConnectionStatusChange( |
|
2466 TInt /*aSessionId*/, |
|
2467 TCRConnectionStatus aStatus, |
|
2468 TInt /* aErr */ ) |
|
2469 { |
|
2470 switch( aStatus ) |
|
2471 { |
|
2472 // Connection has gone up or bearer has changed -> check bandwidth |
|
2473 case ECRBearerChanged: |
|
2474 { |
|
2475 LOG( "CCRRtspPacketSource::ConnectionStatusChange: IapUp or IapUp2G" ); |
|
2476 if ( iSdpParser && iObserver ) |
|
2477 { |
|
2478 // Unknown bitrate or bandwidth are returned as zero. Bitrates in kbit/s |
|
2479 TInt bitrate( iSdpParser->VideoBitrate() + |
|
2480 iSdpParser->AudioBitrate() ); |
|
2481 TInt bandwidth( iConnection.MaximumBandwidth() / 1000 ); |
|
2482 if ( bitrate > 0 && bandwidth > 0 && bandwidth < bitrate ) |
|
2483 { |
|
2484 LOG2( "CCRRtspPacketSource::ConnectionStatusChange: clip_bitrate: %d, connection_bandwidth: %d -> NotEnoughBandwidth", |
|
2485 bitrate, bandwidth ); |
|
2486 iObserver->ConnectionStatusChange( |
|
2487 iOwningSession.SourceChecksum(), ECRNotEnoughBandwidth, KErrNone ); |
|
2488 } |
|
2489 } |
|
2490 break; |
|
2491 } |
|
2492 |
|
2493 // Connection has gone down or error occured -> switch back to RTP/UDP transport |
|
2494 case ECRConnectionError: |
|
2495 case ECRIapDown: |
|
2496 { |
|
2497 LOG( "CCRRtspPacketSource::ConnectionStatusChange: IapDown or ConnectionError -> switch to RTP/UDP streaming" ); |
|
2498 iConnection.SetHeuristic( CCRConnection::EUdpStreamingBlocked, EFalse ); |
|
2499 break; |
|
2500 } |
|
2501 |
|
2502 // Nothing to do for: |
|
2503 // ECRConnecting |
|
2504 // ECRAuthenticationNeeded |
|
2505 // ECRNotEnoughBandwidth |
|
2506 // ECRNormalEndOfStream |
|
2507 default: |
|
2508 { |
|
2509 LOG1( "CCRRtspPacketSource::ConnectionStatusChange: unhandled status: %d", aStatus ); |
|
2510 break; |
|
2511 } |
|
2512 } |
|
2513 } |
|
2514 |
|
2515 // ----------------------------------------------------------------------------- |
|
2516 // CCRRtspPacketSource::RegisterConnectionObs |
|
2517 // ----------------------------------------------------------------------------- |
|
2518 // |
|
2519 void CCRRtspPacketSource::RegisterConnectionObs( MCRConnectionObserver* aObserver ) |
|
2520 { |
|
2521 iObserver = aObserver; |
|
2522 } |
|
2523 |
|
2524 // ----------------------------------------------------------------------------- |
|
2525 // CCRRtspPacketSource::UnregisterConnectionObs |
|
2526 // ----------------------------------------------------------------------------- |
|
2527 // |
|
2528 void CCRRtspPacketSource::UnregisterConnectionObs( ) |
|
2529 { |
|
2530 iObserver = NULL; |
|
2531 } |
|
2532 |
|
2533 // ----------------------------------------------------------------------------- |
|
2534 // CCRRtspPacketSource::SetRtpSession |
|
2535 // ----------------------------------------------------------------------------- |
|
2536 // |
|
2537 void CCRRtspPacketSource::SetRtpSession( |
|
2538 RRtpSession& aSession, |
|
2539 TReal aGranularity ) |
|
2540 { |
|
2541 // Unit is 1/second |
|
2542 __ASSERT_DEBUG( iSdpParser != NULL, User::Panic( _L( "RTSP source" ), KErrBadHandle ) ); |
|
2543 TUint32 howManyNanoSecondsIsOneTick( |
|
2544 ( TUint32 )( TReal( 1000000000.0L ) / aGranularity ) ); |
|
2545 LOG1( "CCRRtspPacketSource::SetRtpSession clock tick: %u", howManyNanoSecondsIsOneTick ); |
|
2546 aSession.SetRTPTimeConversion( 0, howManyNanoSecondsIsOneTick ); |
|
2547 aSession.SetRtpStreamParameters( KDVRMinSequential, // 1 |
|
2548 KDVRMaxMisorder, // 50 |
|
2549 KDVRMaxDropOut ); // 3000 |
|
2550 } |
|
2551 |
|
2552 // ----------------------------------------------------------------------------- |
|
2553 // CCRRtspPacketSource::SendRtspPing |
|
2554 // ----------------------------------------------------------------------------- |
|
2555 // |
|
2556 TInt CCRRtspPacketSource::SendRtspPing( TAny* aSelfPtr ) |
|
2557 { |
|
2558 CCRRtspPacketSource* ptr = static_cast<CCRRtspPacketSource*> ( aSelfPtr ); |
|
2559 TRAPD( err, ptr->SendOptionsCommandL() ); |
|
2560 return err; |
|
2561 } |
|
2562 |
|
2563 // ----------------------------------------------------------------------------- |
|
2564 // CCRRtspPacketSource::ConstructSeqAndTsForSink |
|
2565 // ----------------------------------------------------------------------------- |
|
2566 // |
|
2567 void CCRRtspPacketSource::ConstructSeqAndTsForSink ( |
|
2568 MCRPacketSource::TCRPacketStreamId aStreamId, |
|
2569 TUint32 aMSWTimestamp, |
|
2570 TUint32 aLSWTimestamp, |
|
2571 TUint32 aRTPTimestamp, |
|
2572 TUint aSeq ) |
|
2573 { |
|
2574 switch ( aStreamId ) |
|
2575 { |
|
2576 case EAudioStream: |
|
2577 if ( iRTPTimeStampAudio ) |
|
2578 { |
|
2579 iSeqFromRtpInfoForAudio = aSeq; |
|
2580 if ( iSeqFromRtpInfoForAudio == 0 ) |
|
2581 { |
|
2582 iSeqFromRtpInfoForAudio++; |
|
2583 } |
|
2584 LOG1( "CCRRtspPacketSource::ConstructSeqAndTsForSink(), Audio seq: %d ", ( int )aSeq ); |
|
2585 // We may declare that we have seq+ts if we're here and have only audio or |
|
2586 // if we're here and have both audio and video and have also seq for video |
|
2587 if ( ( iSdpParser->SupportedContent() == CDvrSdpParser::EDvrAudioOnly ) || |
|
2588 ( iSdpParser->SupportedContent() == CDvrSdpParser::EDvrBothAudioAndVideo && |
|
2589 iSeqFromRtpInfoForVideo && iRTPTimeStampVideo ) ) |
|
2590 { |
|
2591 iSessionObs.StatusChanged( |
|
2592 MCRPacketSource::ERtpStateSeqAndTSAvailable ); |
|
2593 iNoRtpInfoHeader = EFalse; |
|
2594 if ( iStage == ERTSPPlaying ) |
|
2595 { |
|
2596 iSessionObs.StatusChanged( |
|
2597 MCRPacketSource::ERtpStatePlaying ); |
|
2598 } |
|
2599 } |
|
2600 } |
|
2601 break; |
|
2602 |
|
2603 case EAudioControlStream: |
|
2604 if ( !iMSWTimestamp ) |
|
2605 { // no wall clock time yet set |
|
2606 iMSWTimestamp = aMSWTimestamp; |
|
2607 iLSWTimestamp = aLSWTimestamp; |
|
2608 iRTPTimeStampAudio = aRTPTimestamp; |
|
2609 if ( iRTPTimeStampAudio == 0 ) |
|
2610 { |
|
2611 iRTPTimeStampAudio++; |
|
2612 } |
|
2613 } |
|
2614 else |
|
2615 { |
|
2616 // Sync audio with video |
|
2617 TInt64 wallClockOfVideo = MAKE_TINT64 ( iMSWTimestamp , iLSWTimestamp ); |
|
2618 TInt64 wallClockOfAudio = MAKE_TINT64 ( aMSWTimestamp , aLSWTimestamp ); |
|
2619 // Then figure out the difference. unit is now difficult ; upper |
|
2620 // 32 bits contain whole seconds, lower contains fraction |
|
2621 TInt64 wallClockDifference( wallClockOfVideo - wallClockOfAudio ); |
|
2622 // Now, the aRTPTimestamp has different scale, declared in SDP. |
|
2623 // first make one second that has same scale as wallClockDifference |
|
2624 TInt64 granularity( MAKE_TINT64( 1, 0 ) ); |
|
2625 // Then divide that one second with the given granularity. variable |
|
2626 // granularity will now contain in its low 32 bits the fraction of the |
|
2627 // second that re-presents one clock tick (e.g. 1/90000 sec for video) |
|
2628 granularity = granularity / static_cast<TInt64>( |
|
2629 iSdpParser->AudioTimerGranularity() ); |
|
2630 // Then divide our difference with this fraction of second |
|
2631 TInt64 wallClockDifferenceGranular = wallClockDifference / granularity; |
|
2632 // unit of wallClockDifferenceGranular is now 2^32 / granularity |
|
2633 TInt32 wallClockDifferenceGranular32 = wallClockDifferenceGranular; |
|
2634 LOG2( "CCRRtspPacketSource::ConstructSeqAndTsForSink(), Audio ts: %u adjust by: %d", |
|
2635 aRTPTimestamp , wallClockDifferenceGranular32 ); |
|
2636 iRTPTimeStampAudio = aRTPTimestamp + wallClockDifferenceGranular32; |
|
2637 if ( iRTPTimeStampAudio == 0 ) |
|
2638 { |
|
2639 iRTPTimeStampAudio++; |
|
2640 } |
|
2641 } |
|
2642 break; |
|
2643 |
|
2644 case EVideoStream: |
|
2645 if ( iRTPTimeStampVideo ) |
|
2646 { |
|
2647 iSeqFromRtpInfoForVideo = aSeq; |
|
2648 if ( iSeqFromRtpInfoForVideo == 0 ) |
|
2649 { |
|
2650 iSeqFromRtpInfoForVideo++; |
|
2651 } |
|
2652 LOG1( "CCRRtspPacketSource::ConstructSeqAndTsForSink(), Video seq: %d ", |
|
2653 ( int )aSeq ); |
|
2654 |
|
2655 // We may declare that we have seq+ts if we're here and have only video or |
|
2656 // if we're here and have both and have also seq for video |
|
2657 if ( ( iSdpParser->SupportedContent() == CDvrSdpParser::EDvrVideoOnly ) || |
|
2658 ( iSdpParser->SupportedContent() == CDvrSdpParser::EDvrBothAudioAndVideo && |
|
2659 iSeqFromRtpInfoForAudio && iRTPTimeStampAudio ) ) |
|
2660 { |
|
2661 iSessionObs.StatusChanged( |
|
2662 MCRPacketSource::ERtpStateSeqAndTSAvailable ); |
|
2663 iNoRtpInfoHeader = EFalse; |
|
2664 if ( iStage == ERTSPPlaying ) |
|
2665 { |
|
2666 iSessionObs.StatusChanged( |
|
2667 MCRPacketSource::ERtpStatePlaying ); |
|
2668 } |
|
2669 } |
|
2670 } |
|
2671 break; |
|
2672 |
|
2673 case EVideoControlStream: |
|
2674 if ( !iMSWTimestamp ) |
|
2675 { // No wall clock time yet set |
|
2676 iMSWTimestamp = aMSWTimestamp; |
|
2677 iLSWTimestamp = aLSWTimestamp; |
|
2678 iRTPTimeStampVideo = aRTPTimestamp; |
|
2679 if ( iRTPTimeStampVideo == 0 ) |
|
2680 { |
|
2681 iRTPTimeStampVideo++; |
|
2682 } |
|
2683 } |
|
2684 else |
|
2685 { |
|
2686 // Sync audio with video |
|
2687 TInt64 wallClockOfAudio = MAKE_TINT64 ( iMSWTimestamp , iLSWTimestamp ); |
|
2688 TInt64 wallClockOfVideo = MAKE_TINT64 ( aMSWTimestamp , aLSWTimestamp ); |
|
2689 // Then figure out the difference. unit is now difficult ; upper |
|
2690 // 32 bits contain whole seconds, lower contains fraction |
|
2691 TInt64 wallClockDifference( wallClockOfAudio - wallClockOfVideo ); |
|
2692 // Now, the aRTPTimestamp has different scale, declared in SDP. |
|
2693 // first make one second that has same scale as wallClockDifference |
|
2694 TInt64 granularity( MAKE_TINT64( 1, 0 ) ); |
|
2695 // Then divide that one second with the given granularity. variable |
|
2696 // granularity will now contain in its low 32 bits the fraction of the |
|
2697 // second that re-presents one clock tick (e.g. 1/90000 sec for video) |
|
2698 granularity = granularity / static_cast<TInt64>( |
|
2699 iSdpParser->VideoTimerGranularity()); |
|
2700 // Then divide our difference with this fraction of second |
|
2701 TInt64 wallClockDifferenceGranular = wallClockDifference / granularity; |
|
2702 // Unit of wallClockDifferenceGranular is now 2^32 / granularity |
|
2703 TInt32 wallClockDifferenceGranular32 = wallClockDifferenceGranular; |
|
2704 LOG2( "CCRRtspPacketSource::ConstructSeqAndTsForSink(), Video ts: %u adjust by: %d", |
|
2705 aRTPTimestamp , wallClockDifferenceGranular32 ); |
|
2706 iRTPTimeStampVideo = aRTPTimestamp + wallClockDifferenceGranular32; |
|
2707 if ( iRTPTimeStampVideo == 0 ) |
|
2708 { |
|
2709 iRTPTimeStampVideo++; |
|
2710 } |
|
2711 } |
|
2712 break; |
|
2713 |
|
2714 default: |
|
2715 // no thing |
|
2716 break; |
|
2717 } |
|
2718 } |
|
2719 |
|
2720 // ----------------------------------------------------------------------------- |
|
2721 // CCRRtspPacketSource::ConditionallySetupMultiCastOrTcpStreamingL |
|
2722 // ----------------------------------------------------------------------------- |
|
2723 // |
|
2724 void CCRRtspPacketSource::ConditionallySetupMultiCastOrTcpStreamingL ( void ) |
|
2725 { |
|
2726 // UDP: Punch packets or play sent in ProcessRTSPResponseL, so do nothing. |
|
2727 if ( iTransport == ERTPOverUDP ) |
|
2728 { |
|
2729 } |
|
2730 // Multicast: no punch packets needed but session setup yes |
|
2731 else if ( iTransport == ERTPOverMulticast ) |
|
2732 { |
|
2733 SetupSessionsAndPlay(); |
|
2734 } |
|
2735 |
|
2736 // TCP: no punch packets or session, just send PLAY .. but wait for UI |
|
2737 else if ( iTransport == ERTPOverTCP ) |
|
2738 { |
|
2739 if ( iReadyToPlay ) |
|
2740 { |
|
2741 SendPlayCommandL(); |
|
2742 } |
|
2743 else |
|
2744 { |
|
2745 iStage = ERTSPReadyToPlay; |
|
2746 } |
|
2747 } |
|
2748 } |
|
2749 |
|
2750 // ----------------------------------------------------------------------------- |
|
2751 // CCRRtspPacketSource::CheckReceiveOfStreams |
|
2752 // ----------------------------------------------------------------------------- |
|
2753 // |
|
2754 TBool CCRRtspPacketSource::CheckReceiveOfStreams() |
|
2755 { |
|
2756 TBool retVal( ETrue ); |
|
2757 |
|
2758 // Go through all streams and check that all streams have receive flag on, |
|
2759 // if not return false. |
|
2760 for ( TInt i = 0 ; i < iReceiveStreams.Count() ; i++ ) |
|
2761 { |
|
2762 if ( iReceiveStreams[i].iDataReceived == EFalse ) |
|
2763 { |
|
2764 LOG1( "CCRRtspPacketSource::CheckReceiveOfStreams - Missing atleast stream %d", iReceiveStreams[i].iStreamType ); |
|
2765 retVal = EFalse; |
|
2766 break; |
|
2767 } |
|
2768 } |
|
2769 |
|
2770 if ( retVal ) |
|
2771 { |
|
2772 LOG( "CCRRtspPacketSource::CheckReceiveOfStreams - Receiving from all streams!" ); |
|
2773 } |
|
2774 |
|
2775 return retVal; |
|
2776 } |
|
2777 |
|
2778 // ----------------------------------------------------------------------------- |
|
2779 // CCRRtspPacketSource::StreamFound |
|
2780 // ----------------------------------------------------------------------------- |
|
2781 // |
|
2782 void CCRRtspPacketSource::StreamFound( TCRPacketStreamId aStreamType ) |
|
2783 { |
|
2784 // Go through streams and find correct stream to set the receive flag. |
|
2785 for ( TInt i = 0 ; i < iReceiveStreams.Count(); i++ ) |
|
2786 { |
|
2787 if ( iReceiveStreams[i].iStreamType == aStreamType ) |
|
2788 { |
|
2789 iReceiveStreams[i].iDataReceived = ETrue; |
|
2790 LOG1( "CCRRtspPacketSource::StreamFound - Stream %d found", iReceiveStreams[i].iStreamType ); |
|
2791 break; |
|
2792 } |
|
2793 } |
|
2794 } |
|
2795 |
|
2796 // ----------------------------------------------------------------------------- |
|
2797 // CCRRtspPacketSource::ResetStreamFlags |
|
2798 // ----------------------------------------------------------------------------- |
|
2799 // |
|
2800 void CCRRtspPacketSource::ResetStreamFlags( ) |
|
2801 { |
|
2802 // Go through streams and clear receiving flag. |
|
2803 for ( TInt i = 0 ; i < iReceiveStreams.Count() ; i++ ) |
|
2804 { |
|
2805 iReceiveStreams[i].iDataReceived = EFalse; |
|
2806 } |
|
2807 |
|
2808 // We have to check receive again |
|
2809 iTrafficFound = EFalse; |
|
2810 } |
|
2811 |
|
2812 #if defined ( LIVE_TV_FILE_TRACE ) || defined ( LIVE_TV_RDEBUG_TRACE ) |
|
2813 // ----------------------------------------------------------------------------- |
|
2814 // CCRRtspPacketSource::ShowHeader |
|
2815 // ----------------------------------------------------------------------------- |
|
2816 // |
|
2817 void CCRRtspPacketSource::ShowHeader( |
|
2818 const TDesC8& aRtcpHeader, |
|
2819 const TCRRtpSRReportHeader& aSrReport ) |
|
2820 { |
|
2821 TBuf<100> b( KNullDesC ); |
|
2822 LOG1( "CCRRtspPacketSource::TCP control packet len: %d", aRtcpHeader.Length() ); |
|
2823 for ( TInt j( 0 ); j < 32 && j < aRtcpHeader.Length(); j++ ) |
|
2824 { |
|
2825 b.AppendFormat( _L( "%2X " ), ( unsigned )( aRtcpHeader[j] ) ); |
|
2826 if ( j > 0 && ( ( j % 16 ) == 0 ) ) |
|
2827 { |
|
2828 LOG2( "%d -> %S", j, &b ); |
|
2829 b.Zero(); |
|
2830 } |
|
2831 } |
|
2832 |
|
2833 LOG1( "iVersion %u", ( unsigned )aSrReport.iVersion ); |
|
2834 LOG1( "iPadding %u", ( unsigned )aSrReport.iPadding ); |
|
2835 LOG1( "iReportCount %u",( unsigned )aSrReport.iReportCount ); |
|
2836 LOG1( "iPacketType %u", ( unsigned )aSrReport.iPacketType ); |
|
2837 LOG1( "iLength %u", |
|
2838 ( unsigned)BigEndian::Get16( ( const TUint8* )&aSrReport.iLength ) ); |
|
2839 LOG1( "iSenderSSRC %u", |
|
2840 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iSenderSSRC ) ); |
|
2841 LOG1( "iMSWTimestamp %u", |
|
2842 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iMSWTimestamp) ); |
|
2843 LOG1( "iLSWTimestamp %u", |
|
2844 ( unsigned)BigEndian::Get32( ( const TUint8* )&aSrReport.iLSWTimestamp ) ); |
|
2845 LOG1( "iRTPTimestamp %u", |
|
2846 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iRTPTimestamp ) ); |
|
2847 LOG1( "iSenderPacketCount %u", |
|
2848 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iSenderPacketCount) ); |
|
2849 LOG1( "iSenderOctetCount %u", |
|
2850 ( unsigned )BigEndian::Get32( ( const TUint8* )&aSrReport.iSenderOctetCount ) ); |
|
2851 |
|
2852 } |
|
2853 #endif // LIVE_TV_FILE_TRACE || LIVE_TV_RDEBUG_TRACE |
|
2854 |
|
2855 // End of File |