os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/RTPStreamer.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <bluetoothav.h>
    17 #include <mmf/server/mmfcodec.h>
    18 #include "mmfSBCCodecImplementationUIDs.hrh"
    19 #include <hal.h>
    20 #include "A2dpCodecUtilities.h"
    21 #include "AudioBufferArray.h"
    22 #include "RTPStreamer.h"
    23 
    24 
    25 /**
    26 RTP Streamer Panics
    27 **/
    28 enum TRTPStreamerPanic
    29 	{
    30 	ERTPStreamerSendPacketMiscount, //0
    31 	ERTPStreamerSendNotCompleted, //1
    32 	ERTPStreamerEmptyBuffer, //2
    33 	ERTPStreamerRTPEventError, //3
    34 	ERTPStreamerIncompleteSBCFrame, //4
    35 	ERTPStreamerUnexpectedEvent, //5
    36 	ERTPStreamerBufferProcessingLengthMismatch, //6
    37 	ERTPStreamerInvalidDataType, //7
    38 	ERTPStreamerNoConfiguration //8
    39 	};
    40 
    41 
    42 static void Panic(TRTPStreamerPanic aPanic)
    43 // Panic client
    44 	{
    45 	_LIT(KRTPStreamerPanicName, "RTP Streamer");
    46 	User::Panic(KRTPStreamerPanicName, aPanic);
    47 	}
    48 	
    49 	
    50 
    51 /**
    52 Creates CActiveRTPStreamer
    53 
    54 @param aSock RSocket that can be used to stream audio to the headset
    55 @param aRTPStreamObserver mixin used to inform the CA2dpBTHeadsetAudioInterface
    56 of asynchronous error events
    57 @return CActiveRTPStreamer*
    58 */
    59 CActiveRTPStreamer* CActiveRTPStreamer::NewL(RSocket& aSock, MRTPStreamerObserver& aRTPStreamerObserver)
    60 	{
    61 	CActiveRTPStreamer* self = new (ELeave) CActiveRTPStreamer (aRTPStreamerObserver);
    62 	CleanupStack::PushL(self);
    63 	self->ConstructL(aSock);
    64 	CleanupStack::Pop(self);
    65 	return self;
    66 	}
    67 
    68 
    69 /**
    70 Make priortiy high so other RunLs don't impact CTimer accuracy too much
    71 */
    72 CActiveRTPStreamer::CActiveRTPStreamer(MRTPStreamerObserver& aRTPStreamerObserver) : CTimer(EPriorityHigh), iRTPStreamerObserver(aRTPStreamerObserver), iRtpCanSend(ETrue)
    73 	{
    74 	CActiveScheduler::Add(this);
    75 	}
    76 
    77 
    78 CActiveRTPStreamer::~CActiveRTPStreamer()
    79 	{
    80 	Cancel();
    81 	delete iAudioBufferArray;
    82 	
    83 	//RTP defect fix DEF57144- RRtpSendSource Cancel()
    84 	//If the line of code below does not compile then your build is too old
    85 	iRTPSendSource.Cancel();
    86 	
    87 	iRTPSendSource.Close();	
    88 	iRTPSession.Close();	
    89 	}
    90 
    91 
    92 void CActiveRTPStreamer::ConstructL(RSocket& aSock)
    93 	{
    94 	CTimer::ConstructL();
    95 	// get the MTU length limit
    96 	TInt mtu = 0;
    97 	User::LeaveIfError(aSock.GetOpt(EAvdtpMediaGetMaximumPacketSize, KSolBtAVDTPMedia, mtu));
    98 	iMaxMTULength = mtu;//the line above wont accept iMaxMTULength directly because it is unsigned
    99 	iRTPSession.OpenL(aSock, iMaxMTULength);
   100 	iRTPSendSource = iRTPSession.NewSendSourceL();
   101 	
   102 	//register callbacks - all terminal callbacks are one shot
   103 	iRTPSession.RegisterEventCallbackL(ERtpAnyEvent,RTPCallback,this);									
   104 	iRTPSession.RegisterEventCallbackL(ERtpSessionFail,RTPCallback,this, ERtpOneShot);
   105 	iRTPSession.RegisterEventCallbackL(ERtpBufferOverflow,RTPCallback,this);
   106 	iRTPSession.RegisterEventCallbackL(ERtpUndersizedPacket,RTPCallback,this);
   107 	iRTPSendSource.RegisterEventCallbackL(ERtpAnyEvent,RTPSendSourceCallback,this);
   108 	iRTPSendSource.RegisterEventCallbackL(ERtpSendFail,RTPSendSourceCallback,this, ERtpOneShot);
   109 	}
   110 
   111 
   112 /**
   113 Function called by the CA2dpBTHeadsetAudioInterface to set the codec and the codec
   114 settings used by the CActiveRTPStreamer.
   115 Calling this function forces a recalculation of all the timings the next
   116 time Send() is called
   117 
   118 @param aCodec the codec to be used.  If this is set to NULL then no codec is used
   119 only the CSBCCodec can be used here
   120 @param aConfigType a Uid to identify the aConfigData used to configure the settings
   121 only KMmfUidSBCConfigure is currently defined.  In future other types may be defined
   122 for mp3, AAC and ATRAC3
   123 @param aConfigData The configuration data
   124 @return standard SymbianOS error code
   125 */
   126 void CActiveRTPStreamer::SetCodec(CMMFCodec& aCodec)
   127 	{
   128 	//if there is a codec then it must be SBC else codec must be on the headset
   129 	iCodec = &aCodec;
   130 	}
   131 
   132 
   133 void CActiveRTPStreamer::SetAudioConfiguration(const CA2dpAudioCodecConfiguration& aAudioCodecConfiguration)
   134 	{
   135 	iA2dpAudioCodecConfiguration = const_cast<CA2dpAudioCodecConfiguration*>(&aAudioCodecConfiguration);
   136 	//if there is a new codec configuration then cannot assume the buffer 
   137 	//length will be the same so reset
   138 	iBufferLength = 0;
   139 	iBufferParamsInitialized = EFalse;//will result in a call to InitializeForSendL
   140 	iTimeStampIncrement = 0;
   141 	iNumberOfInputBytesToMakeRTPPacket = 0;
   142 	}
   143 
   144 /**
   145 Internal function to perform frame size related initialization
   146 ie creation and setting of the RTPSendPacket audio buffer array.
   147 Assumes all buffers are the same size (except for the last buffer)
   148 
   149 @param The length of the audio buffer sent in Send()
   150 */
   151 void CActiveRTPStreamer::InitializeForSendL(const TDesC8& aData)
   152 	{
   153 	iSendBufferSize = aData.Size(); //store buffer length - this shouldn't change till the last buffer
   154 	__ASSERT_DEBUG(iSendBufferSize,Panic(ERTPStreamerEmptyBuffer));
   155 	__ASSERT_DEBUG(iA2dpAudioCodecConfiguration,Panic(ERTPStreamerNoConfiguration));
   156 	TUint encodedBufferSize = iSendBufferSize;
   157 	
   158 	if (iCodec)
   159 		{
   160 		iCodec->ResetL(); //clear out any cached data from previous settings
   161 		//if we are using a local codec - ie SBC then we get the frame length 
   162 		//and bit rate from the local codec settings
   163 		//since aData will contain pcm16
   164 		iFrameLength = iA2dpAudioCodecConfiguration->LocalSBCCodecConfiguration().CalcFrameLength();
   165 		iBitRate = iA2dpAudioCodecConfiguration->LocalSBCCodecConfiguration().CalcBitRate(iFrameLength)*1000;//*1000 as bitrate is in KHz
   166 		//if we are putting data through the local SBC codec then 
   167 		//the encoded buffer size sent to the headset in not the same as the aData buffer in Send()
   168 		encodedBufferSize = iA2dpAudioCodecConfiguration->CalculateSBCBufferLength(iSendBufferSize);
   169 		}
   170 	else
   171 		{
   172 		//if we don't use a local codec then we get the frame legth and bit rate
   173 		//direct from the header
   174 		CA2dpCodecFrameHeaderParser* headerParser = CA2dpCodecFrameHeaderParser::NewL(iA2dpAudioCodecConfiguration->HeadsetCodecDataType(), aData);
   175 		iFrameLength = headerParser->FrameLength();
   176 		iBitRate = headerParser->BitRate();
   177 		delete headerParser;
   178 		}
   179 	iPayloadType = TRTPa2dpCodecSpecificUtils::PayloadType(iA2dpAudioCodecConfiguration->HeadsetCodecDataType());	
   180 	
   181 	//if the settings have changed then any existing buffered audio buffers
   182 	// will have the old settings so we need to delete the buffer array
   183 	//and recreate from new with the new settings.
   184 	//we also need to cancel in case we are waiting on a RTPSendSourceCallback
   185 	//from a previous send packet
   186 	//RTP defect fix DEF57144- RRtpSendSource Cancel() not in MCL
   187 	//decomment this out when the Cancel method is on the MCL
   188 	//iRTPSendSource.Cancel();
   189 
   190 	delete iAudioBufferArray;
   191 	iAudioBufferArray = NULL;
   192 	//calculate the size of the RTP header
   193 	TUint mediaPayloadHeaderLength = TRTPa2dpCodecSpecificUtils::MediaPayloadHeaderLength(iA2dpAudioCodecConfiguration->HeadsetCodecDataType());
   194 	TUint rtpHeaderLength = KRTPHeaderSize + mediaPayloadHeaderLength;
   195 	iAudioBufferArray = CAudioBufferArray::NewL(iRTPSendSource, KSendBucketSize, encodedBufferSize, iMaxMTULength, rtpHeaderLength, iFrameLength);
   196 	
   197 	//determine the payload header
   198 	switch(const_cast<TFourCC&>(iA2dpAudioCodecConfiguration->HeadsetCodecDataType()).FourCC())
   199 		{
   200 		case KMMFFourCCCodeSBC:
   201 			iMediaPayloadHeader.Append(iAudioBufferArray->NumberOfFramesPerRtpPacket());
   202 			break;
   203 		case KMMFFourCCCodeMP3:
   204 			//RFC2250-section 3.5 MBZ+Frag_Offset
   205 			//= 4 bytes all set to 0
   206 			iMediaPayloadHeader.FillZ(4); //0000
   207 			break;
   208 		case KMMFFourCCCodeAAC:
   209 			break;
   210 		case KMMFFourCCCodeATRAC3:
   211 			break;
   212 		default:
   213 			//the datatype is a non A2DP datatype
   214 			//which is not supported so panic
   215 			Panic(ERTPStreamerInvalidDataType);
   216 			break;
   217 		}
   218 	
   219 	//get the number of bytes of data sent that was sent to the RTP streamer
   220 	//that make up one RTP packet
   221 	//in the case of a codec this is the value pre codec processing
   222 	if (iCodec)	
   223 		{
   224 		iNumberOfInputBytesToMakeRTPPacket = iSendBufferSize/iAudioBufferArray->NumberOfRtpPacketsPerAudioBuffer();
   225 		if (iNumberOfInputBytesToMakeRTPPacket%2)
   226 			{//we have an odd number of bytes
   227 			iNumberOfInputBytesToMakeRTPPacket++;//round up to next byte
   228 			}
   229 		}
   230 	else
   231 		{
   232 		iNumberOfInputBytesToMakeRTPPacket = iAudioBufferArray->InputBytesPerRTPPacket();
   233 		}
   234 	//else other codecs not supported
   235 	
   236 	//we set the iFrameDuration which is used to trigger the timer
   237 	//this means that RunL should be called every iFrameDuration and
   238 	//if an RTP packet is ready to sent then it shall be sent
   239 	//since there is no control channel back from the headset, the best
   240 	//we can hope for is to send the data at approx the rate the headset 
   241 	//would expect it and hope that the headset provides it's own approriate
   242 	//internal buffering
   243 	//Note that dues to other AOs running the timing is not accurate and
   244 	//usually slower than the specified time - what is really needed
   245 	//here is a feedback loop where the initial time interval is somewhat
   246 	//faster than the calculated time interval and is adjusted against the
   247 	//system clock and bit rate throughput acordingly so the throughput always
   248 	//matches the bit rate.
   249 	iRTPPacketDuration = TTimeIntervalMicroSeconds32(TFrameTimingUtils::FrameDuration(iFrameLength,iBitRate).Int() * iAudioBufferArray->NumberOfFramesPerRtpPacket());
   250 	RDebug::Printf("RTP Packet Duration = %d mS", iRTPPacketDuration.Int());
   251 	TInt fastCounterFrequency;
   252 	HAL::Get(HALData::EFastCounterFrequency,fastCounterFrequency);
   253 	RDebug::Printf("sys clock timing frequency = %d Hz", fastCounterFrequency);
   254 	iTimeStampIncrement = TFrameTimingUtils::TimeStampIncrementPerFrame(iA2dpAudioCodecConfiguration->HeadsetCodecDataType(), iFrameLength, iBitRate, iA2dpAudioCodecConfiguration->SampleRate())
   255 						 * iAudioBufferArray->NumberOfFramesPerRtpPacket();	
   256 	RDebug::Printf("Calculated RTP packet time stamp increment = %d",iTimeStampIncrement);
   257 	RDebug::Printf("FrameLength = %d", iFrameLength);
   258 	RDebug::Printf("Calculated bitRate = %d", iBitRate);
   259 	RDebug::Printf("Number of frames per RTP packet = %d", iAudioBufferArray->NumberOfFramesPerRtpPacket());
   260 	RDebug::Printf("Number of RTP packets per audio buffer = %d", iAudioBufferArray->NumberOfRtpPacketsPerAudioBuffer());
   261 	RDebug::Printf("Sample rate = %d", iA2dpAudioCodecConfiguration->SampleRate());
   262 	}
   263 	
   264 
   265 /**
   266 Internal function to pass the pcm16 audio data in aData and use the codec
   267 to process the data back in aPayload
   268 
   269 @return the number of source bytes processed
   270 */
   271 TUint CActiveRTPStreamer::CodecProcessPayloadL(const TDesC8& aData,TDes8& aPayload)
   272 	{
   273 	TPtr8 srcBufferPtr(const_cast<TUint8*>(aData.Ptr()),aData.Length());
   274 	srcBufferPtr.SetLength(aData.Length());
   275 	//+1 -1 to skip SBC media payload header
   276 	TPtr8 dstBufferPtr(const_cast<TUint8*>(aPayload.Ptr()+1),aPayload.MaxLength()-1);
   277 	CMMFPtrBuffer* srcBuffer = CMMFPtrBuffer::NewL(srcBufferPtr);
   278 	CleanupStack::PushL(srcBuffer);
   279 	CMMFPtrBuffer* dstBuffer = CMMFPtrBuffer::NewL(dstBufferPtr);
   280 	CleanupStack::PushL(dstBuffer);
   281 	TCodecProcessResult result = iCodec->ProcessL(*srcBuffer,*dstBuffer);
   282 	if (result == 	TCodecProcessResult::EProcessIncomplete)
   283 		{
   284 		User::Leave(KErrArgument);
   285 		}
   286 	aPayload.Append(dstBuffer->Data());
   287 	CleanupStack::PopAndDestroy(dstBuffer);
   288 	CleanupStack::PopAndDestroy(srcBuffer);
   289 	return result.iSrcBytesProcessed;
   290 	}
   291 
   292 
   293 /**
   294 This is the main function for CActiveRTPStreamer in that it is the 
   295 function used to send data to the headset over RTP.
   296 The function is asynchronous to the RunL which does the actual sending.
   297 The data is stored in the CRtpSendPackets FIFO and will be sent at the 
   298 next RunL provided the RTP can accept the data.  If not it just stays
   299 buffered in the CRtpSendPackets FIFO until it can be sent.
   300 The request status is completed when the buffer is stored, not when it is sent
   301 this is to more closely mimic the behaviour of the sound driver.
   302 If adding the buffer to the CRtpSendPackets FIFO causes it to be full
   303 then the request status won't be completed until there is space in the FIFO
   304 which won't be until a callback from the RTP stack has been received 
   305 indicating that the CRtpSendPackets FIFO can now discard that entry.
   306 Only one Send at a time is accepted ie the request status
   307 of the previous send must be completed before Send can be called again.
   308 To simplify the software and improve performance, fixed sized buffers are assumed.ie
   309 the buffer length is only calculated once on the first frame and when the settings
   310 change.
   311 
   312 @param aData  The data to be sent to the headset. This may go via 
   313 a codec eg if the data is pcm16 or sent directly to the headset if the data is SBC,mp3,AAC,ATRAC3
   314 It is the responsibility of the client ie CA2dpBTHeadsetAudioInterface to
   315 call SetCodecConfiguration first.
   316 
   317 @param aStatus
   318 */
   319 void CActiveRTPStreamer::Send(const TDesC8& aData, TRequestStatus& aStatus)
   320 	{
   321 	if (iSendStatus)
   322 		{
   323 		__ASSERT_DEBUG((*iSendStatus != KRequestPending),Panic(ERTPStreamerSendNotCompleted));
   324 		}
   325 	iSendStatus = &aStatus;
   326 	*iSendStatus = KRequestPending;
   327 	
   328 	if (iUnrecoverableError)
   329 		{
   330 		User::RequestComplete(iSendStatus,iUnrecoverableError);
   331 		return;
   332 		}
   333 		
   334 	if (!iBufferParamsInitialized)
   335 		{
   336 		TRAPD(err,InitializeForSendL(aData));
   337 		if (err)
   338 			{
   339 			User::RequestComplete(iSendStatus,err);
   340 			return;
   341 			}
   342 		iBufferParamsInitialized = ETrue;
   343 		}
   344 		
   345 	TUint numberOfRtpPacketsPerAudioBuffer = iAudioBufferArray->NumberOfRtpPacketsPerAudioBuffer();	
   346 
   347 	if (aData.Size() != iSendBufferSize)
   348 		{
   349 		//then we are on the last buffer
   350 		//in which case we need to recalculate the number of Rtp packets
   351 		//required to make up the audio frame since the last buffer
   352 		//is smaller.
   353 		TUint lastBufferLength = aData.Size();
   354 		if (iCodec)
   355 			{
   356 			lastBufferLength = iA2dpAudioCodecConfiguration->CalculateSBCBufferLength(aData.Size());
   357 			}
   358 		//we keep the same number of RTP packets per audio buffer as before
   359 		TUint numberOfSBCFramesInLastBuffer = lastBufferLength/iFrameLength;
   360 		TUint numberOfFramesPerRtpPacket = iAudioBufferArray->NumberOfFramesPerRtpPacket();
   361 		
   362 		//the devisor below may not always devide without a remainder
   363 		//which means the last Rtp packet sent will not be full
   364 		//if we have a remainder then we need another Rtp packet
   365 		numberOfRtpPacketsPerAudioBuffer = numberOfSBCFramesInLastBuffer/numberOfFramesPerRtpPacket;
   366 		if (numberOfSBCFramesInLastBuffer%numberOfFramesPerRtpPacket)
   367 			{
   368 			numberOfRtpPacketsPerAudioBuffer++;
   369 			}
   370 		}
   371 
   372 		
   373 	CRtpSendPackets* sendPackets = iAudioBufferArray->CurrentAudioBufferRtpSendPackets();
   374 	TUint srcBytesProcessed = 0;
   375 	for (TUint i=0; i<numberOfRtpPacketsPerAudioBuffer;i++)
   376 		{
   377 		RDebug::Printf("NewRTPPacketReceived %d",User::FastCounter());
   378 		RRtpSendPacket& sendPacket = sendPackets->Packet(i);
   379 		sendPacket.SetPayloadType(iPayloadType);
   380 		sendPacket.SetTimestamp(iTimeStamp);
   381 		iTimeStamp += iTimeStampIncrement;
   382 		TDes8& payload = sendPacket.WritePayload();
   383 		payload.Zero();
   384 		payload.Append(iMediaPayloadHeader);
   385 			
   386 		//aData may have to be sent as multiple packets
   387 		TUint8* sourceDataOffset = const_cast<TUint8*>(aData.Ptr())+srcBytesProcessed;
   388 		TPtr8 srcBufferPtr(sourceDataOffset,iNumberOfInputBytesToMakeRTPPacket);
   389 		TUint srcBytesStillRemaining = aData.Size() - srcBytesProcessed;
   390 		TUint lengthOfsrcBuffer = iNumberOfInputBytesToMakeRTPPacket;
   391 		if (srcBytesStillRemaining < lengthOfsrcBuffer )
   392 			{//probably a last buffer condition or modulo 2 pcm16 rounding condition
   393 			lengthOfsrcBuffer = srcBytesStillRemaining;
   394 			}
   395 		srcBufferPtr.SetLength(lengthOfsrcBuffer);
   396 		
   397 		//sanity check - the following should always be true
   398 		__ASSERT_DEBUG((srcBytesProcessed == iNumberOfInputBytesToMakeRTPPacket*i),Panic(ERTPStreamerBufferProcessingLengthMismatch));
   399 				
   400 		if (iCodec)
   401 			{
   402 			TRAPD(err,srcBytesProcessed += CodecProcessPayloadL(srcBufferPtr,payload));
   403 			if (err)
   404 				{
   405 				//something has gone wrong so abort streaming
   406 				User::RequestComplete(iSendStatus,err);
   407 				return;
   408 				}
   409 			}
   410 		else //no need to process via codec - aData can go straight to the headset
   411 			{
   412 			srcBytesProcessed +=lengthOfsrcBuffer;
   413 			payload.Append(srcBufferPtr);
   414 			}
   415 		}//	for (TUint i=0; i<iAudioBufferArray->NumberOfRtpPacketsPerAudioBuffer();i++)
   416 	iAudioBufferArray->CurrentAudioBufferReadyToSend();
   417 	//else we have no more send packets so cannot complete request status
   418 	//until one of the send packets has been sent and acknowledged.
   419 
   420 
   421 	//we'll send an event to ourselves and either send the packet if we can
   422 	//we could complete the iSendStatus TRequestStatus here before returing 
   423 	//from the Send but we won't in order to more closely mimic the existing
   424 	// sound driver PlayData behaviour
   425 	//if there is already a request active then it will be the timer
   426 	//ie this will effectively kick things off if the timer is not running
   427 	TRequestStatus* stat = &iStatus;
   428 	if (!IsActive())
   429 		{
   430 		User::RequestComplete(stat, KErrNone);
   431 		SetActive();
   432 		}			
   433 	}
   434 
   435 
   436 /**
   437 Function to stop further internally buffered packets being sent to the headset
   438 */	
   439 void CActiveRTPStreamer::Pause()
   440 	{
   441 	iPaused = ETrue;
   442 	Cancel();
   443 	}
   444 
   445 
   446 /**
   447 Function called after pause to resume sending buffers to the headset
   448 */	
   449 void CActiveRTPStreamer::Resume()
   450 	{
   451 	if (iPaused)
   452 		{
   453 		iPaused = EFalse;
   454 		TRequestStatus* stat = &iStatus;
   455 		if (!IsActive())
   456 			{
   457 			User::RequestComplete(stat, KErrNone);
   458 			SetActive();
   459 			}
   460 		}
   461 	}
   462 
   463 
   464 /**
   465 Function called from  CA2dpBTHeadsetAudioInterface::CancelPlayData()
   466 Used to cancel an outstanding status request for a Send()
   467 */
   468 void CActiveRTPStreamer::CancelLastSendBuffer()
   469 	{
   470 	if (iSendStatus)
   471 		{
   472 		if (*iSendStatus == KRequestPending)//make sure there is a pending request to cancel
   473 			{
   474 			iAudioBufferArray->CancelMostRecentAudioBuffer(!iRtpCanSend);
   475 			User::RequestComplete(iSendStatus, KErrCancel);
   476 			}
   477 		}
   478 	}
   479 	
   480 
   481 /**
   482 Function to flush out the bufferes stored in CRtpSenPackets
   483 */
   484 void CActiveRTPStreamer::FlushPendingSendBuffers()
   485 	{
   486 	iAudioBufferArray->FlushPendingPackets();
   487 	
   488 	if(iCodec)
   489 		{//flush out codec cache
   490 		TRAP_IGNORE(iCodec->ResetL());
   491 		}
   492 	}
   493 
   494 	
   495 /**
   496 Function to return total number of bytes sent prior to codec processing
   497 ie bytes of pcm16 not SBC
   498 Note this the number of bytes sent is only updated when the packet
   499 has been acknowledged as being sent correctly by the RTP stack
   500 ie this value will always be slightly less than the bytes sent in Send()
   501 */
   502 TUint CActiveRTPStreamer::BytesSent() const
   503 	{
   504 	return iBytesSent;
   505 	}
   506 
   507 
   508 /**
   509 Function to reset the number of bytes sent
   510 */	
   511 void CActiveRTPStreamer::ResetBytesSent()
   512 	{
   513 	iBytesSent = 0;
   514 	}
   515 
   516 
   517 /**
   518 The RunL is called every frame duration interval.
   519 It checks to see if there are any packets to be sent to the headset
   520 and if so send it.
   521 One issue to be resolved at integration testing is if there are no packets
   522 to send then this is analogous to a KErrUnderflow condition on the 
   523 sound driver. Do we need to mimic this behaviour for the a2dp interface?
   524 
   525 The Send request status is completed if there is room in the CRtpSendPackets
   526 for another buffer.
   527 */	
   528 void CActiveRTPStreamer::RunL()
   529 	{
   530 	if ((iPaused)||(!iAudioBufferArray))
   531 		{
   532 		return;
   533 		}
   534 		
   535 	if(iRtpCanSend && iAudioBufferArray->NumberOfAudioBuffersReadyToSend())
   536 		{
   537 		RRtpSendPacket& sendPacket = iAudioBufferArray->CurrentSendPacket();
   538 		sendPacket.Send();
   539 		iRtpCanSend = EFalse; //have to wait for callback before we can send again
   540 		}
   541 
   542 	if (iSendStatus)
   543 		{
   544 		if ((iAudioBufferArray->NumberOfAudioBuffersReadyToSend() < KSendBucketSize)
   545 	    	&&(*iSendStatus == KRequestPending))
   546 			{//still some free packets to fill so complete request status
   547 			User::RequestComplete(iSendStatus, KErrNone);
   548 			iSendStatus = NULL;
   549 			}
   550 		//else if the iRtpSendPackets FIFO is full then we can't complete
   551 		//the request status until we've had an ERtpSendSucceeded event
   552 		}
   553 		//are there any more buffers that are ready to send?
   554 		//if so then send the next packet after a time delay
   555 		//keep calling this RunL every frame duration till as long as we have packets to send
   556 		//if there are no packets ready to send then we need to wait 
   557 		//for another call to Send();
   558 	if (iAudioBufferArray->NumberOfAudioBuffersReadyToSend()) 
   559 		{//there are packets ready to send so fire off next RunL after one RTP packet duration
   560 		RDebug::Printf("RTPPacket Sent %d",User::FastCounter());
   561 		After(iRTPPacketDuration);
   562 		}
   563 	}
   564 
   565 
   566 /**
   567 Cancel
   568 */	
   569 void CActiveRTPStreamer::DoCancel()
   570 	{
   571 	CTimer::DoCancel();
   572 	CompleteSendRequestStatus(KErrCancel);
   573 	}
   574 
   575 
   576 /**
   577 Utility function to complete Send TRequestStatus with aError
   578 */
   579 void CActiveRTPStreamer::CompleteSendRequestStatus(TInt aError)
   580 	{
   581 	if (iSendStatus)
   582 		{
   583 		if (*iSendStatus == KRequestPending)
   584 			{
   585 			User::RequestComplete(iSendStatus, aError);
   586 			}
   587 		}
   588 	}
   589 
   590 
   591 /**
   592 Called by RTP stack when a packet has been sent
   593 If the packet was sent ok then complete the iSendStatus if it is pending
   594 and update the number of bytes sent
   595 If the packet was not sent ok then the error is regarded as unrecoverable
   596 since this should not happen.  If it does happen then the CA2dpBTHeadsetAudioInterface
   597 is informed.  If there is an outstanding Send TRequestStatus then this is
   598 completed with KErrCommsFrame.  Not sure if this is the most appropriate error code?
   599 */	
   600 void CActiveRTPStreamer::PacketSent(TRtpEventType aEvent)
   601 	{
   602 	if (aEvent == ERtpSendSucceeded)
   603 		{
   604 		RDebug::Printf("Sent RTPPacket Acknowledged %d",User::FastCounter());
   605 		TBool entireAudioBufferSent = EFalse;	
   606 		iAudioBufferArray->CurrentSendPacketSent(entireAudioBufferSent);		
   607 		//check if there is an outstanding send request status
   608 		//we can only complete the send request status if all the
   609 		//RTP packets in the audio buffer have been sent.
   610 		if (entireAudioBufferSent)
   611 			{
   612 			CompleteSendRequestStatus(KErrNone);
   613 			}
   614 		iRtpCanSend = ETrue;
   615 		iBytesSent += iNumberOfInputBytesToMakeRTPPacket;
   616 		}
   617 	else if (aEvent == ERtpSendFail)
   618 		{
   619 		//if we fail to send the packet then chances are something
   620 		//has gone wrong that may not be recoverable
   621 		//so we will complete the request status and halt further streaming
   622 		//some testing may be required to see if it is possible to
   623 		//recover in which case the packet could be sent again
   624 		iUnrecoverableError = KErrCommsFrame;//probably the nearest error code
   625 		CompleteSendRequestStatus(iUnrecoverableError);
   626 		//inform iRTPStreamerObserver ie the CA2dpBTHeadsetAudioInterface
   627 		//this will initiate a GAVDP state machine reset which will destroy the CActiveRTPStreamer 
   628 		iRTPStreamerObserver.RTPStreamerEvent(iUnrecoverableError);
   629 		}
   630 	else 
   631 		{//we've not registered for any other events so this shouldn't happen
   632 		Panic(ERTPStreamerUnexpectedEvent);
   633 		}
   634 	}
   635 	
   636 
   637 /**
   638 Called by RTP stack when some sort of general error has occured
   639 eg switching off the headset, or the headset going out of range 
   640 The CA2dpBTHeadsetAudioInterface is informed. 
   641 */
   642 void CActiveRTPStreamer::RTPSessionEvent(const TRtpEvent& aEvent)
   643 	{
   644 	switch(aEvent.Type())
   645 		{
   646 		case ERtpSessionFail:
   647 			iUnrecoverableError = KErrDisconnected;
   648 			break;
   649 		case ERtpBufferOverflow:
   650 			iUnrecoverableError = KErrOverflow;
   651 			break;
   652 		case ERtpUndersizedPacket:
   653 			iUnrecoverableError = KErrCommsFrame;
   654 			break;
   655 		default:
   656 			Panic(ERTPStreamerRTPEventError); //we haven't registered for anything else
   657 			break;
   658 		}
   659 		
   660 	//complete outstanding Send (CA2dpBTHeadsetAudioInterface::PlayData) request status
   661 	CompleteSendRequestStatus(iUnrecoverableError);		
   662 	//inform CA2dpBTHeadsetAudioInterface
   663 	iRTPStreamerObserver.RTPStreamerEvent(iUnrecoverableError);
   664 	}
   665 
   666 
   667 /**
   668 Static callback from RTP stack
   669 */	
   670 void CActiveRTPStreamer::RTPSendSourceCallback(CActiveRTPStreamer* aStreamer, const TRtpEvent& aEvent)
   671 	{
   672 	__ASSERT_DEBUG((aEvent.IsSendSourceEvent()),Panic(ERTPStreamerRTPEventError));
   673 	__ASSERT_DEBUG((aEvent.SendSource() == aStreamer->iRTPSendSource),Panic(ERTPStreamerRTPEventError));
   674 	// for now assume it was sending complete
   675 	// do next bit
   676 	aStreamer->PacketSent(aEvent.Type());
   677 	}
   678 	
   679 
   680 /**
   681 Static callback from RTP stack
   682 */
   683 void CActiveRTPStreamer::RTPCallback(CActiveRTPStreamer* aStreamer, const TRtpEvent& aEvent)
   684 	{
   685 	__ASSERT_DEBUG((aEvent.IsSessionEvent()),Panic(ERTPStreamerRTPEventError)); 
   686 	__ASSERT_DEBUG((aEvent.Session() == aStreamer->iRTPSession),Panic(ERTPStreamerRTPEventError));
   687 	
   688 	aStreamer->RTPSessionEvent(aEvent);
   689 	}