os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/AudioBufferArray.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 "AudioBufferArray.h"
    17 #include "BtSBCFrameParameters.h"
    18 #include "A2dpCodecUtilities.h"
    19 
    20 /**
    21 Audio Buffer Array Panics
    22 **/
    23 enum TAudioBufferArrayPanic
    24 	{
    25 	EAudioBufferArrayIncompleteFrame, //0
    26 	EAudioBufferArrayMiscount, //1
    27 	EAudioBufferArrayNonA2dpDataType, //2
    28 	EAudioBufferArrayNoRTPPacketsPerAudioBuffer //3
    29 	};
    30 
    31 
    32 static void Panic(TAudioBufferArrayPanic aPanic)
    33 // Panic client
    34 	{
    35 	_LIT(KAudioBufferArrayPanicName, "A2DP Audio Buf Panic");
    36 	User::Panic(KAudioBufferArrayPanicName, aPanic);
    37 	}
    38 	
    39 
    40 /**
    41 Creates a CRtpSendPackets array of RRtpSendPackets
    42 
    43 @param aRtpSendSource
    44 @param aNumberOfPackets this is the number of RRtpSendPackets stored in
    45 the array
    46 */	
    47 CRtpSendPackets* CRtpSendPackets::NewL(RRtpSendSource& aRtpSendSource, TUint aNumberOfPackets)
    48 	{
    49 	CRtpSendPackets* self = new (ELeave) CRtpSendPackets ();
    50 	CleanupStack::PushL(self);
    51 	self->ConstructL(aRtpSendSource, aNumberOfPackets);
    52 	CleanupStack::Pop(self);
    53 	return self;
    54 	}
    55 
    56 	
    57 void CRtpSendPackets::ConstructL(RRtpSendSource& aRtpSendSource, TUint aNumberOfPackets)
    58 	{
    59 	// create all the RTP send packets now	
    60 	TInt err = KErrNone;
    61 	for (TInt i=0; i<aNumberOfPackets; i++)
    62 		{
    63 		RRtpSendPacket sendPacket = aRtpSendSource.NewSendPacketL();
    64 		err = iRtpSendPackets.Append(sendPacket);
    65 		if (err)
    66 			{//probably run out of memory so need to close the packets
    67 			CloseAndResetSendPackets();
    68 			User::Leave(err);
    69 			}
    70 		}
    71 	}
    72 
    73 	
    74 CRtpSendPackets::~CRtpSendPackets()
    75 	{
    76 	CloseAndResetSendPackets();
    77 	}
    78 
    79 
    80 void CRtpSendPackets::CloseAndResetSendPackets()
    81 	{
    82 	// destroy all the RTP send packets now
    83 	TUint numberOfSendPackets = iRtpSendPackets.Count();
    84 	for (TInt i=0; i<numberOfSendPackets; i++)
    85 		{
    86 		RRtpSendPacket& p = iRtpSendPackets[i];
    87 		p.Close();
    88 		}
    89 	iRtpSendPackets.Reset();
    90 	}
    91 
    92 /**
    93 Creates  a FIFO array of audio buffers stored as CRtpSendPackets
    94 The paramers passed in are used to determine the size and number
    95 of RTP packets required to store an audio buffer
    96 The payload size on aRtpSendSource is set.
    97 
    98 @param aRtpSendSource used to create the send packets that contain
    99 the audio buffers.  The payload size is set on the aRtpSendSource to
   100 a value calculated from the other parameters
   101 @param aNumberOfAudioBuffers this is the number of audio buffers
   102 stored in the FIFO
   103 @param aAudioBufferLength this is the length of the audio buffer that needs
   104 to be sent to the headset ie buffer size after SBC processing in the case of SBC
   105 @param aMTULength this is the max data length allowing for the restriction imposed
   106 by the underlying MTU bearer ie bluetooth and the headset.
   107 @param aTotalRTPHeaderLength the RTP header length including the 
   108 RTP media payload header ie RTP header length + media payload header length
   109 @param aFrameLength 
   110 */	
   111 CAudioBufferArray* CAudioBufferArray::NewL(RRtpSendSource& aRtpSendSource, 
   112 									TUint aNumberOfAudioBuffers, 
   113 									TUint aAudioBufferLength, 
   114 									TUint aMTULength, 
   115 								    TUint aTotalRTPHeaderLength,
   116 									TUint aFrameLength)
   117 	{
   118 	CAudioBufferArray* self = new (ELeave) CAudioBufferArray();
   119 	CleanupStack::PushL(self);
   120 	self->ConstructL(aRtpSendSource, aNumberOfAudioBuffers, aAudioBufferLength, aMTULength, aTotalRTPHeaderLength, aFrameLength);
   121 	CleanupStack::Pop(self);
   122 	return self;
   123 	}
   124 
   125 
   126 void CAudioBufferArray::ConstructL(RRtpSendSource& aRtpSendSource,
   127 						TUint aNumberOfAudioBuffers,
   128 						TUint aAudioBufferLength,
   129 						TUint aMTULength,
   130 						TUint aTotalRTPHeaderLength,
   131 						TUint aFrameLength)
   132 	{
   133 	//the buffer should always contain an intiger number of audio frames
   134 	//the following ASSERT_DEBUG should be present but is commented out as the RVCT 
   135 	//compiler generates a warning
   136 	//__ASSERT_DEBUG(!(aAudioBufferLength%aFrameLength),EAudioBufferArrayIncompleteFrame);
   137 	
   138 	//calculate the number of frames in the audio buffer size and if 
   139 	//more than 15 frames then calculate the highest common factor and use this 
   140 	//calculate the frames length
   141 	iFrameLength = aFrameLength;
   142 
   143 	//calculate the total number of frames in the buffer
   144 	TUint numberOfFramesPerAudioBuffer = aAudioBufferLength/iFrameLength;
   145 	//for now set the number of audio frames in an RTP packet to the total
   146 	iNumberOfFramesPerRtpPacket = numberOfFramesPerAudioBuffer;
   147 	
   148 	TUint lengthOfAudioDataInRtpPacket = 0;
   149 	TInt usableRTPPayloadLength = aMTULength-aTotalRTPHeaderLength;
   150 	
   151 	//check whether all the audio frames will actually fit into one RTP packet
   152 	if ((numberOfFramesPerAudioBuffer > KMaxNumberOfSBCFramesPerRTPPacket)||((aAudioBufferLength+iFrameLength)>usableRTPPayloadLength))//+iFrameLength in case of cached frame
   153 		{
   154 		//we cannot get all the audio frames into a single RTP packet
   155 		//for SBC only a max of 15 SBC frames allowed per packet
   156 		//if the buffer size exceeds 15 frames and/or is too large
   157 		//for the underlying MTU size then we need to break
   158 		//the buffer into buffers of less then 16 frames.
   159 		//for non SBC the frames are generaly larger so we'll keep
   160 		//the 15 for now even for non SBC
   161 		//we need to calculate how may frames should go into
   162 		//each RTP packet and how many RTP packets we need to send a
   163 		//complete audio buffer
   164 		//we are going to calculate such that every RTP packet
   165 		//has the same number of frames
   166 		//note that if we are using non SBC then the frame size tends to be larger
   167 		//so the MTU limit is likely to be the dominant factor
   168 		//although in principle this code should only use the 15 frame limit for
   169 		//for SBC
   170 		iNumberOfFramesPerRtpPacket = 0; 
   171 		
   172 		
   173 		//only a max of 15 SBC frames allowed per packet
   174 		//if the buffer size exceeds 15 frames then we need to break
   175 		//the buffer into buffers of less then 16 frames.
   176 		//so find HCF 
   177 		//-1 for cached frames ie if iNumberOfFramesPerRtpPacket
   178 		//was the same as KMaxNumberOfSBCFramesPerRTPPacket and we got a cached frame
   179 		//then we would blow the limit
   180 		for (TUint i=KMaxNumberOfSBCFramesPerRTPPacket-1; i; i--)
   181 			{
   182 			if (!(numberOfFramesPerAudioBuffer%i))
   183 				{
   184 				//check we don't blow the MTU size
   185 				if ((i*iFrameLength) <= usableRTPPayloadLength)
   186 					{
   187 					iNumberOfFramesPerRtpPacket = i;
   188 					break;
   189 					}
   190 				}
   191 			}
   192 		if (!iNumberOfFramesPerRtpPacket)
   193 			{//the frame length was too big for the MTU length
   194 			//one frame of audio + one frame of cached audio
   195 			//would exceed the length supported by the underlying bearer
   196 			//note that the A2DP specification section 4.3.4 does allow
   197 			//SBC frames to be fragmented across multiple packets if
   198 			//less than one frame, but this ref implementation
   199 			//does not support this, since this should be rare.
   200 			//this may happen more often for non SBC eg mp3 frames
   201 			//but we don't support fragmented frames
   202 			User::Leave(KErrTooBig);
   203 			}
   204 		iNumberOfRtpPacketsPerAudioBuffer = numberOfFramesPerAudioBuffer/iNumberOfFramesPerRtpPacket;
   205 		
   206 		//this could probably be optimized somewhat such that the
   207 		//iInputBytesPerRtpPacket value was such that no caching was required 
   208 		//in the codec
   209 		
   210 		if (!iNumberOfRtpPacketsPerAudioBuffer)//this isn't really necessary or could be ASSERT but needed supress armv5 compiler warning
   211 			{
   212 			Panic(EAudioBufferArrayNoRTPPacketsPerAudioBuffer);
   213 			}
   214 			
   215 		iInputBytesPerRtpPacket = aAudioBufferLength/iNumberOfRtpPacketsPerAudioBuffer;
   216 		if (iInputBytesPerRtpPacket%2)
   217 			{//we have an odd number of bytes
   218 			iInputBytesPerRtpPacket++;//round up to next byte
   219 			}
   220 		lengthOfAudioDataInRtpPacket = iNumberOfFramesPerRtpPacket*iFrameLength;
   221 		}//if ((numberOfFramesPerAudioBuffer > KMaxNumberOfSBCFramesPerRTPPacket)||((encodedAudioBufferLength+iFrameLength)>aMaxMTULength))
   222 	else
   223 		{//we can fit the entire buffer in one RTP packet
   224 		iNumberOfRtpPacketsPerAudioBuffer = 1;
   225 		iInputBytesPerRtpPacket = aAudioBufferLength;
   226 		lengthOfAudioDataInRtpPacket = aAudioBufferLength;
   227 		}
   228 
   229 	TUint payloadSize = aTotalRTPHeaderLength+lengthOfAudioDataInRtpPacket+iFrameLength;//+ extra framelength for cached frames
   230 	aRtpSendSource.SetDefaultPayloadSize(payloadSize);
   231 	
   232 	//now we have set the payload size we can create the audio buffers
   233 	//stored as CRtpSendPackets* 
   234 	for (TInt i=0; i<aNumberOfAudioBuffers; i++)
   235 		{
   236 		CRtpSendPackets* sendPacketArray = CRtpSendPackets::NewL(aRtpSendSource, iNumberOfRtpPacketsPerAudioBuffer);
   237 		User::LeaveIfError(iAudioBufferArray.Append(sendPacketArray));
   238 		}
   239 	}
   240 
   241 	
   242 CAudioBufferArray::~CAudioBufferArray()
   243 	{
   244 	// destroy all the audio buffers now
   245 	TUint numberOfAudioBuffers = iAudioBufferArray.Count();
   246 	for (TInt i=0; i<numberOfAudioBuffers; i++)
   247 		{
   248 		CRtpSendPackets* sendPacketArray = iAudioBufferArray[i];
   249 		delete sendPacketArray;
   250 		}
   251 	iAudioBufferArray.Close();
   252 	}
   253 
   254 
   255 /**
   256 This function is called when the current audio buffer has been filled
   257 with audio and is in a state to be sent to the headset
   258 The function updates the next audio buffer to fill to the next 
   259 available free audio buffer
   260 */
   261 void CAudioBufferArray::CurrentAudioBufferReadyToSend()
   262 	{
   263 	iNextAudioBufferToFill++;
   264 	if (iNextAudioBufferToFill >= iAudioBufferArray.Count())
   265 		{
   266 		iNextAudioBufferToFill = 0;
   267 		}
   268 	iNumberOfReadyAudioBuffers++;
   269 	__ASSERT_DEBUG((iNumberOfReadyAudioBuffers<=iAudioBufferArray.Count()),Panic(EAudioBufferArrayMiscount));
   270 	}
   271 
   272 
   273 /**
   274 This function cancels the most recently filled audio buffer that is ready to send
   275 The audio buffer corresponds to the audio buffer sent in the last CActiveRTPStreamer::Send()
   276 This is used in order to cancel a Send request.
   277 It effectively undoes the operation performed in CurrentAudioBufferReadyToSend()
   278 so CurrentAudioBufferReadyToSend() must have been called at least once prior.
   279 
   280 @param aSendInProgress set to ETrue if an audio buffer is currently being
   281 sent
   282 */
   283 void CAudioBufferArray::CancelMostRecentAudioBuffer(TBool aSendInProgress)
   284 	{
   285 	__ASSERT_DEBUG((iNumberOfReadyAudioBuffers),Panic(EAudioBufferArrayMiscount));
   286 	if ((iNumberOfReadyAudioBuffers == 1) && (aSendInProgress))
   287 		{//then we only have one ready buffer , which is being sent
   288 		//so we want to stop any further sending of the current buffer
   289 		__ASSERT_DEBUG((iAudioBufferBeingSent == iNextAudioBufferToFill),Panic(EAudioBufferArrayMiscount));
   290 		//now we need prevent any further send packets in the current audio buffer being sent
   291 		//the following line of code will force us to move onto the next audio 
   292 		//buffer discarding any RTP packets in the current audio buffer
   293 		//see CurrentSendPacketSent()
   294 		iNextRtpPacketToSend = iNumberOfRtpPacketsPerAudioBuffer-1;
   295 		}
   296 	else if (iNumberOfReadyAudioBuffers)
   297 		{
   298 		if (!iNextAudioBufferToFill)
   299 			{
   300 			iNextAudioBufferToFill = iAudioBufferArray.Count();
   301 			}
   302 		else
   303 			{
   304 			iNextAudioBufferToFill--;
   305 			}
   306 		iNumberOfReadyAudioBuffers--;
   307 		}	
   308 	}
   309 	
   310 
   311 /**
   312 This function flushes the pending send packets that are ready to send.
   313 Only the current send packet is valid
   314 */
   315 void CAudioBufferArray::FlushPendingPackets()	
   316 	{
   317 	//check that we actually have some audio buffers to flush
   318 	if (iNumberOfReadyAudioBuffers > 1)
   319 		{
   320 		if (iAudioBufferBeingSent >= iAudioBufferArray.Count())
   321 			{
   322 			iNextAudioBufferToFill = 0;
   323 			}
   324 		else
   325 			{
   326 			iNextAudioBufferToFill = iAudioBufferBeingSent+1;
   327 			}
   328 		iNumberOfReadyAudioBuffers = 1; //the current send packet
   329 		}
   330 	else if (iNumberOfReadyAudioBuffers == 1)
   331 		{
   332 		//now we need to flush out the send packets in the current audio buffer being sent
   333 		//the following line of code will force us to move onto the next audio 
   334 		//buffer discarding any RTP packets in the current audio buffer
   335 		//see CurrentSendPacketSent()
   336 		iNextRtpPacketToSend = iNumberOfRtpPacketsPerAudioBuffer-1;
   337 		}
   338 	}
   339 
   340 	
   341 /*
   342 This function returns the current RTP packet to be sent to the headet
   343 if there are no packets that are ready to be sent
   344 ie iNumberOfReadyPackets = 0 then the RRtpSendPacket
   345 will be invalid.
   346 CurrentSendPacketSent() needs to be called when a send packet has been
   347 acknowledged as being sent by the RTP stack
   348 */	
   349 RRtpSendPacket& CAudioBufferArray::CurrentSendPacket()
   350 	{
   351 	CRtpSendPackets* currentSendAudioBuffer = iAudioBufferArray[iAudioBufferBeingSent];
   352 	return currentSendAudioBuffer->Packet(iNextRtpPacketToSend);
   353 	}	
   354 
   355 
   356 /*
   357 This function is called when the RTP module has made the callback indicating that the 
   358 current send packet has been sent.
   359 The function updates the current send packet to the next packet to be sent
   360 
   361 @param aEntireAudioBufferSent this is set to true if the 
   362 current entire audio buffer has been sent.  The RTPStreamer uses
   363 this information to determine whether to complete the send request status
   364 */	
   365 void CAudioBufferArray::CurrentSendPacketSent(TBool& aEntireAudioBufferSent)
   366 	{
   367 	aEntireAudioBufferSent = EFalse;
   368 	if (iNumberOfReadyAudioBuffers)//this could be 0 if the current packet sent was sent and subsequently cancelled
   369 		{
   370 		iNextRtpPacketToSend++;
   371 		if (iNextRtpPacketToSend >= iNumberOfRtpPacketsPerAudioBuffer)
   372 			{//then we have sent all the RTP packets in the current audio buffer
   373 			iNextRtpPacketToSend = 0;
   374 			iAudioBufferBeingSent++; //we've finished with this audio buffer so move onto the next one
   375 			//do something to show we are finished with audio buffer and complete request status
   376 			if (iAudioBufferBeingSent >= iAudioBufferArray.Count())
   377 				{
   378 				iAudioBufferBeingSent = 0;
   379 				}
   380 			iNumberOfReadyAudioBuffers--;
   381 			aEntireAudioBufferSent = ETrue;	
   382 			}		
   383 		}
   384 	//else if iNumberOfReadyAudioBuffers = 0 then the packet must have been canceled so do nothing
   385 	__ASSERT_DEBUG((iNumberOfReadyAudioBuffers<=iAudioBufferArray.Count()),Panic(EAudioBufferArrayMiscount));//check underflow
   386 	}
   387 	
   388 
   389 
   390 
   391 
   392 
   393 
   394 	
   395 
   396 
   397 
   398 
   399 
   400 
   401 	
   402