|
1 /* |
|
2 * Copyright (c) 2002-2003 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 "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: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 #include "rtptranstream.h" |
|
22 |
|
23 // --------------------------------------------------------------------------- |
|
24 // C++ default constructor can NOT contain any code, that |
|
25 // might leave. |
|
26 // --------------------------------------------------------------------------- |
|
27 // |
|
28 CRtpTranStream::CRtpTranStream( const TRtpPayloadType aPayloadType, |
|
29 const TRtpId aSessionId, |
|
30 const TRtpId aStreamId, |
|
31 const TRtpSSRC aSSRC, |
|
32 MRtcpObserver* aRtcpObserver, |
|
33 const TUint32* aProfileRTPTimeRates ) |
|
34 : |
|
35 CRtpStream( aStreamId, |
|
36 aSessionId, |
|
37 aProfileRTPTimeRates, |
|
38 aRtcpObserver, |
|
39 aPayloadType ), |
|
40 iFlagSentRTPPackets( EFalse ), |
|
41 iPreviousTime( 0 ), |
|
42 iPreviousRemoteSN( 0 ), |
|
43 iPrevRemoteTime( 0 ), |
|
44 iCumNumOctetsSent( 0 ), |
|
45 iCumNumOctetsReceived( 0 ), |
|
46 iCumNumOctetsSent_last( 0 ), |
|
47 iFSentRtcpReport( EFalse ) |
|
48 { |
|
49 iLocalSSRC = aSSRC; |
|
50 iTimeStamp = 0; |
|
51 iSeqNumCycles = 0; |
|
52 |
|
53 for ( TUint i = 0; i < KSNMaxArray; i++ ) |
|
54 { |
|
55 iSN_size[i] = 0; |
|
56 } |
|
57 // If the client application does not specify sequence numbers, we |
|
58 // randomize the first one. |
|
59 TTime tmp_time; |
|
60 tmp_time.HomeTime(); |
|
61 TInt64 seed = tmp_time.Int64(); |
|
62 iBaseSeqNum = static_cast<TRtpSequence>( TRtpUtil::Random( seed ) |
|
63 & 0xFFFF ); // Use 16-LSB only |
|
64 iSeqNum = iBaseSeqNum; |
|
65 } |
|
66 |
|
67 // --------------------------------------------------------------------------- |
|
68 // Symbian 2nd phase constructor can leave. |
|
69 // --------------------------------------------------------------------------- |
|
70 // |
|
71 void CRtpTranStream::ConstructL() |
|
72 { |
|
73 } |
|
74 |
|
75 |
|
76 // --------------------------------------------------------------------------- |
|
77 // Two-phased constructor. |
|
78 // --------------------------------------------------------------------------- |
|
79 // |
|
80 CRtpTranStream* CRtpTranStream::NewL( const TRtpPayloadType aPayloadType, |
|
81 const TRtpId aSessionId, |
|
82 const TRtpId aTranStreamId, |
|
83 const TRtpSSRC aSSRC, |
|
84 MRtcpObserver* aRtcpObserver, |
|
85 const TUint32* aProfileRTPTimeRates ) |
|
86 { |
|
87 CRtpTranStream* self = |
|
88 new ( ELeave ) CRtpTranStream( aPayloadType, |
|
89 aSessionId, |
|
90 aTranStreamId, |
|
91 aSSRC, |
|
92 aRtcpObserver, |
|
93 aProfileRTPTimeRates ); |
|
94 CleanupStack::PushL( self ); |
|
95 self->ConstructL(); |
|
96 CleanupStack::Pop(); // self |
|
97 return self; |
|
98 } |
|
99 |
|
100 // --------------------------------------------------------------------------- |
|
101 // Destructor |
|
102 // --------------------------------------------------------------------------- |
|
103 // |
|
104 CRtpTranStream::~CRtpTranStream() |
|
105 { |
|
106 } |
|
107 |
|
108 |
|
109 // --------------------------------------------------------------------------- |
|
110 // TInt CRtpTranStream::ResetStreamStat() |
|
111 // |
|
112 // --------------------------------------------------------------------------- |
|
113 // |
|
114 TInt CRtpTranStream::ResetStreamStat() |
|
115 { |
|
116 TRtcpStats rtcpStat; |
|
117 |
|
118 RtcpStats( rtcpStat ); |
|
119 |
|
120 rtcpStat.iRtcpSenderStats.iNumPacketsSent = 0; |
|
121 rtcpStat.iRtcpSenderStats.iCumNumOctetsSent = 0; |
|
122 rtcpStat.iRtcpSenderStats.iNTPTimeStampSec = 0; // NTP seconds |
|
123 rtcpStat.iRtcpSenderStats.iNTPTimeStampFrac = 0; // NTPfraction |
|
124 rtcpStat.iRtcpSenderStats.iTimeStamp = 0; |
|
125 |
|
126 // The receiver stats are updated when receiving RR packets, so reset |
|
127 rtcpStat.iRtcpReceiverStats.iChannelBufferSize = 0; |
|
128 rtcpStat.iRtcpReceiverStats.iRoundTripDelay = 0; |
|
129 rtcpStat.iRtcpReceiverStats.iFractionLost = 0; |
|
130 rtcpStat.iRtcpReceiverStats.iCumNumPacketsLost = 0; |
|
131 rtcpStat.iRtcpReceiverStats.iSeqNumReceived = 0; |
|
132 rtcpStat.iRtcpReceiverStats.iSSRC = 0; |
|
133 |
|
134 iRtcpStats = rtcpStat; |
|
135 |
|
136 iFlagSentRTPPackets = EFalse; |
|
137 iFSentRtcpReport = EFalse; |
|
138 |
|
139 iCumNumOctetsSent = 0; |
|
140 iCumNumOctetsSent_last = 0; |
|
141 iPreviousTime = 0; |
|
142 iPreviousRemoteSN = 0; |
|
143 iSeqNumCycles = 0; |
|
144 |
|
145 for ( TUint i = 0; i < KSNMaxArray; i++ ) |
|
146 { |
|
147 iSN_size[i] = 0; |
|
148 } |
|
149 |
|
150 return KErrNone; |
|
151 } |
|
152 |
|
153 // --------------------------------------------------------------------------- |
|
154 // TInt CRtpTranStream::GetStreamStat() |
|
155 // |
|
156 // --------------------------------------------------------------------------- |
|
157 // |
|
158 TInt CRtpTranStream::GetStreamStat( TRtpPeerStat& aStat ) |
|
159 { |
|
160 TRtcpStats rtcpStat; |
|
161 |
|
162 RtcpStats( rtcpStat ); |
|
163 |
|
164 aStat.iCumNumOctetsSent = rtcpStat.iRtcpSenderStats.iCumNumOctetsSent; |
|
165 aStat.iNumPacketsSent = rtcpStat.iRtcpSenderStats.iNumPacketsSent; |
|
166 |
|
167 aStat.iTxBandwidth = rtcpStat.iRtcpReceiverStats.iTxBandwidth; |
|
168 aStat.iArrivalJitter = rtcpStat.iRtcpReceiverStats.iArrivalJitter; |
|
169 aStat.iCumNumPacketsLost = rtcpStat.iRtcpReceiverStats.iCumNumPacketsLost; |
|
170 aStat.iFractionLost = rtcpStat.iRtcpReceiverStats.iFractionLost; |
|
171 aStat.iRoundTripDelay = rtcpStat.iRtcpReceiverStats.iRoundTripDelay; |
|
172 aStat.iRxBandwidth = rtcpStat.iRtcpReceiverStats.iBandwidth; |
|
173 aStat.iChannelBufferSize = rtcpStat.iRtcpReceiverStats.iChannelBufferSize; |
|
174 aStat.iNTPTimeStampSec = rtcpStat.iRtcpSenderStats.iNTPTimeStampSec; |
|
175 aStat.iNTPTimeStampFrac = rtcpStat.iRtcpSenderStats.iNTPTimeStampFrac; |
|
176 aStat.iTimeStamp = rtcpStat.iRtcpSenderStats.iTimeStamp; |
|
177 |
|
178 return KErrNone; |
|
179 } |
|
180 |
|
181 // --------------------------------------------------------------------------- |
|
182 // TInt CRtpTranStream::BuildRtpPacket() |
|
183 // |
|
184 // --------------------------------------------------------------------------- |
|
185 // |
|
186 TInt CRtpTranStream::BuildRtpPacket( const TRtpSendHeader& aHeaderInfo, |
|
187 const TDesC8& aPayloadData, |
|
188 TRtpSequence aSeqNum, |
|
189 TBool aSetSeqNum, |
|
190 CRtpPacket* aPktSnd ) |
|
191 { |
|
192 TRtpPacketStreamParam streamParam; |
|
193 TRtpPacketIOParam inParam; |
|
194 |
|
195 if ( FirstPkg() ) |
|
196 { |
|
197 RtpStreamSyncInit( aHeaderInfo.iTimestamp ); |
|
198 SetFirstPkg( EFalse ); |
|
199 } |
|
200 |
|
201 // |
|
202 // The interpretation of the marker is defined by a profile. |
|
203 // It is used for marking significant events such as frame boundaries or |
|
204 // talkspurts in the packet stream. |
|
205 |
|
206 // Timestamp |
|
207 // -- random initial value |
|
208 // -- monotonically increasing |
|
209 // -- increases by one sampling period for fixed-rate audio |
|
210 // -- increases for every sample independent of whether the block is |
|
211 // transmitted or dropped as silent. |
|
212 // -- used for playout and inter-media synchronization. |
|
213 // |
|
214 |
|
215 // |
|
216 // construct RTP packet |
|
217 // |
|
218 |
|
219 inParam.TRTP.padding = aHeaderInfo.iPadding; |
|
220 |
|
221 if ( aHeaderInfo.iHeaderExtension ) |
|
222 { |
|
223 inParam.TRTP.fHeaderExtension = 1; |
|
224 inParam.TRTP.extension.type = aHeaderInfo.iHeaderExtension->iType; |
|
225 inParam.TRTP.extension.length = aHeaderInfo.iHeaderExtension->iLength; |
|
226 inParam.TRTP.extension.data = aHeaderInfo.iHeaderExtension->iData; |
|
227 } |
|
228 else |
|
229 { |
|
230 inParam.TRTP.extension.data = NULL; |
|
231 } |
|
232 |
|
233 inParam.TRTP.marker = aHeaderInfo.iMarker; |
|
234 |
|
235 inParam.TRTP.payloadData = const_cast<TUint8*>( aPayloadData.Ptr() ); |
|
236 inParam.TRTP.payloadDataLen = aPayloadData.Length(); |
|
237 |
|
238 streamParam.TRTP.payload = aHeaderInfo.iPayloadType; |
|
239 |
|
240 if ( aSetSeqNum ) |
|
241 { |
|
242 iSeqNum = aSeqNum; |
|
243 } |
|
244 streamParam.TRTP.seqNum = iSeqNum; |
|
245 |
|
246 streamParam.TRTP.SSRC = iLocalSSRC; |
|
247 streamParam.TRTP.timeStamp = aHeaderInfo.iTimestamp; |
|
248 |
|
249 // |
|
250 // build and send the packet |
|
251 // |
|
252 aPktSnd->RtpPacketBuild( &streamParam, &inParam ); |
|
253 |
|
254 |
|
255 RTP_DEBUG_DETAIL_DVALUE( "CRtpTranStream::BuildRtpPacket, Stream ID = ", |
|
256 iStreamId ); |
|
257 RTP_DEBUG_DETAIL_DVALUE( "CRtpTranStream::BuildRtpPacket, SSRC = ", |
|
258 streamParam.TRTP.SSRC ); |
|
259 RTP_DEBUG_DETAIL_DVALUE( "CRtpTranStream::BuildRtpPacket, Seq Num = ", |
|
260 static_cast<TInt>( streamParam.TRTP.seqNum ) ); |
|
261 RTP_DEBUG_DETAIL_DVALUE( "CRtpTranStream::BuildRtpPacket, Time Stamp = ", |
|
262 aHeaderInfo.iTimestamp ); |
|
263 |
|
264 |
|
265 // update sent octets and remote bandwidth parameters |
|
266 IncCumNumOctetsSent( aPayloadData.Length() ); |
|
267 |
|
268 // update stream parameters |
|
269 iTimeStamp = aHeaderInfo.iTimestamp; |
|
270 iSeqNum++; |
|
271 if ( iSeqNum == 0 ) |
|
272 { |
|
273 iSeqNumCycles++; |
|
274 } |
|
275 |
|
276 SetSentRTPPackets( ETrue ); |
|
277 |
|
278 return KErrNone; |
|
279 } |
|
280 |
|
281 // --------------------------------------------------------------------------- |
|
282 // TInt CRtpTranStream::BuildRtcpBYEPacket() |
|
283 // |
|
284 // --------------------------------------------------------------------------- |
|
285 // |
|
286 TInt CRtpTranStream::BuildRtcpBYEPacket( const TDesC8& aReason, |
|
287 CRtpPacket* aPktRtcpSnd ) |
|
288 { |
|
289 TInt paddingSize = 0; |
|
290 TRtpPacketStreamParam streamParam; |
|
291 TRtpPacketIOParam initParam; |
|
292 TInt ret = KErrNone; |
|
293 |
|
294 TInt byeSize = aReason.Size(); |
|
295 |
|
296 // build RTCP BYE packet header |
|
297 TInt sourceCount = 1; |
|
298 TInt length = 0; |
|
299 |
|
300 initParam.TRTCP_HEADER.pt = ERTCP_BYE; |
|
301 |
|
302 if ( ( 1 + byeSize ) % 4 == 0 ) |
|
303 { |
|
304 // multiples of 4 bytes, no padding is needed |
|
305 // calculate total number of 32 bit words in SDES packet |
|
306 length = ( 1 + byeSize ) / 4 + 1; |
|
307 } |
|
308 else |
|
309 { |
|
310 // not multiples of 4 bytes, padding is needed |
|
311 paddingSize = 4 - ( 1 + byeSize ) % 4; |
|
312 length = ( 1 + byeSize ) / 4 + 2; |
|
313 } |
|
314 |
|
315 initParam.TRTCP_HEADER.sourceCount = sourceCount; |
|
316 initParam.TRTCP_HEADER.length = length; |
|
317 aPktRtcpSnd->SetType( ERTCP_HEADER ); |
|
318 |
|
319 aPktRtcpSnd->RtpPacketBuild( &streamParam, &initParam ); |
|
320 |
|
321 streamParam.TRTCP_BYE.SSRC = iLocalSSRC; |
|
322 |
|
323 initParam.TRTCP_BYE.reason = ( TUint8 * ) aReason.Ptr(); |
|
324 initParam.TRTCP_BYE.reasonSize = byeSize; |
|
325 initParam.TRTCP_BYE.paddingSize = paddingSize; |
|
326 |
|
327 aPktRtcpSnd->SetType( ERTCP_BYE ); |
|
328 aPktRtcpSnd->RtpPacketBuild( &streamParam, &initParam ); |
|
329 |
|
330 |
|
331 RTCP_DEBUG_DETAIL_DVALUE( "SEND: Send BYE Packet TX Stream ID = ", |
|
332 iStreamId ); |
|
333 RTCP_DEBUG_DETAIL_DVALUE( "SEND: Send BYE Packet SSRC = ", |
|
334 iLocalSSRC ); |
|
335 RTCP_DEBUG_DETAIL( "SEND: Sending RTCP BYE message as" ); |
|
336 RTCP_DEBUG_DETAIL( initParam.TRTCP_BYE.reason ); |
|
337 |
|
338 return ret; |
|
339 } |
|
340 |
|
341 // --------------------------------------------------------------------------- |
|
342 // TInt CRtpTranStream::BuildRtcpAPPPacket() |
|
343 // |
|
344 // --------------------------------------------------------------------------- |
|
345 // |
|
346 TInt CRtpTranStream::BuildRtcpAPPPacket( const TRtcpApp& aApp, |
|
347 CRtpPacket* aPktRtcpSnd ) |
|
348 { |
|
349 TRtpPacketStreamParam streamParam; |
|
350 TRtpPacketIOParam initParam; |
|
351 |
|
352 initParam.TRTCP_HEADER.pt = ERTCP_APP; |
|
353 |
|
354 initParam.TRTCP_HEADER.sourceCount = aApp.iSubType; |
|
355 |
|
356 initParam.TRTCP_HEADER.length = aApp.iAppDataLen / 4 + 3 - 1; |
|
357 |
|
358 aPktRtcpSnd->SetType( ERTCP_HEADER ); |
|
359 |
|
360 aPktRtcpSnd->RtpPacketBuild( &streamParam, &initParam ); |
|
361 |
|
362 streamParam.TRTCP_APP.SSRC = iLocalSSRC; |
|
363 |
|
364 Mem::Copy( initParam.TRTCP_APP.name, aApp.iName, 4 ); |
|
365 initParam.TRTCP_APP.appData = const_cast<TUint8*>( aApp.iAppData ); |
|
366 initParam.TRTCP_APP.appDataLen = aApp.iAppDataLen; |
|
367 |
|
368 aPktRtcpSnd->SetType( ERTCP_APP ); |
|
369 |
|
370 aPktRtcpSnd->RtpPacketBuild( &streamParam, &initParam ) ; |
|
371 |
|
372 RTP_DEBUG_DETAIL_DVALUE( "SEND: Send APP Packet TX Stream ID = ", iStreamId ); |
|
373 RTP_DEBUG_DETAIL_DVALUE( "SEND: Send APP Packet SSRC = " , iLocalSSRC ); |
|
374 RTCP_DEBUG_DETAIL( "SEND: Sending RTCP APP packet as " ); |
|
375 RTCP_DEBUG_DETAIL( "InitParam.TRTCP_APP.appData " ); |
|
376 |
|
377 return KErrNone; |
|
378 } |
|
379 |
|
380 // --------------------------------------------------------------------------- |
|
381 // CRtpTranStream::RtpStreamSyncInit() |
|
382 // For transmission stream, iSyncInfo is initialized by the |
|
383 // first packet sent. |
|
384 // --------------------------------------------------------------------------- |
|
385 // |
|
386 void CRtpTranStream::RtpStreamSyncInit( TRtpTimeStamp aInitTimeStamp ) |
|
387 { |
|
388 TUint32 gtTime = TRtpUtil::GtGetTime(); |
|
389 |
|
390 TTime time1; |
|
391 TTime time2; |
|
392 TTimeIntervalSeconds interval; |
|
393 time1.HomeTime(); |
|
394 _LIT( KTime, "19700101:000000.000000" ); |
|
395 time2.Set( KTime ); // microsecond from Jan. 1 1970 |
|
396 time1.SecondsFrom( time2, interval ); |
|
397 |
|
398 iSyncInfo.iNTPTimeStampSec = interval.Int() + KGetTimeOfDayToNTPOffset; |
|
399 |
|
400 |
|
401 iSyncInfo.iNTPTimeStampFrac = static_cast<TUint32>( |
|
402 ( ( ( ( TUint32 ) ( gtTime % KTenthOfmsPerSecond ) ) << 16 ) |
|
403 / KTenthOfmsPerSecond ) << 16 ); |
|
404 |
|
405 iSyncInfo.iTimeStamp = aInitTimeStamp; |
|
406 iSyncInfo.iLastUpdateLocalTime = gtTime; |
|
407 } |
|
408 |
|
409 // --------------------------------------------------------------------------- |
|
410 // CRtpTranStream::RtpStreamSyncCurrent() |
|
411 // iSyncInfo : NTP timestamp of initialization as a reference |
|
412 // to update the current NTP timestamp |
|
413 // aSyncInfoCurrent : Bring back current NTP Time stamp |
|
414 // --------------------------------------------------------------------------- |
|
415 // |
|
416 void CRtpTranStream::RtpStreamSyncCurrent( TRtpTimeSync* aSyncInfoCurrent ) |
|
417 { |
|
418 if ( !aSyncInfoCurrent ) |
|
419 { |
|
420 return; |
|
421 } |
|
422 TUint32 gtTime = TRtpUtil::GtGetTime(); |
|
423 TUint32 diffFraction = ( gtTime - iSyncInfo.iLastUpdateLocalTime ) |
|
424 % KTenthOfmsPerSecond; |
|
425 |
|
426 aSyncInfoCurrent->iNTPTimeStampSec = iSyncInfo.iNTPTimeStampSec + |
|
427 static_cast<TUint32>( gtTime - iSyncInfo.iLastUpdateLocalTime ) |
|
428 / KTenthOfmsPerSecond; |
|
429 aSyncInfoCurrent->iNTPTimeStampFrac = ( static_cast<TUint32>( |
|
430 ( diffFraction << 16 ) / KTenthOfmsPerSecond ) << 16 ); |
|
431 } |
|
432 |
|
433 // --------------------------------------------------------------------------- |
|
434 // CRtpTranStream::RtpStreamCreateRtcpReportSection() |
|
435 // For transmission stream, it only generates SR packet. |
|
436 // --------------------------------------------------------------------------- |
|
437 // |
|
438 void CRtpTranStream::RtpStreamCreateRtcpReportSection( CRtpPacket* aPkt ) |
|
439 { |
|
440 TRtpPacketStreamParam streamParam; |
|
441 TRtpPacketIOParam inParam; |
|
442 |
|
443 TRtpTimeSync syncInfoCurrent; |
|
444 |
|
445 streamParam.TRTCP_SR.SSRC = iLocalSSRC; |
|
446 |
|
447 streamParam.TRTCP_SR.numPacketsSent = iSeqNum + ( iSeqNumCycles << 16 ) |
|
448 - iBaseSeqNum; |
|
449 streamParam.TRTCP_SR.cumNumOctetsSent = iCumNumOctetsSent; |
|
450 |
|
451 iRtcpStats.iRtcpSenderStats.iNumPacketsSent = |
|
452 streamParam.TRTCP_SR.numPacketsSent; |
|
453 iRtcpStats.iRtcpSenderStats.iCumNumOctetsSent = |
|
454 streamParam.TRTCP_SR.cumNumOctetsSent; |
|
455 iRtcpStats.iRtcpSenderStats.iSSRC = streamParam.TRTCP_SR.SSRC; |
|
456 |
|
457 RtpStreamSyncCurrent( &syncInfoCurrent ); |
|
458 |
|
459 inParam.TRTCP_SR.NTPTimeStampSec = syncInfoCurrent.iNTPTimeStampSec; |
|
460 inParam.TRTCP_SR.NTPTimeStampFrac = syncInfoCurrent.iNTPTimeStampFrac; |
|
461 inParam.TRTCP_SR.timeStamp = iTimeStamp; |
|
462 |
|
463 iRtcpStats.iRtcpSenderStats.iNTPTimeStampSec = |
|
464 inParam.TRTCP_SR.NTPTimeStampSec; |
|
465 iRtcpStats.iRtcpSenderStats.iNTPTimeStampFrac = |
|
466 inParam.TRTCP_SR.NTPTimeStampFrac; |
|
467 iRtcpStats.iRtcpSenderStats.iTimeStamp = inParam.TRTCP_SR.timeStamp; |
|
468 |
|
469 |
|
470 RTP_DEBUG_STAT( "----- TX: Create RTCP Report Statistics -----" ); |
|
471 RTP_DEBUG_STAT_DVALUE( "TX: numPacketsSent = ", |
|
472 iRtcpStats.iRtcpSenderStats.iNumPacketsSent ); |
|
473 RTP_DEBUG_STAT_DVALUE( "TX: cumNumOctetsSent = ", |
|
474 iRtcpStats.iRtcpSenderStats.iCumNumOctetsSent ); |
|
475 RTP_DEBUG_STAT_DVALUE( "TX: SSRC (Tx) = ", |
|
476 iRtcpStats.iRtcpSenderStats.iSSRC ); |
|
477 RTP_DEBUG_STAT_DVALUE( "TX: NTPTimeStampSec = ", |
|
478 iRtcpStats.iRtcpSenderStats.iNTPTimeStampSec ); |
|
479 RTP_DEBUG_STAT_DVALUE( "TX: NTPTimeStampFrac = ", |
|
480 iRtcpStats.iRtcpSenderStats.iNTPTimeStampFrac ); |
|
481 RTP_DEBUG_STAT_DVALUE( "TX: timeStamp = ", |
|
482 iRtcpStats.iRtcpSenderStats.iTimeStamp ); |
|
483 |
|
484 |
|
485 // For transmission stream, it only generates SR packet. |
|
486 aPkt->SetType( ERTCP_SR ); |
|
487 aPkt->RtpPacketBuild( &streamParam, &inParam ); |
|
488 } |
|
489 |
|
490 |
|
491 // --------------------------------------------------------------------------- |
|
492 // TRtpRtcpEnum CRtpTranStream::RtpStreamProcessRtcpReportSectionL() |
|
493 // For transmission stream, it only processes RR packet. |
|
494 // --------------------------------------------------------------------------- |
|
495 // |
|
496 TRtpRtcpEnum CRtpTranStream::RtpStreamProcessRtcpReportSectionL( |
|
497 CRtpPacket* aPkt ) |
|
498 { |
|
499 TRtpPacketStreamParam streamParam; |
|
500 TRtpPacketIOParam extractParam; |
|
501 TRtpRtcpEnum parseResult = ERTCP_NO_ERROR; |
|
502 TUint32 gtTime = TRtpUtil::GtGetTime(); |
|
503 |
|
504 parseResult = aPkt->RtpPacketProcessL( &streamParam, &extractParam ); |
|
505 if ( parseResult == ERTCP_PACKET_ERROR ) |
|
506 { |
|
507 return ERTCP_PACKET_ERROR; |
|
508 } |
|
509 |
|
510 // For transmission stream, it only processes RR packet. |
|
511 if ( aPkt->Type() == ERTCP_RR ) |
|
512 { |
|
513 TInt roundTripDelay; |
|
514 |
|
515 roundTripDelay = RtpStreamSyncGetRoundTripDelay( |
|
516 extractParam.TRTCP_RR.lastSRTimeStamp, |
|
517 extractParam.TRTCP_RR.delaySinceLSR ); |
|
518 |
|
519 iCumNumOctetsReceived += iSN_size[streamParam.TRTCP_RR.seqNumReceived |
|
520 % KSNMaxArray] - |
|
521 iSN_size[iPreviousRemoteSN % KSNMaxArray]; |
|
522 |
|
523 if ( iCumNumOctetsSent > iCumNumOctetsReceived ) |
|
524 { |
|
525 iRtcpStats.iRtcpReceiverStats.iChannelBufferSize = |
|
526 8 * ( iCumNumOctetsSent - iCumNumOctetsReceived ); |
|
527 } |
|
528 else |
|
529 { |
|
530 iRtcpStats.iRtcpReceiverStats.iChannelBufferSize = 0; |
|
531 } |
|
532 |
|
533 iRtcpStats.iRtcpReceiverStats.iRoundTripDelay = roundTripDelay; |
|
534 iRtcpStats.iRtcpReceiverStats.iFractionLost = |
|
535 streamParam.TRTCP_RR.fractionLost; |
|
536 iRtcpStats.iRtcpReceiverStats.iCumNumPacketsLost = |
|
537 streamParam.TRTCP_RR.cumNumPacketsLost; |
|
538 iRtcpStats.iRtcpReceiverStats.iSeqNumReceived = |
|
539 streamParam.TRTCP_RR.seqNumReceived; |
|
540 |
|
541 // SSRC coming from the source |
|
542 iRtcpStats.iRtcpReceiverStats.iSSRC = streamParam.TRTCP_RR.SSRC; |
|
543 |
|
544 EstimateBandWidths( gtTime ); |
|
545 |
|
546 // Remember some things for next time we receive an RR |
|
547 iPreviousRemoteSN = streamParam.TRTCP_RR.seqNumReceived; |
|
548 iPrevRemoteTime = gtTime; |
|
549 iPreviousTime = gtTime; |
|
550 iCumNumOctetsSent_last = iCumNumOctetsSent; |
|
551 |
|
552 |
|
553 RTP_DEBUG_STAT( "----- TX: Process RTCP Report Statistics -----" ); |
|
554 RTP_DEBUG_STAT_DVALUE( "TX: bandwidth (Tx) = ", |
|
555 iRtcpStats.iRtcpReceiverStats.iTxBandwidth ); |
|
556 RTP_DEBUG_STAT_DVALUE( "TX: roundTripDelay = ", |
|
557 iRtcpStats.iRtcpReceiverStats.iRoundTripDelay ); |
|
558 RTP_DEBUG_STAT_DVALUE( "TX: fractionLost = ", |
|
559 static_cast<TInt>( |
|
560 iRtcpStats.iRtcpReceiverStats.iFractionLost ) ); |
|
561 RTP_DEBUG_STAT_DVALUE( "TX: cumNumPacketsLost = ", |
|
562 iRtcpStats.iRtcpReceiverStats.iCumNumPacketsLost ); |
|
563 RTP_DEBUG_STAT_DVALUE( "TX: seqNumReceived = ", |
|
564 iRtcpStats.iRtcpReceiverStats.iSeqNumReceived ); |
|
565 RTP_DEBUG_STAT_DVALUE( "TX: SSRC (Rx) = ", |
|
566 iRtcpStats.iRtcpReceiverStats.iSSRC ); |
|
567 |
|
568 |
|
569 if ( iRtcpObserver ) |
|
570 { |
|
571 iRtcpObserver->RrReceived( iStreamId, |
|
572 iRtcpStats.iRtcpReceiverStats.iSSRC ); |
|
573 } |
|
574 } |
|
575 |
|
576 return parseResult; |
|
577 } |
|
578 |
|
579 // --------------------------------------------------------------------------- |
|
580 // TUint32 CRtpTranStream::EstimateBandWidths() |
|
581 // Make an estimate of the Tx and Rx bandwidths. |
|
582 // --------------------------------------------------------------------------- |
|
583 // |
|
584 void CRtpTranStream::EstimateBandWidths( TUint32 aCurrentTime ) |
|
585 { |
|
586 /* NOTE: This is just a simple estimate, which assumes the following: |
|
587 * - this is an end-to-end session |
|
588 * - the sessions and streams are set up before traffic starts |
|
589 * - the payload bitrate is constant |
|
590 * The result of this estimation should not be used in any other contexts. |
|
591 */ |
|
592 |
|
593 // Tx bandwidth |
|
594 TReal B_A( 0 ); |
|
595 |
|
596 // Rx bandwidth |
|
597 TReal B_B( 0 ); |
|
598 |
|
599 // number of received packets between the current and previous RR's |
|
600 TInt N_B( 0 ); |
|
601 |
|
602 TReal avgPacketSize( 0 ); |
|
603 TUint8 fracLost_i( iRtcpStats.iRtcpReceiverStats.iFractionLost ); |
|
604 TUint32 lastRecvd_i( iRtcpStats.iRtcpReceiverStats.iSeqNumReceived ); |
|
605 TUint32 lastRecvd_k( iPreviousRemoteSN ); |
|
606 TUint packetsSent( iRtcpStats.iRtcpSenderStats.iNumPacketsSent ); |
|
607 |
|
608 TReal timeBetweenRRs = static_cast<TReal>( aCurrentTime - iPreviousTime ) |
|
609 / KTenthOfmsPerSecond; |
|
610 |
|
611 // Continue only if two RR's have been received and numbers are valid |
|
612 if ( iCumNumOctetsSent_last == 0 || |
|
613 iPreviousRemoteSN == 0 || |
|
614 iPrevRemoteTime == 0 || |
|
615 iPreviousTime == 0 || |
|
616 timeBetweenRRs <= 0 || |
|
617 packetsSent == 0 || |
|
618 fracLost_i == 255 /* Would result in divide by zero and B_B = 0 */ ) |
|
619 { |
|
620 // If this is the first RR to be received, this returns 0, |
|
621 // otherwise this returns the result of the previous calculation |
|
622 iRtcpStats.iRtcpReceiverStats.iBandwidth = 0; |
|
623 iRtcpStats.iRtcpReceiverStats.iTxBandwidth = 0; |
|
624 return; |
|
625 } |
|
626 |
|
627 B_A = 8 * static_cast<TReal>( ( iCumNumOctetsSent - |
|
628 iCumNumOctetsSent_last ) ) / timeBetweenRRs; |
|
629 iRtcpStats.iRtcpReceiverStats.iTxBandwidth = static_cast<TUint32>( B_A ); |
|
630 |
|
631 avgPacketSize = static_cast<TReal>( iCumNumOctetsSent )/ packetsSent; |
|
632 |
|
633 /* The fraction lost is the fractional part of a decimal value between 0 |
|
634 * and 1 (the fixed point is at the left edge of this value. The decimal |
|
635 * equivalent can be computed by dividing by 255. */ |
|
636 N_B = static_cast<TInt>( |
|
637 ( lastRecvd_i - lastRecvd_k ) * ( 1 - ( fracLost_i / 255.0 ) ) ); |
|
638 |
|
639 B_B = 8 * ( avgPacketSize * N_B ) / timeBetweenRRs; |
|
640 |
|
641 iRtcpStats.iRtcpReceiverStats.iBandwidth = static_cast<TUint32>( B_B ); |
|
642 } |
|
643 |
|
644 // --------------------------------------------------------------------------- |
|
645 // TUint32 CRtpTranStream::RtpStreamSyncGetRoundTripDelay() |
|
646 // It is transmission stream's duty to calculate round trip delay. |
|
647 // --------------------------------------------------------------------------- |
|
648 // |
|
649 TUint32 CRtpTranStream::RtpStreamSyncGetRoundTripDelay( |
|
650 TUint32 aLastSRTimeStamp, TUint32 aDelaySinceLSR ) |
|
651 { |
|
652 TInt roundTripDelay = 0; |
|
653 TRtpTimeStamp currentNTP; |
|
654 TUint32 gtTime = TRtpUtil::GtGetTime(); |
|
655 TUint32 diffFraction = ( gtTime - iSyncInfo.iLastUpdateLocalTime ) |
|
656 % KTenthOfmsPerSecond; |
|
657 |
|
658 if ( aLastSRTimeStamp != 0 ) |
|
659 { |
|
660 // calculate current NTP in a 16+16 bit precision |
|
661 // (same format as lastSRTimeStamp) |
|
662 currentNTP = ( ( iSyncInfo.iNTPTimeStampSec + |
|
663 ( gtTime - iSyncInfo.iLastUpdateLocalTime ) |
|
664 / KTenthOfmsPerSecond ) << 16 ); |
|
665 currentNTP += static_cast<TUint32>( ( diffFraction << 16 ) |
|
666 / KTenthOfmsPerSecond ); |
|
667 |
|
668 roundTripDelay = currentNTP - aLastSRTimeStamp - aDelaySinceLSR; |
|
669 if ( roundTripDelay > 0 ) |
|
670 { |
|
671 // 16-MSB of roundTripDelay are seconds, 16-LSB of roundTripDelay |
|
672 // is the fraction part. Transform this to a decimal value |
|
673 // representing the round trip delay in tenths of millisecons |
|
674 // ( 10^4 ). See RFC 3550 page 34 for details. |
|
675 roundTripDelay = ( static_cast<TUint32>( roundTripDelay ) >> 16 ) * |
|
676 KTenthOfmsPerSecond + |
|
677 ( ( ( roundTripDelay & 0xFFFF ) * |
|
678 KTenthOfmsPerSecond ) >> 16 ); |
|
679 } |
|
680 else |
|
681 { |
|
682 // here we assume the delay is so small that we cannot get |
|
683 // an accurate reading |
|
684 roundTripDelay = 0; |
|
685 } |
|
686 } |
|
687 |
|
688 return static_cast<TUint32>( roundTripDelay ); |
|
689 } |
|
690 |
|
691 //end of file |
|
692 |
|
693 |