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: Class that takes packet from the buffer and forward them thrue* |
|
15 */ |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 // INCLUDES |
|
21 #include "CCRXpsSink.h" |
|
22 #include "CCRPacketBuffer.h" |
|
23 #include "CCRStreamingSession.h" |
|
24 #include <ipvideo/CDvrSdpParser.h> |
|
25 #include "CCRTimer.h" |
|
26 #include "CRtpPacket.h" |
|
27 #include "CRtpTsConverter.h" |
|
28 #include <CXPSPacketSink.h> |
|
29 |
|
30 // CONSTANTS |
|
31 _LIT( KCRXpsServerName, "IpVideoXps" ); |
|
32 _LIT8( KAttributeDefRange, "a=range:npt=0-86400.0" ); |
|
33 #ifdef VIA_FEA_IPTV_USE_IPDC |
|
34 _LIT8( KMtvAvc, "X-MTV-AVC" ); |
|
35 _LIT8( KHxAvc1, "X-HX-AVC1" ); |
|
36 #endif // VIA_FEA_IPTV_USE_IPDC |
|
37 const TInt KRangeIdentifierLen( 8 ); |
|
38 const TInt KXpsBufferedPackets( 300 ); // about 3s |
|
39 const TInt KXpsOverflowDelay( 300 * 1000 ); // 300ms |
|
40 |
|
41 // ============================ MEMBER FUNCTIONS =============================== |
|
42 |
|
43 // ----------------------------------------------------------------------------- |
|
44 // CCRXpsSink::NewL |
|
45 // Two-phased constructor. |
|
46 // ----------------------------------------------------------------------------- |
|
47 // |
|
48 CCRXpsSink* CCRXpsSink::NewL( |
|
49 CCRStreamingSession::TCRSinkId aSinkId, |
|
50 CCRStreamingSession& aOwningSession ) |
|
51 { |
|
52 CCRXpsSink* self = new( ELeave ) |
|
53 CCRXpsSink( aSinkId, aOwningSession ); |
|
54 CleanupStack::PushL( self ); |
|
55 self->ConstructL(); |
|
56 CleanupStack::Pop( self ); |
|
57 return self; |
|
58 } |
|
59 |
|
60 // ----------------------------------------------------------------------------- |
|
61 // CCRXpsSink::CCRXpsSink |
|
62 // C++ default constructor can NOT contain any code, that might leave. |
|
63 // ----------------------------------------------------------------------------- |
|
64 // |
|
65 CCRXpsSink::CCRXpsSink( |
|
66 CCRStreamingSession::TCRSinkId aSinkId, |
|
67 CCRStreamingSession& aOwningSession ) |
|
68 : CCRPacketSinkBase( aOwningSession, aSinkId ), |
|
69 iWaitPlayer( KErrNotFound ), |
|
70 iRequested( KErrNotFound ), |
|
71 iXpsResetOk( EFalse ), |
|
72 iAudioStreamId( KErrNotFound ), |
|
73 iVideoStreamId( KErrNotFound ), |
|
74 iTitleStreamId( KErrNotFound ) |
|
75 { |
|
76 // None |
|
77 } |
|
78 |
|
79 // ----------------------------------------------------------------------------- |
|
80 // CCRXpsSink::ConstructL |
|
81 // 2nd phase. |
|
82 // ----------------------------------------------------------------------------- |
|
83 // |
|
84 void CCRXpsSink::ConstructL() |
|
85 { |
|
86 LOG( "CCRXpsSink::ConstructL() in" ); |
|
87 |
|
88 iRtpPacket = CRtpPacket::NewL(); |
|
89 iPacketSink = CXPSPacketSink::New(); |
|
90 LOG1( "CCRXpsSink::ConstructL(), iPacketSink: %d", iPacketSink ); |
|
91 User::LeaveIfNull( iPacketSink ); |
|
92 TInt err( iPacketSink->Init( KCRXpsServerName, this ) ); |
|
93 if ( err ) |
|
94 { |
|
95 LOG1( "CCRXpsSink::ConstructL(), iPacketSink->Init() err: %d", err ); |
|
96 User::Leave( err ); |
|
97 } |
|
98 |
|
99 LOG( "CCRXpsSink::ConstructL() out" ); |
|
100 } |
|
101 |
|
102 // ----------------------------------------------------------------------------- |
|
103 // CCRXpsSink::~CCRXpsSink |
|
104 // Destructor. |
|
105 // ----------------------------------------------------------------------------- |
|
106 // |
|
107 CCRXpsSink::~CCRXpsSink() |
|
108 { |
|
109 LOG( "CCRXpsSink::~CCRXpsSink()" ); |
|
110 |
|
111 // Delete variables |
|
112 StopTimer(); |
|
113 delete iPacketSink; |
|
114 delete iAudioConv; |
|
115 delete iVideoConv; |
|
116 delete iTitleConv; |
|
117 delete iRtpPacket; |
|
118 |
|
119 #ifdef VIA_FEA_IPTV_USE_IPDC |
|
120 delete iVideoDepacketizer; |
|
121 #endif // VIA_FEA_IPTV_USE_IPDC |
|
122 } |
|
123 |
|
124 // ----------------------------------------------------------------------------- |
|
125 // CCRXpsSink::SetSdpL |
|
126 // Sets SDP, parses it and initiates XPS. |
|
127 // ----------------------------------------------------------------------------- |
|
128 // |
|
129 void CCRXpsSink::SetSdpL( const TDesC8& aSdp ) |
|
130 { |
|
131 LOG1( "CCRXpsSink::SetSdpL(), SDP len: %d", aSdp.Length() ); |
|
132 |
|
133 #if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) |
|
134 LOG( "CCRXpsSink::SetSdpL(), SDP content:" ); |
|
135 TName d( KNullDesC ); |
|
136 for ( TInt i( 0 ); i < aSdp.Length(); i++ ) |
|
137 { |
|
138 TChar c = aSdp[i]; |
|
139 d.Append( c ); |
|
140 if ( ( i > 0 ) && ( i % 80 ) == 0 ) |
|
141 { |
|
142 LOG1( ">%S<", &d ); |
|
143 d.Zero(); |
|
144 } |
|
145 } |
|
146 |
|
147 LOG1( ">%S<", &d ); |
|
148 #endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE |
|
149 |
|
150 if ( iWaitPlayer != KErrNotFound ) |
|
151 { |
|
152 LOG( "CCRXpsSink::SetSdpL(), SDP already set !" ); |
|
153 return; |
|
154 } |
|
155 |
|
156 // SDP parser |
|
157 CDvrSdpParser* sdpParser = CDvrSdpParser::NewLC(); |
|
158 sdpParser->TryParseL( aSdp ); |
|
159 |
|
160 // TS converter |
|
161 delete iAudioConv; iAudioConv = NULL; |
|
162 iAudioConv = CRtpTsConverter::NewL( sdpParser->AudioTimerGranularity() ); |
|
163 LOG1( "CCRXpsSink::SetSdpL(), AudioTimerGranularity: %d", |
|
164 sdpParser->AudioTimerGranularity() ); |
|
165 |
|
166 delete iVideoConv; iVideoConv = NULL; |
|
167 iVideoConv = CRtpTsConverter::NewL( sdpParser->VideoTimerGranularity() ); |
|
168 LOG1( "CCRXpsSink::SetSdpL(), VideoTimerGranularity: %d", |
|
169 sdpParser->VideoTimerGranularity() ); |
|
170 |
|
171 delete iTitleConv; iTitleConv = NULL; |
|
172 |
|
173 // Streams count |
|
174 TInt streams( 0 ); |
|
175 const CDvrSdpParser::TDvrPacketProvidings providings( |
|
176 sdpParser->SupportedContent() ); |
|
177 if ( providings == CDvrSdpParser::EDvrAudioOnly || |
|
178 providings == CDvrSdpParser::EDvrVideoOnly ) |
|
179 { |
|
180 streams = 1; |
|
181 } |
|
182 if ( providings == CDvrSdpParser::EDvrBothAudioAndVideo ) |
|
183 { |
|
184 streams = 2; |
|
185 } |
|
186 |
|
187 // Stream ids |
|
188 iAudioStreamId = sdpParser->AudioStreamId(); |
|
189 iVideoStreamId = sdpParser->VideoStreamId(); |
|
190 LOG2( "CCRXpsSink::SetSdpL(), iAudioStreamId: %d, iVideoStreamId: %d", |
|
191 iAudioStreamId, iVideoStreamId ); |
|
192 // Verify/update range |
|
193 if ( aSdp.FindC( |
|
194 KAttributeDefRange().Left( KRangeIdentifierLen ) ) == KErrNotFound ) |
|
195 { |
|
196 LOG( "CCRXpsSink::SetSdpL(), setting default range" ); |
|
197 iRangeKnown = EFalse; |
|
198 sdpParser->NewLineL( KErrNotFound, KAttributeDefRange ); |
|
199 } |
|
200 else |
|
201 { |
|
202 LOG( "CCRXpsSink::SetSdpL() sdp already did contain range, not changed" ); |
|
203 iRangeKnown = ETrue; |
|
204 } |
|
205 |
|
206 // Get SDP data |
|
207 TPtrC8 sdp( NULL, 0 ); |
|
208 User::LeaveIfError( sdpParser->GetSdp( sdp ) ); |
|
209 HBufC8* tmpSdpData = NULL; |
|
210 |
|
211 // See if recorded from ISMA crypted content |
|
212 #ifdef VIA_FEA_IPTV_USE_IPDC |
|
213 TInt mimePos( sdp.Find( KMtvAvc ) ); |
|
214 if ( mimePos != KErrNotFound || sdp.Find( KHxAvc1 ) != KErrNotFound ) |
|
215 { |
|
216 LOG( "CCRXpsSink::SetSdpL(), Playback of ISMA clip.." ); |
|
217 delete iVideoDepacketizer; iVideoDepacketizer = NULL; |
|
218 iVideoDepacketizer = CH264Mpeg4GenrToFileformat::New(); |
|
219 User::LeaveIfNull( iVideoDepacketizer ); |
|
220 HBufC8* fmtp = FindFmtpLC( sdp ); |
|
221 TInt err( iVideoDepacketizer->Init( *fmtp ) ); |
|
222 CleanupStack::PopAndDestroy( fmtp ); |
|
223 if ( err ) |
|
224 { |
|
225 delete iVideoDepacketizer; iVideoDepacketizer = NULL; |
|
226 LOG1( "CCRXpsSink::SetSdpL(), Depacketizer Init() failed: %d", err ); |
|
227 } |
|
228 else |
|
229 { |
|
230 // Change MIME type from X-MTV-AVC to X-HX-AVC1 for playback |
|
231 // KMtvAvc mime prevents Helix crash in non DVB-H phones |
|
232 if ( mimePos != KErrNotFound ) |
|
233 { |
|
234 tmpSdpData = HBufC8::NewLC( sdp.Length() - |
|
235 KMtvAvc().Length() + KHxAvc1().Length() ); |
|
236 TPtr8 ptr( tmpSdpData->Des() ); |
|
237 ptr.Copy( sdp.Left( mimePos ) ); |
|
238 ptr.Append( KHxAvc1 ); |
|
239 ptr.Append( sdp.Mid( mimePos + KMtvAvc().Length() ) ); |
|
240 sdp.Set( ptr ); |
|
241 } |
|
242 } |
|
243 } |
|
244 #endif // VIA_FEA_IPTV_USE_IPDC |
|
245 |
|
246 // Pass SDP to XPS |
|
247 LOG( "CCRXpsSink::SetSdpL(), iPacketSink->SetSessionDescription.." ); |
|
248 User::LeaveIfError( iPacketSink->SetSessionDescription( sdp, streams ) ); |
|
249 if ( tmpSdpData != NULL ) |
|
250 { |
|
251 CleanupStack::PopAndDestroy( tmpSdpData ); |
|
252 } |
|
253 |
|
254 // Config streams |
|
255 for ( TInt i( 0 ); i < streams; i++ ) |
|
256 { |
|
257 LOG2( "CCRXpsSink::SetSdpL(), iPacketSink->ConfigStream: %d, KXpsBufferedPackets: %d", |
|
258 i, KXpsBufferedPackets ); |
|
259 User::LeaveIfError( iPacketSink->ConfigStream( i, KXpsBufferedPackets ) ); |
|
260 } |
|
261 |
|
262 CleanupStack::PopAndDestroy( sdpParser ); |
|
263 iWaitPlayer = KErrNone; |
|
264 } |
|
265 |
|
266 // ----------------------------------------------------------------------------- |
|
267 // CCRXpsSink::NewPacketAvailable |
|
268 // From CCRPacketSinkBase. |
|
269 // ----------------------------------------------------------------------------- |
|
270 // |
|
271 void CCRXpsSink::NewPacketAvailable() |
|
272 { |
|
273 // Kill flow timer |
|
274 StopTimer(); |
|
275 |
|
276 // Ok to enqueue? |
|
277 if ( iBuffer ) |
|
278 { |
|
279 if ( iWaitPlayer == KErrNone ) |
|
280 { |
|
281 // Enqueue packet |
|
282 if ( SendPacket() ) |
|
283 { |
|
284 // Keep buffer size reasonable |
|
285 iBuffer->HandleBufferSize(); |
|
286 } |
|
287 |
|
288 if ( iBuffer->ContinousStream() ) |
|
289 { |
|
290 // Make sure all will be sent from the buffer in continous stream case |
|
291 if ( iBuffer->PacketsCount( iSinkId ) > KErrNotFound ) |
|
292 { |
|
293 StartTimer( 0 ); |
|
294 } |
|
295 } |
|
296 else |
|
297 { |
|
298 // Group done, need request more |
|
299 if ( !iBuffer->MoreComing() ) |
|
300 { |
|
301 StartTimer( 0 ); |
|
302 } |
|
303 } |
|
304 } |
|
305 else |
|
306 { |
|
307 iBuffer->HandleBufferSize(); |
|
308 // Make sure that process never end |
|
309 if ( !iBuffer->ContinousStream() ) |
|
310 { |
|
311 StartTimer( KXpsOverflowDelay ); |
|
312 } |
|
313 } |
|
314 } |
|
315 } |
|
316 |
|
317 // ----------------------------------------------------------------------------- |
|
318 // CCRXpsSink::BufferResetting |
|
319 // From CCRPacketSinkBase. |
|
320 // ----------------------------------------------------------------------------- |
|
321 // |
|
322 void CCRXpsSink::BufferResetDone() |
|
323 { |
|
324 StopTimer(); |
|
325 iWaitPlayer = KErrNone; |
|
326 iRequested = KErrNotFound; |
|
327 |
|
328 // XPS reset possible? |
|
329 if ( iXpsResetOk ) |
|
330 { |
|
331 LOG( "CCRXpsSink::BufferResetDone(), Resets XPS.." ); |
|
332 iPacketSink->Reset(); |
|
333 iXpsResetOk = EFalse; |
|
334 } |
|
335 |
|
336 // Uninit TS converters |
|
337 LOG( "CCRXpsSink::BufferResetDone(), Uninitiates TS converters.." ); |
|
338 if ( iAudioConv ) |
|
339 { |
|
340 iAudioConv->UnInitiate(); |
|
341 } |
|
342 if ( iVideoConv ) |
|
343 { |
|
344 iVideoConv->UnInitiate(); |
|
345 } |
|
346 if ( iTitleConv ) |
|
347 { |
|
348 iTitleConv->UnInitiate(); |
|
349 } |
|
350 |
|
351 #if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) |
|
352 iLogXps = 0; |
|
353 #endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE |
|
354 } |
|
355 |
|
356 // ----------------------------------------------------------------------------- |
|
357 // CCRXpsSink::TimerExpired |
|
358 // From MCRTimerObserver. |
|
359 // ----------------------------------------------------------------------------- |
|
360 // |
|
361 void CCRXpsSink::TimerExpired( CCRTimer* /*aTimer*/ ) |
|
362 { |
|
363 RestoreSink(); |
|
364 } |
|
365 |
|
366 // ----------------------------------------------------------------------------- |
|
367 // CCRXpsSink::RestorePacketSupply |
|
368 // From CCRPacketSinkBase. |
|
369 // ----------------------------------------------------------------------------- |
|
370 // |
|
371 void CCRXpsSink::RestorePacketSupply( TUint aStreamId ) |
|
372 { |
|
373 #if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) |
|
374 if ( iLogXps < 5 ) |
|
375 { |
|
376 iLogXps++; |
|
377 LOG2( "CCRXpsSink::RestorePacketSupply(), aStreamId: %d, iWaitPlayer: %d", |
|
378 aStreamId, iWaitPlayer ); |
|
379 } |
|
380 #endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE |
|
381 |
|
382 if ( iWaitPlayer != TInt( ETrue ) ) |
|
383 { |
|
384 if ( iBuffer->ContinousStream() ) |
|
385 { |
|
386 iRequested = aStreamId; |
|
387 iWaitPlayer = KErrNone; |
|
388 RestoreSink(); |
|
389 } |
|
390 else |
|
391 { |
|
392 iWaitPlayer = KErrNone; |
|
393 StartTimer( KXpsOverflowDelay ); |
|
394 } |
|
395 } |
|
396 } |
|
397 |
|
398 // ----------------------------------------------------------------------------- |
|
399 // CCRXpsSink::RestoreSink |
|
400 // ----------------------------------------------------------------------------- |
|
401 // |
|
402 void CCRXpsSink::RestoreSink() |
|
403 { |
|
404 if ( iBuffer ) |
|
405 { |
|
406 // See if more waits in packet buffer |
|
407 if ( iBuffer->PacketsCount( iSinkId ) > KErrNotFound ) |
|
408 { |
|
409 NewPacketAvailable(); |
|
410 } |
|
411 else |
|
412 { |
|
413 StopTimer(); |
|
414 // This is only for non continous stream, like .rtp clip |
|
415 iOwningSession.SourceRestore(); |
|
416 } |
|
417 } |
|
418 } |
|
419 |
|
420 // ----------------------------------------------------------------------------- |
|
421 // CCRXpsSink::SendPacket |
|
422 // Initialises time stamp converter for audio and video stream and passes RTP |
|
423 // packets with adjusted time stamp to XPS interface. All packets before |
|
424 // converter has beeen initialized are dumbed. |
|
425 // ----------------------------------------------------------------------------- |
|
426 // |
|
427 TBool CCRXpsSink::SendPacket() |
|
428 { |
|
429 TBool packetSent( ETrue ); |
|
430 MCRPacketSource::TCRPacketStreamId bufferId( MCRPacketSource::EStreamIdCount ); |
|
431 const TInt book( iBuffer->GetStream( iSinkId, bufferId ) ); |
|
432 TPtr8 packet( NULL, 0 ); |
|
433 |
|
434 // Packet type related action |
|
435 TInt err( KErrNone ); |
|
436 switch ( bufferId ) |
|
437 { |
|
438 case MCRPacketSource::EAudioStream: |
|
439 if ( iAudioConv->Initiated() ) |
|
440 { |
|
441 iBuffer->GetPacket( book, packet ); |
|
442 if ( iRequested == KErrNotFound || iRequested == iAudioStreamId ) |
|
443 { |
|
444 iRequested = KErrNotFound; |
|
445 err = SendAudioPacket( packet ); |
|
446 } |
|
447 else |
|
448 { |
|
449 LOG( "CCRXpsSink::SendPacket(), Audio packet DROPPED after XPS overflow !" ) |
|
450 } |
|
451 } |
|
452 else |
|
453 { |
|
454 packetSent = EFalse; |
|
455 SearchForControlStreamPackets(); |
|
456 } |
|
457 break; |
|
458 |
|
459 case MCRPacketSource::EAudioControlStream: |
|
460 { |
|
461 iBuffer->GetPacket( book, packet ); |
|
462 if ( !iAudioConv->Initiated() ) |
|
463 { |
|
464 iAudioConv->Init( packet ); |
|
465 LOG1( "CCRXpsSink::SendPacket(), Audio TS initiated, status: %d", |
|
466 iAudioConv->Initiated() ) |
|
467 } |
|
468 } |
|
469 break; |
|
470 |
|
471 case MCRPacketSource::EVideoStream: |
|
472 if ( iVideoConv->Initiated() ) |
|
473 { |
|
474 iBuffer->GetPacket( book, packet ); |
|
475 if ( iRequested == KErrNotFound || iRequested == iVideoStreamId ) |
|
476 { |
|
477 iRequested = KErrNotFound; |
|
478 err = SendVideoPacket( packet ); |
|
479 } |
|
480 else |
|
481 { |
|
482 LOG( "CCRXpsSink::SendPacket(), Video packet DROPPED after XPS overflow !" ) |
|
483 } |
|
484 } |
|
485 else |
|
486 { |
|
487 packetSent = EFalse; |
|
488 SearchForControlStreamPackets(); |
|
489 } |
|
490 break; |
|
491 |
|
492 case MCRPacketSource::EVideoControlStream: |
|
493 { |
|
494 iBuffer->GetPacket( book, packet ); |
|
495 if ( !iVideoConv->Initiated() ) |
|
496 { |
|
497 iVideoConv->Init( packet ); |
|
498 LOG1( "CCRXpsSink::SendPacket(), Video TS initiated, status: %d", |
|
499 iVideoConv->Initiated() ) |
|
500 } |
|
501 } |
|
502 break; |
|
503 |
|
504 case MCRPacketSource::ESubTitleStream: |
|
505 if ( iTitleConv->Initiated() ) |
|
506 { |
|
507 iBuffer->GetPacket( book, packet ); |
|
508 err = SendTitlePacket( packet ); |
|
509 } |
|
510 else |
|
511 { |
|
512 packetSent = EFalse; |
|
513 SearchForControlStreamPackets(); |
|
514 } |
|
515 break; |
|
516 |
|
517 case MCRPacketSource::ESubTitleControlStream: |
|
518 { |
|
519 iBuffer->GetPacket( book, packet ); |
|
520 if ( !iTitleConv->Initiated() ) |
|
521 { |
|
522 iTitleConv->Init( packet ); |
|
523 LOG1( "CCRXpsSink::SendPacket(), Title TS initiated, status: %d", |
|
524 iTitleConv->Initiated() ) |
|
525 } |
|
526 } |
|
527 break; |
|
528 |
|
529 case MCRPacketSource::EDisContinousStream: |
|
530 { |
|
531 LOG( "CCRXpsSink::SendPacket(), EDiscontinousStream" ); |
|
532 // Just wait player's "MvloLoadingStartedL" event, |
|
533 // PlayCommand( -1.0, -1.0 ) will then handle pause packet |
|
534 iWaitPlayer = ETrue; |
|
535 // Used packet out from the buffer |
|
536 iBuffer->GetPacket( book, packet ); |
|
537 } |
|
538 break; |
|
539 |
|
540 case MCRPacketSource::EStreamEndTag: |
|
541 LOG1( "CCRXpsSink::SendPacket(), EStreamEndTag, iRangeKnown: %d", iRangeKnown ); |
|
542 if ( iRangeKnown ) |
|
543 { |
|
544 if ( iAudioStreamId > KErrNotFound ) |
|
545 { |
|
546 iPacketSink->StreamEnd( iAudioStreamId ); |
|
547 } |
|
548 if ( iVideoStreamId > KErrNotFound ) |
|
549 { |
|
550 iPacketSink->StreamEnd( iVideoStreamId ); |
|
551 } |
|
552 } |
|
553 //else |
|
554 // { |
|
555 // Just wait player's "MvloLoadingStartedL" event, |
|
556 // Play ends with PlayCommand( -1.0, -1.0 ) in .rtp clip case and/or |
|
557 // VIA will stop the play if play position goes beond the clip's lenght |
|
558 // } |
|
559 |
|
560 // Used packet out from the buffer |
|
561 iBuffer->GetPacket( book, packet ); |
|
562 break; |
|
563 |
|
564 default: |
|
565 LOG1( "CCRXpsSink::SendPacket(), Bad bufferId: %d", bufferId ); |
|
566 // Used packet out from the buffer |
|
567 iBuffer->GetPacket( book, packet ); |
|
568 break; |
|
569 } |
|
570 |
|
571 // Stop sink if error? |
|
572 if ( err ) |
|
573 { |
|
574 LOG2( "CCRXpsSink::SendPacket(), error: %d, bufferId: %d", err, bufferId ); |
|
575 LOG2( "CCRXpsSink::SendPacket(), iAudioStreamId: %d, iVideoStreamId: %d", |
|
576 iAudioStreamId, iVideoStreamId ); |
|
577 iOwningSession.SinkStops( Id() ); |
|
578 } |
|
579 |
|
580 return packetSent; |
|
581 } |
|
582 |
|
583 // ----------------------------------------------------------------------------- |
|
584 // CCRXpsSink::SendAudioPacket |
|
585 // Adjust RTP timestamp and enqueue the packet. |
|
586 // ----------------------------------------------------------------------------- |
|
587 // |
|
588 TInt CCRXpsSink::SendAudioPacket( const TDesC8& aPacket ) |
|
589 { |
|
590 // Parse packet |
|
591 TInt err( iRtpPacket->ParseRtp( aPacket ) ); |
|
592 if ( err ) |
|
593 { |
|
594 LOG1( "CCRXpsSink::SendAudioPacket(), Parsing error: %d", err ); |
|
595 return err; |
|
596 } |
|
597 |
|
598 // Adjust time stamp |
|
599 iRtpPacket->SetTimeStamp( |
|
600 iAudioConv->ConvertTs( iRtpPacket->iRtpRecvHeader.iTimestamp ) ); |
|
601 |
|
602 // Send to player |
|
603 return EnqueuePacket( iAudioStreamId ); |
|
604 } |
|
605 |
|
606 // ----------------------------------------------------------------------------- |
|
607 // CCRXpsSink::SendVideoPacket |
|
608 // Adjust RTP timestamp and enqueue the packet. |
|
609 // ----------------------------------------------------------------------------- |
|
610 // |
|
611 TInt CCRXpsSink::SendVideoPacket( const TDesC8& aPacket ) |
|
612 { |
|
613 TPtrC8 packet( aPacket ); |
|
614 |
|
615 #ifdef VIA_FEA_IPTV_USE_IPDC |
|
616 // Do ISMA Depacketizer |
|
617 if ( iVideoDepacketizer != NULL ) |
|
618 { |
|
619 TInt result( iVideoDepacketizer->PushPacket( packet ) ); |
|
620 if ( result != KErrCompletion ) // KErrCompletion means Ok |
|
621 { |
|
622 return KErrNone; |
|
623 } |
|
624 |
|
625 // Next packet should be available |
|
626 TInt err( iVideoDepacketizer->NextFrame( packet ) ); |
|
627 if ( err ) |
|
628 { |
|
629 LOG1( "CCRXpsSink::SendVideoPacket(), NextFrame error: %d", err ); |
|
630 return err; |
|
631 } |
|
632 } |
|
633 #endif // VIA_FEA_IPTV_USE_IPDC |
|
634 |
|
635 // Parse packet |
|
636 TInt err( iRtpPacket->ParseRtp( packet ) ); |
|
637 if ( err ) |
|
638 { |
|
639 LOG1( "CCRXpsSink::SendVideoPacket(), Parsing error: %d", err ); |
|
640 return err; |
|
641 } |
|
642 |
|
643 // Adjust time stamp |
|
644 iRtpPacket->SetTimeStamp( |
|
645 iVideoConv->ConvertTs( iRtpPacket->iRtpRecvHeader.iTimestamp ) ); |
|
646 |
|
647 // Send to player |
|
648 return EnqueuePacket( iVideoStreamId ); |
|
649 } |
|
650 |
|
651 // ----------------------------------------------------------------------------- |
|
652 // CCRXpsSink::SendTitlePacket |
|
653 // Adjust RTP timestamp and enqueue the packet. |
|
654 // ----------------------------------------------------------------------------- |
|
655 // |
|
656 TInt CCRXpsSink::SendTitlePacket( const TDesC8& /*aPacket*/ ) |
|
657 { |
|
658 // Title implementation unknown |
|
659 return KErrNotSupported; |
|
660 } |
|
661 |
|
662 // ----------------------------------------------------------------------------- |
|
663 // CCRXpsSink::EnqueuePacket |
|
664 // Sends packet to the player. |
|
665 // ----------------------------------------------------------------------------- |
|
666 // |
|
667 TInt CCRXpsSink::EnqueuePacket( const TUint aStreamId ) |
|
668 { |
|
669 TInt err( iPacketSink->Enqueue( |
|
670 aStreamId, iRtpPacket->iRtpRecvHeader, iRtpPacket->iPayload ) ); |
|
671 |
|
672 #if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) |
|
673 if ( err && ( iLogXps < 5 || err != KErrOverflow ) ) |
|
674 { |
|
675 LOG3( "CCRXpsSink::EnqueuePacket(), aStreamId: %d, err: %d, payload len: %d", |
|
676 aStreamId, err, iRtpPacket->iPayload.Length() ); |
|
677 } |
|
678 #endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE |
|
679 |
|
680 if ( err == KErrOverflow ) |
|
681 { |
|
682 iWaitPlayer = err; |
|
683 return KErrNone; |
|
684 } |
|
685 |
|
686 // XPS reset can not be done before first packet is enqued |
|
687 iXpsResetOk = ETrue; |
|
688 return err; |
|
689 } |
|
690 |
|
691 // ----------------------------------------------------------------------------- |
|
692 // CCRXpsSink::SearchForControlStreamPackets |
|
693 // Checks buffer for control stream packets. |
|
694 // ----------------------------------------------------------------------------- |
|
695 // |
|
696 void CCRXpsSink::SearchForControlStreamPackets() |
|
697 { |
|
698 // Check if RTCP packet already in buffer |
|
699 if ( CheckBufferForControlStreamPackets() ) |
|
700 { |
|
701 iBuffer->AdjustBuffer(); |
|
702 } |
|
703 else |
|
704 { |
|
705 // Get more packets if group not contains any RTCP packet(s) |
|
706 if ( !iBuffer->ContinousStream() && !iBuffer->MoreComing() ) |
|
707 { |
|
708 iBuffer->AdjustBuffer(); |
|
709 iOwningSession.SourceRestore(); |
|
710 } |
|
711 } |
|
712 } |
|
713 |
|
714 // ----------------------------------------------------------------------------- |
|
715 // CCRXpsSink::CheckBufferForControlStreamPackets |
|
716 // Checks buffer for control stream packets. |
|
717 // ----------------------------------------------------------------------------- |
|
718 // |
|
719 TBool CCRXpsSink::CheckBufferForControlStreamPackets() |
|
720 { |
|
721 TBool audioOk( iAudioConv->Initiated() || iAudioStreamId == KErrNotFound ); |
|
722 TBool videoOk( iVideoConv->Initiated() || iVideoStreamId == KErrNotFound ); |
|
723 |
|
724 // Loop packets, oldest first |
|
725 for ( TInt offset( iBuffer->PacketsCount( iSinkId ) - 1 ); |
|
726 ( !audioOk || !videoOk ) && offset >= 0; offset-- ) |
|
727 { |
|
728 MCRPacketSource::TCRPacketStreamId streamId( MCRPacketSource::EStreamIdCount ); |
|
729 const TInt book( iBuffer->GetStream( iSinkId, offset, streamId ) ); |
|
730 TPtr8 packet( NULL, 0 ); |
|
731 |
|
732 switch ( streamId ) |
|
733 { |
|
734 case MCRPacketSource::EAudioControlStream: |
|
735 if ( !iAudioConv->Initiated() ) |
|
736 { |
|
737 audioOk = ETrue; |
|
738 iBuffer->PeekPacket( book, packet, offset ); |
|
739 iAudioConv->Init( packet ); |
|
740 LOG1( "CCRXpsSink::CheckBufferForControlStreamPackets(), Audio TS initiated, status: %d", |
|
741 iAudioConv->Initiated() ) |
|
742 } |
|
743 break; |
|
744 |
|
745 case MCRPacketSource::EVideoControlStream: |
|
746 if ( !iVideoConv->Initiated() ) |
|
747 { |
|
748 videoOk = ETrue; |
|
749 iBuffer->PeekPacket( book, packet, offset ); |
|
750 iVideoConv->Init( packet ); |
|
751 LOG1( "CCRXpsSink::CheckBufferForControlStreamPackets(), Video TS initiated, status: %d", |
|
752 iVideoConv->Initiated() ) |
|
753 } |
|
754 break; |
|
755 |
|
756 case MCRPacketSource::ESubTitleControlStream: |
|
757 if ( !iTitleConv->Initiated() ) |
|
758 { |
|
759 iBuffer->PeekPacket( book, packet, offset ); |
|
760 iTitleConv->Init( packet ); |
|
761 LOG1( "CCRXpsSink::CheckBufferForControlStreamPackets(), Title TS initiated, status: %d", |
|
762 iTitleConv->Initiated() ) |
|
763 } |
|
764 break; |
|
765 |
|
766 default: |
|
767 break; |
|
768 } |
|
769 } |
|
770 |
|
771 return ( audioOk && videoOk ); |
|
772 } |
|
773 |
|
774 // ----------------------------------------------------------------------------- |
|
775 // CCRXpsSink::StartTimer |
|
776 // Starts packet flow timer. |
|
777 // ----------------------------------------------------------------------------- |
|
778 // |
|
779 void CCRXpsSink::StartTimer( const TInt& aInterval ) |
|
780 { |
|
781 StopTimer(); |
|
782 TRAPD( err, iFlowTimer = CCRTimer::NewL( |
|
783 CActive::EPriorityLow, *this ) ); |
|
784 if ( !err ) |
|
785 { |
|
786 iFlowTimer->After( aInterval ); |
|
787 } |
|
788 else |
|
789 { |
|
790 LOG1( "CCRXpsSink::StartTimer(), Flowtimer err: %d", err ); |
|
791 iOwningSession.SinkStops( Id() ); |
|
792 } |
|
793 } |
|
794 |
|
795 // ----------------------------------------------------------------------------- |
|
796 // CCRXpsSink::StopTimer |
|
797 // Starts packet flow timer. |
|
798 // ----------------------------------------------------------------------------- |
|
799 // |
|
800 void CCRXpsSink::StopTimer() |
|
801 { |
|
802 delete iFlowTimer; iFlowTimer = NULL; |
|
803 } |
|
804 |
|
805 #ifdef VIA_FEA_IPTV_USE_IPDC |
|
806 // ----------------------------------------------------------------------------- |
|
807 // CCRXpsSink::FindFmtpL |
|
808 // Finds the fmtp string. |
|
809 // ----------------------------------------------------------------------------- |
|
810 // |
|
811 HBufC8* CCRXpsSink::FindFmtpLC( const TDesC8& aSdpData ) |
|
812 { |
|
813 LOG( "CCRXpsSink::FindFmtpLC() in" ); |
|
814 _LIT8( KCRStr, "\r" ); |
|
815 _LIT8( KLFStr, "\n" ); |
|
816 _LIT8( KHxAVCfmtp, "a=hxavcfmtp:" ); |
|
817 |
|
818 // Get the video fmtp string |
|
819 HBufC8* fmtp = NULL; |
|
820 TInt pos = aSdpData.Find( KHxAVCfmtp ); |
|
821 if ( pos > KErrNotFound ) |
|
822 { |
|
823 // Extract the right most from the fist char after KHxAVCfmtp |
|
824 TPtrC8 rightPtr( aSdpData.Mid( pos + KHxAVCfmtp().Length() ) ); |
|
825 |
|
826 // We need the first line of rightPtr |
|
827 TInt posLFStr( rightPtr.Find( KLFStr ) ); |
|
828 TInt posCRStr( rightPtr.Find( KCRStr ) ); |
|
829 if ( posLFStr > 0 && posCRStr > 0 ) |
|
830 { |
|
831 fmtp = rightPtr.Left( Min( posLFStr, posCRStr ) ).AllocLC(); |
|
832 } |
|
833 else if ( posLFStr > 0 ) |
|
834 { |
|
835 fmtp = rightPtr.Left( posLFStr ).AllocLC(); |
|
836 } |
|
837 else if ( posCRStr > 0 ) |
|
838 { |
|
839 fmtp = rightPtr.Left( posCRStr ).AllocLC(); |
|
840 } |
|
841 else |
|
842 { |
|
843 fmtp = rightPtr.AllocLC(); |
|
844 } |
|
845 } |
|
846 |
|
847 User::LeaveIfNull( fmtp ); |
|
848 #if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) |
|
849 HBufC* buf = HBufC::NewL( fmtp->Length() ); |
|
850 TPtr ptr( buf->Des() ); ptr.Copy( *fmtp ); |
|
851 LOG1( "CCRXpsSink::FindFmtpLC() out, Fmtp: %S", &ptr ); |
|
852 #endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE |
|
853 return fmtp; |
|
854 } |
|
855 |
|
856 #endif // VIA_FEA_IPTV_USE_IPDC |
|
857 |
|
858 // End of File |
|